diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 8af972c..0000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -/gradlew text eol=lf -*.bat text eol=crlf -*.jar binary diff --git a/.gitignore b/.gitignore index d9c14fa..9cf672c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,40 +1,31 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ +# Compiled Elixir/Phoenix artifacts +_build/ +priv/static/cache_manifest.json +tmp/ + +# Elixir dependencies +deps/ + +# Test coverage reports +cover/ + +# Generated documentation +doc/ + +# Crash dumps +erl_crash.dump -**/node_modules -target +# Archive artifacts +*.ez + +# Hex packages +*.tar.gz + +# Node.js/npm dependencies (if using assets with Node.js) +node_modules/ + +# Editor/IDE specific files (examples) +.idea/ +.vscode/ +*.swp +*~ \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7952511 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,301 @@ +This is a web application written using the Phoenix web framework. + +## Project guidelines + +- Use `mix precommit` alias when you are done with all changes and fix any pending issues +- Use the already included and available `:req` (`Req`) library for HTTP requests, **avoid** `:httpoison`, `:tesla`, and `:httpc`. Req is included by default and is the preferred HTTP client for Phoenix apps +### Phoenix v1.8 guidelines + +- **Always** begin your LiveView templates with `` which wraps all inner content +- The `MyAppWeb.Layouts` module is aliased in the `my_app_web.ex` file, so you can use it without needing to alias it again +- Anytime you run into errors with no `current_scope` assign: + - You failed to follow the Authenticated Routes guidelines, or you failed to pass `current_scope` to `` + - **Always** fix the `current_scope` error by moving your routes to the proper `live_session` and ensure you pass `current_scope` as needed +- Phoenix v1.8 moved the `<.flash_group>` component to the `Layouts` module. You are **forbidden** from calling `<.flash_group>` outside of the `layouts.ex` module +- Out of the box, `core_components.ex` imports an `<.icon name="hero-x-mark" class="w-5 h-5"/>` component for for hero icons. **Always** use the `<.icon>` component for icons, **never** use `Heroicons` modules or similar +- **Always** use the imported `<.input>` component for form inputs from `core_components.ex` when available. `<.input>` is imported and using it will will save steps and prevent errors +- If you override the default input classes (`<.input class="myclass px-2 py-1 rounded-lg">)`) class with your own values, no default classes are inherited, so your +custom classes must fully style the input + + + +## Elixir guidelines + +- Elixir lists **do not support index based access via the access syntax** + + **Never do this (invalid)**: + + i = 0 + mylist = ["blue", "green"] + mylist[i] + + Instead, **always** use `Enum.at`, pattern matching, or `List` for index based list access, ie: + + i = 0 + mylist = ["blue", "green"] + Enum.at(mylist, i) + +- Elixir variables are immutable, but can be rebound, so for block expressions like `if`, `case`, `cond`, etc + you *must* bind the result of the expression to a variable if you want to use it and you CANNOT rebind the result inside the expression, ie: + + # INVALID: we are rebinding inside the `if` and the result never gets assigned + if connected?(socket) do + socket = assign(socket, :val, val) + end + + # VALID: we rebind the result of the `if` to a new variable + socket = + if connected?(socket) do + assign(socket, :val, val) + end + +- **Never** nest multiple modules in the same file as it can cause cyclic dependencies and compilation errors +- **Never** use map access syntax (`changeset[:field]`) on structs as they do not implement the Access behaviour by default. For regular structs, you **must** access the fields directly, such as `my_struct.field` or use higher level APIs that are available on the struct if they exist, `Ecto.Changeset.get_field/2` for changesets +- Elixir's standard library has everything necessary for date and time manipulation. Familiarize yourself with the common `Time`, `Date`, `DateTime`, and `Calendar` interfaces by accessing their documentation as necessary. **Never** install additional dependencies unless asked or for date/time parsing (which you can use the `date_time_parser` package) +- Don't use `String.to_atom/1` on user input (memory leak risk) +- Predicate function names should not start with `is_` and should end in a question mark. Names like `is_thing` should be reserved for guards +- Elixir's builtin OTP primitives like `DynamicSupervisor` and `Registry`, require names in the child spec, such as `{DynamicSupervisor, name: MyApp.MyDynamicSup}`, then you can use `DynamicSupervisor.start_child(MyApp.MyDynamicSup, child_spec)` +- Use `Task.async_stream(collection, callback, options)` for concurrent enumeration with back-pressure. The majority of times you will want to pass `timeout: :infinity` as option + +## Mix guidelines + +- Read the docs and options before using tasks (by using `mix help task_name`) +- To debug test failures, run tests in a specific file with `mix test test/my_test.exs` or run all previously failed tests with `mix test --failed` +- `mix deps.clean --all` is **almost never needed**. **Avoid** using it unless you have good reason + + +## Phoenix guidelines + +- Remember Phoenix router `scope` blocks include an optional alias which is prefixed for all routes within the scope. **Always** be mindful of this when creating routes within a scope to avoid duplicate module prefixes. + +- You **never** need to create your own `alias` for route definitions! The `scope` provides the alias, ie: + + scope "/admin", AppWeb.Admin do + pipe_through :browser + + live "/users", UserLive, :index + end + + the UserLive route would point to the `AppWeb.Admin.UserLive` module + +- `Phoenix.View` no longer is needed or included with Phoenix, don't use it + + +## Ecto Guidelines + +- **Always** preload Ecto associations in queries when they'll be accessed in templates, ie a message that needs to reference the `message.user.email` +- Remember `import Ecto.Query` and other supporting modules when you write `seeds.exs` +- `Ecto.Schema` fields always use the `:string` type, even for `:text`, columns, ie: `field :name, :string` +- `Ecto.Changeset.validate_number/2` **DOES NOT SUPPORT the `:allow_nil` option**. By default, Ecto validations only run if a change for the given field exists and the change value is not nil, so such as option is never needed +- You **must** use `Ecto.Changeset.get_field(changeset, :field)` to access changeset fields +- Fields which are set programatically, such as `user_id`, must not be listed in `cast` calls or similar for security purposes. Instead they must be explicitly set when creating the struct + + +## Phoenix HTML guidelines + +- Phoenix templates **always** use `~H` or .html.heex files (known as HEEx), **never** use `~E` +- **Always** use the imported `Phoenix.Component.form/1` and `Phoenix.Component.inputs_for/1` function to build forms. **Never** use `Phoenix.HTML.form_for` or `Phoenix.HTML.inputs_for` as they are outdated +- When building forms **always** use the already imported `Phoenix.Component.to_form/2` (`assign(socket, form: to_form(...))` and `<.form for={@form} id="msg-form">`), then access those forms in the template via `@form[:field]` +- **Always** add unique DOM IDs to key elements (like forms, buttons, etc) when writing templates, these IDs can later be used in tests (`<.form for={@form} id="product-form">`) +- For "app wide" template imports, you can import/alias into the `my_app_web.ex`'s `html_helpers` block, so they will be available to all LiveViews, LiveComponent's, and all modules that do `use MyAppWeb, :html` (replace "my_app" by the actual app name) + +- Elixir supports `if/else` but **does NOT support `if/else if` or `if/elsif`. **Never use `else if` or `elseif` in Elixir**, **always** use `cond` or `case` for multiple conditionals. + + **Never do this (invalid)**: + + <%= if condition do %> + ... + <% else if other_condition %> + ... + <% end %> + + Instead **always** do this: + + <%= cond do %> + <% condition -> %> + ... + <% condition2 -> %> + ... + <% true -> %> + ... + <% end %> + +- HEEx require special tag annotation if you want to insert literal curly's like `{` or `}`. If you want to show a textual code snippet on the page in a `
` or `` block you *must* annotate the parent tag with `phx-no-curly-interpolation`:
+
+      
+        let obj = {key: "val"}
+      
+
+  Within `phx-no-curly-interpolation` annotated tags, you can use `{` and `}` without escaping them, and dynamic Elixir expressions can still be used with `<%= ... %>` syntax
+
+- HEEx class attrs support lists, but you must **always** use list `[...]` syntax. You can use the class list syntax to conditionally add classes, **always do this for multiple class values**:
+
+      Text
+
+  and **always** wrap `if`'s inside `{...}` expressions with parens, like done above (`if(@other_condition, do: "...", else: "...")`)
+
+  and **never** do this, since it's invalid (note the missing `[` and `]`):
+
+       ...
+      => Raises compile syntax error on invalid HEEx attr syntax
+
+- **Never** use `<% Enum.each %>` or non-for comprehensions for generating template content, instead **always** use `<%= for item <- @collection do %>`
+- HEEx HTML comments use `<%!-- comment --%>`. **Always** use the HEEx HTML comment syntax for template comments (`<%!-- comment --%>`)
+- HEEx allows interpolation via `{...}` and `<%= ... %>`, but the `<%= %>` **only** works within tag bodies. **Always** use the `{...}` syntax for interpolation within tag attributes, and for interpolation of values within tag bodies. **Always** interpolate block constructs (if, cond, case, for) within tag bodies using `<%= ... %>`.
+
+  **Always** do this:
+
+      
+ {@my_assign} + <%= if @some_block_condition do %> + {@another_assign} + <% end %> +
+ + and **Never** do this – the program will terminate with a syntax error: + + <%!-- THIS IS INVALID NEVER EVER DO THIS --%> +
+ {if @invalid_block_construct do} + {end} +
+ + +## Phoenix LiveView guidelines + +- **Never** use the deprecated `live_redirect` and `live_patch` functions, instead **always** use the `<.link navigate={href}>` and `<.link patch={href}>` in templates, and `push_navigate` and `push_patch` functions LiveViews +- **Avoid LiveComponent's** unless you have a strong, specific need for them +- LiveViews should be named like `AppWeb.WeatherLive`, with a `Live` suffix. When you go to add LiveView routes to the router, the default `:browser` scope is **already aliased** with the `AppWeb` module, so you can just do `live "/weather", WeatherLive` +- Remember anytime you use `phx-hook="MyHook"` and that js hook manages its own DOM, you **must** also set the `phx-update="ignore"` attribute +- **Never** write embedded ` + + + + {@inner_content} + + diff --git a/lib/myapp_web/controllers/error_html.ex b/lib/myapp_web/controllers/error_html.ex new file mode 100644 index 0000000..04ad294 --- /dev/null +++ b/lib/myapp_web/controllers/error_html.ex @@ -0,0 +1,24 @@ +defmodule MyappWeb.ErrorHTML do + @moduledoc """ + This module is invoked by your endpoint in case of errors on HTML requests. + + See config/config.exs. + """ + use MyappWeb, :html + + # If you want to customize your error pages, + # uncomment the embed_templates/1 call below + # and add pages to the error directory: + # + # * lib/myapp_web/controllers/error_html/404.html.heex + # * lib/myapp_web/controllers/error_html/500.html.heex + # + # embed_templates "error_html/*" + + # The default is to render a plain text page based on + # the template name. For example, "404.html" becomes + # "Not Found". + def render(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/lib/myapp_web/controllers/error_json.ex b/lib/myapp_web/controllers/error_json.ex new file mode 100644 index 0000000..e424d10 --- /dev/null +++ b/lib/myapp_web/controllers/error_json.ex @@ -0,0 +1,21 @@ +defmodule MyappWeb.ErrorJSON do + @moduledoc """ + This module is invoked by your endpoint in case of errors on JSON requests. + + See config/config.exs. + """ + + # If you want to customize a particular status code, + # you may add your own clauses, such as: + # + # def render("500.json", _assigns) do + # %{errors: %{detail: "Internal Server Error"}} + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.json" becomes + # "Not Found". + def render(template, _assigns) do + %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} + end +end diff --git a/lib/myapp_web/controllers/page_controller.ex b/lib/myapp_web/controllers/page_controller.ex new file mode 100644 index 0000000..932cfe9 --- /dev/null +++ b/lib/myapp_web/controllers/page_controller.ex @@ -0,0 +1,7 @@ +defmodule MyappWeb.PageController do + use MyappWeb, :controller + + def home(conn, _params) do + render(conn, :home) + end +end diff --git a/lib/myapp_web/controllers/page_html.ex b/lib/myapp_web/controllers/page_html.ex new file mode 100644 index 0000000..65d9069 --- /dev/null +++ b/lib/myapp_web/controllers/page_html.ex @@ -0,0 +1,10 @@ +defmodule MyappWeb.PageHTML do + @moduledoc """ + This module contains pages rendered by PageController. + + See the `page_html` directory for all templates available. + """ + use MyappWeb, :html + + embed_templates "page_html/*" +end diff --git a/lib/myapp_web/controllers/page_html/home.html.heex b/lib/myapp_web/controllers/page_html/home.html.heex new file mode 100644 index 0000000..eaed272 --- /dev/null +++ b/lib/myapp_web/controllers/page_html/home.html.heex @@ -0,0 +1,251 @@ + + +
diff --git a/lib/myapp_web/endpoint.ex b/lib/myapp_web/endpoint.ex new file mode 100644 index 0000000..10a93cc --- /dev/null +++ b/lib/myapp_web/endpoint.ex @@ -0,0 +1,54 @@ +defmodule MyappWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :myapp + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_myapp_key", + signing_salt: "gS7NlwDp", + same_site: "Lax" + ] + + socket "/live", Phoenix.LiveView.Socket, + websocket: [connect_info: [session: @session_options]], + longpoll: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # When code reloading is disabled (e.g., in production), + # the `gzip` option is enabled to serve compressed + # static files generated by running `phx.digest`. + plug Plug.Static, + at: "/", + from: :myapp, + gzip: not code_reloading?, + only: MyappWeb.static_paths() + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + plug Phoenix.Ecto.CheckRepoStatus, otp_app: :myapp + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug MyappWeb.Router +end diff --git a/lib/myapp_web/gettext.ex b/lib/myapp_web/gettext.ex new file mode 100644 index 0000000..f89e951 --- /dev/null +++ b/lib/myapp_web/gettext.ex @@ -0,0 +1,25 @@ +defmodule MyappWeb.Gettext do + @moduledoc """ + A module providing Internationalization with a gettext-based API. + + By using [Gettext](https://hexdocs.pm/gettext), your module compiles translations + that you can use in your application. To use this Gettext backend module, + call `use Gettext` and pass it as an option: + + use Gettext, backend: MyappWeb.Gettext + + # Simple translation + gettext("Here is the string to translate") + + # Plural translation + ngettext("Here is the string to translate", + "Here are the strings to translate", + 3) + + # Domain-based translation + dgettext("errors", "Here is the error message to translate") + + See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. + """ + use Gettext.Backend, otp_app: :myapp +end diff --git a/lib/myapp_web/router.ex b/lib/myapp_web/router.ex new file mode 100644 index 0000000..d4e5944 --- /dev/null +++ b/lib/myapp_web/router.ex @@ -0,0 +1,44 @@ +defmodule MyappWeb.Router do + use MyappWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, html: {MyappWeb.Layouts, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", MyappWeb do + pipe_through :browser + + get "/", PageController, :home + end + + # Other scopes may use custom stacks. + # scope "/api", MyappWeb do + # pipe_through :api + # end + + # Enable LiveDashboard and Swoosh mailbox preview in development + if Application.compile_env(:myapp, :dev_routes) do + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + import Phoenix.LiveDashboard.Router + + scope "/dev" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: MyappWeb.Telemetry + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end +end diff --git a/lib/myapp_web/telemetry.ex b/lib/myapp_web/telemetry.ex new file mode 100644 index 0000000..731b7bb --- /dev/null +++ b/lib/myapp_web/telemetry.ex @@ -0,0 +1,93 @@ +defmodule MyappWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.start.system_time", + unit: {:native, :millisecond} + ), + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.start.system_time", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.exception.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.socket_connected.duration", + unit: {:native, :millisecond} + ), + sum("phoenix.socket_drain.count"), + summary("phoenix.channel_joined.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.channel_handled_in.duration", + tags: [:event], + unit: {:native, :millisecond} + ), + + # Database Metrics + summary("myapp.repo.query.total_time", + unit: {:native, :millisecond}, + description: "The sum of the other measurements" + ), + summary("myapp.repo.query.decode_time", + unit: {:native, :millisecond}, + description: "The time spent decoding the data received from the database" + ), + summary("myapp.repo.query.query_time", + unit: {:native, :millisecond}, + description: "The time spent executing the query" + ), + summary("myapp.repo.query.queue_time", + unit: {:native, :millisecond}, + description: "The time spent waiting for a database connection" + ), + summary("myapp.repo.query.idle_time", + unit: {:native, :millisecond}, + description: + "The time the connection spent waiting before being checked out for the query" + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {MyappWeb, :count_users, []} + ] + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..bf89d43 --- /dev/null +++ b/mix.exs @@ -0,0 +1,94 @@ +defmodule Myapp.MixProject do + use Mix.Project + + def project do + [ + app: :myapp, + version: "0.1.0", + elixir: "~> 1.15", + elixirc_paths: elixirc_paths(Mix.env()), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps(), + compilers: [:phoenix_live_view] ++ Mix.compilers(), + listeners: [Phoenix.CodeReloader] + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {Myapp.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + def cli do + [ + preferred_envs: [precommit: :test] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.8.0"}, + {:phoenix_ecto, "~> 4.5"}, + {:ecto_sql, "~> 3.13"}, + {:postgrex, ">= 0.0.0"}, + {:phoenix_html, "~> 4.1"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 1.1.0"}, + {:lazy_html, ">= 0.1.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.8.3"}, + {:esbuild, "~> 0.10", runtime: Mix.env() == :dev}, + {:tailwind, "~> 0.3", runtime: Mix.env() == :dev}, + {:heroicons, + github: "tailwindlabs/heroicons", + tag: "v2.2.0", + sparse: "optimized", + app: false, + compile: false, + depth: 1}, + {:swoosh, "~> 1.16"}, + {:req, "~> 0.5"}, + {:telemetry_metrics, "~> 1.0"}, + {:telemetry_poller, "~> 1.0"}, + {:gettext, "~> 0.26"}, + {:jason, "~> 1.2"}, + {:dns_cluster, "~> 0.2.0"}, + {:bandit, "~> 1.5"} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"], + "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], + "ecto.reset": ["ecto.drop", "ecto.setup"], + test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"], + "assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"], + "assets.build": ["tailwind myapp", "esbuild myapp"], + "assets.deploy": [ + "tailwind myapp --minify", + "esbuild myapp --minify", + "phx.digest" + ], + precommit: ["compile --warning-as-errors", "deps.unlock --unused", "format", "test"] + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..ea2a8e1 --- /dev/null +++ b/mix.lock @@ -0,0 +1,44 @@ +%{ + "bandit": {:hex, :bandit, "1.8.0", "c2e93d7e3c5c794272fa4623124f827c6f24b643acc822be64c826f9447d92fb", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "8458ff4eed20ff2a2ea69d4854883a077c33ea42b51f6811b044ceee0fa15422"}, + "cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"}, + "db_connection": {:hex, :db_connection, "2.8.0", "64fd82cfa6d8e25ec6660cea73e92a4cbc6a18b31343910427b702838c4b33b2", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "008399dae5eee1bf5caa6e86d204dcb44242c82b1ed5e22c881f2c34da201b15"}, + "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, + "dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"}, + "ecto": {:hex, :ecto, "3.13.2", "7d0c0863f3fc8d71d17fc3ad3b9424beae13f02712ad84191a826c7169484f01", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "669d9291370513ff56e7b7e7081b7af3283d02e046cf3d403053c557894a0b3e"}, + "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"}, + "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, + "esbuild": {:hex, :esbuild, "0.10.0", "b0aa3388a1c23e727c5a3e7427c932d89ee791746b0081bbe56103e9ef3d291f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "468489cda427b974a7cc9f03ace55368a83e1a7be12fba7e30969af78e5f8c70"}, + "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, + "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, + "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, + "fine": {:hex, :fine, "0.1.4", "b19a89c1476c7c57afb5f9314aed5960b5bc95d5277de4cb5ee8e1d1616ce379", [:mix], [], "hexpm", "be3324cc454a42d80951cf6023b9954e9ff27c6daa255483b3e8d608670303f5"}, + "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]}, + "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "lazy_html": {:hex, :lazy_html, "0.1.6", "bff2c5901b008fd75d41f777eb54a19fcf47544cc8c5e5509d84c2b3ea471c69", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "e04bddfaa09d38e5c3e39278a470550faa7d45d0a30ebc87eb2bd740c364aaaa"}, + "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "phoenix": {:hex, :phoenix, "1.8.0", "dc5d256bb253110266ded8c4a6a167e24fabde2e14b8e474d262840ae8d8ea18", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "15f6e9cb76646ad8d9f2947240519666fc2c4f29f8a93ad9c7664916ab4c167b"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.5", "c4ef322acd15a574a8b1a08eff0ee0a85e73096b53ce1403b6563709f15e1cea", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "26ec3208eef407f31b748cadd044045c6fd485fbff168e35963d2f9dfff28d4b"}, + "phoenix_html": {:hex, :phoenix_html, "4.2.1", "35279e2a39140068fc03f8874408d58eef734e488fc142153f055c5454fd1c08", [:mix], [], "hexpm", "cff108100ae2715dd959ae8f2a8cef8e20b593f8dfd031c9cba92702cf23e053"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.6.0", "2791fac0e2776b640192308cc90c0dbcf67843ad51387ed4ecae2038263d708d", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b3a1fa036d7eb2f956774eda7a7638cf5123f8f2175aca6d6420a7f95e598e1c"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "1.1.7", "53e01a3e238f8ce1cdd9a486aa85333a71029fdfd64483f09b5d835a364758a6", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1b3422beb02857adc0953a8a7b1478b65a8862e03485efc10d901087e6a61895"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, + "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, + "req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"}, + "swoosh": {:hex, :swoosh, "1.19.5", "5abd71be78302ba21be56a2b68d05c9946ff1f1bd254f949efef09d253b771ac", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c953f51ee0a8b237e0f4307c9cefd3eb1eb751c35fcdda2a8bccb991766473be"}, + "tailwind": {:hex, :tailwind, "0.3.1", "a89d2835c580748c7a975ad7dd3f2ea5e63216dc16d44f9df492fbd12c094bed", [:mix], [], "hexpm", "98a45febdf4a87bc26682e1171acdedd6317d0919953c353fcd1b4f9f4b676a2"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"}, + "thousand_island": {:hex, :thousand_island, "1.3.14", "ad45ebed2577b5437582bcc79c5eccd1e2a8c326abf6a3464ab6c06e2055a34a", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d0d24a929d31cdd1d7903a4fe7f2409afeedff092d277be604966cd6aa4307ef"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, +} diff --git a/mvnw b/mvnw deleted file mode 100755 index 19529dd..0000000 --- a/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd deleted file mode 100644 index 249bdf3..0000000 --- a/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 490df88..0000000 --- a/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.4.4 - - - com.pricetra - email_server - 0.0.1-SNAPSHOT - email_server - Email server for Pricetra - - - - - - - - - - - - - - - 17 - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-starter-web - - - - com.sendgrid - sendgrid-java - 4.10.3 - - - - com.auth0 - java-jwt - 4.5.0 - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.5.0 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/priv/gettext/en/LC_MESSAGES/errors.po b/priv/gettext/en/LC_MESSAGES/errors.po new file mode 100644 index 0000000..844c4f5 --- /dev/null +++ b/priv/gettext/en/LC_MESSAGES/errors.po @@ -0,0 +1,112 @@ +## `msgid`s in this file come from POT (.pot) files. +## +## Do not add, change, or remove `msgid`s manually here as +## they're tied to the ones in the corresponding POT file +## (with the same domain). +## +## Use `mix gettext.extract --merge` or `mix gettext.merge` +## to merge POT files into PO files. +msgid "" +msgstr "" +"Language: en\n" + +## From Ecto.Changeset.cast/4 +msgid "can't be blank" +msgstr "" + +## From Ecto.Changeset.unique_constraint/3 +msgid "has already been taken" +msgstr "" + +## From Ecto.Changeset.put_change/3 +msgid "is invalid" +msgstr "" + +## From Ecto.Changeset.validate_acceptance/3 +msgid "must be accepted" +msgstr "" + +## From Ecto.Changeset.validate_format/3 +msgid "has invalid format" +msgstr "" + +## From Ecto.Changeset.validate_subset/3 +msgid "has an invalid entry" +msgstr "" + +## From Ecto.Changeset.validate_exclusion/3 +msgid "is reserved" +msgstr "" + +## From Ecto.Changeset.validate_confirmation/3 +msgid "does not match confirmation" +msgstr "" + +## From Ecto.Changeset.no_assoc_constraint/3 +msgid "is still associated with this entry" +msgstr "" + +msgid "are still associated with this entry" +msgstr "" + +## From Ecto.Changeset.validate_length/3 +msgid "should have %{count} item(s)" +msgid_plural "should have %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be %{count} character(s)" +msgid_plural "should be %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be %{count} byte(s)" +msgid_plural "should be %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should have at least %{count} item(s)" +msgid_plural "should have at least %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at least %{count} character(s)" +msgid_plural "should be at least %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at least %{count} byte(s)" +msgid_plural "should be at least %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should have at most %{count} item(s)" +msgid_plural "should have at most %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at most %{count} character(s)" +msgid_plural "should be at most %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at most %{count} byte(s)" +msgid_plural "should be at most %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +## From Ecto.Changeset.validate_number/3 +msgid "must be less than %{number}" +msgstr "" + +msgid "must be greater than %{number}" +msgstr "" + +msgid "must be less than or equal to %{number}" +msgstr "" + +msgid "must be greater than or equal to %{number}" +msgstr "" + +msgid "must be equal to %{number}" +msgstr "" diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot new file mode 100644 index 0000000..eef2de2 --- /dev/null +++ b/priv/gettext/errors.pot @@ -0,0 +1,109 @@ +## This is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here has no +## effect: edit them in PO (`.po`) files instead. +## From Ecto.Changeset.cast/4 +msgid "can't be blank" +msgstr "" + +## From Ecto.Changeset.unique_constraint/3 +msgid "has already been taken" +msgstr "" + +## From Ecto.Changeset.put_change/3 +msgid "is invalid" +msgstr "" + +## From Ecto.Changeset.validate_acceptance/3 +msgid "must be accepted" +msgstr "" + +## From Ecto.Changeset.validate_format/3 +msgid "has invalid format" +msgstr "" + +## From Ecto.Changeset.validate_subset/3 +msgid "has an invalid entry" +msgstr "" + +## From Ecto.Changeset.validate_exclusion/3 +msgid "is reserved" +msgstr "" + +## From Ecto.Changeset.validate_confirmation/3 +msgid "does not match confirmation" +msgstr "" + +## From Ecto.Changeset.no_assoc_constraint/3 +msgid "is still associated with this entry" +msgstr "" + +msgid "are still associated with this entry" +msgstr "" + +## From Ecto.Changeset.validate_length/3 +msgid "should have %{count} item(s)" +msgid_plural "should have %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be %{count} character(s)" +msgid_plural "should be %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be %{count} byte(s)" +msgid_plural "should be %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should have at least %{count} item(s)" +msgid_plural "should have at least %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at least %{count} character(s)" +msgid_plural "should be at least %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at least %{count} byte(s)" +msgid_plural "should be at least %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should have at most %{count} item(s)" +msgid_plural "should have at most %{count} item(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at most %{count} character(s)" +msgid_plural "should be at most %{count} character(s)" +msgstr[0] "" +msgstr[1] "" + +msgid "should be at most %{count} byte(s)" +msgid_plural "should be at most %{count} byte(s)" +msgstr[0] "" +msgstr[1] "" + +## From Ecto.Changeset.validate_number/3 +msgid "must be less than %{number}" +msgstr "" + +msgid "must be greater than %{number}" +msgstr "" + +msgid "must be less than or equal to %{number}" +msgstr "" + +msgid "must be greater than or equal to %{number}" +msgstr "" + +msgid "must be equal to %{number}" +msgstr "" diff --git a/priv/repo/migrations/.formatter.exs b/priv/repo/migrations/.formatter.exs new file mode 100644 index 0000000..49f9151 --- /dev/null +++ b/priv/repo/migrations/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:ecto_sql], + inputs: ["*.exs"] +] diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs new file mode 100644 index 0000000..1981fcc --- /dev/null +++ b/priv/repo/seeds.exs @@ -0,0 +1,11 @@ +# Script for populating the database. You can run it as: +# +# mix run priv/repo/seeds.exs +# +# Inside the script, you can read and write to any of your +# repositories directly: +# +# Myapp.Repo.insert!(%Myapp.SomeSchema{}) +# +# We recommend using the bang functions (`insert!`, `update!` +# and so on) as they will fail if something goes wrong. diff --git a/priv/static/assets/css/app.css b/priv/static/assets/css/app.css new file mode 100644 index 0000000..3936644 --- /dev/null +++ b/priv/static/assets/css/app.css @@ -0,0 +1,2505 @@ +/*! tailwindcss v4.1.7 | MIT License | https://tailwindcss.com */ +@layer properties; +@layer theme, base, components, utilities; +@layer theme { + :root, :host { + --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + --color-gray-300: oklch(87.2% 0.01 258.338); + --color-black: #000; + --color-white: #fff; + --spacing: 0.25rem; + --container-xl: 36rem; + --container-2xl: 42rem; + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --font-weight-semibold: 600; + --font-weight-bold: 700; + --tracking-tighter: -0.05em; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --animate-spin: spin 1s linear infinite; + --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + --default-font-family: var(--font-sans); + --default-mono-font-family: var(--font-mono); + } +} +@layer base { + *, ::after, ::before, ::backdrop, ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'); + font-feature-settings: var(--default-font-feature-settings, normal); + font-variation-settings: var(--default-font-variation-settings, normal); + -webkit-tap-highlight-color: transparent; + } + hr { + height: 0; + color: inherit; + border-top-width: 1px; + } + abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + } + h1, h2, h3, h4, h5, h6 { + font-size: inherit; + font-weight: inherit; + } + a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; + } + b, strong { + font-weight: bolder; + } + code, kbd, samp, pre { + font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace); + font-feature-settings: var(--default-mono-font-feature-settings, normal); + font-variation-settings: var(--default-mono-font-variation-settings, normal); + font-size: 1em; + } + small { + font-size: 80%; + } + sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + sub { + bottom: -0.25em; + } + sup { + top: -0.5em; + } + table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; + } + :-moz-focusring { + outline: auto; + } + progress { + vertical-align: baseline; + } + summary { + display: list-item; + } + ol, ul, menu { + list-style: none; + } + img, svg, video, canvas, audio, iframe, embed, object { + display: block; + vertical-align: middle; + } + img, video { + max-width: 100%; + height: auto; + } + button, input, select, optgroup, textarea, ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; + } + :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; + } + :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; + } + ::file-selector-button { + margin-inline-end: 4px; + } + ::placeholder { + opacity: 1; + } + @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + ::placeholder { + color: currentcolor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentcolor 50%, transparent); + } + } + } + textarea { + resize: vertical; + } + ::-webkit-search-decoration { + -webkit-appearance: none; + } + ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; + } + ::-webkit-datetime-edit { + display: inline-flex; + } + ::-webkit-datetime-edit-fields-wrapper { + padding: 0; + } + ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; + } + :-moz-ui-invalid { + box-shadow: none; + } + button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button { + appearance: button; + } + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { + height: auto; + } + [hidden]:where(:not([hidden='until-found'])) { + display: none !important; + } +} +@layer utilities { + .btn { + :where(&) { + width: unset; + } + display: inline-flex; + flex-shrink: 0; + cursor: pointer; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + gap: calc(0.25rem * 1.5); + text-align: center; + vertical-align: middle; + outline-offset: 2px; + webkit-user-select: none; + user-select: none; + padding-inline: var(--btn-p); + color: var(--btn-fg); + --tw-prose-links: var(--btn-fg); + height: var(--size); + font-size: var(--fontsize, 0.875rem); + font-weight: 600; + outline-color: var(--btn-color, var(--color-base-content)); + transition-property: color, background-color, border-color, box-shadow; + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); + transition-duration: 0.2s; + border-start-start-radius: var(--join-ss, var(--radius-field)); + border-start-end-radius: var(--join-se, var(--radius-field)); + border-end-start-radius: var(--join-es, var(--radius-field)); + border-end-end-radius: var(--join-ee, var(--radius-field)); + background-color: var(--btn-bg); + background-size: auto, calc(var(--noise) * 100%); + background-image: none, var(--btn-noise); + border-width: var(--border); + border-style: solid; + border-color: var(--btn-border); + text-shadow: 0 0.5px oklch(100% 0 0 / calc(var(--depth) * 0.15)); + touch-action: manipulation; + box-shadow: 0 0.5px 0 0.5px oklch(100% 0 0 / calc(var(--depth) * 6%)) inset, var(--btn-shadow); + --size: calc(var(--size-field, 0.25rem) * 10); + --btn-bg: var(--btn-color, var(--color-base-200)); + --btn-fg: var(--color-base-content); + --btn-p: 1rem; + --btn-border: var(--btn-bg); + @supports (color: color-mix(in lab, red, red)) { + --btn-border: color-mix(in oklab, var(--btn-bg), #000 calc(var(--depth) * 5%)); + } + --btn-shadow: 0 3px 2px -2px var(--btn-bg), + 0 4px 3px -2px var(--btn-bg); + @supports (color: color-mix(in lab, red, red)) { + --btn-shadow: 0 3px 2px -2px color-mix(in oklab, var(--btn-bg) calc(var(--depth) * 30%), #0000), + 0 4px 3px -2px color-mix(in oklab, var(--btn-bg) calc(var(--depth) * 30%), #0000); + } + --btn-noise: var(--fx-noise); + .prose & { + text-decoration-line: none; + } + @media (hover: hover) { + &:hover { + --btn-bg: var(--btn-color, var(--color-base-200)); + @supports (color: color-mix(in lab, red, red)) { + --btn-bg: color-mix(in oklab, var(--btn-color, var(--color-base-200)), #000 7%); + } + } + } + &:focus-visible { + outline-width: 2px; + outline-style: solid; + isolation: isolate; + } + &:active:not(.btn-active) { + translate: 0 0.5px; + --btn-bg: var(--btn-color, var(--color-base-200)); + @supports (color: color-mix(in lab, red, red)) { + --btn-bg: color-mix(in oklab, var(--btn-color, var(--color-base-200)), #000 5%); + } + --btn-border: var(--btn-color, var(--color-base-200)); + @supports (color: color-mix(in lab, red, red)) { + --btn-border: color-mix(in oklab, var(--btn-color, var(--color-base-200)), #000 7%); + } + --btn-shadow: 0 0 0 0 oklch(0% 0 0/0), 0 0 0 0 oklch(0% 0 0/0); + } + &:is(:disabled, [disabled], .btn-disabled) { + &:not(.btn-link, .btn-ghost) { + background-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-base-content) 10%, transparent); + } + box-shadow: none; + } + pointer-events: none; + --btn-border: #0000; + --btn-noise: none; + --btn-fg: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --btn-fg: color-mix(in oklch, var(--color-base-content) 20%, #0000); + } + @media (hover: hover) { + &:hover { + pointer-events: none; + background-color: var(--color-neutral); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-neutral) 20%, transparent); + } + --btn-border: #0000; + --btn-fg: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --btn-fg: color-mix(in oklch, var(--color-base-content) 20%, #0000); + } + } + } + } + &:is(input[type="checkbox"], input[type="radio"]) { + appearance: none; + &::after { + content: attr(aria-label); + } + } + &:where(input:checked:not(.filter .btn)) { + --btn-color: var(--color-primary); + --btn-fg: var(--color-primary-content); + isolation: isolate; + } + } + .list { + display: flex; + flex-direction: column; + font-size: 0.875rem; + :where(.list-row) { + --list-grid-cols: minmax(0, auto) 1fr; + position: relative; + display: grid; + grid-auto-flow: column; + gap: calc(0.25rem * 4); + border-radius: var(--radius-box); + padding: calc(0.25rem * 4); + word-break: break-word; + grid-template-columns: var(--list-grid-cols); + &:has(.list-col-grow:nth-child(1)) { + --list-grid-cols: 1fr; + } + &:has(.list-col-grow:nth-child(2)) { + --list-grid-cols: minmax(0, auto) 1fr; + } + &:has(.list-col-grow:nth-child(3)) { + --list-grid-cols: minmax(0, auto) minmax(0, auto) 1fr; + } + &:has(.list-col-grow:nth-child(4)) { + --list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) 1fr; + } + &:has(.list-col-grow:nth-child(5)) { + --list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) minmax(0, auto) 1fr; + } + &:has(.list-col-grow:nth-child(6)) { + --list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) minmax(0, auto) + minmax(0, auto) 1fr; + } + :not(.list-col-wrap) { + grid-row-start: 1; + } + } + & > :not(:last-child) { + &.list-row, .list-row { + &:after { + content: ""; + border-bottom: var(--border) solid; + inset-inline: var(--radius-box); + position: absolute; + bottom: calc(0.25rem * 0); + border-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + border-color: color-mix(in oklab, var(--color-base-content) 5%, transparent); + } + } + } + } + } + .toast { + position: fixed; + inset-inline-start: auto; + inset-inline-end: calc(0.25rem * 4); + top: auto; + bottom: calc(0.25rem * 4); + display: flex; + flex-direction: column; + gap: calc(0.25rem * 2); + background-color: transparent; + translate: var(--toast-x, 0) var(--toast-y, 0); + width: max-content; + max-width: calc(100vw - 2rem); + & > * { + animation: toast 0.25s ease-out; + } + &:where(.toast-start) { + inset-inline-start: calc(0.25rem * 4); + inset-inline-end: auto; + --toast-x: 0; + } + &:where(.toast-center) { + inset-inline-start: calc(1/2 * 100%); + inset-inline-end: calc(1/2 * 100%); + --toast-x: -50%; + } + &:where(.toast-end) { + inset-inline-start: auto; + inset-inline-end: calc(0.25rem * 4); + --toast-x: 0; + } + &:where(.toast-bottom) { + top: auto; + bottom: calc(0.25rem * 4); + --toast-y: 0; + } + &:where(.toast-middle) { + top: calc(1/2 * 100%); + bottom: auto; + --toast-y: -50%; + } + &:where(.toast-top) { + top: calc(0.25rem * 4); + bottom: auto; + --toast-y: 0; + } + } + .toggle { + border: var(--border) solid currentColor; + color: var(--input-color); + position: relative; + display: inline-grid; + flex-shrink: 0; + cursor: pointer; + appearance: none; + place-content: center; + vertical-align: middle; + webkit-user-select: none; + user-select: none; + grid-template-columns: 0fr 1fr 1fr; + --radius-selector-max: calc( + var(--radius-selector) + var(--radius-selector) + var(--radius-selector) + ); + border-radius: calc( var(--radius-selector) + min(var(--toggle-p), var(--radius-selector-max)) + min(var(--border), var(--radius-selector-max)) ); + padding: var(--toggle-p); + box-shadow: 0 1px currentColor inset; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, currentColor calc(var(--depth) * 10%), #0000) inset; + } + transition: color 0.3s, grid-template-columns 0.2s; + --input-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --input-color: color-mix(in oklab, var(--color-base-content) 50%, #0000); + } + --toggle-p: calc(var(--size) * 0.125); + --size: calc(var(--size-selector, 0.25rem) * 6); + width: calc((var(--size) * 2) - (var(--border) + var(--toggle-p)) * 2); + height: var(--size); + > * { + z-index: 1; + grid-column: span 1 / span 1; + grid-column-start: 2; + grid-row-start: 1; + height: 100%; + cursor: pointer; + appearance: none; + background-color: transparent; + padding: calc(0.25rem * 0.5); + transition: opacity 0.2s, rotate 0.4s; + border: none; + &:focus { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + &:nth-child(2) { + color: var(--color-base-100); + rotate: 0deg; + } + &:nth-child(3) { + color: var(--color-base-100); + opacity: 0%; + rotate: -15deg; + } + } + &:has(:checked) { + > :nth-child(2) { + opacity: 0%; + rotate: 15deg; + } + > :nth-child(3) { + opacity: 100%; + rotate: 0deg; + } + } + &:before { + position: relative; + inset-inline-start: calc(0.25rem * 0); + grid-column-start: 2; + grid-row-start: 1; + aspect-ratio: 1 / 1; + height: 100%; + border-radius: var(--radius-selector); + background-color: currentColor; + translate: 0; + --tw-content: ""; + content: var(--tw-content); + transition: background-color 0.1s, translate 0.2s, inset-inline-start 0.2s; + box-shadow: 0 -1px oklch(0% 0 0 / calc(var(--depth) * 0.1)) inset, 0 8px 0 -4px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset, 0 1px currentColor; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 -1px oklch(0% 0 0 / calc(var(--depth) * 0.1)) inset, 0 8px 0 -4px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset, 0 1px color-mix(in oklab, currentColor calc(var(--depth) * 10%), #0000); + } + background-size: auto, calc(var(--noise) * 100%); + background-image: none, var(--fx-noise); + } + @media (forced-colors: active) { + &:before { + outline-style: var(--tw-outline-style); + outline-width: 1px; + outline-offset: calc(1px * -1); + } + } + @media print { + &:before { + outline: 0.25rem solid; + outline-offset: -1rem; + } + } + &:focus-visible, &:has(:focus-visible) { + outline: 2px solid currentColor; + outline-offset: 2px; + } + &:checked, &[aria-checked="true"], &:has(> input:checked) { + grid-template-columns: 1fr 1fr 0fr; + background-color: var(--color-base-100); + --input-color: var(--color-base-content); + &:before { + background-color: currentColor; + } + @starting-style { + &:before { + opacity: 0; + } + } + } + &:indeterminate { + grid-template-columns: 0.5fr 1fr 0.5fr; + } + &:disabled { + cursor: not-allowed; + opacity: 30%; + &:before { + background-color: transparent; + border: var(--border) solid currentColor; + } + } + } + .input { + cursor: text; + border: var(--border) solid #0000; + position: relative; + display: inline-flex; + flex-shrink: 1; + appearance: none; + align-items: center; + gap: calc(0.25rem * 2); + background-color: var(--color-base-100); + padding-inline: calc(0.25rem * 3); + vertical-align: middle; + white-space: nowrap; + width: clamp(3rem, 20rem, 100%); + height: var(--size); + font-size: 0.875rem; + border-start-start-radius: var(--join-ss, var(--radius-field)); + border-start-end-radius: var(--join-se, var(--radius-field)); + border-end-start-radius: var(--join-es, var(--radius-field)); + border-end-end-radius: var(--join-ee, var(--radius-field)); + border-color: var(--input-color); + box-shadow: 0 1px var(--input-color) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + } + --size: calc(var(--size-field, 0.25rem) * 10); + --input-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --input-color: color-mix(in oklab, var(--color-base-content) 20%, #0000); + } + &:where(input) { + display: inline-flex; + } + :where(input) { + display: inline-flex; + height: 100%; + width: 100%; + appearance: none; + background-color: transparent; + border: none; + &:focus, &:focus-within { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + } + :where(input[type="date"]) { + display: inline-block; + } + &:focus, &:focus-within { + --input-color: var(--color-base-content); + box-shadow: 0 1px var(--input-color); + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000); + } + outline: 2px solid var(--input-color); + outline-offset: 2px; + isolation: isolate; + z-index: 1; + } + &:has(> input[disabled]), &:is(:disabled, [disabled]) { + cursor: not-allowed; + border-color: var(--color-base-200); + background-color: var(--color-base-200); + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 40%, transparent); + } + &::placeholder { + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 20%, transparent); + } + } + box-shadow: none; + } + &:has(> input[disabled]) > input[disabled] { + cursor: not-allowed; + } + &::-webkit-date-and-time-value { + text-align: inherit; + } + &[type="number"] { + &::-webkit-inner-spin-button { + margin-block: calc(0.25rem * -3); + margin-inline-end: calc(0.25rem * -3); + } + } + &::-webkit-calendar-picker-indicator { + position: absolute; + inset-inline-end: 0.75em; + } + } + .table { + font-size: 0.875rem; + position: relative; + width: 100%; + border-radius: var(--radius-box); + text-align: left; + &:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) { + text-align: right; + } + tr.row-hover { + &, &:nth-child(even) { + &:hover { + @media (hover: hover) { + background-color: var(--color-base-200); + } + } + } + } + :where(th, td) { + padding-inline: calc(0.25rem * 4); + padding-block: calc(0.25rem * 3); + vertical-align: middle; + } + :where(thead, tfoot) { + white-space: nowrap; + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 60%, transparent); + } + font-size: 0.875rem; + font-weight: 600; + } + :where(tfoot) { + border-top: var(--border) solid var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + border-top: var(--border) solid color-mix(in oklch, var(--color-base-content) 5%, #0000); + } + } + :where(.table-pin-rows thead tr) { + position: sticky; + top: calc(0.25rem * 0); + z-index: 1; + background-color: var(--color-base-100); + } + :where(.table-pin-rows tfoot tr) { + position: sticky; + bottom: calc(0.25rem * 0); + z-index: 1; + background-color: var(--color-base-100); + } + :where(.table-pin-cols tr th) { + position: sticky; + right: calc(0.25rem * 0); + left: calc(0.25rem * 0); + background-color: var(--color-base-100); + } + :where(thead tr, tbody tr:not(:last-child)) { + border-bottom: var(--border) solid var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + border-bottom: var(--border) solid color-mix(in oklch, var(--color-base-content) 5%, #0000); + } + } + } + .select { + border: var(--border) solid #0000; + position: relative; + display: inline-flex; + flex-shrink: 1; + appearance: none; + align-items: center; + gap: calc(0.25rem * 1.5); + background-color: var(--color-base-100); + padding-inline-start: calc(0.25rem * 4); + padding-inline-end: calc(0.25rem * 7); + vertical-align: middle; + width: clamp(3rem, 20rem, 100%); + height: var(--size); + font-size: 0.875rem; + border-start-start-radius: var(--join-ss, var(--radius-field)); + border-start-end-radius: var(--join-se, var(--radius-field)); + border-end-start-radius: var(--join-es, var(--radius-field)); + border-end-end-radius: var(--join-ee, var(--radius-field)); + background-image: linear-gradient(45deg, #0000 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, #0000 50%); + background-position: calc(100% - 20px) calc(1px + 50%), calc(100% - 16.1px) calc(1px + 50%); + background-size: 4px 4px, 4px 4px; + background-repeat: no-repeat; + text-overflow: ellipsis; + box-shadow: 0 1px var(--input-color) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + } + border-color: var(--input-color); + --input-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --input-color: color-mix(in oklab, var(--color-base-content) 20%, #0000); + } + --size: calc(var(--size-field, 0.25rem) * 10); + [dir="rtl"] & { + background-position: calc(0% + 12px) calc(1px + 50%), calc(0% + 16px) calc(1px + 50%); + } + select { + margin-inline-start: calc(0.25rem * -4); + margin-inline-end: calc(0.25rem * -7); + width: calc(100% + 2.75rem); + appearance: none; + padding-inline-start: calc(0.25rem * 4); + padding-inline-end: calc(0.25rem * 7); + height: calc(100% - 2px); + background: inherit; + border-radius: inherit; + border-style: none; + &:focus, &:focus-within { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + &:not(:last-child) { + margin-inline-end: calc(0.25rem * -5.5); + background-image: none; + } + } + &:focus, &:focus-within { + --input-color: var(--color-base-content); + box-shadow: 0 1px var(--input-color); + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000); + } + outline: 2px solid var(--input-color); + outline-offset: 2px; + isolation: isolate; + z-index: 1; + } + &:has(> select[disabled]), &:is(:disabled, [disabled]) { + cursor: not-allowed; + border-color: var(--color-base-200); + background-color: var(--color-base-200); + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 40%, transparent); + } + &::placeholder { + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 20%, transparent); + } + } + } + &:has(> select[disabled]) > select[disabled] { + cursor: not-allowed; + } + } + .card { + position: relative; + display: flex; + flex-direction: column; + border-radius: var(--radius-box); + outline-width: 2px; + transition: outline 0.2s ease-in-out; + outline: 0 solid #0000; + outline-offset: 2px; + &:focus { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + &:focus-visible { + outline-color: currentColor; + } + :where(figure:first-child) { + overflow: hidden; + border-start-start-radius: inherit; + border-start-end-radius: inherit; + border-end-start-radius: unset; + border-end-end-radius: unset; + } + :where(figure:last-child) { + overflow: hidden; + border-start-start-radius: unset; + border-start-end-radius: unset; + border-end-start-radius: inherit; + border-end-end-radius: inherit; + } + &:where(.card-border) { + border: var(--border) solid var(--color-base-200); + } + &:where(.card-dash) { + border: var(--border) dashed var(--color-base-200); + } + &.image-full { + display: grid; + > * { + grid-column-start: 1; + grid-row-start: 1; + } + > .card-body { + position: relative; + color: var(--color-neutral-content); + } + :where(figure) { + overflow: hidden; + border-radius: inherit; + } + > figure img { + height: 100%; + object-fit: cover; + filter: brightness(28%); + } + } + figure { + display: flex; + align-items: center; + justify-content: center; + } + &:has(> input:is(input[type="checkbox"], input[type="radio"])) { + cursor: pointer; + user-select: none; + } + &:has(> :checked) { + outline: 2px solid currentColor; + } + } + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + .checkbox { + border: var(--border) solid var(--input-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + border: var(--border) solid var(--input-color, color-mix(in oklab, var(--color-base-content) 20%, #0000)); + } + position: relative; + flex-shrink: 0; + cursor: pointer; + appearance: none; + border-radius: var(--radius-selector); + padding: calc(0.25rem * 1); + vertical-align: middle; + color: var(--color-base-content); + box-shadow: 0 1px oklch(0% 0 0 / calc(var(--depth) * 0.1)) inset, 0 0 #0000 inset, 0 0 #0000; + transition: background-color 0.2s, box-shadow 0.2s; + --size: calc(var(--size-selector, 0.25rem) * 6); + width: var(--size); + height: var(--size); + background-size: auto, calc(var(--noise) * 100%); + background-image: none, var(--fx-noise); + &:before { + --tw-content: ""; + content: var(--tw-content); + display: block; + width: 100%; + height: 100%; + rotate: 45deg; + background-color: currentColor; + opacity: 0%; + transition: clip-path 0.3s, opacity 0.1s, rotate 0.3s, translate 0.3s; + transition-delay: 0.1s; + clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%); + box-shadow: 0px 3px 0 0px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + font-size: 1rem; + line-height: 0.75; + } + &:focus-visible { + outline: 2px solid var(--input-color, currentColor); + outline-offset: 2px; + } + &:checked, &[aria-checked="true"] { + background-color: var(--input-color, #0000); + box-shadow: 0 0 #0000 inset, 0 8px 0 -4px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset, 0 1px oklch(0% 0 0 / calc(var(--depth) * 0.1)); + &:before { + clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%); + opacity: 100%; + } + @media (forced-colors: active) { + &:before { + rotate: 0deg; + background-color: transparent; + --tw-content: "✔︎"; + clip-path: none; + } + } + @media print { + &:before { + rotate: 0deg; + background-color: transparent; + --tw-content: "✔︎"; + clip-path: none; + } + } + } + &:indeterminate { + &:before { + rotate: 0deg; + opacity: 100%; + translate: 0 -35%; + clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 80% 80%, 80% 100%); + } + } + &:disabled { + cursor: not-allowed; + opacity: 20%; + } + } + .progress { + position: relative; + height: calc(0.25rem * 2); + width: 100%; + appearance: none; + overflow: hidden; + border-radius: var(--radius-box); + background-color: currentColor; + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, currentColor 20%, transparent); + } + color: var(--color-base-content); + &:indeterminate { + background-image: repeating-linear-gradient( 90deg, currentColor -1%, currentColor 10%, #0000 10%, #0000 90% ); + background-size: 200%; + background-position-x: 15%; + animation: progress 5s ease-in-out infinite; + @supports (-moz-appearance: none) { + &::-moz-progress-bar { + background-color: transparent; + background-image: repeating-linear-gradient( 90deg, currentColor -1%, currentColor 10%, #0000 10%, #0000 90% ); + background-size: 200%; + background-position-x: 15%; + animation: progress 5s ease-in-out infinite; + } + } + } + @supports (-moz-appearance: none) { + &::-moz-progress-bar { + border-radius: var(--radius-box); + background-color: currentColor; + } + } + @supports (-webkit-appearance: none) { + &::-webkit-progress-bar { + border-radius: var(--radius-box); + background-color: transparent; + } + &::-webkit-progress-value { + border-radius: var(--radius-box); + background-color: currentColor; + } + } + } + .absolute { + position: absolute; + } + .fixed { + position: fixed; + } + .relative { + position: relative; + } + .static { + position: static; + } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .inset-y-0 { + inset-block: calc(var(--spacing) * 0); + } + .-top-1 { + top: calc(var(--spacing) * -1); + } + .-top-2 { + top: calc(var(--spacing) * -2); + } + .-right-2 { + right: calc(var(--spacing) * -2); + } + .right-0 { + right: calc(var(--spacing) * 0); + } + .-left-2 { + left: calc(var(--spacing) * -2); + } + .left-0 { + left: calc(var(--spacing) * 0); + } + .left-\[40rem\] { + left: 40rem; + } + .textarea { + border: var(--border) solid #0000; + min-height: calc(0.25rem * 20); + flex-shrink: 1; + appearance: none; + border-radius: var(--radius-field); + background-color: var(--color-base-100); + padding-block: calc(0.25rem * 2); + vertical-align: middle; + width: clamp(3rem, 20rem, 100%); + padding-inline-start: 0.75rem; + padding-inline-end: 0.75rem; + font-size: 0.875rem; + border-color: var(--input-color); + box-shadow: 0 1px var(--input-color) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000) inset, 0 -1px oklch(100% 0 0 / calc(var(--depth) * 0.1)) inset; + } + --input-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + --input-color: color-mix(in oklab, var(--color-base-content) 20%, #0000); + } + textarea { + appearance: none; + background-color: transparent; + border: none; + &:focus, &:focus-within { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + } + &:focus, &:focus-within { + --input-color: var(--color-base-content); + box-shadow: 0 1px var(--input-color); + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 1px color-mix(in oklab, var(--input-color) calc(var(--depth) * 10%), #0000); + } + outline: 2px solid var(--input-color); + outline-offset: 2px; + isolation: isolate; + } + &:has(> textarea[disabled]), &:is(:disabled, [disabled]) { + cursor: not-allowed; + border-color: var(--color-base-200); + background-color: var(--color-base-200); + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 40%, transparent); + } + &::placeholder { + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 20%, transparent); + } + } + box-shadow: none; + } + &:has(> textarea[disabled]) > textarea[disabled] { + cursor: not-allowed; + } + } + .z-0 { + z-index: 0; + } + .z-50 { + z-index: 50; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } + .-mx-2 { + margin-inline: calc(var(--spacing) * -2); + } + .mx-auto { + margin-inline: auto; + } + .-my-0\.5 { + margin-block: calc(var(--spacing) * -0.5); + } + .label { + display: inline-flex; + align-items: center; + gap: calc(0.25rem * 1.5); + white-space: nowrap; + color: currentColor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentColor 60%, transparent); + } + &:has(input) { + cursor: pointer; + } + &:is(.input > *, .select > *) { + display: flex; + height: calc(100% - 0.5rem); + align-items: center; + padding-inline: calc(0.25rem * 3); + white-space: nowrap; + font-size: inherit; + &:first-child { + margin-inline-start: calc(0.25rem * -3); + margin-inline-end: calc(0.25rem * 3); + border-inline-end: var(--border) solid currentColor; + @supports (color: color-mix(in lab, red, red)) { + border-inline-end: var(--border) solid color-mix(in oklab, currentColor 10%, #0000); + } + } + &:last-child { + margin-inline-start: calc(0.25rem * 3); + margin-inline-end: calc(0.25rem * -3); + border-inline-start: var(--border) solid currentColor; + @supports (color: color-mix(in lab, red, red)) { + border-inline-start: var(--border) solid color-mix(in oklab, currentColor 10%, #0000); + } + } + } + } + .-mt-1 { + margin-top: calc(var(--spacing) * -1); + } + .mt-1\.5 { + margin-top: calc(var(--spacing) * 1.5); + } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } + .mt-10 { + margin-top: calc(var(--spacing) * 10); + } + .-mr-1 { + margin-right: calc(var(--spacing) * -1); + } + .mb-1 { + margin-bottom: calc(var(--spacing) * 1); + } + .mb-2 { + margin-bottom: calc(var(--spacing) * 2); + } + .ml-1 { + margin-left: calc(var(--spacing) * 1); + } + .ml-3 { + margin-left: calc(var(--spacing) * 3); + } + .status { + display: inline-block; + aspect-ratio: 1 / 1; + width: calc(0.25rem * 2); + height: calc(0.25rem * 2); + border-radius: var(--radius-selector); + background-color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-base-content) 20%, transparent); + } + background-position: center; + background-repeat: no-repeat; + vertical-align: middle; + color: color-mix(in srgb, #000 30%, transparent); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in srgb, #000 30%, transparent); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-black) 30%, transparent); + } + } + background-image: radial-gradient( circle at 35% 30%, oklch(1 0 0 / calc(var(--depth) * 0.5)), #0000 ); + box-shadow: 0 2px 3px -1px currentColor; + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 2px 3px -1px color-mix(in oklab, currentColor calc(var(--depth) * 100%), #0000); + } + } + .badge { + display: inline-flex; + align-items: center; + justify-content: center; + gap: calc(0.25rem * 2); + border-radius: var(--radius-selector); + vertical-align: middle; + color: var(--badge-fg); + border: var(--border) solid var(--badge-color, var(--color-base-200)); + font-size: 0.875rem; + width: fit-content; + padding-inline: calc(0.25rem * 3 - var(--border)); + background-size: auto, calc(var(--noise) * 100%); + background-image: none, var(--fx-noise); + background-color: var(--badge-bg); + --badge-bg: var(--badge-color, var(--color-base-100)); + --badge-fg: var(--color-base-content); + --size: calc(var(--size-selector, 0.25rem) * 6); + height: var(--size); + &.badge-outline { + --badge-fg: var(--badge-color); + --badge-bg: #0000; + background-image: none; + border-color: currentColor; + } + &.badge-dash { + --badge-fg: var(--badge-color); + --badge-bg: #0000; + background-image: none; + border-color: currentColor; + border-style: dashed; + } + &.badge-soft { + color: var(--badge-color, var(--color-base-content)); + background-color: var(--badge-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix( in oklab, var(--badge-color, var(--color-base-content)) 8%, var(--color-base-100) ); + } + border-color: var(--badge-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + border-color: color-mix( in oklab, var(--badge-color, var(--color-base-content)) 10%, var(--color-base-100) ); + } + background-image: none; + } + } + .hero-arrow-path { + --hero-arrow-path: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M16.023%209.348h4.992v-.001M2.985%2019.644v-4.992m0%200h4.992m-4.993%200%203.181%203.183a8.25%208.25%200%200%200%2013.803-3.7M4.031%209.865a8.25%208.25%200%200%201%2013.803-3.7l3.181%203.182m0-4.991v4.99%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-arrow-path); + mask: var(--hero-arrow-path); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; + } + .hero-computer-desktop-micro { + --hero-computer-desktop-micro: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M2%204.25A2.25%202.25%200%200%201%204.25%202h7.5A2.25%202.25%200%200%201%2014%204.25v5.5A2.25%202.25%200%200%201%2011.75%2012h-1.312c.1.128.21.248.328.36a.75.75%200%200%201%20.234.545v.345a.75.75%200%200%201-.75.75h-4.5a.75.75%200%200%201-.75-.75v-.345a.75.75%200%200%201%20.234-.545c.118-.111.228-.232.328-.36H4.25A2.25%202.25%200%200%201%202%209.75v-5.5Zm2.25-.75a.75.75%200%200%200-.75.75v4.5c0%20.414.336.75.75.75h7.5a.75.75%200%200%200%20.75-.75v-4.5a.75.75%200%200%200-.75-.75h-7.5Z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-computer-desktop-micro); + mask: var(--hero-computer-desktop-micro); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1rem; + height: 1rem; + } + .hero-exclamation-circle { + --hero-exclamation-circle: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%209v3.75m9-.75a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Zm-9%203.75h.008v.008H12v-.008Z%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-exclamation-circle); + mask: var(--hero-exclamation-circle); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; + } + .hero-information-circle { + --hero-information-circle: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22m11.25%2011.25.041-.02a.75.75%200%200%201%201.063.852l-.708%202.836a.75.75%200%200%200%201.063.853l.041-.021M21%2012a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Zm-9-3.75h.008v.008H12V8.25Z%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-information-circle); + mask: var(--hero-information-circle); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; + } + .hero-moon-micro { + --hero-moon-micro: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20d%3D%22M14.438%2010.148c.19-.425-.321-.787-.748-.601A5.5%205.5%200%200%201%206.453%202.31c.186-.427-.176-.938-.6-.748a6.501%206.501%200%201%200%208.585%208.586Z%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-moon-micro); + mask: var(--hero-moon-micro); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1rem; + height: 1rem; + } + .hero-sun-micro { + --hero-sun-micro: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20d%3D%22M8%201a.75.75%200%200%201%20.75.75v1.5a.75.75%200%200%201-1.5%200v-1.5A.75.75%200%200%201%208%201ZM10.5%208a2.5%202.5%200%201%201-5%200%202.5%202.5%200%200%201%205%200ZM12.95%204.11a.75.75%200%201%200-1.06-1.06l-1.062%201.06a.75.75%200%200%200%201.061%201.062l1.06-1.061ZM15%208a.75.75%200%200%201-.75.75h-1.5a.75.75%200%200%201%200-1.5h1.5A.75.75%200%200%201%2015%208ZM11.89%2012.95a.75.75%200%200%200%201.06-1.06l-1.06-1.062a.75.75%200%200%200-1.062%201.061l1.061%201.06ZM8%2012a.75.75%200%200%201%20.75.75v1.5a.75.75%200%200%201-1.5%200v-1.5A.75.75%200%200%201%208%2012ZM5.172%2011.89a.75.75%200%200%200-1.061-1.062L3.05%2011.89a.75.75%200%201%200%201.06%201.06l1.06-1.06ZM4%208a.75.75%200%200%201-.75.75h-1.5a.75.75%200%200%201%200-1.5h1.5A.75.75%200%200%201%204%208ZM4.11%205.172A.75.75%200%200%200%205.173%204.11L4.11%203.05a.75.75%200%201%200-1.06%201.06l1.06%201.06Z%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-sun-micro); + mask: var(--hero-sun-micro); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1rem; + height: 1rem; + } + .hero-x-mark { + --hero-x-mark: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20aria-hidden%3D%22true%22%20data-slot%3D%22icon%22%3E%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M6%2018%2018%206M6%206l12%2012%22%2F%3E%3C%2Fsvg%3E'); + -webkit-mask: var(--hero-x-mark); + mask: var(--hero-x-mark); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; + } + .navbar { + display: flex; + width: 100%; + align-items: center; + padding: 0.5rem; + min-height: 4rem; + } + .alert { + display: grid; + align-items: center; + gap: calc(0.25rem * 4); + border-radius: var(--radius-box); + padding-inline: calc(0.25rem * 4); + padding-block: calc(0.25rem * 3); + color: var(--color-base-content); + background-color: var(--alert-color, var(--color-base-200)); + justify-content: start; + justify-items: start; + grid-auto-flow: column; + grid-template-columns: auto; + text-align: start; + border: var(--border) solid var(--color-base-200); + font-size: 0.875rem; + line-height: 1.25rem; + background-size: auto, calc(var(--noise) * 100%); + background-image: none, var(--fx-noise); + box-shadow: 0 3px 0 -2px oklch(100% 0 0 / calc(var(--depth) * 0.08)) inset, 0 1px #000, 0 4px 3px -2px oklch(0% 0 0 / calc(var(--depth) * 0.08)); + @supports (color: color-mix(in lab, red, red)) { + box-shadow: 0 3px 0 -2px oklch(100% 0 0 / calc(var(--depth) * 0.08)) inset, 0 1px color-mix( in oklab, color-mix(in oklab, #000 20%, var(--alert-color, var(--color-base-200))) calc(var(--depth) * 20%), #0000 ), 0 4px 3px -2px oklch(0% 0 0 / calc(var(--depth) * 0.08)); + } + &:has(:nth-child(2)) { + grid-template-columns: auto minmax(auto, 1fr); + } + &.alert-outline { + background-color: transparent; + color: var(--alert-color); + box-shadow: none; + background-image: none; + } + &.alert-dash { + background-color: transparent; + color: var(--alert-color); + border-style: dashed; + box-shadow: none; + background-image: none; + } + &.alert-soft { + color: var(--alert-color, var(--color-base-content)); + background: var(--alert-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + background: color-mix( in oklab, var(--alert-color, var(--color-base-content)) 8%, var(--color-base-100) ); + } + border-color: var(--alert-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + border-color: color-mix( in oklab, var(--alert-color, var(--color-base-content)) 10%, var(--color-base-100) ); + } + box-shadow: none; + background-image: none; + } + } + .fieldset { + display: grid; + gap: calc(0.25rem * 1.5); + padding-block: calc(0.25rem * 1); + font-size: 0.75rem; + grid-template-columns: 1fr; + grid-auto-rows: max-content; + } + .block { + display: block; + } + .contents { + display: contents; + } + .flex { + display: flex; + } + .grid { + display: grid; + } + .hidden { + display: none; + } + .inline-flex { + display: inline-flex; + } + .table { + display: table; + } + .size-3 { + width: calc(var(--spacing) * 3); + height: calc(var(--spacing) * 3); + } + .size-4 { + width: calc(var(--spacing) * 4); + height: calc(var(--spacing) * 4); + } + .size-5 { + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + } + .h-4 { + height: calc(var(--spacing) * 4); + } + .h-6 { + height: calc(var(--spacing) * 6); + } + .h-12 { + height: calc(var(--spacing) * 12); + } + .h-full { + height: 100%; + } + .w-0 { + width: calc(var(--spacing) * 0); + } + .w-1\/3 { + width: calc(1/3 * 100%); + } + .w-4 { + width: calc(var(--spacing) * 4); + } + .w-6 { + width: calc(var(--spacing) * 6); + } + .w-80 { + width: calc(var(--spacing) * 80); + } + .w-fit { + width: fit-content; + } + .w-full { + width: 100%; + } + .max-w-2xl { + max-width: var(--container-2xl); + } + .max-w-80 { + max-width: calc(var(--spacing) * 80); + } + .max-w-xl { + max-width: var(--container-xl); + } + .flex-1 { + flex: 1; + } + .flex-none { + flex: none; + } + .shrink-0 { + flex-shrink: 0; + } + .translate-y-0 { + --tw-translate-y: calc(var(--spacing) * 0); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-y-4 { + --tw-translate-y: calc(var(--spacing) * 4); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .skeleton { + border-radius: var(--radius-box); + background-color: var(--color-base-300); + @media (prefers-reduced-motion: reduce) { + transition-duration: 15s; + } + will-change: background-position; + animation: skeleton 1.8s ease-in-out infinite; + background-image: linear-gradient( 105deg, #0000 0% 40%, var(--color-base-100) 50%, #0000 60% 100% ); + background-size: 200% auto; + background-repeat: no-repeat; + background-position-x: -50%; + } + .animate-ping { + animation: var(--animate-ping); + } + .link { + cursor: pointer; + text-decoration-line: underline; + &:focus { + --tw-outline-style: none; + outline-style: none; + @media (forced-colors: active) { + outline: 2px solid transparent; + outline-offset: 2px; + } + } + &:focus-visible { + outline: 2px solid currentColor; + outline-offset: 2px; + } + } + .cursor-pointer { + cursor: pointer; + } + .grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); + } + .flex-row { + flex-direction: row; + } + .items-center { + align-items: center; + } + .justify-between { + justify-content: space-between; + } + .gap-2 { + gap: calc(var(--spacing) * 2); + } + .gap-3 { + gap: calc(var(--spacing) * 3); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } + .gap-6 { + gap: calc(var(--spacing) * 6); + } + .space-y-4 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-6 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse))); + } + } + .gap-x-6 { + column-gap: calc(var(--spacing) * 6); + } + .space-x-4 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse))); + } + } + .gap-y-4 { + row-gap: calc(var(--spacing) * 4); + } + .self-start { + align-self: flex-start; + } + .overflow-x-auto { + overflow-x: auto; + } + .rounded-box { + border-radius: var(--radius-box); + } + .rounded-box { + border-radius: var(--radius-box); + } + .rounded-full { + border-radius: calc(infinity * 1px); + } + .rounded-lg { + border-radius: var(--radius-lg); + } + .rounded-md { + border-radius: var(--radius-md); + } + .rounded-xl { + border-radius: var(--radius-xl); + } + .border-1 { + border-style: var(--tw-border-style); + border-width: 1px; + } + .border-2 { + border-style: var(--tw-border-style); + border-width: 2px; + } + .alert-error { + border-color: var(--color-error); + color: var(--color-error-content); + --alert-color: var(--color-error); + } + .alert-info { + border-color: var(--color-info); + color: var(--color-info-content); + --alert-color: var(--color-info); + } + .border-base-200 { + border-color: var(--color-base-200); + } + .border-base-300 { + border-color: var(--color-base-300); + } + .table-zebra { + tbody { + tr { + &:where(:nth-child(even)) { + background-color: var(--color-base-200); + :where(.table-pin-cols tr th) { + background-color: var(--color-base-200); + } + } + &.row-hover { + &, &:where(:nth-child(even)) { + &:hover { + @media (hover: hover) { + background-color: var(--color-base-300); + } + } + } + } + } + } + } + .bg-base-100 { + background-color: var(--color-base-100); + } + .bg-base-200 { + background-color: var(--color-base-200); + } + .bg-base-300 { + background-color: var(--color-base-300); + } + .bg-black\/50 { + background-color: color-mix(in srgb, #000 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-black) 50%, transparent); + } + } + .bg-white { + background-color: var(--color-white); + } + .bg-white\/70 { + background-color: color-mix(in srgb, #fff 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-white) 70%, transparent); + } + } + .bg-white\/80 { + background-color: color-mix(in srgb, #fff 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-white) 80%, transparent); + } + } + .fill-base-content\/40 { + fill: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + fill: color-mix(in oklab, var(--color-base-content) 40%, transparent); + } + } + .stroke-black\/80 { + stroke: color-mix(in srgb, #000 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + stroke: color-mix(in oklab, var(--color-black) 80%, transparent); + } + } + .checkbox-sm { + padding: 0.1875rem; + --size: calc(var(--size-selector, 0.25rem) * 5); + } + .p-1 { + padding: calc(var(--spacing) * 1); + } + .p-2 { + padding: calc(var(--spacing) * 2); + } + .badge-sm { + --size: calc(var(--size-selector, 0.25rem) * 5); + font-size: 0.75rem; + padding-inline: calc(0.25rem * 2.5 - var(--border)); + } + .px-1 { + padding-inline: calc(var(--spacing) * 1); + } + .px-2 { + padding-inline: calc(var(--spacing) * 2); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .px-6 { + padding-inline: calc(var(--spacing) * 6); + } + .px-8 { + padding-inline: calc(var(--spacing) * 8); + } + .py-0\.5 { + padding-block: calc(var(--spacing) * 0.5); + } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-4 { + padding-block: calc(var(--spacing) * 4); + } + .py-10 { + padding-block: calc(var(--spacing) * 10); + } + .py-20 { + padding-block: calc(var(--spacing) * 20); + } + .pt-1 { + padding-top: calc(var(--spacing) * 1); + } + .pb-4 { + padding-bottom: calc(var(--spacing) * 4); + } + .pb-6 { + padding-bottom: calc(var(--spacing) * 6); + } + .text-4xl { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .text-\[1rem\] { + font-size: 1rem; + } + .text-\[2rem\] { + font-size: 2rem; + } + .leading-6 { + --tw-leading: calc(var(--spacing) * 6); + line-height: calc(var(--spacing) * 6); + } + .leading-7 { + --tw-leading: calc(var(--spacing) * 7); + line-height: calc(var(--spacing) * 7); + } + .leading-8 { + --tw-leading: calc(var(--spacing) * 8); + line-height: calc(var(--spacing) * 8); + } + .leading-10 { + --tw-leading: calc(var(--spacing) * 10); + line-height: calc(var(--spacing) * 10); + } + .font-bold { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } + .tracking-tighter { + --tw-tracking: var(--tracking-tighter); + letter-spacing: var(--tracking-tighter); + } + .text-balance { + text-wrap: balance; + } + .text-wrap { + text-wrap: wrap; + } + .whitespace-pre { + white-space: pre; + } + .text-base-content\/70 { + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 70%, transparent); + } + } + .text-base-content\/80 { + color: var(--color-base-content); + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, var(--color-base-content) 80%, transparent); + } + } + .text-error { + color: var(--color-error); + } + .text-gray-300 { + color: var(--color-gray-300); + } + .text-white { + color: var(--color-white); + } + .opacity-0 { + opacity: 0%; + } + .opacity-40 { + opacity: 40%; + } + .opacity-75 { + opacity: 75%; + } + .opacity-100 { + opacity: 100%; + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } + .btn-ghost { + &:not(.btn-active, :hover, :active:focus, :focus-visible) { + --btn-shadow: ""; + --btn-bg: #0000; + --btn-border: #0000; + --btn-noise: none; + &:not(:disabled, [disabled], .btn-disabled) { + outline-color: currentColor; + --btn-fg: currentColor; + } + } + } + .brightness-200 { + --tw-brightness: brightness(200%); + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-\[left\] { + transition-property: left; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-200 { + --tw-duration: 200ms; + transition-duration: 200ms; + } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; + } + .ease-in { + --tw-ease: var(--ease-in); + transition-timing-function: var(--ease-in); + } + .ease-out { + --tw-ease: var(--ease-out); + transition-timing-function: var(--ease-out); + } + .btn-soft { + &:not(.btn-active, :hover, :active:focus, :focus-visible, :disabled, [disabled], .btn-disabled) { + --btn-shadow: ""; + --btn-fg: var(--btn-color, var(--color-base-content)); + --btn-bg: var(--btn-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + --btn-bg: color-mix( + in oklab, + var(--btn-color, var(--color-base-content)) 8%, + var(--color-base-100) + ); + } + --btn-border: var(--btn-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + --btn-border: color-mix( + in oklab, + var(--btn-color, var(--color-base-content)) 10%, + var(--color-base-100) + ); + } + --btn-noise: none; + } + @media (hover: none) { + &:hover:not(.btn-active, :active, :focus-visible, :disabled, [disabled], .btn-disabled) { + --btn-shadow: ""; + --btn-fg: var(--btn-color, var(--color-base-content)); + --btn-bg: var(--btn-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + --btn-bg: color-mix( + in oklab, + var(--btn-color, var(--color-base-content)) 8%, + var(--color-base-100) + ); + } + --btn-border: var(--btn-color, var(--color-base-content)); + @supports (color: color-mix(in lab, red, red)) { + --btn-border: color-mix( + in oklab, + var(--btn-color, var(--color-base-content)) 10%, + var(--color-base-100) + ); + } + --btn-noise: none; + } + } + } + .badge-warning { + --badge-color: var(--color-warning); + --badge-fg: var(--color-warning-content); + } + .btn-primary { + --btn-color: var(--color-primary); + --btn-fg: var(--color-primary-content); + } + .input-error { + &, &:focus, &:focus-within { + --input-color: var(--color-error); + } + } + .select-error { + &, &:focus, &:focus-within { + --input-color: var(--color-error); + } + } + .textarea-error { + &, &:focus, &:focus-within { + --input-color: var(--color-error); + } + } + .group-hover\:bg-base-300 { + &:is(:where(.group):hover *) { + @media (hover: hover) { + background-color: var(--color-base-300); + } + } + } + .group-hover\:fill-base-content { + &:is(:where(.group):hover *) { + @media (hover: hover) { + fill: var(--color-base-content); + } + } + } + .group-hover\:opacity-70 { + &:is(:where(.group):hover *) { + @media (hover: hover) { + opacity: 70%; + } + } + } + .hover\:cursor-pointer { + &:hover { + @media (hover: hover) { + cursor: pointer; + } + } + } + .hover\:bg-base-200 { + &:hover { + @media (hover: hover) { + background-color: var(--color-base-200); + } + } + } + .hover\:bg-white { + &:hover { + @media (hover: hover) { + background-color: var(--color-white); + } + } + } + .hover\:text-base-content { + &:hover { + @media (hover: hover) { + color: var(--color-base-content); + } + } + } + .hover\:opacity-100 { + &:hover { + @media (hover: hover) { + opacity: 100%; + } + } + } + .motion-safe\:animate-spin { + @media (prefers-reduced-motion: no-preference) { + animation: var(--animate-spin); + } + } + .sm\:w-96 { + @media (width >= 40rem) { + width: calc(var(--spacing) * 96); + } + } + .sm\:w-auto { + @media (width >= 40rem) { + width: auto; + } + } + .sm\:max-w-96 { + @media (width >= 40rem) { + max-width: calc(var(--spacing) * 96); + } + } + .sm\:translate-y-0 { + @media (width >= 40rem) { + --tw-translate-y: calc(var(--spacing) * 0); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + } + .sm\:scale-95 { + @media (width >= 40rem) { + --tw-scale-x: 95%; + --tw-scale-y: 95%; + --tw-scale-z: 95%; + scale: var(--tw-scale-x) var(--tw-scale-y); + } + } + .sm\:scale-100 { + @media (width >= 40rem) { + --tw-scale-x: 100%; + --tw-scale-y: 100%; + --tw-scale-z: 100%; + scale: var(--tw-scale-x) var(--tw-scale-y); + } + } + .sm\:grid-cols-2 { + @media (width >= 40rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + .sm\:grid-cols-3 { + @media (width >= 40rem) { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + .sm\:flex-col { + @media (width >= 40rem) { + flex-direction: column; + } + } + .sm\:px-6 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + } + .sm\:py-6 { + @media (width >= 40rem) { + padding-block: calc(var(--spacing) * 6); + } + } + .sm\:py-28 { + @media (width >= 40rem) { + padding-block: calc(var(--spacing) * 28); + } + } + .sm\:group-hover\:scale-105 { + @media (width >= 40rem) { + &:is(:where(.group):hover *) { + @media (hover: hover) { + --tw-scale-x: 105%; + --tw-scale-y: 105%; + --tw-scale-z: 105%; + scale: var(--tw-scale-x) var(--tw-scale-y); + } + } + } + } + .lg\:mx-0 { + @media (width >= 64rem) { + margin-inline: calc(var(--spacing) * 0); + } + } + .lg\:block { + @media (width >= 64rem) { + display: block; + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } + .xl\:left-\[50rem\] { + @media (width >= 80rem) { + left: 50rem; + } + } + .xl\:px-28 { + @media (width >= 80rem) { + padding-inline: calc(var(--spacing) * 28); + } + } + .xl\:py-32 { + @media (width >= 80rem) { + padding-block: calc(var(--spacing) * 32); + } + } + .\[\[data-theme\=dark\]_\&\]\:left-2\/3 { + [data-theme=dark] & { + left: calc(2/3 * 100%); + } + } + .\[\[data-theme\=light\]_\&\]\:left-1\/3 { + [data-theme=light] & { + left: calc(1/3 * 100%); + } + } +} +[data-phx-session], [data-phx-teleported-src] { + display: contents; +} +@layer base { + :root:has( .modal-open, .modal[open], .modal:target, .modal-toggle:checked, .drawer:not([class*="drawer-open"]) > .drawer-toggle:checked ) { + overflow: hidden; + } +} +@layer base { + :root, [data-theme] { + background-color: var(--root-bg, var(--color-base-100)); + color: var(--color-base-content); + } +} +@layer base { + :root { + scrollbar-color: currentColor #0000; + @supports (color: color-mix(in lab, red, red)) { + scrollbar-color: color-mix(in oklch, currentColor 35%, #0000) #0000; + } + } +} +@layer base { + @property --radialprogress { + syntax: ""; + inherits: true; + initial-value: 0%; + } +} +@layer base { + :where( :root:has( .modal-open, .modal[open], .modal:target, .modal-toggle:checked, .drawer:not(.drawer-open) > .drawer-toggle:checked ) ) { + scrollbar-gutter: stable; + background-image: linear-gradient(var(--color-base-100), var(--color-base-100)); + --root-bg: var(--color-base-100); + @supports (color: color-mix(in lab, red, red)) { + --root-bg: color-mix(in srgb, var(--color-base-100), oklch(0% 0 0) 40%); + } + } + :where(.modal[open], .modal-open, .modal-toggle:checked + .modal):not(.modal-start, .modal-end) { + scrollbar-gutter: stable; + } +} +@layer base { + :root { + --fx-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.34' numOctaves='4' stitchTiles='stitch'%3E%3C/feTurbulence%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)' opacity='0.2'%3E%3C/rect%3E%3C/svg%3E"); + } + .chat { + --mask-chat: url("data:image/svg+xml,%3csvg width='13' height='13' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill='black' d='M0 11.5004C0 13.0004 2 13.0004 2 13.0004H12H13V0.00036329L12.5 0C12.5 0 11.977 2.09572 11.8581 2.50033C11.6075 3.35237 10.9149 4.22374 9 5.50036C6 7.50036 0 10.0004 0 11.5004Z'/%3e%3c/svg%3e"); + } +} +@keyframes dropdown { + 0% { + opacity: 0; + } +} +@keyframes progress { + 50% { + background-position-x: -115%; + } +} +@keyframes toast { + 0% { + scale: 0.9; + opacity: 0; + } + 100% { + scale: 1; + opacity: 1; + } +} +@keyframes rating { + 0%, 40% { + scale: 1.1; + filter: brightness(1.05) contrast(1.05); + } +} +@keyframes radio { + 0% { + padding: 5px; + } + 50% { + padding: 3px; + } +} +@keyframes skeleton { + 0% { + background-position: 150%; + } + 100% { + background-position: -50%; + } +} +@layer base { + @media (prefers-color-scheme: dark) { + :root { + color-scheme: dark; + --color-base-100: oklch(30.33% 0.016 252.42); + --color-base-200: oklch(25.26% 0.014 253.1); + --color-base-300: oklch(20.15% 0.012 254.09); + --color-base-content: oklch(97.807% 0.029 256.847); + --color-primary: oklch(58% 0.233 277.117); + --color-primary-content: oklch(96% 0.018 272.314); + --color-secondary: oklch(58% 0.233 277.117); + --color-secondary-content: oklch(96% 0.018 272.314); + --color-accent: oklch(60% 0.25 292.717); + --color-accent-content: oklch(96% 0.016 293.756); + --color-neutral: oklch(37% 0.044 257.287); + --color-neutral-content: oklch(98% 0.003 247.858); + --color-info: oklch(58% 0.158 241.966); + --color-info-content: oklch(97% 0.013 236.62); + --color-success: oklch(60% 0.118 184.704); + --color-success-content: oklch(98% 0.014 180.72); + --color-warning: oklch(66% 0.179 58.318); + --color-warning-content: oklch(98% 0.022 95.277); + --color-error: oklch(58% 0.253 17.585); + --color-error-content: oklch(96% 0.015 12.422); + --radius-selector: 0.25rem; + --radius-field: 0.25rem; + --radius-box: 0.5rem; + --size-selector: 0.21875rem; + --size-field: 0.21875rem; + --border: 1.5px; + --depth: 1; + --noise: 0; + } + } +} +@layer base { + :root:has(input.theme-controller[value=dark]:checked),[data-theme="dark"] { + color-scheme: dark; + --color-base-100: oklch(30.33% 0.016 252.42); + --color-base-200: oklch(25.26% 0.014 253.1); + --color-base-300: oklch(20.15% 0.012 254.09); + --color-base-content: oklch(97.807% 0.029 256.847); + --color-primary: oklch(58% 0.233 277.117); + --color-primary-content: oklch(96% 0.018 272.314); + --color-secondary: oklch(58% 0.233 277.117); + --color-secondary-content: oklch(96% 0.018 272.314); + --color-accent: oklch(60% 0.25 292.717); + --color-accent-content: oklch(96% 0.016 293.756); + --color-neutral: oklch(37% 0.044 257.287); + --color-neutral-content: oklch(98% 0.003 247.858); + --color-info: oklch(58% 0.158 241.966); + --color-info-content: oklch(97% 0.013 236.62); + --color-success: oklch(60% 0.118 184.704); + --color-success-content: oklch(98% 0.014 180.72); + --color-warning: oklch(66% 0.179 58.318); + --color-warning-content: oklch(98% 0.022 95.277); + --color-error: oklch(58% 0.253 17.585); + --color-error-content: oklch(96% 0.015 12.422); + --radius-selector: 0.25rem; + --radius-field: 0.25rem; + --radius-box: 0.5rem; + --size-selector: 0.21875rem; + --size-field: 0.21875rem; + --border: 1.5px; + --depth: 1; + --noise: 0; + } +} +@layer base { + :where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme="light"] { + color-scheme: light; + --color-base-100: oklch(98% 0 0); + --color-base-200: oklch(96% 0.001 286.375); + --color-base-300: oklch(92% 0.004 286.32); + --color-base-content: oklch(21% 0.006 285.885); + --color-primary: oklch(70% 0.213 47.604); + --color-primary-content: oklch(98% 0.016 73.684); + --color-secondary: oklch(55% 0.027 264.364); + --color-secondary-content: oklch(98% 0.002 247.839); + --color-accent: oklch(0% 0 0); + --color-accent-content: oklch(100% 0 0); + --color-neutral: oklch(44% 0.017 285.786); + --color-neutral-content: oklch(98% 0 0); + --color-info: oklch(62% 0.214 259.815); + --color-info-content: oklch(97% 0.014 254.604); + --color-success: oklch(70% 0.14 182.503); + --color-success-content: oklch(98% 0.014 180.72); + --color-warning: oklch(66% 0.179 58.318); + --color-warning-content: oklch(98% 0.022 95.277); + --color-error: oklch(58% 0.253 17.585); + --color-error-content: oklch(96% 0.015 12.422); + --radius-selector: 0.25rem; + --radius-field: 0.25rem; + --radius-box: 0.5rem; + --size-selector: 0.21875rem; + --size-field: 0.21875rem; + --border: 1.5px; + --depth: 1; + --noise: 0; + } +} +@property --tw-translate-x { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-y { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-translate-z { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-space-x-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-leading { + syntax: "*"; + inherits: false; +} +@property --tw-font-weight { + syntax: "*"; + inherits: false; +} +@property --tw-tracking { + syntax: "*"; + inherits: false; +} +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-blur { + syntax: "*"; + inherits: false; +} +@property --tw-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-invert { + syntax: "*"; + inherits: false; +} +@property --tw-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-drop-shadow-size { + syntax: "*"; + inherits: false; +} +@property --tw-duration { + syntax: "*"; + inherits: false; +} +@property --tw-ease { + syntax: "*"; + inherits: false; +} +@property --tw-scale-x { + syntax: "*"; + inherits: false; + initial-value: 1; +} +@property --tw-scale-y { + syntax: "*"; + inherits: false; + initial-value: 1; +} +@property --tw-scale-z { + syntax: "*"; + inherits: false; + initial-value: 1; +} +@keyframes spin { + to { + transform: rotate(360deg); + } +} +@keyframes ping { + 75%, 100% { + transform: scale(2); + opacity: 0; + } +} +@layer properties { + @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { + *, ::before, ::after, ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-translate-z: 0; + --tw-space-y-reverse: 0; + --tw-space-x-reverse: 0; + --tw-border-style: solid; + --tw-leading: initial; + --tw-font-weight: initial; + --tw-tracking: initial; + --tw-outline-style: solid; + --tw-blur: initial; + --tw-brightness: initial; + --tw-contrast: initial; + --tw-grayscale: initial; + --tw-hue-rotate: initial; + --tw-invert: initial; + --tw-opacity: initial; + --tw-saturate: initial; + --tw-sepia: initial; + --tw-drop-shadow: initial; + --tw-drop-shadow-color: initial; + --tw-drop-shadow-alpha: 100%; + --tw-drop-shadow-size: initial; + --tw-duration: initial; + --tw-ease: initial; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-scale-z: 1; + } + } +} diff --git a/priv/static/assets/js/app.js b/priv/static/assets/js/app.js new file mode 100644 index 0000000..59c35f4 --- /dev/null +++ b/priv/static/assets/js/app.js @@ -0,0 +1,8377 @@ +(() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // vendor/topbar.js + var require_topbar = __commonJS({ + "vendor/topbar.js"(exports, module) { + (function(window2, document2) { + "use strict"; + var canvas, currentProgress, showing, progressTimerId = null, fadeTimerId = null, delayTimerId = null, addEvent = function(elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)" + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null + }, repaint = function() { + canvas.width = window2.innerWidth; + canvas.height = options.barThickness * 5; + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, createCanvas = function() { + canvas = document2.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + addEvent(window2, "resize", repaint); + }, topbar2 = { + config: function(opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function(delay) { + if (showing) return; + if (delay) { + if (delayTimerId) return; + delayTimerId = setTimeout(() => topbar2.show(), delay); + } else { + showing = true; + if (fadeTimerId !== null) window2.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + if (!canvas.parentElement) document2.body.appendChild(canvas); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar2.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window2.requestAnimationFrame(loop); + topbar2.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + } + }, + progress: function(to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 ? currentProgress : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function() { + clearTimeout(delayTimerId); + delayTimerId = null; + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window2.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar2.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window2.requestAnimationFrame(loop); + })(); + } + }; + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar2; + } else if (typeof define === "function" && define.amd) { + define(function() { + return topbar2; + }); + } else { + this.topbar = topbar2; + } + }).call(exports, window, document); + } + }); + + // ../deps/phoenix_html/priv/static/phoenix_html.js + (function() { + var PolyfillEvent = eventConstructor(); + function eventConstructor() { + if (typeof window.CustomEvent === "function") return window.CustomEvent; + function CustomEvent2(event, params) { + params = params || { bubbles: false, cancelable: false, detail: void 0 }; + var evt = document.createEvent("CustomEvent"); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + } + CustomEvent2.prototype = window.Event.prototype; + return CustomEvent2; + } + function buildHiddenInput(name, value) { + var input = document.createElement("input"); + input.type = "hidden"; + input.name = name; + input.value = value; + return input; + } + function handleClick(element, targetModifierKey) { + var to = element.getAttribute("data-to"), method = buildHiddenInput("_method", element.getAttribute("data-method")), csrf = buildHiddenInput("_csrf_token", element.getAttribute("data-csrf")), form = document.createElement("form"), submit = document.createElement("input"), target = element.getAttribute("target"); + form.method = element.getAttribute("data-method") === "get" ? "get" : "post"; + form.action = to; + form.style.display = "none"; + if (target) form.target = target; + else if (targetModifierKey) form.target = "_blank"; + form.appendChild(csrf); + form.appendChild(method); + document.body.appendChild(form); + submit.type = "submit"; + form.appendChild(submit); + submit.click(); + } + window.addEventListener("click", function(e) { + var element = e.target; + if (e.defaultPrevented) return; + while (element && element.getAttribute) { + var phoenixLinkEvent = new PolyfillEvent("phoenix.link.click", { + "bubbles": true, + "cancelable": true + }); + if (!element.dispatchEvent(phoenixLinkEvent)) { + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + } + if (element.getAttribute("data-method") && element.getAttribute("data-to")) { + handleClick(element, e.metaKey || e.shiftKey); + e.preventDefault(); + return false; + } else { + element = element.parentNode; + } + } + }, false); + window.addEventListener("phoenix.link.click", function(e) { + var message = e.target.getAttribute("data-confirm"); + if (message && !window.confirm(message)) { + e.preventDefault(); + } + }, false); + })(); + + // ../deps/phoenix/priv/static/phoenix.mjs + var closure = (value) => { + if (typeof value === "function") { + return value; + } else { + let closure22 = function() { + return value; + }; + return closure22; + } + }; + var globalSelf = typeof self !== "undefined" ? self : null; + var phxWindow = typeof window !== "undefined" ? window : null; + var global = globalSelf || phxWindow || globalThis; + var DEFAULT_VSN = "2.0.0"; + var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 }; + var DEFAULT_TIMEOUT = 1e4; + var WS_CLOSE_NORMAL = 1e3; + var CHANNEL_STATES = { + closed: "closed", + errored: "errored", + joined: "joined", + joining: "joining", + leaving: "leaving" + }; + var CHANNEL_EVENTS = { + close: "phx_close", + error: "phx_error", + join: "phx_join", + reply: "phx_reply", + leave: "phx_leave" + }; + var TRANSPORTS = { + longpoll: "longpoll", + websocket: "websocket" + }; + var XHR_STATES = { + complete: 4 + }; + var AUTH_TOKEN_PREFIX = "base64url.bearer.phx."; + var Push = class { + constructor(channel, event, payload, timeout) { + this.channel = channel; + this.event = event; + this.payload = payload || function() { + return {}; + }; + this.receivedResp = null; + this.timeout = timeout; + this.timeoutTimer = null; + this.recHooks = []; + this.sent = false; + } + /** + * + * @param {number} timeout + */ + resend(timeout) { + this.timeout = timeout; + this.reset(); + this.send(); + } + /** + * + */ + send() { + if (this.hasReceived("timeout")) { + return; + } + this.startTimeout(); + this.sent = true; + this.channel.socket.push({ + topic: this.channel.topic, + event: this.event, + payload: this.payload(), + ref: this.ref, + join_ref: this.channel.joinRef() + }); + } + /** + * + * @param {*} status + * @param {*} callback + */ + receive(status, callback) { + if (this.hasReceived(status)) { + callback(this.receivedResp.response); + } + this.recHooks.push({ status, callback }); + return this; + } + /** + * @private + */ + reset() { + this.cancelRefEvent(); + this.ref = null; + this.refEvent = null; + this.receivedResp = null; + this.sent = false; + } + /** + * @private + */ + matchReceive({ status, response, _ref }) { + this.recHooks.filter((h) => h.status === status).forEach((h) => h.callback(response)); + } + /** + * @private + */ + cancelRefEvent() { + if (!this.refEvent) { + return; + } + this.channel.off(this.refEvent); + } + /** + * @private + */ + cancelTimeout() { + clearTimeout(this.timeoutTimer); + this.timeoutTimer = null; + } + /** + * @private + */ + startTimeout() { + if (this.timeoutTimer) { + this.cancelTimeout(); + } + this.ref = this.channel.socket.makeRef(); + this.refEvent = this.channel.replyEventName(this.ref); + this.channel.on(this.refEvent, (payload) => { + this.cancelRefEvent(); + this.cancelTimeout(); + this.receivedResp = payload; + this.matchReceive(payload); + }); + this.timeoutTimer = setTimeout(() => { + this.trigger("timeout", {}); + }, this.timeout); + } + /** + * @private + */ + hasReceived(status) { + return this.receivedResp && this.receivedResp.status === status; + } + /** + * @private + */ + trigger(status, response) { + this.channel.trigger(this.refEvent, { status, response }); + } + }; + var Timer = class { + constructor(callback, timerCalc) { + this.callback = callback; + this.timerCalc = timerCalc; + this.timer = null; + this.tries = 0; + } + reset() { + this.tries = 0; + clearTimeout(this.timer); + } + /** + * Cancels any previous scheduleTimeout and schedules callback + */ + scheduleTimeout() { + clearTimeout(this.timer); + this.timer = setTimeout(() => { + this.tries = this.tries + 1; + this.callback(); + }, this.timerCalc(this.tries + 1)); + } + }; + var Channel = class { + constructor(topic, params, socket) { + this.state = CHANNEL_STATES.closed; + this.topic = topic; + this.params = closure(params || {}); + this.socket = socket; + this.bindings = []; + this.bindingRef = 0; + this.timeout = this.socket.timeout; + this.joinedOnce = false; + this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout); + this.pushBuffer = []; + this.stateChangeRefs = []; + this.rejoinTimer = new Timer(() => { + if (this.socket.isConnected()) { + this.rejoin(); + } + }, this.socket.rejoinAfterMs); + this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset())); + this.stateChangeRefs.push( + this.socket.onOpen(() => { + this.rejoinTimer.reset(); + if (this.isErrored()) { + this.rejoin(); + } + }) + ); + this.joinPush.receive("ok", () => { + this.state = CHANNEL_STATES.joined; + this.rejoinTimer.reset(); + this.pushBuffer.forEach((pushEvent) => pushEvent.send()); + this.pushBuffer = []; + }); + this.joinPush.receive("error", () => { + this.state = CHANNEL_STATES.errored; + if (this.socket.isConnected()) { + this.rejoinTimer.scheduleTimeout(); + } + }); + this.onClose(() => { + this.rejoinTimer.reset(); + if (this.socket.hasLogger()) + this.socket.log("channel", `close ${this.topic} ${this.joinRef()}`); + this.state = CHANNEL_STATES.closed; + this.socket.remove(this); + }); + this.onError((reason) => { + if (this.socket.hasLogger()) + this.socket.log("channel", `error ${this.topic}`, reason); + if (this.isJoining()) { + this.joinPush.reset(); + } + this.state = CHANNEL_STATES.errored; + if (this.socket.isConnected()) { + this.rejoinTimer.scheduleTimeout(); + } + }); + this.joinPush.receive("timeout", () => { + if (this.socket.hasLogger()) + this.socket.log("channel", `timeout ${this.topic} (${this.joinRef()})`, this.joinPush.timeout); + let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout); + leavePush.send(); + this.state = CHANNEL_STATES.errored; + this.joinPush.reset(); + if (this.socket.isConnected()) { + this.rejoinTimer.scheduleTimeout(); + } + }); + this.on(CHANNEL_EVENTS.reply, (payload, ref) => { + this.trigger(this.replyEventName(ref), payload); + }); + } + /** + * Join the channel + * @param {integer} timeout + * @returns {Push} + */ + join(timeout = this.timeout) { + if (this.joinedOnce) { + throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance"); + } else { + this.timeout = timeout; + this.joinedOnce = true; + this.rejoin(); + return this.joinPush; + } + } + /** + * Hook into channel close + * @param {Function} callback + */ + onClose(callback) { + this.on(CHANNEL_EVENTS.close, callback); + } + /** + * Hook into channel errors + * @param {Function} callback + */ + onError(callback) { + return this.on(CHANNEL_EVENTS.error, (reason) => callback(reason)); + } + /** + * Subscribes on channel events + * + * Subscription returns a ref counter, which can be used later to + * unsubscribe the exact event listener + * + * @example + * const ref1 = channel.on("event", do_stuff) + * const ref2 = channel.on("event", do_other_stuff) + * channel.off("event", ref1) + * // Since unsubscription, do_stuff won't fire, + * // while do_other_stuff will keep firing on the "event" + * + * @param {string} event + * @param {Function} callback + * @returns {integer} ref + */ + on(event, callback) { + let ref = this.bindingRef++; + this.bindings.push({ event, ref, callback }); + return ref; + } + /** + * Unsubscribes off of channel events + * + * Use the ref returned from a channel.on() to unsubscribe one + * handler, or pass nothing for the ref to unsubscribe all + * handlers for the given event. + * + * @example + * // Unsubscribe the do_stuff handler + * const ref1 = channel.on("event", do_stuff) + * channel.off("event", ref1) + * + * // Unsubscribe all handlers from event + * channel.off("event") + * + * @param {string} event + * @param {integer} ref + */ + off(event, ref) { + this.bindings = this.bindings.filter((bind) => { + return !(bind.event === event && (typeof ref === "undefined" || ref === bind.ref)); + }); + } + /** + * @private + */ + canPush() { + return this.socket.isConnected() && this.isJoined(); + } + /** + * Sends a message `event` to phoenix with the payload `payload`. + * Phoenix receives this in the `handle_in(event, payload, socket)` + * function. if phoenix replies or it times out (default 10000ms), + * then optionally the reply can be received. + * + * @example + * channel.push("event") + * .receive("ok", payload => console.log("phoenix replied:", payload)) + * .receive("error", err => console.log("phoenix errored", err)) + * .receive("timeout", () => console.log("timed out pushing")) + * @param {string} event + * @param {Object} payload + * @param {number} [timeout] + * @returns {Push} + */ + push(event, payload, timeout = this.timeout) { + payload = payload || {}; + if (!this.joinedOnce) { + throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`); + } + let pushEvent = new Push(this, event, function() { + return payload; + }, timeout); + if (this.canPush()) { + pushEvent.send(); + } else { + pushEvent.startTimeout(); + this.pushBuffer.push(pushEvent); + } + return pushEvent; + } + /** Leaves the channel + * + * Unsubscribes from server events, and + * instructs channel to terminate on server + * + * Triggers onClose() hooks + * + * To receive leave acknowledgements, use the `receive` + * hook to bind to the server ack, ie: + * + * @example + * channel.leave().receive("ok", () => alert("left!") ) + * + * @param {integer} timeout + * @returns {Push} + */ + leave(timeout = this.timeout) { + this.rejoinTimer.reset(); + this.joinPush.cancelTimeout(); + this.state = CHANNEL_STATES.leaving; + let onClose = () => { + if (this.socket.hasLogger()) + this.socket.log("channel", `leave ${this.topic}`); + this.trigger(CHANNEL_EVENTS.close, "leave"); + }; + let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout); + leavePush.receive("ok", () => onClose()).receive("timeout", () => onClose()); + leavePush.send(); + if (!this.canPush()) { + leavePush.trigger("ok", {}); + } + return leavePush; + } + /** + * Overridable message hook + * + * Receives all events for specialized message handling + * before dispatching to the channel callbacks. + * + * Must return the payload, modified or unmodified + * @param {string} event + * @param {Object} payload + * @param {integer} ref + * @returns {Object} + */ + onMessage(_event, payload, _ref) { + return payload; + } + /** + * @private + */ + isMember(topic, event, payload, joinRef) { + if (this.topic !== topic) { + return false; + } + if (joinRef && joinRef !== this.joinRef()) { + if (this.socket.hasLogger()) + this.socket.log("channel", "dropping outdated message", { topic, event, payload, joinRef }); + return false; + } else { + return true; + } + } + /** + * @private + */ + joinRef() { + return this.joinPush.ref; + } + /** + * @private + */ + rejoin(timeout = this.timeout) { + if (this.isLeaving()) { + return; + } + this.socket.leaveOpenTopic(this.topic); + this.state = CHANNEL_STATES.joining; + this.joinPush.resend(timeout); + } + /** + * @private + */ + trigger(event, payload, ref, joinRef) { + let handledPayload = this.onMessage(event, payload, ref, joinRef); + if (payload && !handledPayload) { + throw new Error("channel onMessage callbacks must return the payload, modified or unmodified"); + } + let eventBindings = this.bindings.filter((bind) => bind.event === event); + for (let i = 0; i < eventBindings.length; i++) { + let bind = eventBindings[i]; + bind.callback(handledPayload, ref, joinRef || this.joinRef()); + } + } + /** + * @private + */ + replyEventName(ref) { + return `chan_reply_${ref}`; + } + /** + * @private + */ + isClosed() { + return this.state === CHANNEL_STATES.closed; + } + /** + * @private + */ + isErrored() { + return this.state === CHANNEL_STATES.errored; + } + /** + * @private + */ + isJoined() { + return this.state === CHANNEL_STATES.joined; + } + /** + * @private + */ + isJoining() { + return this.state === CHANNEL_STATES.joining; + } + /** + * @private + */ + isLeaving() { + return this.state === CHANNEL_STATES.leaving; + } + }; + var Ajax = class { + static request(method, endPoint, headers, body, timeout, ontimeout, callback) { + if (global.XDomainRequest) { + let req = new global.XDomainRequest(); + return this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback); + } else if (global.XMLHttpRequest) { + let req = new global.XMLHttpRequest(); + return this.xhrRequest(req, method, endPoint, headers, body, timeout, ontimeout, callback); + } else if (global.fetch && global.AbortController) { + return this.fetchRequest(method, endPoint, headers, body, timeout, ontimeout, callback); + } else { + throw new Error("No suitable XMLHttpRequest implementation found"); + } + } + static fetchRequest(method, endPoint, headers, body, timeout, ontimeout, callback) { + let options = { + method, + headers, + body + }; + let controller = null; + if (timeout) { + controller = new AbortController(); + const _timeoutId = setTimeout(() => controller.abort(), timeout); + options.signal = controller.signal; + } + global.fetch(endPoint, options).then((response) => response.text()).then((data) => this.parseJSON(data)).then((data) => callback && callback(data)).catch((err) => { + if (err.name === "AbortError" && ontimeout) { + ontimeout(); + } else { + callback && callback(null); + } + }); + return controller; + } + static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) { + req.timeout = timeout; + req.open(method, endPoint); + req.onload = () => { + let response = this.parseJSON(req.responseText); + callback && callback(response); + }; + if (ontimeout) { + req.ontimeout = ontimeout; + } + req.onprogress = () => { + }; + req.send(body); + return req; + } + static xhrRequest(req, method, endPoint, headers, body, timeout, ontimeout, callback) { + req.open(method, endPoint, true); + req.timeout = timeout; + for (let [key, value] of Object.entries(headers)) { + req.setRequestHeader(key, value); + } + req.onerror = () => callback && callback(null); + req.onreadystatechange = () => { + if (req.readyState === XHR_STATES.complete && callback) { + let response = this.parseJSON(req.responseText); + callback(response); + } + }; + if (ontimeout) { + req.ontimeout = ontimeout; + } + req.send(body); + return req; + } + static parseJSON(resp) { + if (!resp || resp === "") { + return null; + } + try { + return JSON.parse(resp); + } catch { + console && console.log("failed to parse JSON response", resp); + return null; + } + } + static serialize(obj, parentKey) { + let queryStr = []; + for (var key in obj) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + let paramKey = parentKey ? `${parentKey}[${key}]` : key; + let paramVal = obj[key]; + if (typeof paramVal === "object") { + queryStr.push(this.serialize(paramVal, paramKey)); + } else { + queryStr.push(encodeURIComponent(paramKey) + "=" + encodeURIComponent(paramVal)); + } + } + return queryStr.join("&"); + } + static appendParams(url, params) { + if (Object.keys(params).length === 0) { + return url; + } + let prefix = url.match(/\?/) ? "&" : "?"; + return `${url}${prefix}${this.serialize(params)}`; + } + }; + var arrayBufferToBase64 = (buffer) => { + let binary = ""; + let bytes = new Uint8Array(buffer); + let len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary); + }; + var LongPoll = class { + constructor(endPoint, protocols) { + if (protocols && protocols.length === 2 && protocols[1].startsWith(AUTH_TOKEN_PREFIX)) { + this.authToken = atob(protocols[1].slice(AUTH_TOKEN_PREFIX.length)); + } + this.endPoint = null; + this.token = null; + this.skipHeartbeat = true; + this.reqs = /* @__PURE__ */ new Set(); + this.awaitingBatchAck = false; + this.currentBatch = null; + this.currentBatchTimer = null; + this.batchBuffer = []; + this.onopen = function() { + }; + this.onerror = function() { + }; + this.onmessage = function() { + }; + this.onclose = function() { + }; + this.pollEndpoint = this.normalizeEndpoint(endPoint); + this.readyState = SOCKET_STATES.connecting; + setTimeout(() => this.poll(), 0); + } + normalizeEndpoint(endPoint) { + return endPoint.replace("ws://", "http://").replace("wss://", "https://").replace(new RegExp("(.*)/" + TRANSPORTS.websocket), "$1/" + TRANSPORTS.longpoll); + } + endpointURL() { + return Ajax.appendParams(this.pollEndpoint, { token: this.token }); + } + closeAndRetry(code, reason, wasClean) { + this.close(code, reason, wasClean); + this.readyState = SOCKET_STATES.connecting; + } + ontimeout() { + this.onerror("timeout"); + this.closeAndRetry(1005, "timeout", false); + } + isActive() { + return this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting; + } + poll() { + const headers = { "Accept": "application/json" }; + if (this.authToken) { + headers["X-Phoenix-AuthToken"] = this.authToken; + } + this.ajax("GET", headers, null, () => this.ontimeout(), (resp) => { + if (resp) { + var { status, token, messages } = resp; + this.token = token; + } else { + status = 0; + } + switch (status) { + case 200: + messages.forEach((msg) => { + setTimeout(() => this.onmessage({ data: msg }), 0); + }); + this.poll(); + break; + case 204: + this.poll(); + break; + case 410: + this.readyState = SOCKET_STATES.open; + this.onopen({}); + this.poll(); + break; + case 403: + this.onerror(403); + this.close(1008, "forbidden", false); + break; + case 0: + case 500: + this.onerror(500); + this.closeAndRetry(1011, "internal server error", 500); + break; + default: + throw new Error(`unhandled poll status ${status}`); + } + }); + } + // we collect all pushes within the current event loop by + // setTimeout 0, which optimizes back-to-back procedural + // pushes against an empty buffer + send(body) { + if (typeof body !== "string") { + body = arrayBufferToBase64(body); + } + if (this.currentBatch) { + this.currentBatch.push(body); + } else if (this.awaitingBatchAck) { + this.batchBuffer.push(body); + } else { + this.currentBatch = [body]; + this.currentBatchTimer = setTimeout(() => { + this.batchSend(this.currentBatch); + this.currentBatch = null; + }, 0); + } + } + batchSend(messages) { + this.awaitingBatchAck = true; + this.ajax("POST", { "Content-Type": "application/x-ndjson" }, messages.join("\n"), () => this.onerror("timeout"), (resp) => { + this.awaitingBatchAck = false; + if (!resp || resp.status !== 200) { + this.onerror(resp && resp.status); + this.closeAndRetry(1011, "internal server error", false); + } else if (this.batchBuffer.length > 0) { + this.batchSend(this.batchBuffer); + this.batchBuffer = []; + } + }); + } + close(code, reason, wasClean) { + for (let req of this.reqs) { + req.abort(); + } + this.readyState = SOCKET_STATES.closed; + let opts = Object.assign({ code: 1e3, reason: void 0, wasClean: true }, { code, reason, wasClean }); + this.batchBuffer = []; + clearTimeout(this.currentBatchTimer); + this.currentBatchTimer = null; + if (typeof CloseEvent !== "undefined") { + this.onclose(new CloseEvent("close", opts)); + } else { + this.onclose(opts); + } + } + ajax(method, headers, body, onCallerTimeout, callback) { + let req; + let ontimeout = () => { + this.reqs.delete(req); + onCallerTimeout(); + }; + req = Ajax.request(method, this.endpointURL(), headers, body, this.timeout, ontimeout, (resp) => { + this.reqs.delete(req); + if (this.isActive()) { + callback(resp); + } + }); + this.reqs.add(req); + } + }; + var serializer_default = { + HEADER_LENGTH: 1, + META_LENGTH: 4, + KINDS: { push: 0, reply: 1, broadcast: 2 }, + encode(msg, callback) { + if (msg.payload.constructor === ArrayBuffer) { + return callback(this.binaryEncode(msg)); + } else { + let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]; + return callback(JSON.stringify(payload)); + } + }, + decode(rawPayload, callback) { + if (rawPayload.constructor === ArrayBuffer) { + return callback(this.binaryDecode(rawPayload)); + } else { + let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload); + return callback({ join_ref, ref, topic, event, payload }); + } + }, + // private + binaryEncode(message) { + let { join_ref, ref, event, topic, payload } = message; + let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length; + let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength); + let view = new DataView(header); + let offset = 0; + view.setUint8(offset++, this.KINDS.push); + view.setUint8(offset++, join_ref.length); + view.setUint8(offset++, ref.length); + view.setUint8(offset++, topic.length); + view.setUint8(offset++, event.length); + Array.from(join_ref, (char) => view.setUint8(offset++, char.charCodeAt(0))); + Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0))); + Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0))); + Array.from(event, (char) => view.setUint8(offset++, char.charCodeAt(0))); + var combined = new Uint8Array(header.byteLength + payload.byteLength); + combined.set(new Uint8Array(header), 0); + combined.set(new Uint8Array(payload), header.byteLength); + return combined.buffer; + }, + binaryDecode(buffer) { + let view = new DataView(buffer); + let kind = view.getUint8(0); + let decoder = new TextDecoder(); + switch (kind) { + case this.KINDS.push: + return this.decodePush(buffer, view, decoder); + case this.KINDS.reply: + return this.decodeReply(buffer, view, decoder); + case this.KINDS.broadcast: + return this.decodeBroadcast(buffer, view, decoder); + } + }, + decodePush(buffer, view, decoder) { + let joinRefSize = view.getUint8(1); + let topicSize = view.getUint8(2); + let eventSize = view.getUint8(3); + let offset = this.HEADER_LENGTH + this.META_LENGTH - 1; + let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize)); + offset = offset + joinRefSize; + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); + offset = offset + topicSize; + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); + offset = offset + eventSize; + let data = buffer.slice(offset, buffer.byteLength); + return { join_ref: joinRef, ref: null, topic, event, payload: data }; + }, + decodeReply(buffer, view, decoder) { + let joinRefSize = view.getUint8(1); + let refSize = view.getUint8(2); + let topicSize = view.getUint8(3); + let eventSize = view.getUint8(4); + let offset = this.HEADER_LENGTH + this.META_LENGTH; + let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize)); + offset = offset + joinRefSize; + let ref = decoder.decode(buffer.slice(offset, offset + refSize)); + offset = offset + refSize; + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); + offset = offset + topicSize; + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); + offset = offset + eventSize; + let data = buffer.slice(offset, buffer.byteLength); + let payload = { status: event, response: data }; + return { join_ref: joinRef, ref, topic, event: CHANNEL_EVENTS.reply, payload }; + }, + decodeBroadcast(buffer, view, decoder) { + let topicSize = view.getUint8(1); + let eventSize = view.getUint8(2); + let offset = this.HEADER_LENGTH + 2; + let topic = decoder.decode(buffer.slice(offset, offset + topicSize)); + offset = offset + topicSize; + let event = decoder.decode(buffer.slice(offset, offset + eventSize)); + offset = offset + eventSize; + let data = buffer.slice(offset, buffer.byteLength); + return { join_ref: null, ref: null, topic, event, payload: data }; + } + }; + var Socket = class { + constructor(endPoint, opts = {}) { + this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] }; + this.channels = []; + this.sendBuffer = []; + this.ref = 0; + this.timeout = opts.timeout || DEFAULT_TIMEOUT; + this.transport = opts.transport || global.WebSocket || LongPoll; + this.primaryPassedHealthCheck = false; + this.longPollFallbackMs = opts.longPollFallbackMs; + this.fallbackTimer = null; + this.sessionStore = opts.sessionStorage || global && global.sessionStorage; + this.establishedConnections = 0; + this.defaultEncoder = serializer_default.encode.bind(serializer_default); + this.defaultDecoder = serializer_default.decode.bind(serializer_default); + this.closeWasClean = false; + this.disconnecting = false; + this.binaryType = opts.binaryType || "arraybuffer"; + this.connectClock = 1; + if (this.transport !== LongPoll) { + this.encode = opts.encode || this.defaultEncoder; + this.decode = opts.decode || this.defaultDecoder; + } else { + this.encode = this.defaultEncoder; + this.decode = this.defaultDecoder; + } + let awaitingConnectionOnPageShow = null; + if (phxWindow && phxWindow.addEventListener) { + phxWindow.addEventListener("pagehide", (_e) => { + if (this.conn) { + this.disconnect(); + awaitingConnectionOnPageShow = this.connectClock; + } + }); + phxWindow.addEventListener("pageshow", (_e) => { + if (awaitingConnectionOnPageShow === this.connectClock) { + awaitingConnectionOnPageShow = null; + this.connect(); + } + }); + } + this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4; + this.rejoinAfterMs = (tries) => { + if (opts.rejoinAfterMs) { + return opts.rejoinAfterMs(tries); + } else { + return [1e3, 2e3, 5e3][tries - 1] || 1e4; + } + }; + this.reconnectAfterMs = (tries) => { + if (opts.reconnectAfterMs) { + return opts.reconnectAfterMs(tries); + } else { + return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3; + } + }; + this.logger = opts.logger || null; + if (!this.logger && opts.debug) { + this.logger = (kind, msg, data) => { + console.log(`${kind}: ${msg}`, data); + }; + } + this.longpollerTimeout = opts.longpollerTimeout || 2e4; + this.params = closure(opts.params || {}); + this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`; + this.vsn = opts.vsn || DEFAULT_VSN; + this.heartbeatTimeoutTimer = null; + this.heartbeatTimer = null; + this.pendingHeartbeatRef = null; + this.reconnectTimer = new Timer(() => { + this.teardown(() => this.connect()); + }, this.reconnectAfterMs); + this.authToken = opts.authToken; + } + /** + * Returns the LongPoll transport reference + */ + getLongPollTransport() { + return LongPoll; + } + /** + * Disconnects and replaces the active transport + * + * @param {Function} newTransport - The new transport class to instantiate + * + */ + replaceTransport(newTransport) { + this.connectClock++; + this.closeWasClean = true; + clearTimeout(this.fallbackTimer); + this.reconnectTimer.reset(); + if (this.conn) { + this.conn.close(); + this.conn = null; + } + this.transport = newTransport; + } + /** + * Returns the socket protocol + * + * @returns {string} + */ + protocol() { + return location.protocol.match(/^https/) ? "wss" : "ws"; + } + /** + * The fully qualified socket url + * + * @returns {string} + */ + endPointURL() { + let uri = Ajax.appendParams( + Ajax.appendParams(this.endPoint, this.params()), + { vsn: this.vsn } + ); + if (uri.charAt(0) !== "/") { + return uri; + } + if (uri.charAt(1) === "/") { + return `${this.protocol()}:${uri}`; + } + return `${this.protocol()}://${location.host}${uri}`; + } + /** + * Disconnects the socket + * + * See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes for valid status codes. + * + * @param {Function} callback - Optional callback which is called after socket is disconnected. + * @param {integer} code - A status code for disconnection (Optional). + * @param {string} reason - A textual description of the reason to disconnect. (Optional) + */ + disconnect(callback, code, reason) { + this.connectClock++; + this.disconnecting = true; + this.closeWasClean = true; + clearTimeout(this.fallbackTimer); + this.reconnectTimer.reset(); + this.teardown(() => { + this.disconnecting = false; + callback && callback(); + }, code, reason); + } + /** + * + * @param {Object} params - The params to send when connecting, for example `{user_id: userToken}` + * + * Passing params to connect is deprecated; pass them in the Socket constructor instead: + * `new Socket("/socket", {params: {user_id: userToken}})`. + */ + connect(params) { + if (params) { + console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"); + this.params = closure(params); + } + if (this.conn && !this.disconnecting) { + return; + } + if (this.longPollFallbackMs && this.transport !== LongPoll) { + this.connectWithFallback(LongPoll, this.longPollFallbackMs); + } else { + this.transportConnect(); + } + } + /** + * Logs the message. Override `this.logger` for specialized logging. noops by default + * @param {string} kind + * @param {string} msg + * @param {Object} data + */ + log(kind, msg, data) { + this.logger && this.logger(kind, msg, data); + } + /** + * Returns true if a logger has been set on this socket. + */ + hasLogger() { + return this.logger !== null; + } + /** + * Registers callbacks for connection open events + * + * @example socket.onOpen(function(){ console.info("the socket was opened") }) + * + * @param {Function} callback + */ + onOpen(callback) { + let ref = this.makeRef(); + this.stateChangeCallbacks.open.push([ref, callback]); + return ref; + } + /** + * Registers callbacks for connection close events + * @param {Function} callback + */ + onClose(callback) { + let ref = this.makeRef(); + this.stateChangeCallbacks.close.push([ref, callback]); + return ref; + } + /** + * Registers callbacks for connection error events + * + * @example socket.onError(function(error){ alert("An error occurred") }) + * + * @param {Function} callback + */ + onError(callback) { + let ref = this.makeRef(); + this.stateChangeCallbacks.error.push([ref, callback]); + return ref; + } + /** + * Registers callbacks for connection message events + * @param {Function} callback + */ + onMessage(callback) { + let ref = this.makeRef(); + this.stateChangeCallbacks.message.push([ref, callback]); + return ref; + } + /** + * Pings the server and invokes the callback with the RTT in milliseconds + * @param {Function} callback + * + * Returns true if the ping was pushed or false if unable to be pushed. + */ + ping(callback) { + if (!this.isConnected()) { + return false; + } + let ref = this.makeRef(); + let startTime = Date.now(); + this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref }); + let onMsgRef = this.onMessage((msg) => { + if (msg.ref === ref) { + this.off([onMsgRef]); + callback(Date.now() - startTime); + } + }); + return true; + } + /** + * @private + */ + transportConnect() { + this.connectClock++; + this.closeWasClean = false; + let protocols = void 0; + if (this.authToken) { + protocols = ["phoenix", `${AUTH_TOKEN_PREFIX}${btoa(this.authToken).replace(/=/g, "")}`]; + } + this.conn = new this.transport(this.endPointURL(), protocols); + this.conn.binaryType = this.binaryType; + this.conn.timeout = this.longpollerTimeout; + this.conn.onopen = () => this.onConnOpen(); + this.conn.onerror = (error) => this.onConnError(error); + this.conn.onmessage = (event) => this.onConnMessage(event); + this.conn.onclose = (event) => this.onConnClose(event); + } + getSession(key) { + return this.sessionStore && this.sessionStore.getItem(key); + } + storeSession(key, val) { + this.sessionStore && this.sessionStore.setItem(key, val); + } + connectWithFallback(fallbackTransport, fallbackThreshold = 2500) { + clearTimeout(this.fallbackTimer); + let established = false; + let primaryTransport = true; + let openRef, errorRef; + let fallback = (reason) => { + this.log("transport", `falling back to ${fallbackTransport.name}...`, reason); + this.off([openRef, errorRef]); + primaryTransport = false; + this.replaceTransport(fallbackTransport); + this.transportConnect(); + }; + if (this.getSession(`phx:fallback:${fallbackTransport.name}`)) { + return fallback("memorized"); + } + this.fallbackTimer = setTimeout(fallback, fallbackThreshold); + errorRef = this.onError((reason) => { + this.log("transport", "error", reason); + if (primaryTransport && !established) { + clearTimeout(this.fallbackTimer); + fallback(reason); + } + }); + this.onOpen(() => { + established = true; + if (!primaryTransport) { + if (!this.primaryPassedHealthCheck) { + this.storeSession(`phx:fallback:${fallbackTransport.name}`, "true"); + } + return this.log("transport", `established ${fallbackTransport.name} fallback`); + } + clearTimeout(this.fallbackTimer); + this.fallbackTimer = setTimeout(fallback, fallbackThreshold); + this.ping((rtt) => { + this.log("transport", "connected to primary after", rtt); + this.primaryPassedHealthCheck = true; + clearTimeout(this.fallbackTimer); + }); + }); + this.transportConnect(); + } + clearHeartbeats() { + clearTimeout(this.heartbeatTimer); + clearTimeout(this.heartbeatTimeoutTimer); + } + onConnOpen() { + if (this.hasLogger()) + this.log("transport", `${this.transport.name} connected to ${this.endPointURL()}`); + this.closeWasClean = false; + this.disconnecting = false; + this.establishedConnections++; + this.flushSendBuffer(); + this.reconnectTimer.reset(); + this.resetHeartbeat(); + this.stateChangeCallbacks.open.forEach(([, callback]) => callback()); + } + /** + * @private + */ + heartbeatTimeout() { + if (this.pendingHeartbeatRef) { + this.pendingHeartbeatRef = null; + if (this.hasLogger()) { + this.log("transport", "heartbeat timeout. Attempting to re-establish connection"); + } + this.triggerChanError(); + this.closeWasClean = false; + this.teardown(() => this.reconnectTimer.scheduleTimeout(), WS_CLOSE_NORMAL, "heartbeat timeout"); + } + } + resetHeartbeat() { + if (this.conn && this.conn.skipHeartbeat) { + return; + } + this.pendingHeartbeatRef = null; + this.clearHeartbeats(); + this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs); + } + teardown(callback, code, reason) { + if (!this.conn) { + return callback && callback(); + } + let connectClock = this.connectClock; + this.waitForBufferDone(() => { + if (connectClock !== this.connectClock) { + return; + } + if (this.conn) { + if (code) { + this.conn.close(code, reason || ""); + } else { + this.conn.close(); + } + } + this.waitForSocketClosed(() => { + if (connectClock !== this.connectClock) { + return; + } + if (this.conn) { + this.conn.onopen = function() { + }; + this.conn.onerror = function() { + }; + this.conn.onmessage = function() { + }; + this.conn.onclose = function() { + }; + this.conn = null; + } + callback && callback(); + }); + }); + } + waitForBufferDone(callback, tries = 1) { + if (tries === 5 || !this.conn || !this.conn.bufferedAmount) { + callback(); + return; + } + setTimeout(() => { + this.waitForBufferDone(callback, tries + 1); + }, 150 * tries); + } + waitForSocketClosed(callback, tries = 1) { + if (tries === 5 || !this.conn || this.conn.readyState === SOCKET_STATES.closed) { + callback(); + return; + } + setTimeout(() => { + this.waitForSocketClosed(callback, tries + 1); + }, 150 * tries); + } + onConnClose(event) { + let closeCode = event && event.code; + if (this.hasLogger()) + this.log("transport", "close", event); + this.triggerChanError(); + this.clearHeartbeats(); + if (!this.closeWasClean && closeCode !== 1e3) { + this.reconnectTimer.scheduleTimeout(); + } + this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event)); + } + /** + * @private + */ + onConnError(error) { + if (this.hasLogger()) + this.log("transport", error); + let transportBefore = this.transport; + let establishedBefore = this.establishedConnections; + this.stateChangeCallbacks.error.forEach(([, callback]) => { + callback(error, transportBefore, establishedBefore); + }); + if (transportBefore === this.transport || establishedBefore > 0) { + this.triggerChanError(); + } + } + /** + * @private + */ + triggerChanError() { + this.channels.forEach((channel) => { + if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) { + channel.trigger(CHANNEL_EVENTS.error); + } + }); + } + /** + * @returns {string} + */ + connectionState() { + switch (this.conn && this.conn.readyState) { + case SOCKET_STATES.connecting: + return "connecting"; + case SOCKET_STATES.open: + return "open"; + case SOCKET_STATES.closing: + return "closing"; + default: + return "closed"; + } + } + /** + * @returns {boolean} + */ + isConnected() { + return this.connectionState() === "open"; + } + /** + * @private + * + * @param {Channel} + */ + remove(channel) { + this.off(channel.stateChangeRefs); + this.channels = this.channels.filter((c) => c !== channel); + } + /** + * Removes `onOpen`, `onClose`, `onError,` and `onMessage` registrations. + * + * @param {refs} - list of refs returned by calls to + * `onOpen`, `onClose`, `onError,` and `onMessage` + */ + off(refs) { + for (let key in this.stateChangeCallbacks) { + this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => { + return refs.indexOf(ref) === -1; + }); + } + } + /** + * Initiates a new channel for the given topic + * + * @param {string} topic + * @param {Object} chanParams - Parameters for the channel + * @returns {Channel} + */ + channel(topic, chanParams = {}) { + let chan = new Channel(topic, chanParams, this); + this.channels.push(chan); + return chan; + } + /** + * @param {Object} data + */ + push(data) { + if (this.hasLogger()) { + let { topic, event, payload, ref, join_ref } = data; + this.log("push", `${topic} ${event} (${join_ref}, ${ref})`, payload); + } + if (this.isConnected()) { + this.encode(data, (result) => this.conn.send(result)); + } else { + this.sendBuffer.push(() => this.encode(data, (result) => this.conn.send(result))); + } + } + /** + * Return the next message ref, accounting for overflows + * @returns {string} + */ + makeRef() { + let newRef = this.ref + 1; + if (newRef === this.ref) { + this.ref = 0; + } else { + this.ref = newRef; + } + return this.ref.toString(); + } + sendHeartbeat() { + if (this.pendingHeartbeatRef && !this.isConnected()) { + return; + } + this.pendingHeartbeatRef = this.makeRef(); + this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef }); + this.heartbeatTimeoutTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs); + } + flushSendBuffer() { + if (this.isConnected() && this.sendBuffer.length > 0) { + this.sendBuffer.forEach((callback) => callback()); + this.sendBuffer = []; + } + } + onConnMessage(rawMessage) { + this.decode(rawMessage.data, (msg) => { + let { topic, event, payload, ref, join_ref } = msg; + if (ref && ref === this.pendingHeartbeatRef) { + this.clearHeartbeats(); + this.pendingHeartbeatRef = null; + this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs); + } + if (this.hasLogger()) + this.log("receive", `${payload.status || ""} ${topic} ${event} ${ref && "(" + ref + ")" || ""}`, payload); + for (let i = 0; i < this.channels.length; i++) { + const channel = this.channels[i]; + if (!channel.isMember(topic, event, payload, join_ref)) { + continue; + } + channel.trigger(event, payload, ref, join_ref); + } + for (let i = 0; i < this.stateChangeCallbacks.message.length; i++) { + let [, callback] = this.stateChangeCallbacks.message[i]; + callback(msg); + } + }); + } + leaveOpenTopic(topic) { + let dupChannel = this.channels.find((c) => c.topic === topic && (c.isJoined() || c.isJoining())); + if (dupChannel) { + if (this.hasLogger()) + this.log("transport", `leaving duplicate topic "${topic}"`); + dupChannel.leave(); + } + } + }; + + // ../deps/phoenix_live_view/priv/static/phoenix_live_view.esm.js + var CONSECUTIVE_RELOADS = "consecutive-reloads"; + var MAX_RELOADS = 10; + var RELOAD_JITTER_MIN = 5e3; + var RELOAD_JITTER_MAX = 1e4; + var FAILSAFE_JITTER = 3e4; + var PHX_EVENT_CLASSES = [ + "phx-click-loading", + "phx-change-loading", + "phx-submit-loading", + "phx-keydown-loading", + "phx-keyup-loading", + "phx-blur-loading", + "phx-focus-loading", + "phx-hook-loading" + ]; + var PHX_COMPONENT = "data-phx-component"; + var PHX_VIEW_REF = "data-phx-view"; + var PHX_LIVE_LINK = "data-phx-link"; + var PHX_TRACK_STATIC = "track-static"; + var PHX_LINK_STATE = "data-phx-link-state"; + var PHX_REF_LOADING = "data-phx-ref-loading"; + var PHX_REF_SRC = "data-phx-ref-src"; + var PHX_REF_LOCK = "data-phx-ref-lock"; + var PHX_PENDING_REFS = "phx-pending-refs"; + var PHX_TRACK_UPLOADS = "track-uploads"; + var PHX_UPLOAD_REF = "data-phx-upload-ref"; + var PHX_PREFLIGHTED_REFS = "data-phx-preflighted-refs"; + var PHX_DONE_REFS = "data-phx-done-refs"; + var PHX_DROP_TARGET = "drop-target"; + var PHX_ACTIVE_ENTRY_REFS = "data-phx-active-refs"; + var PHX_LIVE_FILE_UPDATED = "phx:live-file:updated"; + var PHX_SKIP = "data-phx-skip"; + var PHX_MAGIC_ID = "data-phx-id"; + var PHX_PRUNE = "data-phx-prune"; + var PHX_CONNECTED_CLASS = "phx-connected"; + var PHX_LOADING_CLASS = "phx-loading"; + var PHX_ERROR_CLASS = "phx-error"; + var PHX_CLIENT_ERROR_CLASS = "phx-client-error"; + var PHX_SERVER_ERROR_CLASS = "phx-server-error"; + var PHX_PARENT_ID = "data-phx-parent-id"; + var PHX_MAIN = "data-phx-main"; + var PHX_ROOT_ID = "data-phx-root-id"; + var PHX_VIEWPORT_TOP = "viewport-top"; + var PHX_VIEWPORT_BOTTOM = "viewport-bottom"; + var PHX_TRIGGER_ACTION = "trigger-action"; + var PHX_HAS_FOCUSED = "phx-has-focused"; + var FOCUSABLE_INPUTS = [ + "text", + "textarea", + "number", + "email", + "password", + "search", + "tel", + "url", + "date", + "time", + "datetime-local", + "color", + "range" + ]; + var CHECKABLE_INPUTS = ["checkbox", "radio"]; + var PHX_HAS_SUBMITTED = "phx-has-submitted"; + var PHX_SESSION = "data-phx-session"; + var PHX_VIEW_SELECTOR = `[${PHX_SESSION}]`; + var PHX_STICKY = "data-phx-sticky"; + var PHX_STATIC = "data-phx-static"; + var PHX_READONLY = "data-phx-readonly"; + var PHX_DISABLED = "data-phx-disabled"; + var PHX_DISABLE_WITH = "disable-with"; + var PHX_DISABLE_WITH_RESTORE = "data-phx-disable-with-restore"; + var PHX_HOOK = "hook"; + var PHX_DEBOUNCE = "debounce"; + var PHX_THROTTLE = "throttle"; + var PHX_UPDATE = "update"; + var PHX_STREAM = "stream"; + var PHX_STREAM_REF = "data-phx-stream"; + var PHX_PORTAL = "data-phx-portal"; + var PHX_TELEPORTED_REF = "data-phx-teleported"; + var PHX_TELEPORTED_SRC = "data-phx-teleported-src"; + var PHX_RUNTIME_HOOK = "data-phx-runtime-hook"; + var PHX_LV_PID = "data-phx-pid"; + var PHX_KEY = "key"; + var PHX_PRIVATE = "phxPrivate"; + var PHX_AUTO_RECOVER = "auto-recover"; + var PHX_LV_DEBUG = "phx:live-socket:debug"; + var PHX_LV_PROFILE = "phx:live-socket:profiling"; + var PHX_LV_LATENCY_SIM = "phx:live-socket:latency-sim"; + var PHX_LV_HISTORY_POSITION = "phx:nav-history-position"; + var PHX_PROGRESS = "progress"; + var PHX_MOUNTED = "mounted"; + var PHX_RELOAD_STATUS = "__phoenix_reload_status__"; + var LOADER_TIMEOUT = 1; + var MAX_CHILD_JOIN_ATTEMPTS = 3; + var BEFORE_UNLOAD_LOADER_TIMEOUT = 200; + var DISCONNECTED_TIMEOUT = 500; + var BINDING_PREFIX = "phx-"; + var PUSH_TIMEOUT = 3e4; + var DEBOUNCE_TRIGGER = "debounce-trigger"; + var THROTTLED = "throttled"; + var DEBOUNCE_PREV_KEY = "debounce-prev-key"; + var DEFAULTS = { + debounce: 300, + throttle: 300 + }; + var PHX_PENDING_ATTRS = [PHX_REF_LOADING, PHX_REF_SRC, PHX_REF_LOCK]; + var STATIC = "s"; + var ROOT = "r"; + var COMPONENTS = "c"; + var KEYED = "k"; + var KEYED_COUNT = "kc"; + var EVENTS = "e"; + var REPLY = "r"; + var TITLE = "t"; + var TEMPLATES = "p"; + var STREAM = "stream"; + var EntryUploader = class { + constructor(entry, config, liveSocket2) { + const { chunk_size, chunk_timeout } = config; + this.liveSocket = liveSocket2; + this.entry = entry; + this.offset = 0; + this.chunkSize = chunk_size; + this.chunkTimeout = chunk_timeout; + this.chunkTimer = null; + this.errored = false; + this.uploadChannel = liveSocket2.channel(`lvu:${entry.ref}`, { + token: entry.metadata() + }); + } + error(reason) { + if (this.errored) { + return; + } + this.uploadChannel.leave(); + this.errored = true; + clearTimeout(this.chunkTimer); + this.entry.error(reason); + } + upload() { + this.uploadChannel.onError((reason) => this.error(reason)); + this.uploadChannel.join().receive("ok", (_data) => this.readNextChunk()).receive("error", (reason) => this.error(reason)); + } + isDone() { + return this.offset >= this.entry.file.size; + } + readNextChunk() { + const reader = new window.FileReader(); + const blob = this.entry.file.slice( + this.offset, + this.chunkSize + this.offset + ); + reader.onload = (e) => { + if (e.target.error === null) { + this.offset += /** @type {ArrayBuffer} */ + e.target.result.byteLength; + this.pushChunk( + /** @type {ArrayBuffer} */ + e.target.result + ); + } else { + return logError("Read error: " + e.target.error); + } + }; + reader.readAsArrayBuffer(blob); + } + pushChunk(chunk) { + if (!this.uploadChannel.isJoined()) { + return; + } + this.uploadChannel.push("chunk", chunk, this.chunkTimeout).receive("ok", () => { + this.entry.progress(this.offset / this.entry.file.size * 100); + if (!this.isDone()) { + this.chunkTimer = setTimeout( + () => this.readNextChunk(), + this.liveSocket.getLatencySim() || 0 + ); + } + }).receive("error", ({ reason }) => this.error(reason)); + } + }; + var logError = (msg, obj) => console.error && console.error(msg, obj); + var isCid = (cid) => { + const type = typeof cid; + return type === "number" || type === "string" && /^(0|[1-9]\d*)$/.test(cid); + }; + function detectDuplicateIds() { + const ids = /* @__PURE__ */ new Set(); + const elems = document.querySelectorAll("*[id]"); + for (let i = 0, len = elems.length; i < len; i++) { + if (ids.has(elems[i].id)) { + console.error( + `Multiple IDs detected: ${elems[i].id}. Ensure unique element ids.` + ); + } else { + ids.add(elems[i].id); + } + } + } + function detectInvalidStreamInserts(inserts) { + const errors = /* @__PURE__ */ new Set(); + Object.keys(inserts).forEach((id) => { + const streamEl = document.getElementById(id); + if (streamEl && streamEl.parentElement && streamEl.parentElement.getAttribute("phx-update") !== "stream") { + errors.add( + `The stream container with id "${streamEl.parentElement.id}" is missing the phx-update="stream" attribute. Ensure it is set for streams to work properly.` + ); + } + }); + errors.forEach((error) => console.error(error)); + } + var debug = (view, kind, msg, obj) => { + if (view.liveSocket.isDebugEnabled()) { + console.log(`${view.id} ${kind}: ${msg} - `, obj); + } + }; + var closure2 = (val) => typeof val === "function" ? val : function() { + return val; + }; + var clone = (obj) => { + return JSON.parse(JSON.stringify(obj)); + }; + var closestPhxBinding = (el, binding, borderEl) => { + do { + if (el.matches(`[${binding}]`) && !el.disabled) { + return el; + } + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1 && !(borderEl && borderEl.isSameNode(el) || el.matches(PHX_VIEW_SELECTOR))); + return null; + }; + var isObject = (obj) => { + return obj !== null && typeof obj === "object" && !(obj instanceof Array); + }; + var isEqualObj = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2); + var isEmpty = (obj) => { + for (const x in obj) { + return false; + } + return true; + }; + var maybe = (el, callback) => el && callback(el); + var channelUploader = function(entries, onError, resp, liveSocket2) { + entries.forEach((entry) => { + const entryUploader = new EntryUploader(entry, resp.config, liveSocket2); + entryUploader.upload(); + }); + }; + var Browser = { + canPushState() { + return typeof history.pushState !== "undefined"; + }, + dropLocal(localStorage, namespace, subkey) { + return localStorage.removeItem(this.localKey(namespace, subkey)); + }, + updateLocal(localStorage, namespace, subkey, initial, func) { + const current = this.getLocal(localStorage, namespace, subkey); + const key = this.localKey(namespace, subkey); + const newVal = current === null ? initial : func(current); + localStorage.setItem(key, JSON.stringify(newVal)); + return newVal; + }, + getLocal(localStorage, namespace, subkey) { + return JSON.parse(localStorage.getItem(this.localKey(namespace, subkey))); + }, + updateCurrentState(callback) { + if (!this.canPushState()) { + return; + } + history.replaceState( + callback(history.state || {}), + "", + window.location.href + ); + }, + pushState(kind, meta, to) { + if (this.canPushState()) { + if (to !== window.location.href) { + if (meta.type == "redirect" && meta.scroll) { + const currentState = history.state || {}; + currentState.scroll = meta.scroll; + history.replaceState(currentState, "", window.location.href); + } + delete meta.scroll; + history[kind + "State"](meta, "", to || null); + window.requestAnimationFrame(() => { + const hashEl = this.getHashTargetEl(window.location.hash); + if (hashEl) { + hashEl.scrollIntoView(); + } else if (meta.type === "redirect") { + window.scroll(0, 0); + } + }); + } + } else { + this.redirect(to); + } + }, + setCookie(name, value, maxAgeSeconds) { + const expires = typeof maxAgeSeconds === "number" ? ` max-age=${maxAgeSeconds};` : ""; + document.cookie = `${name}=${value};${expires} path=/`; + }, + getCookie(name) { + return document.cookie.replace( + new RegExp(`(?:(?:^|.*;s*)${name}s*=s*([^;]*).*$)|^.*$`), + "$1" + ); + }, + deleteCookie(name) { + document.cookie = `${name}=; max-age=-1; path=/`; + }, + redirect(toURL, flash, navigate = (url) => { + window.location.href = url; + }) { + if (flash) { + this.setCookie("__phoenix_flash__", flash, 60); + } + navigate(toURL); + }, + localKey(namespace, subkey) { + return `${namespace}-${subkey}`; + }, + getHashTargetEl(maybeHash) { + const hash = maybeHash.toString().substring(1); + if (hash === "") { + return; + } + return document.getElementById(hash) || document.querySelector(`a[name="${hash}"]`); + } + }; + var browser_default = Browser; + var DOM = { + byId(id) { + return document.getElementById(id) || logError(`no id found for ${id}`); + }, + removeClass(el, className) { + el.classList.remove(className); + if (el.classList.length === 0) { + el.removeAttribute("class"); + } + }, + all(node, query, callback) { + if (!node) { + return []; + } + const array = Array.from(node.querySelectorAll(query)); + if (callback) { + array.forEach(callback); + } + return array; + }, + childNodeLength(html) { + const template = document.createElement("template"); + template.innerHTML = html; + return template.content.childElementCount; + }, + isUploadInput(el) { + return el.type === "file" && el.getAttribute(PHX_UPLOAD_REF) !== null; + }, + isAutoUpload(inputEl) { + return inputEl.hasAttribute("data-phx-auto-upload"); + }, + findUploadInputs(node) { + const formId = node.id; + const inputsOutsideForm = this.all( + document, + `input[type="file"][${PHX_UPLOAD_REF}][form="${formId}"]` + ); + return this.all(node, `input[type="file"][${PHX_UPLOAD_REF}]`).concat( + inputsOutsideForm + ); + }, + findComponentNodeList(viewId, cid, doc2 = document) { + return this.all( + doc2, + `[${PHX_VIEW_REF}="${viewId}"][${PHX_COMPONENT}="${cid}"]` + ); + }, + isPhxDestroyed(node) { + return node.id && DOM.private(node, "destroyed") ? true : false; + }, + wantsNewTab(e) { + const wantsNewTab = e.ctrlKey || e.shiftKey || e.metaKey || e.button && e.button === 1; + const isDownload = e.target instanceof HTMLAnchorElement && e.target.hasAttribute("download"); + const isTargetBlank = e.target.hasAttribute("target") && e.target.getAttribute("target").toLowerCase() === "_blank"; + const isTargetNamedTab = e.target.hasAttribute("target") && !e.target.getAttribute("target").startsWith("_"); + return wantsNewTab || isTargetBlank || isDownload || isTargetNamedTab; + }, + isUnloadableFormSubmit(e) { + const isDialogSubmit = e.target && e.target.getAttribute("method") === "dialog" || e.submitter && e.submitter.getAttribute("formmethod") === "dialog"; + if (isDialogSubmit) { + return false; + } else { + return !e.defaultPrevented && !this.wantsNewTab(e); + } + }, + isNewPageClick(e, currentLocation) { + const href = e.target instanceof HTMLAnchorElement ? e.target.getAttribute("href") : null; + let url; + if (e.defaultPrevented || href === null || this.wantsNewTab(e)) { + return false; + } + if (href.startsWith("mailto:") || href.startsWith("tel:")) { + return false; + } + if (e.target.isContentEditable) { + return false; + } + try { + url = new URL(href); + } catch { + try { + url = new URL(href, currentLocation); + } catch { + return true; + } + } + if (url.host === currentLocation.host && url.protocol === currentLocation.protocol) { + if (url.pathname === currentLocation.pathname && url.search === currentLocation.search) { + return url.hash === "" && !url.href.endsWith("#"); + } + } + return url.protocol.startsWith("http"); + }, + markPhxChildDestroyed(el) { + if (this.isPhxChild(el)) { + el.setAttribute(PHX_SESSION, ""); + } + this.putPrivate(el, "destroyed", true); + }, + findPhxChildrenInFragment(html, parentId) { + const template = document.createElement("template"); + template.innerHTML = html; + return this.findPhxChildren(template.content, parentId); + }, + isIgnored(el, phxUpdate) { + return (el.getAttribute(phxUpdate) || el.getAttribute("data-phx-update")) === "ignore"; + }, + isPhxUpdate(el, phxUpdate, updateTypes) { + return el.getAttribute && updateTypes.indexOf(el.getAttribute(phxUpdate)) >= 0; + }, + findPhxSticky(el) { + return this.all(el, `[${PHX_STICKY}]`); + }, + findPhxChildren(el, parentId) { + return this.all(el, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}="${parentId}"]`); + }, + findExistingParentCIDs(viewId, cids) { + const parentCids = /* @__PURE__ */ new Set(); + const childrenCids = /* @__PURE__ */ new Set(); + cids.forEach((cid) => { + this.all( + document, + `[${PHX_VIEW_REF}="${viewId}"][${PHX_COMPONENT}="${cid}"]` + ).forEach((parent) => { + parentCids.add(cid); + this.all(parent, `[${PHX_VIEW_REF}="${viewId}"][${PHX_COMPONENT}]`).map((el) => parseInt(el.getAttribute(PHX_COMPONENT))).forEach((childCID) => childrenCids.add(childCID)); + }); + }); + childrenCids.forEach((childCid) => parentCids.delete(childCid)); + return parentCids; + }, + private(el, key) { + return el[PHX_PRIVATE] && el[PHX_PRIVATE][key]; + }, + deletePrivate(el, key) { + el[PHX_PRIVATE] && delete el[PHX_PRIVATE][key]; + }, + putPrivate(el, key, value) { + if (!el[PHX_PRIVATE]) { + el[PHX_PRIVATE] = {}; + } + el[PHX_PRIVATE][key] = value; + }, + updatePrivate(el, key, defaultVal, updateFunc) { + const existing = this.private(el, key); + if (existing === void 0) { + this.putPrivate(el, key, updateFunc(defaultVal)); + } else { + this.putPrivate(el, key, updateFunc(existing)); + } + }, + syncPendingAttrs(fromEl, toEl) { + if (!fromEl.hasAttribute(PHX_REF_SRC)) { + return; + } + PHX_EVENT_CLASSES.forEach((className) => { + fromEl.classList.contains(className) && toEl.classList.add(className); + }); + PHX_PENDING_ATTRS.filter((attr) => fromEl.hasAttribute(attr)).forEach( + (attr) => { + toEl.setAttribute(attr, fromEl.getAttribute(attr)); + } + ); + }, + copyPrivates(target, source) { + if (source[PHX_PRIVATE]) { + target[PHX_PRIVATE] = source[PHX_PRIVATE]; + } + }, + putTitle(str) { + const titleEl = document.querySelector("title"); + if (titleEl) { + const { prefix, suffix, default: defaultTitle } = titleEl.dataset; + const isEmpty2 = typeof str !== "string" || str.trim() === ""; + if (isEmpty2 && typeof defaultTitle !== "string") { + return; + } + const inner = isEmpty2 ? defaultTitle : str; + document.title = `${prefix || ""}${inner || ""}${suffix || ""}`; + } else { + document.title = str; + } + }, + debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, callback) { + let debounce = el.getAttribute(phxDebounce); + let throttle = el.getAttribute(phxThrottle); + if (debounce === "") { + debounce = defaultDebounce; + } + if (throttle === "") { + throttle = defaultThrottle; + } + const value = debounce || throttle; + switch (value) { + case null: + return callback(); + case "blur": + this.incCycle(el, "debounce-blur-cycle", () => { + if (asyncFilter()) { + callback(); + } + }); + if (this.once(el, "debounce-blur")) { + el.addEventListener( + "blur", + () => this.triggerCycle(el, "debounce-blur-cycle") + ); + } + return; + default: + const timeout = parseInt(value); + const trigger = () => throttle ? this.deletePrivate(el, THROTTLED) : callback(); + const currentCycle = this.incCycle(el, DEBOUNCE_TRIGGER, trigger); + if (isNaN(timeout)) { + return logError(`invalid throttle/debounce value: ${value}`); + } + if (throttle) { + let newKeyDown = false; + if (event.type === "keydown") { + const prevKey = this.private(el, DEBOUNCE_PREV_KEY); + this.putPrivate(el, DEBOUNCE_PREV_KEY, event.key); + newKeyDown = prevKey !== event.key; + } + if (!newKeyDown && this.private(el, THROTTLED)) { + return false; + } else { + callback(); + const t = setTimeout(() => { + if (asyncFilter()) { + this.triggerCycle(el, DEBOUNCE_TRIGGER); + } + }, timeout); + this.putPrivate(el, THROTTLED, t); + } + } else { + setTimeout(() => { + if (asyncFilter()) { + this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle); + } + }, timeout); + } + const form = el.form; + if (form && this.once(form, "bind-debounce")) { + form.addEventListener("submit", () => { + Array.from(new FormData(form).entries(), ([name]) => { + const input = form.querySelector(`[name="${name}"]`); + this.incCycle(input, DEBOUNCE_TRIGGER); + this.deletePrivate(input, THROTTLED); + }); + }); + } + if (this.once(el, "bind-debounce")) { + el.addEventListener("blur", () => { + clearTimeout(this.private(el, THROTTLED)); + this.triggerCycle(el, DEBOUNCE_TRIGGER); + }); + } + } + }, + triggerCycle(el, key, currentCycle) { + const [cycle, trigger] = this.private(el, key); + if (!currentCycle) { + currentCycle = cycle; + } + if (currentCycle === cycle) { + this.incCycle(el, key); + trigger(); + } + }, + once(el, key) { + if (this.private(el, key) === true) { + return false; + } + this.putPrivate(el, key, true); + return true; + }, + incCycle(el, key, trigger = function() { + }) { + let [currentCycle] = this.private(el, key) || [0, trigger]; + currentCycle++; + this.putPrivate(el, key, [currentCycle, trigger]); + return currentCycle; + }, + // maintains or adds privately used hook information + // fromEl and toEl can be the same element in the case of a newly added node + // fromEl and toEl can be any HTML node type, so we need to check if it's an element node + maintainPrivateHooks(fromEl, toEl, phxViewportTop, phxViewportBottom) { + if (fromEl.hasAttribute && fromEl.hasAttribute("data-phx-hook") && !toEl.hasAttribute("data-phx-hook")) { + toEl.setAttribute("data-phx-hook", fromEl.getAttribute("data-phx-hook")); + } + if (toEl.hasAttribute && (toEl.hasAttribute(phxViewportTop) || toEl.hasAttribute(phxViewportBottom))) { + toEl.setAttribute("data-phx-hook", "Phoenix.InfiniteScroll"); + } + }, + putCustomElHook(el, hook) { + if (el.isConnected) { + el.setAttribute("data-phx-hook", ""); + } else { + console.error(` + hook attached to non-connected DOM element + ensure you are calling createHook within your connectedCallback. ${el.outerHTML} + `); + } + this.putPrivate(el, "custom-el-hook", hook); + }, + getCustomElHook(el) { + return this.private(el, "custom-el-hook"); + }, + isUsedInput(el) { + return el.nodeType === Node.ELEMENT_NODE && (this.private(el, PHX_HAS_FOCUSED) || this.private(el, PHX_HAS_SUBMITTED)); + }, + resetForm(form) { + Array.from(form.elements).forEach((input) => { + this.deletePrivate(input, PHX_HAS_FOCUSED); + this.deletePrivate(input, PHX_HAS_SUBMITTED); + }); + }, + isPhxChild(node) { + return node.getAttribute && node.getAttribute(PHX_PARENT_ID); + }, + isPhxSticky(node) { + return node.getAttribute && node.getAttribute(PHX_STICKY) !== null; + }, + isChildOfAny(el, parents) { + return !!parents.find((parent) => parent.contains(el)); + }, + firstPhxChild(el) { + return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0]; + }, + isPortalTemplate(el) { + return el.tagName === "TEMPLATE" && el.hasAttribute(PHX_PORTAL); + }, + closestViewEl(el) { + const portalOrViewEl = el.closest( + `[${PHX_TELEPORTED_REF}],${PHX_VIEW_SELECTOR}` + ); + if (!portalOrViewEl) { + return null; + } + if (portalOrViewEl.hasAttribute(PHX_TELEPORTED_REF)) { + return this.byId(portalOrViewEl.getAttribute(PHX_TELEPORTED_REF)); + } else if (portalOrViewEl.hasAttribute(PHX_SESSION)) { + return portalOrViewEl; + } + return null; + }, + dispatchEvent(target, name, opts = {}) { + let defaultBubble = true; + const isUploadTarget = target.nodeName === "INPUT" && target.type === "file"; + if (isUploadTarget && name === "click") { + defaultBubble = false; + } + const bubbles = opts.bubbles === void 0 ? defaultBubble : !!opts.bubbles; + const eventOpts = { + bubbles, + cancelable: true, + detail: opts.detail || {} + }; + const event = name === "click" ? new MouseEvent("click", eventOpts) : new CustomEvent(name, eventOpts); + target.dispatchEvent(event); + }, + cloneNode(node, html) { + if (typeof html === "undefined") { + return node.cloneNode(true); + } else { + const cloned = node.cloneNode(false); + cloned.innerHTML = html; + return cloned; + } + }, + // merge attributes from source to target + // if an element is ignored, we only merge data attributes + // including removing data attributes that are no longer in the source + mergeAttrs(target, source, opts = {}) { + const exclude = new Set(opts.exclude || []); + const isIgnored = opts.isIgnored; + const sourceAttrs = source.attributes; + for (let i = sourceAttrs.length - 1; i >= 0; i--) { + const name = sourceAttrs[i].name; + if (!exclude.has(name)) { + const sourceValue = source.getAttribute(name); + if (target.getAttribute(name) !== sourceValue && (!isIgnored || isIgnored && name.startsWith("data-"))) { + target.setAttribute(name, sourceValue); + } + } else { + if (name === "value") { + const sourceValue = source.value ?? source.getAttribute(name); + if (target.value === sourceValue) { + target.setAttribute("value", source.getAttribute(name)); + } + } + } + } + const targetAttrs = target.attributes; + for (let i = targetAttrs.length - 1; i >= 0; i--) { + const name = targetAttrs[i].name; + if (isIgnored) { + if (name.startsWith("data-") && !source.hasAttribute(name) && !PHX_PENDING_ATTRS.includes(name)) { + target.removeAttribute(name); + } + } else { + if (!source.hasAttribute(name)) { + target.removeAttribute(name); + } + } + } + }, + mergeFocusedInput(target, source) { + if (!(target instanceof HTMLSelectElement)) { + DOM.mergeAttrs(target, source, { exclude: ["value"] }); + } + if (source.readOnly) { + target.setAttribute("readonly", true); + } else { + target.removeAttribute("readonly"); + } + }, + hasSelectionRange(el) { + return el.setSelectionRange && (el.type === "text" || el.type === "textarea"); + }, + restoreFocus(focused, selectionStart, selectionEnd) { + if (focused instanceof HTMLSelectElement) { + focused.focus(); + } + if (!DOM.isTextualInput(focused)) { + return; + } + const wasFocused = focused.matches(":focus"); + if (!wasFocused) { + focused.focus(); + } + if (this.hasSelectionRange(focused)) { + focused.setSelectionRange(selectionStart, selectionEnd); + } + }, + isFormInput(el) { + if (el.localName && customElements.get(el.localName)) { + return customElements.get(el.localName)[`formAssociated`]; + } + return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== "button"; + }, + syncAttrsToProps(el) { + if (el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0) { + el.checked = el.getAttribute("checked") !== null; + } + }, + isTextualInput(el) { + return FOCUSABLE_INPUTS.indexOf(el.type) >= 0; + }, + isNowTriggerFormExternal(el, phxTriggerExternal) { + return el.getAttribute && el.getAttribute(phxTriggerExternal) !== null && document.body.contains(el); + }, + cleanChildNodes(container, phxUpdate) { + if (DOM.isPhxUpdate(container, phxUpdate, ["append", "prepend", PHX_STREAM])) { + const toRemove = []; + container.childNodes.forEach((childNode) => { + if (!childNode.id) { + const isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === ""; + if (!isEmptyTextNode && childNode.nodeType !== Node.COMMENT_NODE) { + logError( + `only HTML element tags with an id are allowed inside containers with phx-update. + +removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}" + +` + ); + } + toRemove.push(childNode); + } + }); + toRemove.forEach((childNode) => childNode.remove()); + } + }, + replaceRootContainer(container, tagName, attrs) { + const retainedAttrs = /* @__PURE__ */ new Set([ + "id", + PHX_SESSION, + PHX_STATIC, + PHX_MAIN, + PHX_ROOT_ID + ]); + if (container.tagName.toLowerCase() === tagName.toLowerCase()) { + Array.from(container.attributes).filter((attr) => !retainedAttrs.has(attr.name.toLowerCase())).forEach((attr) => container.removeAttribute(attr.name)); + Object.keys(attrs).filter((name) => !retainedAttrs.has(name.toLowerCase())).forEach((attr) => container.setAttribute(attr, attrs[attr])); + return container; + } else { + const newContainer = document.createElement(tagName); + Object.keys(attrs).forEach( + (attr) => newContainer.setAttribute(attr, attrs[attr]) + ); + retainedAttrs.forEach( + (attr) => newContainer.setAttribute(attr, container.getAttribute(attr)) + ); + newContainer.innerHTML = container.innerHTML; + container.replaceWith(newContainer); + return newContainer; + } + }, + getSticky(el, name, defaultVal) { + const op = (DOM.private(el, "sticky") || []).find( + ([existingName]) => name === existingName + ); + if (op) { + const [_name, _op, stashedResult] = op; + return stashedResult; + } else { + return typeof defaultVal === "function" ? defaultVal() : defaultVal; + } + }, + deleteSticky(el, name) { + this.updatePrivate(el, "sticky", [], (ops) => { + return ops.filter(([existingName, _]) => existingName !== name); + }); + }, + putSticky(el, name, op) { + const stashedResult = op(el); + this.updatePrivate(el, "sticky", [], (ops) => { + const existingIndex = ops.findIndex( + ([existingName]) => name === existingName + ); + if (existingIndex >= 0) { + ops[existingIndex] = [name, op, stashedResult]; + } else { + ops.push([name, op, stashedResult]); + } + return ops; + }); + }, + applyStickyOperations(el) { + const ops = DOM.private(el, "sticky"); + if (!ops) { + return; + } + ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op)); + }, + isLocked(el) { + return el.hasAttribute && el.hasAttribute(PHX_REF_LOCK); + } + }; + var dom_default = DOM; + var UploadEntry = class { + static isActive(fileEl, file) { + const isNew = file._phxRef === void 0; + const activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(","); + const isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0; + return file.size > 0 && (isNew || isActive); + } + static isPreflighted(fileEl, file) { + const preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(","); + const isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0; + return isPreflighted && this.isActive(fileEl, file); + } + static isPreflightInProgress(file) { + return file._preflightInProgress === true; + } + static markPreflightInProgress(file) { + file._preflightInProgress = true; + } + constructor(fileEl, file, view, autoUpload) { + this.ref = LiveUploader.genFileRef(file); + this.fileEl = fileEl; + this.file = file; + this.view = view; + this.meta = null; + this._isCancelled = false; + this._isDone = false; + this._progress = 0; + this._lastProgressSent = -1; + this._onDone = function() { + }; + this._onElUpdated = this.onElUpdated.bind(this); + this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); + this.autoUpload = autoUpload; + } + metadata() { + return this.meta; + } + progress(progress) { + this._progress = Math.floor(progress); + if (this._progress > this._lastProgressSent) { + if (this._progress >= 100) { + this._progress = 100; + this._lastProgressSent = 100; + this._isDone = true; + this.view.pushFileProgress(this.fileEl, this.ref, 100, () => { + LiveUploader.untrackFile(this.fileEl, this.file); + this._onDone(); + }); + } else { + this._lastProgressSent = this._progress; + this.view.pushFileProgress(this.fileEl, this.ref, this._progress); + } + } + } + isCancelled() { + return this._isCancelled; + } + cancel() { + this.file._preflightInProgress = false; + this._isCancelled = true; + this._isDone = true; + this._onDone(); + } + isDone() { + return this._isDone; + } + error(reason = "failed") { + this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); + this.view.pushFileProgress(this.fileEl, this.ref, { error: reason }); + if (!this.isAutoUpload()) { + LiveUploader.clearFiles(this.fileEl); + } + } + isAutoUpload() { + return this.autoUpload; + } + //private + onDone(callback) { + this._onDone = () => { + this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated); + callback(); + }; + } + onElUpdated() { + const activeRefs = this.fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(","); + if (activeRefs.indexOf(this.ref) === -1) { + LiveUploader.untrackFile(this.fileEl, this.file); + this.cancel(); + } + } + toPreflightPayload() { + return { + last_modified: this.file.lastModified, + name: this.file.name, + relative_path: this.file.webkitRelativePath, + size: this.file.size, + type: this.file.type, + ref: this.ref, + meta: typeof this.file.meta === "function" ? this.file.meta() : void 0 + }; + } + uploader(uploaders) { + if (this.meta.uploader) { + const callback = uploaders[this.meta.uploader] || logError(`no uploader configured for ${this.meta.uploader}`); + return { name: this.meta.uploader, callback }; + } else { + return { name: "channel", callback: channelUploader }; + } + } + zipPostFlight(resp) { + this.meta = resp.entries[this.ref]; + if (!this.meta) { + logError(`no preflight upload response returned with ref ${this.ref}`, { + input: this.fileEl, + response: resp + }); + } + } + }; + var liveUploaderFileRef = 0; + var LiveUploader = class _LiveUploader { + static genFileRef(file) { + const ref = file._phxRef; + if (ref !== void 0) { + return ref; + } else { + file._phxRef = (liveUploaderFileRef++).toString(); + return file._phxRef; + } + } + static getEntryDataURL(inputEl, ref, callback) { + const file = this.activeFiles(inputEl).find( + (file2) => this.genFileRef(file2) === ref + ); + callback(URL.createObjectURL(file)); + } + static hasUploadsInProgress(formEl) { + let active = 0; + dom_default.findUploadInputs(formEl).forEach((input) => { + if (input.getAttribute(PHX_PREFLIGHTED_REFS) !== input.getAttribute(PHX_DONE_REFS)) { + active++; + } + }); + return active > 0; + } + static serializeUploads(inputEl) { + const files = this.activeFiles(inputEl); + const fileData = {}; + files.forEach((file) => { + const entry = { path: inputEl.name }; + const uploadRef = inputEl.getAttribute(PHX_UPLOAD_REF); + fileData[uploadRef] = fileData[uploadRef] || []; + entry.ref = this.genFileRef(file); + entry.last_modified = file.lastModified; + entry.name = file.name || entry.ref; + entry.relative_path = file.webkitRelativePath; + entry.type = file.type; + entry.size = file.size; + if (typeof file.meta === "function") { + entry.meta = file.meta(); + } + fileData[uploadRef].push(entry); + }); + return fileData; + } + static clearFiles(inputEl) { + inputEl.value = null; + inputEl.removeAttribute(PHX_UPLOAD_REF); + dom_default.putPrivate(inputEl, "files", []); + } + static untrackFile(inputEl, file) { + dom_default.putPrivate( + inputEl, + "files", + dom_default.private(inputEl, "files").filter((f) => !Object.is(f, file)) + ); + } + /** + * @param {HTMLInputElement} inputEl + * @param {Array} files + * @param {DataTransfer} [dataTransfer] + */ + static trackFiles(inputEl, files, dataTransfer) { + if (inputEl.getAttribute("multiple") !== null) { + const newFiles = files.filter( + (file) => !this.activeFiles(inputEl).find((f) => Object.is(f, file)) + ); + dom_default.updatePrivate( + inputEl, + "files", + [], + (existing) => existing.concat(newFiles) + ); + inputEl.value = null; + } else { + if (dataTransfer && dataTransfer.files.length > 0) { + inputEl.files = dataTransfer.files; + } + dom_default.putPrivate(inputEl, "files", files); + } + } + static activeFileInputs(formEl) { + const fileInputs = dom_default.findUploadInputs(formEl); + return Array.from(fileInputs).filter( + (el) => el.files && this.activeFiles(el).length > 0 + ); + } + static activeFiles(input) { + return (dom_default.private(input, "files") || []).filter( + (f) => UploadEntry.isActive(input, f) + ); + } + static inputsAwaitingPreflight(formEl) { + const fileInputs = dom_default.findUploadInputs(formEl); + return Array.from(fileInputs).filter( + (input) => this.filesAwaitingPreflight(input).length > 0 + ); + } + static filesAwaitingPreflight(input) { + return this.activeFiles(input).filter( + (f) => !UploadEntry.isPreflighted(input, f) && !UploadEntry.isPreflightInProgress(f) + ); + } + static markPreflightInProgress(entries) { + entries.forEach((entry) => UploadEntry.markPreflightInProgress(entry.file)); + } + constructor(inputEl, view, onComplete) { + this.autoUpload = dom_default.isAutoUpload(inputEl); + this.view = view; + this.onComplete = onComplete; + this._entries = Array.from( + _LiveUploader.filesAwaitingPreflight(inputEl) || [] + ).map((file) => new UploadEntry(inputEl, file, view, this.autoUpload)); + _LiveUploader.markPreflightInProgress(this._entries); + this.numEntriesInProgress = this._entries.length; + } + isAutoUpload() { + return this.autoUpload; + } + entries() { + return this._entries; + } + initAdapterUpload(resp, onError, liveSocket2) { + this._entries = this._entries.map((entry) => { + if (entry.isCancelled()) { + this.numEntriesInProgress--; + if (this.numEntriesInProgress === 0) { + this.onComplete(); + } + } else { + entry.zipPostFlight(resp); + entry.onDone(() => { + this.numEntriesInProgress--; + if (this.numEntriesInProgress === 0) { + this.onComplete(); + } + }); + } + return entry; + }); + const groupedEntries = this._entries.reduce((acc, entry) => { + if (!entry.meta) { + return acc; + } + const { name, callback } = entry.uploader(liveSocket2.uploaders); + acc[name] = acc[name] || { callback, entries: [] }; + acc[name].entries.push(entry); + return acc; + }, {}); + for (const name in groupedEntries) { + const { callback, entries } = groupedEntries[name]; + callback(entries, onError, resp, liveSocket2); + } + } + }; + var ARIA = { + anyOf(instance, classes) { + return classes.find((name) => instance instanceof name); + }, + isFocusable(el, interactiveOnly) { + return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !el.disabled && this.anyOf(el, [ + HTMLInputElement, + HTMLSelectElement, + HTMLTextAreaElement, + HTMLButtonElement + ]) || el instanceof HTMLIFrameElement || el.tabIndex >= 0 && el.getAttribute("aria-hidden") !== "true" || !interactiveOnly && el.getAttribute("tabindex") !== null && el.getAttribute("aria-hidden") !== "true"; + }, + attemptFocus(el, interactiveOnly) { + if (this.isFocusable(el, interactiveOnly)) { + try { + el.focus(); + } catch { + } + } + return !!document.activeElement && document.activeElement.isSameNode(el); + }, + focusFirstInteractive(el) { + let child = el.firstElementChild; + while (child) { + if (this.attemptFocus(child, true) || this.focusFirstInteractive(child)) { + return true; + } + child = child.nextElementSibling; + } + }, + focusFirst(el) { + let child = el.firstElementChild; + while (child) { + if (this.attemptFocus(child) || this.focusFirst(child)) { + return true; + } + child = child.nextElementSibling; + } + }, + focusLast(el) { + let child = el.lastElementChild; + while (child) { + if (this.attemptFocus(child) || this.focusLast(child)) { + return true; + } + child = child.previousElementSibling; + } + } + }; + var aria_default = ARIA; + var Hooks = { + LiveFileUpload: { + activeRefs() { + return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS); + }, + preflightedRefs() { + return this.el.getAttribute(PHX_PREFLIGHTED_REFS); + }, + mounted() { + this.preflightedWas = this.preflightedRefs(); + }, + updated() { + const newPreflights = this.preflightedRefs(); + if (this.preflightedWas !== newPreflights) { + this.preflightedWas = newPreflights; + if (newPreflights === "") { + this.__view().cancelSubmit(this.el.form); + } + } + if (this.activeRefs() === "") { + this.el.value = null; + } + this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED)); + } + }, + LiveImgPreview: { + mounted() { + this.ref = this.el.getAttribute("data-phx-entry-ref"); + this.inputEl = document.getElementById( + this.el.getAttribute(PHX_UPLOAD_REF) + ); + LiveUploader.getEntryDataURL(this.inputEl, this.ref, (url) => { + this.url = url; + this.el.src = url; + }); + }, + destroyed() { + URL.revokeObjectURL(this.url); + } + }, + FocusWrap: { + mounted() { + this.focusStart = this.el.firstElementChild; + this.focusEnd = this.el.lastElementChild; + this.focusStart.addEventListener("focus", (e) => { + if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) { + const nextFocus = e.target.nextElementSibling; + aria_default.attemptFocus(nextFocus) || aria_default.focusFirst(nextFocus); + } else { + aria_default.focusLast(this.el); + } + }); + this.focusEnd.addEventListener("focus", (e) => { + if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) { + const nextFocus = e.target.previousElementSibling; + aria_default.attemptFocus(nextFocus) || aria_default.focusLast(nextFocus); + } else { + aria_default.focusFirst(this.el); + } + }); + if (!this.el.contains(document.activeElement)) { + this.el.addEventListener("phx:show-end", () => this.el.focus()); + if (window.getComputedStyle(this.el).display !== "none") { + aria_default.focusFirst(this.el); + } + } + } + } + }; + var findScrollContainer = (el) => { + if (["HTML", "BODY"].indexOf(el.nodeName.toUpperCase()) >= 0) + return null; + if (["scroll", "auto"].indexOf(getComputedStyle(el).overflowY) >= 0) + return el; + return findScrollContainer(el.parentElement); + }; + var scrollTop = (scrollContainer) => { + if (scrollContainer) { + return scrollContainer.scrollTop; + } else { + return document.documentElement.scrollTop || document.body.scrollTop; + } + }; + var bottom = (scrollContainer) => { + if (scrollContainer) { + return scrollContainer.getBoundingClientRect().bottom; + } else { + return window.innerHeight || document.documentElement.clientHeight; + } + }; + var top = (scrollContainer) => { + if (scrollContainer) { + return scrollContainer.getBoundingClientRect().top; + } else { + return 0; + } + }; + var isAtViewportTop = (el, scrollContainer) => { + const rect = el.getBoundingClientRect(); + return Math.ceil(rect.top) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.top) <= bottom(scrollContainer); + }; + var isAtViewportBottom = (el, scrollContainer) => { + const rect = el.getBoundingClientRect(); + return Math.ceil(rect.bottom) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.bottom) <= bottom(scrollContainer); + }; + var isWithinViewport = (el, scrollContainer) => { + const rect = el.getBoundingClientRect(); + return Math.ceil(rect.top) >= top(scrollContainer) && Math.ceil(rect.left) >= 0 && Math.floor(rect.top) <= bottom(scrollContainer); + }; + Hooks.InfiniteScroll = { + mounted() { + this.scrollContainer = findScrollContainer(this.el); + let scrollBefore = scrollTop(this.scrollContainer); + let topOverran = false; + const throttleInterval = 500; + let pendingOp = null; + const onTopOverrun = this.throttle( + throttleInterval, + (topEvent, firstChild) => { + pendingOp = () => true; + this.liveSocket.js().push(this.el, topEvent, { + value: { id: firstChild.id, _overran: true }, + callback: () => { + pendingOp = null; + } + }); + } + ); + const onFirstChildAtTop = this.throttle( + throttleInterval, + (topEvent, firstChild) => { + pendingOp = () => firstChild.scrollIntoView({ block: "start" }); + this.liveSocket.js().push(this.el, topEvent, { + value: { id: firstChild.id }, + callback: () => { + pendingOp = null; + window.requestAnimationFrame(() => { + if (!isWithinViewport(firstChild, this.scrollContainer)) { + firstChild.scrollIntoView({ block: "start" }); + } + }); + } + }); + } + ); + const onLastChildAtBottom = this.throttle( + throttleInterval, + (bottomEvent, lastChild) => { + pendingOp = () => lastChild.scrollIntoView({ block: "end" }); + this.liveSocket.js().push(this.el, bottomEvent, { + value: { id: lastChild.id }, + callback: () => { + pendingOp = null; + window.requestAnimationFrame(() => { + if (!isWithinViewport(lastChild, this.scrollContainer)) { + lastChild.scrollIntoView({ block: "end" }); + } + }); + } + }); + } + ); + this.onScroll = (_e) => { + const scrollNow = scrollTop(this.scrollContainer); + if (pendingOp) { + scrollBefore = scrollNow; + return pendingOp(); + } + const rect = this.el.getBoundingClientRect(); + const topEvent = this.el.getAttribute( + this.liveSocket.binding("viewport-top") + ); + const bottomEvent = this.el.getAttribute( + this.liveSocket.binding("viewport-bottom") + ); + const lastChild = this.el.lastElementChild; + const firstChild = this.el.firstElementChild; + const isScrollingUp = scrollNow < scrollBefore; + const isScrollingDown = scrollNow > scrollBefore; + if (isScrollingUp && topEvent && !topOverran && rect.top >= 0) { + topOverran = true; + onTopOverrun(topEvent, firstChild); + } else if (isScrollingDown && topOverran && rect.top <= 0) { + topOverran = false; + } + if (topEvent && isScrollingUp && isAtViewportTop(firstChild, this.scrollContainer)) { + onFirstChildAtTop(topEvent, firstChild); + } else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild, this.scrollContainer)) { + onLastChildAtBottom(bottomEvent, lastChild); + } + scrollBefore = scrollNow; + }; + if (this.scrollContainer) { + this.scrollContainer.addEventListener("scroll", this.onScroll); + } else { + window.addEventListener("scroll", this.onScroll); + } + }, + destroyed() { + if (this.scrollContainer) { + this.scrollContainer.removeEventListener("scroll", this.onScroll); + } else { + window.removeEventListener("scroll", this.onScroll); + } + }, + throttle(interval, callback) { + let lastCallAt = 0; + let timer; + return (...args) => { + const now = Date.now(); + const remainingTime = interval - (now - lastCallAt); + if (remainingTime <= 0 || remainingTime > interval) { + if (timer) { + clearTimeout(timer); + timer = null; + } + lastCallAt = now; + callback(...args); + } else if (!timer) { + timer = setTimeout(() => { + lastCallAt = Date.now(); + timer = null; + callback(...args); + }, remainingTime); + } + }; + } + }; + var hooks_default = Hooks; + var ElementRef = class { + static onUnlock(el, callback) { + if (!dom_default.isLocked(el) && !el.closest(`[${PHX_REF_LOCK}]`)) { + return callback(); + } + const closestLock = el.closest(`[${PHX_REF_LOCK}]`); + const ref = closestLock.closest(`[${PHX_REF_LOCK}]`).getAttribute(PHX_REF_LOCK); + closestLock.addEventListener( + `phx:undo-lock:${ref}`, + () => { + callback(); + }, + { once: true } + ); + } + constructor(el) { + this.el = el; + this.loadingRef = el.hasAttribute(PHX_REF_LOADING) ? parseInt(el.getAttribute(PHX_REF_LOADING), 10) : null; + this.lockRef = el.hasAttribute(PHX_REF_LOCK) ? parseInt(el.getAttribute(PHX_REF_LOCK), 10) : null; + } + // public + maybeUndo(ref, phxEvent, eachCloneCallback) { + if (!this.isWithin(ref)) { + dom_default.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => { + pendingRefs.push(ref); + return pendingRefs; + }); + return; + } + this.undoLocks(ref, phxEvent, eachCloneCallback); + this.undoLoading(ref, phxEvent); + dom_default.updatePrivate(this.el, PHX_PENDING_REFS, [], (pendingRefs) => { + return pendingRefs.filter((pendingRef) => { + let opts = { + detail: { ref: pendingRef, event: phxEvent }, + bubbles: true, + cancelable: false + }; + if (this.loadingRef && this.loadingRef > pendingRef) { + this.el.dispatchEvent( + new CustomEvent(`phx:undo-loading:${pendingRef}`, opts) + ); + } + if (this.lockRef && this.lockRef > pendingRef) { + this.el.dispatchEvent( + new CustomEvent(`phx:undo-lock:${pendingRef}`, opts) + ); + } + return pendingRef > ref; + }); + }); + if (this.isFullyResolvedBy(ref)) { + this.el.removeAttribute(PHX_REF_SRC); + } + } + // private + isWithin(ref) { + return !(this.loadingRef !== null && this.loadingRef > ref && this.lockRef !== null && this.lockRef > ref); + } + // Check for cloned PHX_REF_LOCK element that has been morphed behind + // the scenes while this element was locked in the DOM. + // When we apply the cloned tree to the active DOM element, we must + // + // 1. execute pending mounted hooks for nodes now in the DOM + // 2. undo any ref inside the cloned tree that has since been ack'd + undoLocks(ref, phxEvent, eachCloneCallback) { + if (!this.isLockUndoneBy(ref)) { + return; + } + const clonedTree = dom_default.private(this.el, PHX_REF_LOCK); + if (clonedTree) { + eachCloneCallback(clonedTree); + dom_default.deletePrivate(this.el, PHX_REF_LOCK); + } + this.el.removeAttribute(PHX_REF_LOCK); + const opts = { + detail: { ref, event: phxEvent }, + bubbles: true, + cancelable: false + }; + this.el.dispatchEvent( + new CustomEvent(`phx:undo-lock:${this.lockRef}`, opts) + ); + } + undoLoading(ref, phxEvent) { + if (!this.isLoadingUndoneBy(ref)) { + if (this.canUndoLoading(ref) && this.el.classList.contains("phx-submit-loading")) { + this.el.classList.remove("phx-change-loading"); + } + return; + } + if (this.canUndoLoading(ref)) { + this.el.removeAttribute(PHX_REF_LOADING); + const disabledVal = this.el.getAttribute(PHX_DISABLED); + const readOnlyVal = this.el.getAttribute(PHX_READONLY); + if (readOnlyVal !== null) { + this.el.readOnly = readOnlyVal === "true" ? true : false; + this.el.removeAttribute(PHX_READONLY); + } + if (disabledVal !== null) { + this.el.disabled = disabledVal === "true" ? true : false; + this.el.removeAttribute(PHX_DISABLED); + } + const disableRestore = this.el.getAttribute(PHX_DISABLE_WITH_RESTORE); + if (disableRestore !== null) { + this.el.innerText = disableRestore; + this.el.removeAttribute(PHX_DISABLE_WITH_RESTORE); + } + const opts = { + detail: { ref, event: phxEvent }, + bubbles: true, + cancelable: false + }; + this.el.dispatchEvent( + new CustomEvent(`phx:undo-loading:${this.loadingRef}`, opts) + ); + } + PHX_EVENT_CLASSES.forEach((name) => { + if (name !== "phx-submit-loading" || this.canUndoLoading(ref)) { + dom_default.removeClass(this.el, name); + } + }); + } + isLoadingUndoneBy(ref) { + return this.loadingRef === null ? false : this.loadingRef <= ref; + } + isLockUndoneBy(ref) { + return this.lockRef === null ? false : this.lockRef <= ref; + } + isFullyResolvedBy(ref) { + return (this.loadingRef === null || this.loadingRef <= ref) && (this.lockRef === null || this.lockRef <= ref); + } + // only remove the phx-submit-loading class if we are not locked + canUndoLoading(ref) { + return this.lockRef === null || this.lockRef <= ref; + } + }; + var DOMPostMorphRestorer = class { + constructor(containerBefore, containerAfter, updateType) { + const idsBefore = /* @__PURE__ */ new Set(); + const idsAfter = new Set( + [...containerAfter.children].map((child) => child.id) + ); + const elementsToModify = []; + Array.from(containerBefore.children).forEach((child) => { + if (child.id) { + idsBefore.add(child.id); + if (idsAfter.has(child.id)) { + const previousElementId = child.previousElementSibling && child.previousElementSibling.id; + elementsToModify.push({ + elementId: child.id, + previousElementId + }); + } + } + }); + this.containerId = containerAfter.id; + this.updateType = updateType; + this.elementsToModify = elementsToModify; + this.elementIdsToAdd = [...idsAfter].filter((id) => !idsBefore.has(id)); + } + // We do the following to optimize append/prepend operations: + // 1) Track ids of modified elements & of new elements + // 2) All the modified elements are put back in the correct position in the DOM tree + // by storing the id of their previous sibling + // 3) New elements are going to be put in the right place by morphdom during append. + // For prepend, we move them to the first position in the container + perform() { + const container = dom_default.byId(this.containerId); + if (!container) { + return; + } + this.elementsToModify.forEach((elementToModify) => { + if (elementToModify.previousElementId) { + maybe( + document.getElementById(elementToModify.previousElementId), + (previousElem) => { + maybe( + document.getElementById(elementToModify.elementId), + (elem) => { + const isInRightPlace = elem.previousElementSibling && elem.previousElementSibling.id == previousElem.id; + if (!isInRightPlace) { + previousElem.insertAdjacentElement("afterend", elem); + } + } + ); + } + ); + } else { + maybe(document.getElementById(elementToModify.elementId), (elem) => { + const isInRightPlace = elem.previousElementSibling == null; + if (!isInRightPlace) { + container.insertAdjacentElement("afterbegin", elem); + } + }); + } + }); + if (this.updateType == "prepend") { + this.elementIdsToAdd.reverse().forEach((elemId) => { + maybe( + document.getElementById(elemId), + (elem) => container.insertAdjacentElement("afterbegin", elem) + ); + }); + } + } + }; + var DOCUMENT_FRAGMENT_NODE = 11; + function morphAttrs(fromNode, toNode) { + var toNodeAttrs = toNode.attributes; + var attr; + var attrName; + var attrNamespaceURI; + var attrValue; + var fromValue; + if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) { + return; + } + for (var i = toNodeAttrs.length - 1; i >= 0; i--) { + attr = toNodeAttrs[i]; + attrName = attr.name; + attrNamespaceURI = attr.namespaceURI; + attrValue = attr.value; + if (attrNamespaceURI) { + attrName = attr.localName || attrName; + fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName); + if (fromValue !== attrValue) { + if (attr.prefix === "xmlns") { + attrName = attr.name; + } + fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue); + } + } else { + fromValue = fromNode.getAttribute(attrName); + if (fromValue !== attrValue) { + fromNode.setAttribute(attrName, attrValue); + } + } + } + var fromNodeAttrs = fromNode.attributes; + for (var d = fromNodeAttrs.length - 1; d >= 0; d--) { + attr = fromNodeAttrs[d]; + attrName = attr.name; + attrNamespaceURI = attr.namespaceURI; + if (attrNamespaceURI) { + attrName = attr.localName || attrName; + if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) { + fromNode.removeAttributeNS(attrNamespaceURI, attrName); + } + } else { + if (!toNode.hasAttribute(attrName)) { + fromNode.removeAttribute(attrName); + } + } + } + } + var range; + var NS_XHTML = "http://www.w3.org/1999/xhtml"; + var doc = typeof document === "undefined" ? void 0 : document; + var HAS_TEMPLATE_SUPPORT = !!doc && "content" in doc.createElement("template"); + var HAS_RANGE_SUPPORT = !!doc && doc.createRange && "createContextualFragment" in doc.createRange(); + function createFragmentFromTemplate(str) { + var template = doc.createElement("template"); + template.innerHTML = str; + return template.content.childNodes[0]; + } + function createFragmentFromRange(str) { + if (!range) { + range = doc.createRange(); + range.selectNode(doc.body); + } + var fragment = range.createContextualFragment(str); + return fragment.childNodes[0]; + } + function createFragmentFromWrap(str) { + var fragment = doc.createElement("body"); + fragment.innerHTML = str; + return fragment.childNodes[0]; + } + function toElement(str) { + str = str.trim(); + if (HAS_TEMPLATE_SUPPORT) { + return createFragmentFromTemplate(str); + } else if (HAS_RANGE_SUPPORT) { + return createFragmentFromRange(str); + } + return createFragmentFromWrap(str); + } + function compareNodeNames(fromEl, toEl) { + var fromNodeName = fromEl.nodeName; + var toNodeName = toEl.nodeName; + var fromCodeStart, toCodeStart; + if (fromNodeName === toNodeName) { + return true; + } + fromCodeStart = fromNodeName.charCodeAt(0); + toCodeStart = toNodeName.charCodeAt(0); + if (fromCodeStart <= 90 && toCodeStart >= 97) { + return fromNodeName === toNodeName.toUpperCase(); + } else if (toCodeStart <= 90 && fromCodeStart >= 97) { + return toNodeName === fromNodeName.toUpperCase(); + } else { + return false; + } + } + function createElementNS(name, namespaceURI) { + return !namespaceURI || namespaceURI === NS_XHTML ? doc.createElement(name) : doc.createElementNS(namespaceURI, name); + } + function moveChildren(fromEl, toEl) { + var curChild = fromEl.firstChild; + while (curChild) { + var nextChild = curChild.nextSibling; + toEl.appendChild(curChild); + curChild = nextChild; + } + return toEl; + } + function syncBooleanAttrProp(fromEl, toEl, name) { + if (fromEl[name] !== toEl[name]) { + fromEl[name] = toEl[name]; + if (fromEl[name]) { + fromEl.setAttribute(name, ""); + } else { + fromEl.removeAttribute(name); + } + } + } + var specialElHandlers = { + OPTION: function(fromEl, toEl) { + var parentNode = fromEl.parentNode; + if (parentNode) { + var parentName = parentNode.nodeName.toUpperCase(); + if (parentName === "OPTGROUP") { + parentNode = parentNode.parentNode; + parentName = parentNode && parentNode.nodeName.toUpperCase(); + } + if (parentName === "SELECT" && !parentNode.hasAttribute("multiple")) { + if (fromEl.hasAttribute("selected") && !toEl.selected) { + fromEl.setAttribute("selected", "selected"); + fromEl.removeAttribute("selected"); + } + parentNode.selectedIndex = -1; + } + } + syncBooleanAttrProp(fromEl, toEl, "selected"); + }, + /** + * The "value" attribute is special for the element since it sets + * the initial value. Changing the "value" attribute without changing the + * "value" property will have no effect since it is only used to the set the + * initial value. Similar for the "checked" attribute, and "disabled". + */ + INPUT: function(fromEl, toEl) { + syncBooleanAttrProp(fromEl, toEl, "checked"); + syncBooleanAttrProp(fromEl, toEl, "disabled"); + if (fromEl.value !== toEl.value) { + fromEl.value = toEl.value; + } + if (!toEl.hasAttribute("value")) { + fromEl.removeAttribute("value"); + } + }, + TEXTAREA: function(fromEl, toEl) { + var newValue = toEl.value; + if (fromEl.value !== newValue) { + fromEl.value = newValue; + } + var firstChild = fromEl.firstChild; + if (firstChild) { + var oldValue = firstChild.nodeValue; + if (oldValue == newValue || !newValue && oldValue == fromEl.placeholder) { + return; + } + firstChild.nodeValue = newValue; + } + }, + SELECT: function(fromEl, toEl) { + if (!toEl.hasAttribute("multiple")) { + var selectedIndex = -1; + var i = 0; + var curChild = fromEl.firstChild; + var optgroup; + var nodeName; + while (curChild) { + nodeName = curChild.nodeName && curChild.nodeName.toUpperCase(); + if (nodeName === "OPTGROUP") { + optgroup = curChild; + curChild = optgroup.firstChild; + if (!curChild) { + curChild = optgroup.nextSibling; + optgroup = null; + } + } else { + if (nodeName === "OPTION") { + if (curChild.hasAttribute("selected")) { + selectedIndex = i; + break; + } + i++; + } + curChild = curChild.nextSibling; + if (!curChild && optgroup) { + curChild = optgroup.nextSibling; + optgroup = null; + } + } + } + fromEl.selectedIndex = selectedIndex; + } + } + }; + var ELEMENT_NODE = 1; + var DOCUMENT_FRAGMENT_NODE$1 = 11; + var TEXT_NODE = 3; + var COMMENT_NODE = 8; + function noop() { + } + function defaultGetNodeKey(node) { + if (node) { + return node.getAttribute && node.getAttribute("id") || node.id; + } + } + function morphdomFactory(morphAttrs2) { + return function morphdom2(fromNode, toNode, options) { + if (!options) { + options = {}; + } + if (typeof toNode === "string") { + if (fromNode.nodeName === "#document" || fromNode.nodeName === "HTML" || fromNode.nodeName === "BODY") { + var toNodeHtml = toNode; + toNode = doc.createElement("html"); + toNode.innerHTML = toNodeHtml; + } else { + toNode = toElement(toNode); + } + } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) { + toNode = toNode.firstElementChild; + } + var getNodeKey = options.getNodeKey || defaultGetNodeKey; + var onBeforeNodeAdded = options.onBeforeNodeAdded || noop; + var onNodeAdded = options.onNodeAdded || noop; + var onBeforeElUpdated = options.onBeforeElUpdated || noop; + var onElUpdated = options.onElUpdated || noop; + var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop; + var onNodeDiscarded = options.onNodeDiscarded || noop; + var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop; + var skipFromChildren = options.skipFromChildren || noop; + var addChild = options.addChild || function(parent, child) { + return parent.appendChild(child); + }; + var childrenOnly = options.childrenOnly === true; + var fromNodesLookup = /* @__PURE__ */ Object.create(null); + var keyedRemovalList = []; + function addKeyedRemoval(key) { + keyedRemovalList.push(key); + } + function walkDiscardedChildNodes(node, skipKeyedNodes) { + if (node.nodeType === ELEMENT_NODE) { + var curChild = node.firstChild; + while (curChild) { + var key = void 0; + if (skipKeyedNodes && (key = getNodeKey(curChild))) { + addKeyedRemoval(key); + } else { + onNodeDiscarded(curChild); + if (curChild.firstChild) { + walkDiscardedChildNodes(curChild, skipKeyedNodes); + } + } + curChild = curChild.nextSibling; + } + } + } + function removeNode(node, parentNode, skipKeyedNodes) { + if (onBeforeNodeDiscarded(node) === false) { + return; + } + if (parentNode) { + parentNode.removeChild(node); + } + onNodeDiscarded(node); + walkDiscardedChildNodes(node, skipKeyedNodes); + } + function indexTree(node) { + if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) { + var curChild = node.firstChild; + while (curChild) { + var key = getNodeKey(curChild); + if (key) { + fromNodesLookup[key] = curChild; + } + indexTree(curChild); + curChild = curChild.nextSibling; + } + } + } + indexTree(fromNode); + function handleNodeAdded(el) { + onNodeAdded(el); + var curChild = el.firstChild; + while (curChild) { + var nextSibling = curChild.nextSibling; + var key = getNodeKey(curChild); + if (key) { + var unmatchedFromEl = fromNodesLookup[key]; + if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) { + curChild.parentNode.replaceChild(unmatchedFromEl, curChild); + morphEl(unmatchedFromEl, curChild); + } else { + handleNodeAdded(curChild); + } + } else { + handleNodeAdded(curChild); + } + curChild = nextSibling; + } + } + function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) { + while (curFromNodeChild) { + var fromNextSibling = curFromNodeChild.nextSibling; + if (curFromNodeKey = getNodeKey(curFromNodeChild)) { + addKeyedRemoval(curFromNodeKey); + } else { + removeNode( + curFromNodeChild, + fromEl, + true + /* skip keyed nodes */ + ); + } + curFromNodeChild = fromNextSibling; + } + } + function morphEl(fromEl, toEl, childrenOnly2) { + var toElKey = getNodeKey(toEl); + if (toElKey) { + delete fromNodesLookup[toElKey]; + } + if (!childrenOnly2) { + var beforeUpdateResult = onBeforeElUpdated(fromEl, toEl); + if (beforeUpdateResult === false) { + return; + } else if (beforeUpdateResult instanceof HTMLElement) { + fromEl = beforeUpdateResult; + indexTree(fromEl); + } + morphAttrs2(fromEl, toEl); + onElUpdated(fromEl); + if (onBeforeElChildrenUpdated(fromEl, toEl) === false) { + return; + } + } + if (fromEl.nodeName !== "TEXTAREA") { + morphChildren(fromEl, toEl); + } else { + specialElHandlers.TEXTAREA(fromEl, toEl); + } + } + function morphChildren(fromEl, toEl) { + var skipFrom = skipFromChildren(fromEl, toEl); + var curToNodeChild = toEl.firstChild; + var curFromNodeChild = fromEl.firstChild; + var curToNodeKey; + var curFromNodeKey; + var fromNextSibling; + var toNextSibling; + var matchingFromEl; + outer: + while (curToNodeChild) { + toNextSibling = curToNodeChild.nextSibling; + curToNodeKey = getNodeKey(curToNodeChild); + while (!skipFrom && curFromNodeChild) { + fromNextSibling = curFromNodeChild.nextSibling; + if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) { + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + continue outer; + } + curFromNodeKey = getNodeKey(curFromNodeChild); + var curFromNodeType = curFromNodeChild.nodeType; + var isCompatible = void 0; + if (curFromNodeType === curToNodeChild.nodeType) { + if (curFromNodeType === ELEMENT_NODE) { + if (curToNodeKey) { + if (curToNodeKey !== curFromNodeKey) { + if (matchingFromEl = fromNodesLookup[curToNodeKey]) { + if (fromNextSibling === matchingFromEl) { + isCompatible = false; + } else { + fromEl.insertBefore(matchingFromEl, curFromNodeChild); + if (curFromNodeKey) { + addKeyedRemoval(curFromNodeKey); + } else { + removeNode( + curFromNodeChild, + fromEl, + true + /* skip keyed nodes */ + ); + } + curFromNodeChild = matchingFromEl; + curFromNodeKey = getNodeKey(curFromNodeChild); + } + } else { + isCompatible = false; + } + } + } else if (curFromNodeKey) { + isCompatible = false; + } + isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild); + if (isCompatible) { + morphEl(curFromNodeChild, curToNodeChild); + } + } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) { + isCompatible = true; + if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) { + curFromNodeChild.nodeValue = curToNodeChild.nodeValue; + } + } + } + if (isCompatible) { + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + continue outer; + } + if (curFromNodeKey) { + addKeyedRemoval(curFromNodeKey); + } else { + removeNode( + curFromNodeChild, + fromEl, + true + /* skip keyed nodes */ + ); + } + curFromNodeChild = fromNextSibling; + } + if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) { + if (!skipFrom) { + addChild(fromEl, matchingFromEl); + } + morphEl(matchingFromEl, curToNodeChild); + } else { + var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild); + if (onBeforeNodeAddedResult !== false) { + if (onBeforeNodeAddedResult) { + curToNodeChild = onBeforeNodeAddedResult; + } + if (curToNodeChild.actualize) { + curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc); + } + addChild(fromEl, curToNodeChild); + handleNodeAdded(curToNodeChild); + } + } + curToNodeChild = toNextSibling; + curFromNodeChild = fromNextSibling; + } + cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey); + var specialElHandler = specialElHandlers[fromEl.nodeName]; + if (specialElHandler) { + specialElHandler(fromEl, toEl); + } + } + var morphedNode = fromNode; + var morphedNodeType = morphedNode.nodeType; + var toNodeType = toNode.nodeType; + if (!childrenOnly) { + if (morphedNodeType === ELEMENT_NODE) { + if (toNodeType === ELEMENT_NODE) { + if (!compareNodeNames(fromNode, toNode)) { + onNodeDiscarded(fromNode); + morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI)); + } + } else { + morphedNode = toNode; + } + } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { + if (toNodeType === morphedNodeType) { + if (morphedNode.nodeValue !== toNode.nodeValue) { + morphedNode.nodeValue = toNode.nodeValue; + } + return morphedNode; + } else { + morphedNode = toNode; + } + } + } + if (morphedNode === toNode) { + onNodeDiscarded(fromNode); + } else { + if (toNode.isSameNode && toNode.isSameNode(morphedNode)) { + return; + } + morphEl(morphedNode, toNode, childrenOnly); + if (keyedRemovalList) { + for (var i = 0, len = keyedRemovalList.length; i < len; i++) { + var elToRemove = fromNodesLookup[keyedRemovalList[i]]; + if (elToRemove) { + removeNode(elToRemove, elToRemove.parentNode, false); + } + } + } + } + if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) { + if (morphedNode.actualize) { + morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc); + } + fromNode.parentNode.replaceChild(morphedNode, fromNode); + } + return morphedNode; + }; + } + var morphdom = morphdomFactory(morphAttrs); + var morphdom_esm_default = morphdom; + var DOMPatch = class { + constructor(view, container, id, html, streams, targetCID, opts = {}) { + this.view = view; + this.liveSocket = view.liveSocket; + this.container = container; + this.id = id; + this.rootID = view.root.id; + this.html = html; + this.streams = streams; + this.streamInserts = {}; + this.streamComponentRestore = {}; + this.targetCID = targetCID; + this.cidPatch = isCid(this.targetCID); + this.pendingRemoves = []; + this.phxRemove = this.liveSocket.binding("remove"); + this.targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container; + this.callbacks = { + beforeadded: [], + beforeupdated: [], + beforephxChildAdded: [], + afteradded: [], + afterupdated: [], + afterdiscarded: [], + afterphxChildAdded: [], + aftertransitionsDiscarded: [] + }; + this.withChildren = opts.withChildren || opts.undoRef || false; + this.undoRef = opts.undoRef; + } + before(kind, callback) { + this.callbacks[`before${kind}`].push(callback); + } + after(kind, callback) { + this.callbacks[`after${kind}`].push(callback); + } + trackBefore(kind, ...args) { + this.callbacks[`before${kind}`].forEach((callback) => callback(...args)); + } + trackAfter(kind, ...args) { + this.callbacks[`after${kind}`].forEach((callback) => callback(...args)); + } + markPrunableContentForRemoval() { + const phxUpdate = this.liveSocket.binding(PHX_UPDATE); + dom_default.all( + this.container, + `[${phxUpdate}=append] > *, [${phxUpdate}=prepend] > *`, + (el) => { + el.setAttribute(PHX_PRUNE, ""); + } + ); + } + perform(isJoinPatch) { + const { view, liveSocket: liveSocket2, html, container } = this; + let targetContainer = this.targetContainer; + if (this.isCIDPatch() && !this.targetContainer) { + return; + } + if (this.isCIDPatch()) { + const closestLock = targetContainer.closest(`[${PHX_REF_LOCK}]`); + if (closestLock) { + const clonedTree = dom_default.private(closestLock, PHX_REF_LOCK); + if (clonedTree) { + targetContainer = clonedTree.querySelector( + `[data-phx-component="${this.targetCID}"]` + ); + } + } + } + const focused = liveSocket2.getActiveElement(); + const { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {}; + const phxUpdate = liveSocket2.binding(PHX_UPDATE); + const phxViewportTop = liveSocket2.binding(PHX_VIEWPORT_TOP); + const phxViewportBottom = liveSocket2.binding(PHX_VIEWPORT_BOTTOM); + const phxTriggerExternal = liveSocket2.binding(PHX_TRIGGER_ACTION); + const added = []; + const updates = []; + const appendPrependUpdates = []; + const portalCallbacks = []; + let externalFormTriggered = null; + const morph = (targetContainer2, source, withChildren = this.withChildren) => { + const morphCallbacks = { + // normally, we are running with childrenOnly, as the patch HTML for a LV + // does not include the LV attrs (data-phx-session, etc.) + // when we are patching a live component, we do want to patch the root element as well; + // another case is the recursive patch of a stream item that was kept on reset (-> onBeforeNodeAdded) + childrenOnly: targetContainer2.getAttribute(PHX_COMPONENT) === null && !withChildren, + getNodeKey: (node) => { + if (dom_default.isPhxDestroyed(node)) { + return null; + } + if (isJoinPatch) { + return node.id; + } + return node.id || node.getAttribute && node.getAttribute(PHX_MAGIC_ID); + }, + // skip indexing from children when container is stream + skipFromChildren: (from) => { + return from.getAttribute(phxUpdate) === PHX_STREAM; + }, + // tell morphdom how to add a child + addChild: (parent, child) => { + const { ref, streamAt } = this.getStreamInsert(child); + if (ref === void 0) { + return parent.appendChild(child); + } + this.setStreamRef(child, ref); + if (streamAt === 0) { + parent.insertAdjacentElement("afterbegin", child); + } else if (streamAt === -1) { + const lastChild = parent.lastElementChild; + if (lastChild && !lastChild.hasAttribute(PHX_STREAM_REF)) { + const nonStreamChild = Array.from(parent.children).find( + (c) => !c.hasAttribute(PHX_STREAM_REF) + ); + parent.insertBefore(child, nonStreamChild); + } else { + parent.appendChild(child); + } + } else if (streamAt > 0) { + const sibling = Array.from(parent.children)[streamAt]; + parent.insertBefore(child, sibling); + } + }, + onBeforeNodeAdded: (el) => { + if (this.getStreamInsert(el)?.updateOnly && !this.streamComponentRestore[el.id]) { + return false; + } + dom_default.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom); + this.trackBefore("added", el); + let morphedEl = el; + if (this.streamComponentRestore[el.id]) { + morphedEl = this.streamComponentRestore[el.id]; + delete this.streamComponentRestore[el.id]; + morph(morphedEl, el, true); + } + return morphedEl; + }, + onNodeAdded: (el) => { + if (el.getAttribute) { + this.maybeReOrderStream(el, true); + } + if (dom_default.isPortalTemplate(el)) { + portalCallbacks.push(() => this.teleport(el, morph)); + } + if (el instanceof HTMLImageElement && el.srcset) { + el.srcset = el.srcset; + } else if (el instanceof HTMLVideoElement && el.autoplay) { + el.play(); + } + if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) { + externalFormTriggered = el; + } + if (dom_default.isPhxChild(el) && view.ownsElement(el) || dom_default.isPhxSticky(el) && view.ownsElement(el.parentNode)) { + this.trackAfter("phxChildAdded", el); + } + if (el.nodeName === "SCRIPT" && el.hasAttribute(PHX_RUNTIME_HOOK)) { + this.handleRuntimeHook(el, source); + } + added.push(el); + }, + onNodeDiscarded: (el) => this.onNodeDiscarded(el), + onBeforeNodeDiscarded: (el) => { + if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) { + return true; + } + if (el.parentElement !== null && el.id && dom_default.isPhxUpdate(el.parentElement, phxUpdate, [ + PHX_STREAM, + "append", + "prepend" + ])) { + return false; + } + if (el.getAttribute && el.getAttribute(PHX_TELEPORTED_REF)) { + return false; + } + if (this.maybePendingRemove(el)) { + return false; + } + if (this.skipCIDSibling(el)) { + return false; + } + if (dom_default.isPortalTemplate(el)) { + const teleportedEl = document.getElementById( + el.content.firstElementChild.id + ); + if (teleportedEl) { + teleportedEl.remove(); + morphCallbacks.onNodeDiscarded(teleportedEl); + this.view.dropPortalElementId(teleportedEl.id); + } + } + return true; + }, + onElUpdated: (el) => { + if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) { + externalFormTriggered = el; + } + updates.push(el); + this.maybeReOrderStream(el, false); + }, + onBeforeElUpdated: (fromEl, toEl) => { + if (fromEl.id && fromEl.isSameNode(targetContainer2) && fromEl.id !== toEl.id) { + morphCallbacks.onNodeDiscarded(fromEl); + fromEl.replaceWith(toEl); + return morphCallbacks.onNodeAdded(toEl); + } + dom_default.syncPendingAttrs(fromEl, toEl); + dom_default.maintainPrivateHooks( + fromEl, + toEl, + phxViewportTop, + phxViewportBottom + ); + dom_default.cleanChildNodes(toEl, phxUpdate); + if (this.skipCIDSibling(toEl)) { + this.maybeReOrderStream(fromEl); + return false; + } + if (dom_default.isPhxSticky(fromEl)) { + [PHX_SESSION, PHX_STATIC, PHX_ROOT_ID].map((attr) => [ + attr, + fromEl.getAttribute(attr), + toEl.getAttribute(attr) + ]).forEach(([attr, fromVal, toVal]) => { + if (toVal && fromVal !== toVal) { + fromEl.setAttribute(attr, toVal); + } + }); + return false; + } + if (dom_default.isIgnored(fromEl, phxUpdate) || fromEl.form && fromEl.form.isSameNode(externalFormTriggered)) { + this.trackBefore("updated", fromEl, toEl); + dom_default.mergeAttrs(fromEl, toEl, { + isIgnored: dom_default.isIgnored(fromEl, phxUpdate) + }); + updates.push(fromEl); + dom_default.applyStickyOperations(fromEl); + return false; + } + if (fromEl.type === "number" && fromEl.validity && fromEl.validity.badInput) { + return false; + } + const isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl); + const focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl); + if (fromEl.hasAttribute(PHX_REF_SRC)) { + const ref = new ElementRef(fromEl); + if (ref.lockRef && (!this.undoRef || !ref.isLockUndoneBy(this.undoRef))) { + if (dom_default.isUploadInput(fromEl)) { + dom_default.mergeAttrs(fromEl, toEl, { isIgnored: true }); + this.trackBefore("updated", fromEl, toEl); + updates.push(fromEl); + } + dom_default.applyStickyOperations(fromEl); + const isLocked = fromEl.hasAttribute(PHX_REF_LOCK); + const clone2 = isLocked ? dom_default.private(fromEl, PHX_REF_LOCK) || fromEl.cloneNode(true) : null; + if (clone2) { + dom_default.putPrivate(fromEl, PHX_REF_LOCK, clone2); + if (!isFocusedFormEl) { + fromEl = clone2; + } + } + } + } + if (dom_default.isPhxChild(toEl)) { + const prevSession = fromEl.getAttribute(PHX_SESSION); + dom_default.mergeAttrs(fromEl, toEl, { exclude: [PHX_STATIC] }); + if (prevSession !== "") { + fromEl.setAttribute(PHX_SESSION, prevSession); + } + fromEl.setAttribute(PHX_ROOT_ID, this.rootID); + dom_default.applyStickyOperations(fromEl); + return false; + } + if (this.undoRef && dom_default.private(toEl, PHX_REF_LOCK)) { + dom_default.putPrivate( + fromEl, + PHX_REF_LOCK, + dom_default.private(toEl, PHX_REF_LOCK) + ); + } + dom_default.copyPrivates(toEl, fromEl); + if (dom_default.isPortalTemplate(toEl)) { + portalCallbacks.push(() => this.teleport(toEl, morph)); + return false; + } + if (isFocusedFormEl && fromEl.type !== "hidden" && !focusedSelectChanged) { + this.trackBefore("updated", fromEl, toEl); + dom_default.mergeFocusedInput(fromEl, toEl); + dom_default.syncAttrsToProps(fromEl); + updates.push(fromEl); + dom_default.applyStickyOperations(fromEl); + return false; + } else { + if (focusedSelectChanged) { + fromEl.blur(); + } + if (dom_default.isPhxUpdate(toEl, phxUpdate, ["append", "prepend"])) { + appendPrependUpdates.push( + new DOMPostMorphRestorer( + fromEl, + toEl, + toEl.getAttribute(phxUpdate) + ) + ); + } + dom_default.syncAttrsToProps(toEl); + dom_default.applyStickyOperations(toEl); + this.trackBefore("updated", fromEl, toEl); + return fromEl; + } + } + }; + morphdom_esm_default(targetContainer2, source, morphCallbacks); + }; + this.trackBefore("added", container); + this.trackBefore("updated", container, container); + liveSocket2.time("morphdom", () => { + this.streams.forEach(([ref, inserts, deleteIds, reset]) => { + inserts.forEach(([key, streamAt, limit, updateOnly]) => { + this.streamInserts[key] = { ref, streamAt, limit, reset, updateOnly }; + }); + if (reset !== void 0) { + dom_default.all(container, `[${PHX_STREAM_REF}="${ref}"]`, (child) => { + this.removeStreamChildElement(child); + }); + } + deleteIds.forEach((id) => { + const child = container.querySelector(`[id="${id}"]`); + if (child) { + this.removeStreamChildElement(child); + } + }); + }); + if (isJoinPatch) { + dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`).filter((el) => this.view.ownsElement(el)).forEach((el) => { + Array.from(el.children).forEach((child) => { + this.removeStreamChildElement(child, true); + }); + }); + } + morph(targetContainer, html); + portalCallbacks.forEach((callback) => callback()); + this.view.portalElementIds.forEach((id) => { + const el = document.getElementById(id); + if (el) { + const source = document.getElementById( + el.getAttribute(PHX_TELEPORTED_SRC) + ); + if (!source) { + el.remove(); + this.onNodeDiscarded(el); + this.view.dropPortalElementId(id); + } + } + }); + }); + if (liveSocket2.isDebugEnabled()) { + detectDuplicateIds(); + detectInvalidStreamInserts(this.streamInserts); + Array.from(document.querySelectorAll("input[name=id]")).forEach( + (node) => { + if (node instanceof HTMLInputElement && node.form) { + console.error( + 'Detected an input with name="id" inside a form! This will cause problems when patching the DOM.\n', + node + ); + } + } + ); + } + if (appendPrependUpdates.length > 0) { + liveSocket2.time("post-morph append/prepend restoration", () => { + appendPrependUpdates.forEach((update) => update.perform()); + }); + } + liveSocket2.silenceEvents( + () => dom_default.restoreFocus(focused, selectionStart, selectionEnd) + ); + dom_default.dispatchEvent(document, "phx:update"); + added.forEach((el) => this.trackAfter("added", el)); + updates.forEach((el) => this.trackAfter("updated", el)); + this.transitionPendingRemoves(); + if (externalFormTriggered) { + liveSocket2.unload(); + const submitter = dom_default.private(externalFormTriggered, "submitter"); + if (submitter && submitter.name && targetContainer.contains(submitter)) { + const input = document.createElement("input"); + input.type = "hidden"; + const formId = submitter.getAttribute("form"); + if (formId) { + input.setAttribute("form", formId); + } + input.name = submitter.name; + input.value = submitter.value; + submitter.parentElement.insertBefore(input, submitter); + } + Object.getPrototypeOf(externalFormTriggered).submit.call( + externalFormTriggered + ); + } + return true; + } + onNodeDiscarded(el) { + if (dom_default.isPhxChild(el) || dom_default.isPhxSticky(el)) { + this.liveSocket.destroyViewByEl(el); + } + this.trackAfter("discarded", el); + } + maybePendingRemove(node) { + if (node.getAttribute && node.getAttribute(this.phxRemove) !== null) { + this.pendingRemoves.push(node); + return true; + } else { + return false; + } + } + removeStreamChildElement(child, force = false) { + if (!force && !this.view.ownsElement(child)) { + return; + } + if (this.streamInserts[child.id]) { + this.streamComponentRestore[child.id] = child; + child.remove(); + } else { + if (!this.maybePendingRemove(child)) { + child.remove(); + this.onNodeDiscarded(child); + } + } + } + getStreamInsert(el) { + const insert = el.id ? this.streamInserts[el.id] : {}; + return insert || {}; + } + setStreamRef(el, ref) { + dom_default.putSticky( + el, + PHX_STREAM_REF, + (el2) => el2.setAttribute(PHX_STREAM_REF, ref) + ); + } + maybeReOrderStream(el, isNew) { + const { ref, streamAt, reset } = this.getStreamInsert(el); + if (streamAt === void 0) { + return; + } + this.setStreamRef(el, ref); + if (!reset && !isNew) { + return; + } + if (!el.parentElement) { + return; + } + if (streamAt === 0) { + el.parentElement.insertBefore(el, el.parentElement.firstElementChild); + } else if (streamAt > 0) { + const children = Array.from(el.parentElement.children); + const oldIndex = children.indexOf(el); + if (streamAt >= children.length - 1) { + el.parentElement.appendChild(el); + } else { + const sibling = children[streamAt]; + if (oldIndex > streamAt) { + el.parentElement.insertBefore(el, sibling); + } else { + el.parentElement.insertBefore(el, sibling.nextElementSibling); + } + } + } + this.maybeLimitStream(el); + } + maybeLimitStream(el) { + const { limit } = this.getStreamInsert(el); + const children = limit !== null && Array.from(el.parentElement.children); + if (limit && limit < 0 && children.length > limit * -1) { + children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child)); + } else if (limit && limit >= 0 && children.length > limit) { + children.slice(limit).forEach((child) => this.removeStreamChildElement(child)); + } + } + transitionPendingRemoves() { + const { pendingRemoves, liveSocket: liveSocket2 } = this; + if (pendingRemoves.length > 0) { + liveSocket2.transitionRemoves(pendingRemoves, () => { + pendingRemoves.forEach((el) => { + const child = dom_default.firstPhxChild(el); + if (child) { + liveSocket2.destroyViewByEl(child); + } + el.remove(); + }); + this.trackAfter("transitionsDiscarded", pendingRemoves); + }); + } + } + isChangedSelect(fromEl, toEl) { + if (!(fromEl instanceof HTMLSelectElement) || fromEl.multiple) { + return false; + } + if (fromEl.options.length !== toEl.options.length) { + return true; + } + toEl.value = fromEl.value; + return !fromEl.isEqualNode(toEl); + } + isCIDPatch() { + return this.cidPatch; + } + skipCIDSibling(el) { + return el.nodeType === Node.ELEMENT_NODE && el.hasAttribute(PHX_SKIP); + } + targetCIDContainer(html) { + if (!this.isCIDPatch()) { + return; + } + const [first, ...rest] = dom_default.findComponentNodeList( + this.view.id, + this.targetCID + ); + if (rest.length === 0 && dom_default.childNodeLength(html) === 1) { + return first; + } else { + return first && first.parentNode; + } + } + indexOf(parent, child) { + return Array.from(parent.children).indexOf(child); + } + teleport(el, morph) { + const targetSelector = el.getAttribute(PHX_PORTAL); + const portalContainer = document.querySelector(targetSelector); + if (!portalContainer) { + throw new Error( + "portal target with selector " + targetSelector + " not found" + ); + } + const toTeleport = el.content.firstElementChild; + if (this.skipCIDSibling(toTeleport)) { + return; + } + if (!toTeleport?.id) { + throw new Error( + "phx-portal template must have a single root element with ID!" + ); + } + const existing = document.getElementById(toTeleport.id); + let portalTarget; + if (existing) { + if (!portalContainer.contains(existing)) { + portalContainer.appendChild(existing); + } + portalTarget = existing; + } else { + portalTarget = document.createElement(toTeleport.tagName); + portalContainer.appendChild(portalTarget); + } + toTeleport.setAttribute(PHX_TELEPORTED_REF, this.view.id); + toTeleport.setAttribute(PHX_TELEPORTED_SRC, el.id); + morph(portalTarget, toTeleport, true); + toTeleport.removeAttribute(PHX_TELEPORTED_REF); + toTeleport.removeAttribute(PHX_TELEPORTED_SRC); + this.view.pushPortalElementId(toTeleport.id); + } + handleRuntimeHook(el, source) { + const name = el.getAttribute(PHX_RUNTIME_HOOK); + let nonce = el.hasAttribute("nonce") ? el.getAttribute("nonce") : null; + if (el.hasAttribute("nonce")) { + const template = document.createElement("template"); + template.innerHTML = source; + nonce = template.content.querySelector(`script[${PHX_RUNTIME_HOOK}="${CSS.escape(name)}"]`).getAttribute("nonce"); + } + const script = document.createElement("script"); + script.textContent = el.textContent; + dom_default.mergeAttrs(script, el, { isIgnored: false }); + if (nonce) { + script.nonce = nonce; + } + el.replaceWith(script); + el = script; + } + }; + var VOID_TAGS = /* @__PURE__ */ new Set([ + "area", + "base", + "br", + "col", + "command", + "embed", + "hr", + "img", + "input", + "keygen", + "link", + "meta", + "param", + "source", + "track", + "wbr" + ]); + var quoteChars = /* @__PURE__ */ new Set(["'", '"']); + var modifyRoot = (html, attrs, clearInnerHTML) => { + let i = 0; + let insideComment = false; + let beforeTag, afterTag, tag, tagNameEndsAt, id, newHTML; + const lookahead = html.match(/^(\s*(?:\s*)*)<([^\s\/>]+)/); + if (lookahead === null) { + throw new Error(`malformed html ${html}`); + } + i = lookahead[0].length; + beforeTag = lookahead[1]; + tag = lookahead[2]; + tagNameEndsAt = i; + for (i; i < html.length; i++) { + if (html.charAt(i) === ">") { + break; + } + if (html.charAt(i) === "=") { + const isId = html.slice(i - 3, i) === " id"; + i++; + const char = html.charAt(i); + if (quoteChars.has(char)) { + const attrStartsAt = i; + i++; + for (i; i < html.length; i++) { + if (html.charAt(i) === char) { + break; + } + } + if (isId) { + id = html.slice(attrStartsAt + 1, i); + break; + } + } + } + } + let closeAt = html.length - 1; + insideComment = false; + while (closeAt >= beforeTag.length + tag.length) { + const char = html.charAt(closeAt); + if (insideComment) { + if (char === "-" && html.slice(closeAt - 3, closeAt) === "" && html.slice(closeAt - 2, closeAt) === "--") { + insideComment = true; + closeAt -= 3; + } else if (char === ">") { + break; + } else { + closeAt -= 1; + } + } + afterTag = html.slice(closeAt + 1, html.length); + const attrsStr = Object.keys(attrs).map((attr) => attrs[attr] === true ? attr : `${attr}="${attrs[attr]}"`).join(" "); + if (clearInnerHTML) { + const idAttrStr = id ? ` id="${id}"` : ""; + if (VOID_TAGS.has(tag)) { + newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}/>`; + } else { + newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}>`; + } + } else { + const rest = html.slice(tagNameEndsAt, closeAt + 1); + newHTML = `<${tag}${attrsStr === "" ? "" : " "}${attrsStr}${rest}`; + } + return [newHTML, beforeTag, afterTag]; + }; + var Rendered = class { + static extract(diff) { + const { [REPLY]: reply, [EVENTS]: events, [TITLE]: title } = diff; + delete diff[REPLY]; + delete diff[EVENTS]; + delete diff[TITLE]; + return { diff, title, reply: reply || null, events: events || [] }; + } + constructor(viewId, rendered) { + this.viewId = viewId; + this.rendered = {}; + this.magicId = 0; + this.mergeDiff(rendered); + } + parentViewId() { + return this.viewId; + } + toString(onlyCids) { + const { buffer: str, streams } = this.recursiveToString( + this.rendered, + this.rendered[COMPONENTS], + onlyCids, + true, + {} + ); + return { buffer: str, streams }; + } + recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids, changeTracking, rootAttrs) { + onlyCids = onlyCids ? new Set(onlyCids) : null; + const output = { + buffer: "", + components, + onlyCids, + streams: /* @__PURE__ */ new Set() + }; + this.toOutputBuffer(rendered, null, output, changeTracking, rootAttrs); + return { buffer: output.buffer, streams: output.streams }; + } + componentCIDs(diff) { + return Object.keys(diff[COMPONENTS] || {}).map((i) => parseInt(i)); + } + isComponentOnlyDiff(diff) { + if (!diff[COMPONENTS]) { + return false; + } + return Object.keys(diff).length === 1; + } + getComponent(diff, cid) { + return diff[COMPONENTS][cid]; + } + resetRender(cid) { + if (this.rendered[COMPONENTS][cid]) { + this.rendered[COMPONENTS][cid].reset = true; + } + } + mergeDiff(diff) { + const newc = diff[COMPONENTS]; + const cache = {}; + delete diff[COMPONENTS]; + this.rendered = this.mutableMerge(this.rendered, diff); + this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {}; + if (newc) { + const oldc = this.rendered[COMPONENTS]; + for (const cid in newc) { + newc[cid] = this.cachedFindComponent(cid, newc[cid], oldc, newc, cache); + } + for (const cid in newc) { + oldc[cid] = newc[cid]; + } + diff[COMPONENTS] = newc; + } + } + cachedFindComponent(cid, cdiff, oldc, newc, cache) { + if (cache[cid]) { + return cache[cid]; + } else { + let ndiff, stat, scid = cdiff[STATIC]; + if (isCid(scid)) { + let tdiff; + if (scid > 0) { + tdiff = this.cachedFindComponent(scid, newc[scid], oldc, newc, cache); + } else { + tdiff = oldc[-scid]; + } + stat = tdiff[STATIC]; + ndiff = this.cloneMerge(tdiff, cdiff, true); + ndiff[STATIC] = stat; + } else { + ndiff = cdiff[STATIC] !== void 0 || oldc[cid] === void 0 ? cdiff : this.cloneMerge(oldc[cid], cdiff, false); + } + cache[cid] = ndiff; + return ndiff; + } + } + mutableMerge(target, source) { + if (source[STATIC] !== void 0) { + return source; + } else { + this.doMutableMerge(target, source); + return target; + } + } + doMutableMerge(target, source) { + if (source[KEYED]) { + this.mergeKeyed(target, source); + } else { + for (const key in source) { + const val = source[key]; + const targetVal = target[key]; + const isObjVal = isObject(val); + if (isObjVal && val[STATIC] === void 0 && isObject(targetVal)) { + this.doMutableMerge(targetVal, val); + } else { + target[key] = val; + } + } + } + if (target[ROOT]) { + target.newRender = true; + } + } + clone(diff) { + if ("structuredClone" in window) { + return structuredClone(diff); + } else { + return JSON.parse(JSON.stringify(diff)); + } + } + // keyed comprehensions + mergeKeyed(target, source) { + const clonedTarget = this.clone(target); + Object.entries(source[KEYED]).forEach(([i, entry]) => { + if (i === KEYED_COUNT) { + return; + } + if (Array.isArray(entry)) { + const [old_idx, diff] = entry; + target[KEYED][i] = clonedTarget[KEYED][old_idx]; + this.doMutableMerge(target[KEYED][i], diff); + } else if (typeof entry === "number") { + const old_idx = entry; + target[KEYED][i] = clonedTarget[KEYED][old_idx]; + } else if (typeof entry === "object") { + if (!target[KEYED][i]) { + target[KEYED][i] = {}; + } + this.doMutableMerge(target[KEYED][i], entry); + } + }); + if (source[KEYED][KEYED_COUNT] < target[KEYED][KEYED_COUNT]) { + for (let i = source[KEYED][KEYED_COUNT]; i < target[KEYED][KEYED_COUNT]; i++) { + delete target[KEYED][i]; + } + } + target[KEYED][KEYED_COUNT] = source[KEYED][KEYED_COUNT]; + if (source[STREAM]) { + target[STREAM] = source[STREAM]; + } + if (source[TEMPLATES]) { + target[TEMPLATES] = source[TEMPLATES]; + } + } + // Merges cid trees together, copying statics from source tree. + // + // The `pruneMagicId` is passed to control pruning the magicId of the + // target. We must always prune the magicId when we are sharing statics + // from another component. If not pruning, we replicate the logic from + // mutableMerge, where we set newRender to true if there is a root + // (effectively forcing the new version to be rendered instead of skipped) + // + cloneMerge(target, source, pruneMagicId) { + const merged = { ...target, ...source }; + for (const key in merged) { + const val = source[key]; + const targetVal = target[key]; + if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) { + merged[key] = this.cloneMerge(targetVal, val, pruneMagicId); + } else if (val === void 0 && isObject(targetVal)) { + merged[key] = this.cloneMerge(targetVal, {}, pruneMagicId); + } + } + if (pruneMagicId) { + delete merged.magicId; + delete merged.newRender; + } else if (target[ROOT]) { + merged.newRender = true; + } + return merged; + } + componentToString(cid) { + const { buffer: str, streams } = this.recursiveCIDToString( + this.rendered[COMPONENTS], + cid, + null + ); + const [strippedHTML, _before, _after] = modifyRoot(str, {}); + return { buffer: strippedHTML, streams }; + } + pruneCIDs(cids) { + cids.forEach((cid) => delete this.rendered[COMPONENTS][cid]); + } + // private + get() { + return this.rendered; + } + isNewFingerprint(diff = {}) { + return !!diff[STATIC]; + } + templateStatic(part, templates) { + if (typeof part === "number") { + return templates[part]; + } else { + return part; + } + } + nextMagicID() { + this.magicId++; + return `m${this.magicId}-${this.parentViewId()}`; + } + // Converts rendered tree to output buffer. + // + // changeTracking controls if we can apply the PHX_SKIP optimization. + toOutputBuffer(rendered, templates, output, changeTracking, rootAttrs = {}) { + if (rendered[KEYED]) { + return this.comprehensionToBuffer( + rendered, + templates, + output, + changeTracking + ); + } + if (rendered[TEMPLATES]) { + templates = rendered[TEMPLATES]; + delete rendered[TEMPLATES]; + } + let { [STATIC]: statics } = rendered; + statics = this.templateStatic(statics, templates); + rendered[STATIC] = statics; + const isRoot = rendered[ROOT]; + const prevBuffer = output.buffer; + if (isRoot) { + output.buffer = ""; + } + if (changeTracking && isRoot && !rendered.magicId) { + rendered.newRender = true; + rendered.magicId = this.nextMagicID(); + } + output.buffer += statics[0]; + for (let i = 1; i < statics.length; i++) { + this.dynamicToBuffer(rendered[i - 1], templates, output, changeTracking); + output.buffer += statics[i]; + } + if (isRoot) { + let skip = false; + let attrs; + if (changeTracking || rendered.magicId) { + skip = changeTracking && !rendered.newRender; + attrs = { [PHX_MAGIC_ID]: rendered.magicId, ...rootAttrs }; + } else { + attrs = rootAttrs; + } + if (skip) { + attrs[PHX_SKIP] = true; + } + const [newRoot, commentBefore, commentAfter] = modifyRoot( + output.buffer, + attrs, + skip + ); + rendered.newRender = false; + output.buffer = prevBuffer + commentBefore + newRoot + commentAfter; + } + } + comprehensionToBuffer(rendered, templates, output, changeTracking) { + const keyedTemplates = templates || rendered[TEMPLATES]; + const statics = this.templateStatic(rendered[STATIC], templates); + rendered[STATIC] = statics; + delete rendered[TEMPLATES]; + for (let i = 0; i < rendered[KEYED][KEYED_COUNT]; i++) { + output.buffer += statics[0]; + for (let j = 1; j < statics.length; j++) { + this.dynamicToBuffer( + rendered[KEYED][i][j - 1], + keyedTemplates, + output, + changeTracking + ); + output.buffer += statics[j]; + } + } + if (rendered[STREAM]) { + const stream = rendered[STREAM]; + const [_ref, _inserts, deleteIds, reset] = stream || [null, {}, [], null]; + if (stream !== void 0 && (rendered[KEYED][KEYED_COUNT] > 0 || deleteIds.length > 0 || reset)) { + delete rendered[STREAM]; + rendered[KEYED] = { + [KEYED_COUNT]: 0 + }; + output.streams.add(stream); + } + } + } + dynamicToBuffer(rendered, templates, output, changeTracking) { + if (typeof rendered === "number") { + const { buffer: str, streams } = this.recursiveCIDToString( + output.components, + rendered, + output.onlyCids + ); + output.buffer += str; + output.streams = /* @__PURE__ */ new Set([...output.streams, ...streams]); + } else if (isObject(rendered)) { + this.toOutputBuffer(rendered, templates, output, changeTracking, {}); + } else { + output.buffer += rendered; + } + } + recursiveCIDToString(components, cid, onlyCids) { + const component = components[cid] || logError(`no component for CID ${cid}`, components); + const attrs = { [PHX_COMPONENT]: cid, [PHX_VIEW_REF]: this.viewId }; + const skip = onlyCids && !onlyCids.has(cid); + component.newRender = !skip; + component.magicId = `c${cid}-${this.parentViewId()}`; + const changeTracking = !component.reset; + const { buffer: html, streams } = this.recursiveToString( + component, + components, + onlyCids, + changeTracking, + attrs + ); + delete component.reset; + return { buffer: html, streams }; + } + }; + var focusStack = []; + var default_transition_time = 200; + var JS = { + // private + exec(e, eventType, phxEvent, view, sourceEl, defaults) { + const [defaultKind, defaultArgs] = defaults || [ + null, + { callback: defaults && defaults.callback } + ]; + const commands = phxEvent.charAt(0) === "[" ? JSON.parse(phxEvent) : [[defaultKind, defaultArgs]]; + commands.forEach(([kind, args]) => { + if (kind === defaultKind) { + args = { ...defaultArgs, ...args }; + args.callback = args.callback || defaultArgs.callback; + } + this.filterToEls(view.liveSocket, sourceEl, args).forEach((el) => { + this[`exec_${kind}`](e, eventType, phxEvent, view, sourceEl, el, args); + }); + }); + }, + isVisible(el) { + return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0); + }, + // returns true if any part of the element is inside the viewport + isInViewport(el) { + const rect = el.getBoundingClientRect(); + const windowHeight = window.innerHeight || document.documentElement.clientHeight; + const windowWidth = window.innerWidth || document.documentElement.clientWidth; + return rect.right > 0 && rect.bottom > 0 && rect.left < windowWidth && rect.top < windowHeight; + }, + // private + // commands + exec_exec(e, eventType, phxEvent, view, sourceEl, el, { attr, to }) { + const encodedJS = el.getAttribute(attr); + if (!encodedJS) { + throw new Error(`expected ${attr} to contain JS command on "${to}"`); + } + view.liveSocket.execJS(el, encodedJS, eventType); + }, + exec_dispatch(e, eventType, phxEvent, view, sourceEl, el, { event, detail, bubbles, blocking }) { + detail = detail || {}; + detail.dispatcher = sourceEl; + if (blocking) { + const promise = new Promise((resolve, _reject) => { + detail.done = resolve; + }); + view.liveSocket.asyncTransition(promise); + } + dom_default.dispatchEvent(el, event, { detail, bubbles }); + }, + exec_push(e, eventType, phxEvent, view, sourceEl, el, args) { + const { + event, + data, + target, + page_loading, + loading, + value, + dispatcher, + callback + } = args; + const pushOpts = { + loading, + value, + target, + page_loading: !!page_loading, + originalEvent: e + }; + const targetSrc = eventType === "change" && dispatcher ? dispatcher : sourceEl; + const phxTarget = target || targetSrc.getAttribute(view.binding("target")) || targetSrc; + const handler = (targetView, targetCtx) => { + if (!targetView.isConnected()) { + return; + } + if (eventType === "change") { + let { newCid, _target } = args; + _target = _target || (dom_default.isFormInput(sourceEl) ? sourceEl.name : void 0); + if (_target) { + pushOpts._target = _target; + } + targetView.pushInput( + sourceEl, + targetCtx, + newCid, + event || phxEvent, + pushOpts, + callback + ); + } else if (eventType === "submit") { + const { submitter } = args; + targetView.submitForm( + sourceEl, + targetCtx, + event || phxEvent, + submitter, + pushOpts, + callback + ); + } else { + targetView.pushEvent( + eventType, + sourceEl, + targetCtx, + event || phxEvent, + data, + pushOpts, + callback + ); + } + }; + if (args.targetView && args.targetCtx) { + handler(args.targetView, args.targetCtx); + } else { + view.withinTargets(phxTarget, handler); + } + }, + exec_navigate(e, eventType, phxEvent, view, sourceEl, el, { href, replace }) { + view.liveSocket.historyRedirect( + e, + href, + replace ? "replace" : "push", + null, + sourceEl + ); + }, + exec_patch(e, eventType, phxEvent, view, sourceEl, el, { href, replace }) { + view.liveSocket.pushHistoryPatch( + e, + href, + replace ? "replace" : "push", + sourceEl + ); + }, + exec_focus(e, eventType, phxEvent, view, sourceEl, el) { + aria_default.attemptFocus(el); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => aria_default.attemptFocus(el)); + }); + }, + exec_focus_first(e, eventType, phxEvent, view, sourceEl, el) { + aria_default.focusFirstInteractive(el) || aria_default.focusFirst(el); + window.requestAnimationFrame(() => { + window.requestAnimationFrame( + () => aria_default.focusFirstInteractive(el) || aria_default.focusFirst(el) + ); + }); + }, + exec_push_focus(e, eventType, phxEvent, view, sourceEl, el) { + focusStack.push(el || sourceEl); + }, + exec_pop_focus(_e, _eventType, _phxEvent, _view, _sourceEl, _el) { + const el = focusStack.pop(); + if (el) { + el.focus(); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => el.focus()); + }); + } + }, + exec_add_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { + this.addOrRemoveClasses(el, names, [], transition, time, view, blocking); + }, + exec_remove_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { + this.addOrRemoveClasses(el, [], names, transition, time, view, blocking); + }, + exec_toggle_class(e, eventType, phxEvent, view, sourceEl, el, { names, transition, time, blocking }) { + this.toggleClasses(el, names, transition, time, view, blocking); + }, + exec_toggle_attr(e, eventType, phxEvent, view, sourceEl, el, { attr: [attr, val1, val2] }) { + this.toggleAttr(el, attr, val1, val2); + }, + exec_ignore_attrs(e, eventType, phxEvent, view, sourceEl, el, { attrs }) { + this.ignoreAttrs(el, attrs); + }, + exec_transition(e, eventType, phxEvent, view, sourceEl, el, { time, transition, blocking }) { + this.addOrRemoveClasses(el, [], [], transition, time, view, blocking); + }, + exec_toggle(e, eventType, phxEvent, view, sourceEl, el, { display, ins, outs, time, blocking }) { + this.toggle(eventType, view, el, display, ins, outs, time, blocking); + }, + exec_show(e, eventType, phxEvent, view, sourceEl, el, { display, transition, time, blocking }) { + this.show(eventType, view, el, display, transition, time, blocking); + }, + exec_hide(e, eventType, phxEvent, view, sourceEl, el, { display, transition, time, blocking }) { + this.hide(eventType, view, el, display, transition, time, blocking); + }, + exec_set_attr(e, eventType, phxEvent, view, sourceEl, el, { attr: [attr, val] }) { + this.setOrRemoveAttrs(el, [[attr, val]], []); + }, + exec_remove_attr(e, eventType, phxEvent, view, sourceEl, el, { attr }) { + this.setOrRemoveAttrs(el, [], [attr]); + }, + ignoreAttrs(el, attrs) { + dom_default.putPrivate(el, "JS:ignore_attrs", { + apply: (fromEl, toEl) => { + Array.from(fromEl.attributes).forEach((attr) => { + if (attrs.some( + (toIgnore) => attr.name == toIgnore || toIgnore.includes("*") && attr.name.match(toIgnore) != null + )) { + toEl.setAttribute(attr.name, attr.value); + } + }); + } + }); + }, + onBeforeElUpdated(fromEl, toEl) { + const ignoreAttrs = dom_default.private(fromEl, "JS:ignore_attrs"); + if (ignoreAttrs) { + ignoreAttrs.apply(fromEl, toEl); + } + }, + // utils for commands + show(eventType, view, el, display, transition, time, blocking) { + if (!this.isVisible(el)) { + this.toggle( + eventType, + view, + el, + display, + transition, + null, + time, + blocking + ); + } + }, + hide(eventType, view, el, display, transition, time, blocking) { + if (this.isVisible(el)) { + this.toggle( + eventType, + view, + el, + display, + null, + transition, + time, + blocking + ); + } + }, + toggle(eventType, view, el, display, ins, outs, time, blocking) { + time = time || default_transition_time; + const [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []]; + const [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []]; + if (inClasses.length > 0 || outClasses.length > 0) { + if (this.isVisible(el)) { + const onStart = () => { + this.addOrRemoveClasses( + el, + outStartClasses, + inClasses.concat(inStartClasses).concat(inEndClasses) + ); + window.requestAnimationFrame(() => { + this.addOrRemoveClasses(el, outClasses, []); + window.requestAnimationFrame( + () => this.addOrRemoveClasses(el, outEndClasses, outStartClasses) + ); + }); + }; + const onEnd = () => { + this.addOrRemoveClasses(el, [], outClasses.concat(outEndClasses)); + dom_default.putSticky( + el, + "toggle", + (currentEl) => currentEl.style.display = "none" + ); + el.dispatchEvent(new Event("phx:hide-end")); + }; + el.dispatchEvent(new Event("phx:hide-start")); + if (blocking === false) { + onStart(); + setTimeout(onEnd, time); + } else { + view.transition(time, onStart, onEnd); + } + } else { + if (eventType === "remove") { + return; + } + const onStart = () => { + this.addOrRemoveClasses( + el, + inStartClasses, + outClasses.concat(outStartClasses).concat(outEndClasses) + ); + const stickyDisplay = display || this.defaultDisplay(el); + window.requestAnimationFrame(() => { + this.addOrRemoveClasses(el, inClasses, []); + window.requestAnimationFrame(() => { + dom_default.putSticky( + el, + "toggle", + (currentEl) => currentEl.style.display = stickyDisplay + ); + this.addOrRemoveClasses(el, inEndClasses, inStartClasses); + }); + }); + }; + const onEnd = () => { + this.addOrRemoveClasses(el, [], inClasses.concat(inEndClasses)); + el.dispatchEvent(new Event("phx:show-end")); + }; + el.dispatchEvent(new Event("phx:show-start")); + if (blocking === false) { + onStart(); + setTimeout(onEnd, time); + } else { + view.transition(time, onStart, onEnd); + } + } + } else { + if (this.isVisible(el)) { + window.requestAnimationFrame(() => { + el.dispatchEvent(new Event("phx:hide-start")); + dom_default.putSticky( + el, + "toggle", + (currentEl) => currentEl.style.display = "none" + ); + el.dispatchEvent(new Event("phx:hide-end")); + }); + } else { + window.requestAnimationFrame(() => { + el.dispatchEvent(new Event("phx:show-start")); + const stickyDisplay = display || this.defaultDisplay(el); + dom_default.putSticky( + el, + "toggle", + (currentEl) => currentEl.style.display = stickyDisplay + ); + el.dispatchEvent(new Event("phx:show-end")); + }); + } + } + }, + toggleClasses(el, classes, transition, time, view, blocking) { + window.requestAnimationFrame(() => { + const [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]); + const newAdds = classes.filter( + (name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name) + ); + const newRemoves = classes.filter( + (name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name) + ); + this.addOrRemoveClasses( + el, + newAdds, + newRemoves, + transition, + time, + view, + blocking + ); + }); + }, + toggleAttr(el, attr, val1, val2) { + if (el.hasAttribute(attr)) { + if (val2 !== void 0) { + if (el.getAttribute(attr) === val1) { + this.setOrRemoveAttrs(el, [[attr, val2]], []); + } else { + this.setOrRemoveAttrs(el, [[attr, val1]], []); + } + } else { + this.setOrRemoveAttrs(el, [], [attr]); + } + } else { + this.setOrRemoveAttrs(el, [[attr, val1]], []); + } + }, + addOrRemoveClasses(el, adds, removes, transition, time, view, blocking) { + time = time || default_transition_time; + const [transitionRun, transitionStart, transitionEnd] = transition || [ + [], + [], + [] + ]; + if (transitionRun.length > 0) { + const onStart = () => { + this.addOrRemoveClasses( + el, + transitionStart, + [].concat(transitionRun).concat(transitionEnd) + ); + window.requestAnimationFrame(() => { + this.addOrRemoveClasses(el, transitionRun, []); + window.requestAnimationFrame( + () => this.addOrRemoveClasses(el, transitionEnd, transitionStart) + ); + }); + }; + const onDone = () => this.addOrRemoveClasses( + el, + adds.concat(transitionEnd), + removes.concat(transitionRun).concat(transitionStart) + ); + if (blocking === false) { + onStart(); + setTimeout(onDone, time); + } else { + view.transition(time, onStart, onDone); + } + return; + } + window.requestAnimationFrame(() => { + const [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]); + const keepAdds = adds.filter( + (name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name) + ); + const keepRemoves = removes.filter( + (name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name) + ); + const newAdds = prevAdds.filter((name) => removes.indexOf(name) < 0).concat(keepAdds); + const newRemoves = prevRemoves.filter((name) => adds.indexOf(name) < 0).concat(keepRemoves); + dom_default.putSticky(el, "classes", (currentEl) => { + currentEl.classList.remove(...newRemoves); + currentEl.classList.add(...newAdds); + return [newAdds, newRemoves]; + }); + }); + }, + setOrRemoveAttrs(el, sets, removes) { + const [prevSets, prevRemoves] = dom_default.getSticky(el, "attrs", [[], []]); + const alteredAttrs = sets.map(([attr, _val]) => attr).concat(removes); + const newSets = prevSets.filter(([attr, _val]) => !alteredAttrs.includes(attr)).concat(sets); + const newRemoves = prevRemoves.filter((attr) => !alteredAttrs.includes(attr)).concat(removes); + dom_default.putSticky(el, "attrs", (currentEl) => { + newRemoves.forEach((attr) => currentEl.removeAttribute(attr)); + newSets.forEach(([attr, val]) => currentEl.setAttribute(attr, val)); + return [newSets, newRemoves]; + }); + }, + hasAllClasses(el, classes) { + return classes.every((name) => el.classList.contains(name)); + }, + isToggledOut(el, outClasses) { + return !this.isVisible(el) || this.hasAllClasses(el, outClasses); + }, + filterToEls(liveSocket2, sourceEl, { to }) { + const defaultQuery = () => { + if (typeof to === "string") { + return document.querySelectorAll(to); + } else if (to.closest) { + const toEl = sourceEl.closest(to.closest); + return toEl ? [toEl] : []; + } else if (to.inner) { + return sourceEl.querySelectorAll(to.inner); + } + }; + return to ? liveSocket2.jsQuerySelectorAll(sourceEl, to, defaultQuery) : [sourceEl]; + }, + defaultDisplay(el) { + return { tr: "table-row", td: "table-cell" }[el.tagName.toLowerCase()] || "block"; + }, + transitionClasses(val) { + if (!val) { + return null; + } + let [trans, tStart, tEnd] = Array.isArray(val) ? val : [val.split(" "), [], []]; + trans = Array.isArray(trans) ? trans : trans.split(" "); + tStart = Array.isArray(tStart) ? tStart : tStart.split(" "); + tEnd = Array.isArray(tEnd) ? tEnd : tEnd.split(" "); + return [trans, tStart, tEnd]; + } + }; + var js_default = JS; + var js_commands_default = (liveSocket2, eventType) => { + return { + exec(el, encodedJS) { + liveSocket2.execJS(el, encodedJS, eventType); + }, + show(el, opts = {}) { + const owner = liveSocket2.owner(el); + js_default.show( + eventType, + owner, + el, + opts.display, + js_default.transitionClasses(opts.transition), + opts.time, + opts.blocking + ); + }, + hide(el, opts = {}) { + const owner = liveSocket2.owner(el); + js_default.hide( + eventType, + owner, + el, + null, + js_default.transitionClasses(opts.transition), + opts.time, + opts.blocking + ); + }, + toggle(el, opts = {}) { + const owner = liveSocket2.owner(el); + const inTransition = js_default.transitionClasses(opts.in); + const outTransition = js_default.transitionClasses(opts.out); + js_default.toggle( + eventType, + owner, + el, + opts.display, + inTransition, + outTransition, + opts.time, + opts.blocking + ); + }, + addClass(el, names, opts = {}) { + const classNames = Array.isArray(names) ? names : names.split(" "); + const owner = liveSocket2.owner(el); + js_default.addOrRemoveClasses( + el, + classNames, + [], + js_default.transitionClasses(opts.transition), + opts.time, + owner, + opts.blocking + ); + }, + removeClass(el, names, opts = {}) { + const classNames = Array.isArray(names) ? names : names.split(" "); + const owner = liveSocket2.owner(el); + js_default.addOrRemoveClasses( + el, + [], + classNames, + js_default.transitionClasses(opts.transition), + opts.time, + owner, + opts.blocking + ); + }, + toggleClass(el, names, opts = {}) { + const classNames = Array.isArray(names) ? names : names.split(" "); + const owner = liveSocket2.owner(el); + js_default.toggleClasses( + el, + classNames, + js_default.transitionClasses(opts.transition), + opts.time, + owner, + opts.blocking + ); + }, + transition(el, transition, opts = {}) { + const owner = liveSocket2.owner(el); + js_default.addOrRemoveClasses( + el, + [], + [], + js_default.transitionClasses(transition), + opts.time, + owner, + opts.blocking + ); + }, + setAttribute(el, attr, val) { + js_default.setOrRemoveAttrs(el, [[attr, val]], []); + }, + removeAttribute(el, attr) { + js_default.setOrRemoveAttrs(el, [], [attr]); + }, + toggleAttribute(el, attr, val1, val2) { + js_default.toggleAttr(el, attr, val1, val2); + }, + push(el, type, opts = {}) { + liveSocket2.withinOwners(el, (view) => { + const data = opts.value || {}; + delete opts.value; + let e = new CustomEvent("phx:exec", { detail: { sourceElement: el } }); + js_default.exec(e, eventType, type, view, el, ["push", { data, ...opts }]); + }); + }, + navigate(href, opts = {}) { + const customEvent = new CustomEvent("phx:exec"); + liveSocket2.historyRedirect( + customEvent, + href, + opts.replace ? "replace" : "push", + null, + null + ); + }, + patch(href, opts = {}) { + const customEvent = new CustomEvent("phx:exec"); + liveSocket2.pushHistoryPatch( + customEvent, + href, + opts.replace ? "replace" : "push", + null + ); + }, + ignoreAttributes(el, attrs) { + js_default.ignoreAttrs(el, Array.isArray(attrs) ? attrs : [attrs]); + } + }; + }; + var HOOK_ID = "hookId"; + var viewHookID = 1; + var ViewHook = class _ViewHook { + static makeID() { + return viewHookID++; + } + static elementID(el) { + return dom_default.private(el, HOOK_ID); + } + constructor(view, el, callbacks) { + this.el = el; + this.__attachView(view); + this.__listeners = /* @__PURE__ */ new Set(); + this.__isDisconnected = false; + dom_default.putPrivate(this.el, HOOK_ID, _ViewHook.makeID()); + if (callbacks) { + const protectedProps = /* @__PURE__ */ new Set([ + "el", + "liveSocket", + "__view", + "__listeners", + "__isDisconnected", + "constructor", + // Standard object properties + // Core ViewHook API methods + "js", + "pushEvent", + "pushEventTo", + "handleEvent", + "removeHandleEvent", + "upload", + "uploadTo", + // Internal lifecycle callers + "__mounted", + "__updated", + "__beforeUpdate", + "__destroyed", + "__reconnected", + "__disconnected", + "__cleanup__" + ]); + for (const key in callbacks) { + if (Object.prototype.hasOwnProperty.call(callbacks, key)) { + this[key] = callbacks[key]; + if (protectedProps.has(key)) { + console.warn( + `Hook object for element #${el.id} overwrites core property '${key}'!` + ); + } + } + } + const lifecycleMethods = [ + "mounted", + "beforeUpdate", + "updated", + "destroyed", + "disconnected", + "reconnected" + ]; + lifecycleMethods.forEach((methodName) => { + if (callbacks[methodName] && typeof callbacks[methodName] === "function") { + this[methodName] = callbacks[methodName]; + } + }); + } + } + /** @internal */ + __attachView(view) { + if (view) { + this.__view = () => view; + this.liveSocket = view.liveSocket; + } else { + this.__view = () => { + throw new Error( + `hook not yet attached to a live view: ${this.el.outerHTML}` + ); + }; + this.liveSocket = null; + } + } + // Default lifecycle methods + mounted() { + } + beforeUpdate() { + } + updated() { + } + destroyed() { + } + disconnected() { + } + reconnected() { + } + // Internal lifecycle callers - called by the View + /** @internal */ + __mounted() { + this.mounted(); + } + /** @internal */ + __updated() { + this.updated(); + } + /** @internal */ + __beforeUpdate() { + this.beforeUpdate(); + } + /** @internal */ + __destroyed() { + this.destroyed(); + dom_default.deletePrivate(this.el, HOOK_ID); + } + /** @internal */ + __reconnected() { + if (this.__isDisconnected) { + this.__isDisconnected = false; + this.reconnected(); + } + } + /** @internal */ + __disconnected() { + this.__isDisconnected = true; + this.disconnected(); + } + js() { + return { + ...js_commands_default(this.__view().liveSocket, "hook"), + exec: (encodedJS) => { + this.__view().liveSocket.execJS(this.el, encodedJS, "hook"); + } + }; + } + pushEvent(event, payload, onReply) { + const promise = this.__view().pushHookEvent( + this.el, + null, + event, + payload || {} + ); + if (onReply === void 0) { + return promise.then(({ reply }) => reply); + } + promise.then(({ reply, ref }) => onReply(reply, ref)).catch(() => { + }); + return; + } + pushEventTo(selectorOrTarget, event, payload, onReply) { + if (onReply === void 0) { + const targetPair = []; + this.__view().withinTargets(selectorOrTarget, (view, targetCtx) => { + targetPair.push({ view, targetCtx }); + }); + const promises = targetPair.map(({ view, targetCtx }) => { + return view.pushHookEvent(this.el, targetCtx, event, payload || {}); + }); + return Promise.allSettled(promises); + } + this.__view().withinTargets(selectorOrTarget, (view, targetCtx) => { + view.pushHookEvent(this.el, targetCtx, event, payload || {}).then(({ reply, ref }) => onReply(reply, ref)).catch(() => { + }); + }); + return; + } + handleEvent(event, callback) { + const callbackRef = { + event, + callback: (customEvent) => callback(customEvent.detail) + }; + window.addEventListener( + `phx:${event}`, + callbackRef.callback + ); + this.__listeners.add(callbackRef); + return callbackRef; + } + removeHandleEvent(ref) { + window.removeEventListener( + `phx:${ref.event}`, + ref.callback + ); + this.__listeners.delete(ref); + } + upload(name, files) { + return this.__view().dispatchUploads(null, name, files); + } + uploadTo(selectorOrTarget, name, files) { + return this.__view().withinTargets(selectorOrTarget, (view, targetCtx) => { + view.dispatchUploads(targetCtx, name, files); + }); + } + /** @internal */ + __cleanup__() { + this.__listeners.forEach( + (callbackRef) => this.removeHandleEvent(callbackRef) + ); + } + }; + var prependFormDataKey = (key, prefix) => { + const isArray = key.endsWith("[]"); + let baseKey = isArray ? key.slice(0, -2) : key; + baseKey = baseKey.replace(/([^\[\]]+)(\]?$)/, `${prefix}$1$2`); + if (isArray) { + baseKey += "[]"; + } + return baseKey; + }; + var serializeForm = (form, opts, onlyNames = []) => { + const { submitter } = opts; + let injectedElement; + if (submitter && submitter.name) { + const input = document.createElement("input"); + input.type = "hidden"; + const formId = submitter.getAttribute("form"); + if (formId) { + input.setAttribute("form", formId); + } + input.name = submitter.name; + input.value = submitter.value; + submitter.parentElement.insertBefore(input, submitter); + injectedElement = input; + } + const formData = new FormData(form); + const toRemove = []; + formData.forEach((val, key, _index) => { + if (val instanceof File) { + toRemove.push(key); + } + }); + toRemove.forEach((key) => formData.delete(key)); + const params = new URLSearchParams(); + const { inputsUnused, onlyHiddenInputs } = Array.from(form.elements).reduce( + (acc, input) => { + const { inputsUnused: inputsUnused2, onlyHiddenInputs: onlyHiddenInputs2 } = acc; + const key = input.name; + if (!key) { + return acc; + } + if (inputsUnused2[key] === void 0) { + inputsUnused2[key] = true; + } + if (onlyHiddenInputs2[key] === void 0) { + onlyHiddenInputs2[key] = true; + } + const isUsed = dom_default.private(input, PHX_HAS_FOCUSED) || dom_default.private(input, PHX_HAS_SUBMITTED); + const isHidden = input.type === "hidden"; + inputsUnused2[key] = inputsUnused2[key] && !isUsed; + onlyHiddenInputs2[key] = onlyHiddenInputs2[key] && isHidden; + return acc; + }, + { inputsUnused: {}, onlyHiddenInputs: {} } + ); + for (const [key, val] of formData.entries()) { + if (onlyNames.length === 0 || onlyNames.indexOf(key) >= 0) { + const isUnused = inputsUnused[key]; + const hidden = onlyHiddenInputs[key]; + if (isUnused && !(submitter && submitter.name == key) && !hidden) { + params.append(prependFormDataKey(key, "_unused_"), ""); + } + if (typeof val === "string") { + params.append(key, val); + } + } + } + if (submitter && injectedElement) { + submitter.parentElement.removeChild(injectedElement); + } + return params.toString(); + }; + var View = class _View { + static closestView(el) { + const liveViewEl = el.closest(PHX_VIEW_SELECTOR); + return liveViewEl ? dom_default.private(liveViewEl, "view") : null; + } + constructor(el, liveSocket2, parentView, flash, liveReferer) { + this.isDead = false; + this.liveSocket = liveSocket2; + this.flash = flash; + this.parent = parentView; + this.root = parentView ? parentView.root : this; + this.el = el; + const boundView = dom_default.private(this.el, "view"); + if (boundView !== void 0 && boundView.isDead !== true) { + logError( + `The DOM element for this view has already been bound to a view. + + An element can only ever be associated with a single view! + Please ensure that you are not trying to initialize multiple LiveSockets on the same page. + This could happen if you're accidentally trying to render your root layout more than once. + Ensure that the template set on the LiveView is different than the root layout. + `, + { view: boundView } + ); + throw new Error("Cannot bind multiple views to the same DOM element."); + } + dom_default.putPrivate(this.el, "view", this); + this.id = this.el.id; + this.ref = 0; + this.lastAckRef = null; + this.childJoins = 0; + this.loaderTimer = null; + this.disconnectedTimer = null; + this.pendingDiffs = []; + this.pendingForms = /* @__PURE__ */ new Set(); + this.redirect = false; + this.href = null; + this.joinCount = this.parent ? this.parent.joinCount - 1 : 0; + this.joinAttempts = 0; + this.joinPending = true; + this.destroyed = false; + this.joinCallback = function(onDone) { + onDone && onDone(); + }; + this.stopCallback = function() { + }; + this.pendingJoinOps = this.parent ? null : []; + this.viewHooks = {}; + this.formSubmits = []; + this.children = this.parent ? null : {}; + this.root.children[this.id] = {}; + this.formsForRecovery = {}; + this.channel = this.liveSocket.channel(`lv:${this.id}`, () => { + const url = this.href && this.expandURL(this.href); + return { + redirect: this.redirect ? url : void 0, + url: this.redirect ? void 0 : url || void 0, + params: this.connectParams(liveReferer), + session: this.getSession(), + static: this.getStatic(), + flash: this.flash, + sticky: this.el.hasAttribute(PHX_STICKY) + }; + }); + this.portalElementIds = /* @__PURE__ */ new Set(); + } + setHref(href) { + this.href = href; + } + setRedirect(href) { + this.redirect = true; + this.href = href; + } + isMain() { + return this.el.hasAttribute(PHX_MAIN); + } + connectParams(liveReferer) { + const params = this.liveSocket.params(this.el); + const manifest = dom_default.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`).map((node) => node.src || node.href).filter((url) => typeof url === "string"); + if (manifest.length > 0) { + params["_track_static"] = manifest; + } + params["_mounts"] = this.joinCount; + params["_mount_attempts"] = this.joinAttempts; + params["_live_referer"] = liveReferer; + this.joinAttempts++; + return params; + } + isConnected() { + return this.channel.canPush(); + } + getSession() { + return this.el.getAttribute(PHX_SESSION); + } + getStatic() { + const val = this.el.getAttribute(PHX_STATIC); + return val === "" ? null : val; + } + destroy(callback = function() { + }) { + this.destroyAllChildren(); + this.destroyPortalElements(); + this.destroyed = true; + dom_default.deletePrivate(this.el, "view"); + delete this.root.children[this.id]; + if (this.parent) { + delete this.root.children[this.parent.id][this.id]; + } + clearTimeout(this.loaderTimer); + const onFinished = () => { + callback(); + for (const id in this.viewHooks) { + this.destroyHook(this.viewHooks[id]); + } + }; + dom_default.markPhxChildDestroyed(this.el); + this.log("destroyed", () => ["the child has been removed from the parent"]); + this.channel.leave().receive("ok", onFinished).receive("error", onFinished).receive("timeout", onFinished); + } + setContainerClasses(...classes) { + this.el.classList.remove( + PHX_CONNECTED_CLASS, + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_CLIENT_ERROR_CLASS, + PHX_SERVER_ERROR_CLASS + ); + this.el.classList.add(...classes); + } + showLoader(timeout) { + clearTimeout(this.loaderTimer); + if (timeout) { + this.loaderTimer = setTimeout(() => this.showLoader(), timeout); + } else { + for (const id in this.viewHooks) { + this.viewHooks[id].__disconnected(); + } + this.setContainerClasses(PHX_LOADING_CLASS); + } + } + execAll(binding) { + dom_default.all( + this.el, + `[${binding}]`, + (el) => this.liveSocket.execJS(el, el.getAttribute(binding)) + ); + } + hideLoader() { + clearTimeout(this.loaderTimer); + clearTimeout(this.disconnectedTimer); + this.setContainerClasses(PHX_CONNECTED_CLASS); + this.execAll(this.binding("connected")); + } + triggerReconnected() { + for (const id in this.viewHooks) { + this.viewHooks[id].__reconnected(); + } + } + log(kind, msgCallback) { + this.liveSocket.log(this, kind, msgCallback); + } + transition(time, onStart, onDone = function() { + }) { + this.liveSocket.transition(time, onStart, onDone); + } + // calls the callback with the view and target element for the given phxTarget + // targets can be: + // * an element itself, then it is simply passed to liveSocket.owner; + // * a CID (Component ID), then we first search the component's element in the DOM + // * a selector, then we search the selector in the DOM and call the callback + // for each element found with the corresponding owner view + withinTargets(phxTarget, callback, dom = document) { + if (phxTarget instanceof HTMLElement || phxTarget instanceof SVGElement) { + return this.liveSocket.owner( + phxTarget, + (view) => callback(view, phxTarget) + ); + } + if (isCid(phxTarget)) { + const targets = dom_default.findComponentNodeList(this.id, phxTarget, dom); + if (targets.length === 0) { + logError(`no component found matching phx-target of ${phxTarget}`); + } else { + callback(this, parseInt(phxTarget)); + } + } else { + const targets = Array.from(dom.querySelectorAll(phxTarget)); + if (targets.length === 0) { + logError( + `nothing found matching the phx-target selector "${phxTarget}"` + ); + } + targets.forEach( + (target) => this.liveSocket.owner(target, (view) => callback(view, target)) + ); + } + } + applyDiff(type, rawDiff, callback) { + this.log(type, () => ["", clone(rawDiff)]); + const { diff, reply, events, title } = Rendered.extract(rawDiff); + callback({ diff, reply, events }); + if (typeof title === "string" || type == "mount") { + window.requestAnimationFrame(() => dom_default.putTitle(title)); + } + } + onJoin(resp) { + const { rendered, container, liveview_version, pid } = resp; + if (container) { + const [tag, attrs] = container; + this.el = dom_default.replaceRootContainer(this.el, tag, attrs); + } + this.childJoins = 0; + this.joinPending = true; + this.flash = null; + if (this.root === this) { + this.formsForRecovery = this.getFormsForRecovery(); + } + if (this.isMain() && window.history.state === null) { + browser_default.pushState("replace", { + type: "patch", + id: this.id, + position: this.liveSocket.currentHistoryPosition + }); + } + if (liveview_version !== this.liveSocket.version()) { + console.error( + `LiveView asset version mismatch. JavaScript version ${this.liveSocket.version()} vs. server ${liveview_version}. To avoid issues, please ensure that your assets use the same version as the server.` + ); + } + if (pid) { + this.el.setAttribute(PHX_LV_PID, pid); + } + browser_default.dropLocal( + this.liveSocket.localStorage, + window.location.pathname, + CONSECUTIVE_RELOADS + ); + this.applyDiff("mount", rendered, ({ diff, events }) => { + this.rendered = new Rendered(this.id, diff); + const [html, streams] = this.renderContainer(null, "join"); + this.dropPendingRefs(); + this.joinCount++; + this.joinAttempts = 0; + this.maybeRecoverForms(html, () => { + this.onJoinComplete(resp, html, streams, events); + }); + }); + } + dropPendingRefs() { + dom_default.all(document, `[${PHX_REF_SRC}="${this.refSrc()}"]`, (el) => { + el.removeAttribute(PHX_REF_LOADING); + el.removeAttribute(PHX_REF_SRC); + el.removeAttribute(PHX_REF_LOCK); + }); + } + onJoinComplete({ live_patch }, html, streams, events) { + if (this.joinCount > 1 || this.parent && !this.parent.isJoinPending()) { + return this.applyJoinPatch(live_patch, html, streams, events); + } + const newChildren = dom_default.findPhxChildrenInFragment(html, this.id).filter( + (toEl) => { + const fromEl = toEl.id && this.el.querySelector(`[id="${toEl.id}"]`); + const phxStatic = fromEl && fromEl.getAttribute(PHX_STATIC); + if (phxStatic) { + toEl.setAttribute(PHX_STATIC, phxStatic); + } + if (fromEl) { + fromEl.setAttribute(PHX_ROOT_ID, this.root.id); + } + return this.joinChild(toEl); + } + ); + if (newChildren.length === 0) { + if (this.parent) { + this.root.pendingJoinOps.push([ + this, + () => this.applyJoinPatch(live_patch, html, streams, events) + ]); + this.parent.ackJoin(this); + } else { + this.onAllChildJoinsComplete(); + this.applyJoinPatch(live_patch, html, streams, events); + } + } else { + this.root.pendingJoinOps.push([ + this, + () => this.applyJoinPatch(live_patch, html, streams, events) + ]); + } + } + attachTrueDocEl() { + this.el = dom_default.byId(this.id); + this.el.setAttribute(PHX_ROOT_ID, this.root.id); + } + // this is invoked for dead and live views, so we must filter by + // by owner to ensure we aren't duplicating hooks across disconnect + // and connected states. This also handles cases where hooks exist + // in a root layout with a LV in the body + execNewMounted(parent = document) { + let phxViewportTop = this.binding(PHX_VIEWPORT_TOP); + let phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM); + this.all( + parent, + `[${phxViewportTop}], [${phxViewportBottom}]`, + (hookEl) => { + dom_default.maintainPrivateHooks( + hookEl, + hookEl, + phxViewportTop, + phxViewportBottom + ); + this.maybeAddNewHook(hookEl); + } + ); + this.all( + parent, + `[${this.binding(PHX_HOOK)}], [data-phx-${PHX_HOOK}]`, + (hookEl) => { + this.maybeAddNewHook(hookEl); + } + ); + this.all(parent, `[${this.binding(PHX_MOUNTED)}]`, (el) => { + this.maybeMounted(el); + }); + } + all(parent, selector, callback) { + dom_default.all(parent, selector, (el) => { + if (this.ownsElement(el)) { + callback(el); + } + }); + } + applyJoinPatch(live_patch, html, streams, events) { + this.attachTrueDocEl(); + const patch = new DOMPatch(this, this.el, this.id, html, streams, null); + patch.markPrunableContentForRemoval(); + this.performPatch(patch, false, true); + this.joinNewChildren(); + this.execNewMounted(); + this.joinPending = false; + this.liveSocket.dispatchEvents(events); + this.applyPendingUpdates(); + if (live_patch) { + const { kind, to } = live_patch; + this.liveSocket.historyPatch(to, kind); + } + this.hideLoader(); + if (this.joinCount > 1) { + this.triggerReconnected(); + } + this.stopCallback(); + } + triggerBeforeUpdateHook(fromEl, toEl) { + this.liveSocket.triggerDOM("onBeforeElUpdated", [fromEl, toEl]); + const hook = this.getHook(fromEl); + const isIgnored = hook && dom_default.isIgnored(fromEl, this.binding(PHX_UPDATE)); + if (hook && !fromEl.isEqualNode(toEl) && !(isIgnored && isEqualObj(fromEl.dataset, toEl.dataset))) { + hook.__beforeUpdate(); + return hook; + } + } + maybeMounted(el) { + const phxMounted = el.getAttribute(this.binding(PHX_MOUNTED)); + const hasBeenInvoked = phxMounted && dom_default.private(el, "mounted"); + if (phxMounted && !hasBeenInvoked) { + this.liveSocket.execJS(el, phxMounted); + dom_default.putPrivate(el, "mounted", true); + } + } + maybeAddNewHook(el) { + const newHook = this.addHook(el); + if (newHook) { + newHook.__mounted(); + } + } + performPatch(patch, pruneCids, isJoinPatch = false) { + const removedEls = []; + let phxChildrenAdded = false; + const updatedHookIds = /* @__PURE__ */ new Set(); + this.liveSocket.triggerDOM("onPatchStart", [patch.targetContainer]); + patch.after("added", (el) => { + this.liveSocket.triggerDOM("onNodeAdded", [el]); + const phxViewportTop = this.binding(PHX_VIEWPORT_TOP); + const phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM); + dom_default.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom); + this.maybeAddNewHook(el); + if (el.getAttribute) { + this.maybeMounted(el); + } + }); + patch.after("phxChildAdded", (el) => { + if (dom_default.isPhxSticky(el)) { + this.liveSocket.joinRootViews(); + } else { + phxChildrenAdded = true; + } + }); + patch.before("updated", (fromEl, toEl) => { + const hook = this.triggerBeforeUpdateHook(fromEl, toEl); + if (hook) { + updatedHookIds.add(fromEl.id); + } + js_default.onBeforeElUpdated(fromEl, toEl); + }); + patch.after("updated", (el) => { + if (updatedHookIds.has(el.id)) { + this.getHook(el).__updated(); + } + }); + patch.after("discarded", (el) => { + if (el.nodeType === Node.ELEMENT_NODE) { + removedEls.push(el); + } + }); + patch.after( + "transitionsDiscarded", + (els) => this.afterElementsRemoved(els, pruneCids) + ); + patch.perform(isJoinPatch); + this.afterElementsRemoved(removedEls, pruneCids); + this.liveSocket.triggerDOM("onPatchEnd", [patch.targetContainer]); + return phxChildrenAdded; + } + afterElementsRemoved(elements, pruneCids) { + const destroyedCIDs = []; + elements.forEach((parent) => { + const components = dom_default.all( + parent, + `[${PHX_VIEW_REF}="${this.id}"][${PHX_COMPONENT}]` + ); + const hooks2 = dom_default.all( + parent, + `[${this.binding(PHX_HOOK)}], [data-phx-hook]` + ); + components.concat(parent).forEach((el) => { + const cid = this.componentID(el); + if (isCid(cid) && destroyedCIDs.indexOf(cid) === -1 && el.getAttribute(PHX_VIEW_REF) === this.id) { + destroyedCIDs.push(cid); + } + }); + hooks2.concat(parent).forEach((hookEl) => { + const hook = this.getHook(hookEl); + hook && this.destroyHook(hook); + }); + }); + if (pruneCids) { + this.maybePushComponentsDestroyed(destroyedCIDs); + } + } + joinNewChildren() { + dom_default.findPhxChildren(document, this.id).forEach((el) => this.joinChild(el)); + } + maybeRecoverForms(html, callback) { + const phxChange = this.binding("change"); + const oldForms = this.root.formsForRecovery; + const template = document.createElement("template"); + template.innerHTML = html; + const rootEl = template.content.firstElementChild; + rootEl.id = this.id; + rootEl.setAttribute(PHX_ROOT_ID, this.root.id); + rootEl.setAttribute(PHX_SESSION, this.getSession()); + rootEl.setAttribute(PHX_STATIC, this.getStatic()); + rootEl.setAttribute(PHX_PARENT_ID, this.parent ? this.parent.id : null); + const formsToRecover = ( + // we go over all forms in the new DOM; because this is only the HTML for the current + // view, we can be sure that all forms are owned by this view: + dom_default.all(template.content, "form").filter((newForm) => newForm.id && oldForms[newForm.id]).filter((newForm) => !this.pendingForms.has(newForm.id)).filter( + (newForm) => oldForms[newForm.id].getAttribute(phxChange) === newForm.getAttribute(phxChange) + ).map((newForm) => { + return [oldForms[newForm.id], newForm]; + }) + ); + if (formsToRecover.length === 0) { + return callback(); + } + formsToRecover.forEach(([oldForm, newForm], i) => { + this.pendingForms.add(newForm.id); + this.pushFormRecovery( + oldForm, + newForm, + template.content.firstElementChild, + () => { + this.pendingForms.delete(newForm.id); + if (i === formsToRecover.length - 1) { + callback(); + } + } + ); + }); + } + getChildById(id) { + return this.root.children[this.id][id]; + } + getDescendentByEl(el) { + if (el.id === this.id) { + return this; + } else { + return this.children[el.getAttribute(PHX_PARENT_ID)]?.[el.id]; + } + } + destroyDescendent(id) { + for (const parentId in this.root.children) { + for (const childId in this.root.children[parentId]) { + if (childId === id) { + return this.root.children[parentId][childId].destroy(); + } + } + } + } + joinChild(el) { + const child = this.getChildById(el.id); + if (!child) { + const view = new _View(el, this.liveSocket, this); + this.root.children[this.id][view.id] = view; + view.join(); + this.childJoins++; + return true; + } + } + isJoinPending() { + return this.joinPending; + } + ackJoin(_child) { + this.childJoins--; + if (this.childJoins === 0) { + if (this.parent) { + this.parent.ackJoin(this); + } else { + this.onAllChildJoinsComplete(); + } + } + } + onAllChildJoinsComplete() { + this.pendingForms.clear(); + this.formsForRecovery = {}; + this.joinCallback(() => { + this.pendingJoinOps.forEach(([view, op]) => { + if (!view.isDestroyed()) { + op(); + } + }); + this.pendingJoinOps = []; + }); + } + update(diff, events) { + if (this.isJoinPending() || this.liveSocket.hasPendingLink() && this.root.isMain()) { + return this.pendingDiffs.push({ diff, events }); + } + this.rendered.mergeDiff(diff); + let phxChildrenAdded = false; + if (this.rendered.isComponentOnlyDiff(diff)) { + this.liveSocket.time("component patch complete", () => { + const parentCids = dom_default.findExistingParentCIDs( + this.id, + this.rendered.componentCIDs(diff) + ); + parentCids.forEach((parentCID) => { + if (this.componentPatch( + this.rendered.getComponent(diff, parentCID), + parentCID + )) { + phxChildrenAdded = true; + } + }); + }); + } else if (!isEmpty(diff)) { + this.liveSocket.time("full patch complete", () => { + const [html, streams] = this.renderContainer(diff, "update"); + const patch = new DOMPatch(this, this.el, this.id, html, streams, null); + phxChildrenAdded = this.performPatch(patch, true); + }); + } + this.liveSocket.dispatchEvents(events); + if (phxChildrenAdded) { + this.joinNewChildren(); + } + } + renderContainer(diff, kind) { + return this.liveSocket.time(`toString diff (${kind})`, () => { + const tag = this.el.tagName; + const cids = diff ? this.rendered.componentCIDs(diff) : null; + const { buffer: html, streams } = this.rendered.toString(cids); + return [`<${tag}>${html}`, streams]; + }); + } + componentPatch(diff, cid) { + if (isEmpty(diff)) + return false; + const { buffer: html, streams } = this.rendered.componentToString(cid); + const patch = new DOMPatch(this, this.el, this.id, html, streams, cid); + const childrenAdded = this.performPatch(patch, true); + return childrenAdded; + } + getHook(el) { + return this.viewHooks[ViewHook.elementID(el)]; + } + addHook(el) { + const hookElId = ViewHook.elementID(el); + if (el.getAttribute && !this.ownsElement(el)) { + return; + } + if (hookElId && !this.viewHooks[hookElId]) { + const hook = dom_default.getCustomElHook(el) || logError(`no hook found for custom element: ${el.id}`); + this.viewHooks[hookElId] = hook; + hook.__attachView(this); + return hook; + } else if (hookElId || !el.getAttribute) { + return; + } else { + const hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK)); + if (!hookName) { + return; + } + const hookDefinition = this.liveSocket.getHookDefinition(hookName); + if (hookDefinition) { + if (!el.id) { + logError( + `no DOM ID for hook "${hookName}". Hooks require a unique ID on each element.`, + el + ); + return; + } + let hookInstance; + try { + if (typeof hookDefinition === "function" && hookDefinition.prototype instanceof ViewHook) { + hookInstance = new hookDefinition(this, el); + } else if (typeof hookDefinition === "object" && hookDefinition !== null) { + hookInstance = new ViewHook(this, el, hookDefinition); + } else { + logError( + `Invalid hook definition for "${hookName}". Expected a class extending ViewHook or an object definition.`, + el + ); + return; + } + } catch (e) { + const errorMessage = e instanceof Error ? e.message : String(e); + logError(`Failed to create hook "${hookName}": ${errorMessage}`, el); + return; + } + this.viewHooks[ViewHook.elementID(hookInstance.el)] = hookInstance; + return hookInstance; + } else if (hookName !== null) { + logError(`unknown hook found for "${hookName}"`, el); + } + } + } + destroyHook(hook) { + const hookId = ViewHook.elementID(hook.el); + hook.__destroyed(); + hook.__cleanup__(); + delete this.viewHooks[hookId]; + } + applyPendingUpdates() { + if (this.liveSocket.hasPendingLink() && this.root.isMain()) { + return; + } + this.pendingDiffs.forEach(({ diff, events }) => this.update(diff, events)); + this.pendingDiffs = []; + this.eachChild((child) => child.applyPendingUpdates()); + } + eachChild(callback) { + const children = this.root.children[this.id] || {}; + for (const id in children) { + callback(this.getChildById(id)); + } + } + onChannel(event, cb) { + this.liveSocket.onChannel(this.channel, event, (resp) => { + if (this.isJoinPending()) { + this.root.pendingJoinOps.push([this, () => cb(resp)]); + } else { + this.liveSocket.requestDOMUpdate(() => cb(resp)); + } + }); + } + bindChannel() { + this.liveSocket.onChannel(this.channel, "diff", (rawDiff) => { + this.liveSocket.requestDOMUpdate(() => { + this.applyDiff( + "update", + rawDiff, + ({ diff, events }) => this.update(diff, events) + ); + }); + }); + this.onChannel( + "redirect", + ({ to, flash }) => this.onRedirect({ to, flash }) + ); + this.onChannel("live_patch", (redir) => this.onLivePatch(redir)); + this.onChannel("live_redirect", (redir) => this.onLiveRedirect(redir)); + this.channel.onError((reason) => this.onError(reason)); + this.channel.onClose((reason) => this.onClose(reason)); + } + destroyAllChildren() { + this.eachChild((child) => child.destroy()); + } + onLiveRedirect(redir) { + const { to, kind, flash } = redir; + const url = this.expandURL(to); + const e = new CustomEvent("phx:server-navigate", { + detail: { to, kind, flash } + }); + this.liveSocket.historyRedirect(e, url, kind, flash); + } + onLivePatch(redir) { + const { to, kind } = redir; + this.href = this.expandURL(to); + this.liveSocket.historyPatch(to, kind); + } + expandURL(to) { + return to.startsWith("/") ? `${window.location.protocol}//${window.location.host}${to}` : to; + } + /** + * @param {{to: string, flash?: string, reloadToken?: string}} redirect + */ + onRedirect({ to, flash, reloadToken }) { + this.liveSocket.redirect(to, flash, reloadToken); + } + isDestroyed() { + return this.destroyed; + } + joinDead() { + this.isDead = true; + } + joinPush() { + this.joinPush = this.joinPush || this.channel.join(); + return this.joinPush; + } + join(callback) { + this.showLoader(this.liveSocket.loaderTimeout); + this.bindChannel(); + if (this.isMain()) { + this.stopCallback = this.liveSocket.withPageLoading({ + to: this.href, + kind: "initial" + }); + } + this.joinCallback = (onDone) => { + onDone = onDone || function() { + }; + callback ? callback(this.joinCount, onDone) : onDone(); + }; + this.wrapPush(() => this.channel.join(), { + ok: (resp) => this.liveSocket.requestDOMUpdate(() => this.onJoin(resp)), + error: (error) => this.onJoinError(error), + timeout: () => this.onJoinError({ reason: "timeout" }) + }); + } + onJoinError(resp) { + if (resp.reason === "reload") { + this.log("error", () => [ + `failed mount with ${resp.status}. Falling back to page reload`, + resp + ]); + this.onRedirect({ to: this.root.href, reloadToken: resp.token }); + return; + } else if (resp.reason === "unauthorized" || resp.reason === "stale") { + this.log("error", () => [ + "unauthorized live_redirect. Falling back to page request", + resp + ]); + this.onRedirect({ to: this.root.href, flash: this.flash }); + return; + } + if (resp.redirect || resp.live_redirect) { + this.joinPending = false; + this.channel.leave(); + } + if (resp.redirect) { + return this.onRedirect(resp.redirect); + } + if (resp.live_redirect) { + return this.onLiveRedirect(resp.live_redirect); + } + this.log("error", () => ["unable to join", resp]); + if (this.isMain()) { + this.displayError([ + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_SERVER_ERROR_CLASS + ]); + if (this.liveSocket.isConnected()) { + this.liveSocket.reloadWithJitter(this); + } + } else { + if (this.joinAttempts >= MAX_CHILD_JOIN_ATTEMPTS) { + this.root.displayError([ + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_SERVER_ERROR_CLASS + ]); + this.log("error", () => [ + `giving up trying to mount after ${MAX_CHILD_JOIN_ATTEMPTS} tries`, + resp + ]); + this.destroy(); + } + const trueChildEl = dom_default.byId(this.el.id); + if (trueChildEl) { + dom_default.mergeAttrs(trueChildEl, this.el); + this.displayError([ + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_SERVER_ERROR_CLASS + ]); + this.el = trueChildEl; + } else { + this.destroy(); + } + } + } + onClose(reason) { + if (this.isDestroyed()) { + return; + } + if (this.isMain() && this.liveSocket.hasPendingLink() && reason !== "leave") { + return this.liveSocket.reloadWithJitter(this); + } + this.destroyAllChildren(); + this.liveSocket.dropActiveElement(this); + if (this.liveSocket.isUnloaded()) { + this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT); + } + } + onError(reason) { + this.onClose(reason); + if (this.liveSocket.isConnected()) { + this.log("error", () => ["view crashed", reason]); + } + if (!this.liveSocket.isUnloaded()) { + if (this.liveSocket.isConnected()) { + this.displayError([ + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_SERVER_ERROR_CLASS + ]); + } else { + this.displayError([ + PHX_LOADING_CLASS, + PHX_ERROR_CLASS, + PHX_CLIENT_ERROR_CLASS + ]); + } + } + } + displayError(classes) { + if (this.isMain()) { + dom_default.dispatchEvent(window, "phx:page-loading-start", { + detail: { to: this.href, kind: "error" } + }); + } + this.showLoader(); + this.setContainerClasses(...classes); + this.delayedDisconnected(); + } + delayedDisconnected() { + this.disconnectedTimer = setTimeout(() => { + this.execAll(this.binding("disconnected")); + }, this.liveSocket.disconnectedTimeout); + } + wrapPush(callerPush, receives) { + const latency = this.liveSocket.getLatencySim(); + const withLatency = latency ? (cb) => setTimeout(() => !this.isDestroyed() && cb(), latency) : (cb) => !this.isDestroyed() && cb(); + withLatency(() => { + callerPush().receive( + "ok", + (resp) => withLatency(() => receives.ok && receives.ok(resp)) + ).receive( + "error", + (reason) => withLatency(() => receives.error && receives.error(reason)) + ).receive( + "timeout", + () => withLatency(() => receives.timeout && receives.timeout()) + ); + }); + } + pushWithReply(refGenerator, event, payload) { + if (!this.isConnected()) { + return Promise.reject(new Error("no connection")); + } + const [ref, [el], opts] = refGenerator ? refGenerator({ payload }) : [null, [], {}]; + const oldJoinCount = this.joinCount; + let onLoadingDone = function() { + }; + if (opts.page_loading) { + onLoadingDone = this.liveSocket.withPageLoading({ + kind: "element", + target: el + }); + } + if (typeof payload.cid !== "number") { + delete payload.cid; + } + return new Promise((resolve, reject) => { + this.wrapPush(() => this.channel.push(event, payload, PUSH_TIMEOUT), { + ok: (resp) => { + if (ref !== null) { + this.lastAckRef = ref; + } + const finish = (hookReply) => { + if (resp.redirect) { + this.onRedirect(resp.redirect); + } + if (resp.live_patch) { + this.onLivePatch(resp.live_patch); + } + if (resp.live_redirect) { + this.onLiveRedirect(resp.live_redirect); + } + onLoadingDone(); + resolve({ resp, reply: hookReply, ref }); + }; + if (resp.diff) { + this.liveSocket.requestDOMUpdate(() => { + this.applyDiff("update", resp.diff, ({ diff, reply, events }) => { + if (ref !== null) { + this.undoRefs(ref, payload.event); + } + this.update(diff, events); + finish(reply); + }); + }); + } else { + if (ref !== null) { + this.undoRefs(ref, payload.event); + } + finish(null); + } + }, + error: (reason) => reject(new Error(`failed with reason: ${reason}`)), + timeout: () => { + reject(new Error("timeout")); + if (this.joinCount === oldJoinCount) { + this.liveSocket.reloadWithJitter(this, () => { + this.log("timeout", () => [ + "received timeout while communicating with server. Falling back to hard refresh for recovery" + ]); + }); + } + } + }); + }); + } + undoRefs(ref, phxEvent, onlyEls) { + if (!this.isConnected()) { + return; + } + const selector = `[${PHX_REF_SRC}="${this.refSrc()}"]`; + if (onlyEls) { + onlyEls = new Set(onlyEls); + dom_default.all(document, selector, (parent) => { + if (onlyEls && !onlyEls.has(parent)) { + return; + } + dom_default.all( + parent, + selector, + (child) => this.undoElRef(child, ref, phxEvent) + ); + this.undoElRef(parent, ref, phxEvent); + }); + } else { + dom_default.all(document, selector, (el) => this.undoElRef(el, ref, phxEvent)); + } + } + undoElRef(el, ref, phxEvent) { + const elRef = new ElementRef(el); + elRef.maybeUndo(ref, phxEvent, (clonedTree) => { + const patch = new DOMPatch(this, el, this.id, clonedTree, [], null, { + undoRef: ref + }); + const phxChildrenAdded = this.performPatch(patch, true); + dom_default.all( + el, + `[${PHX_REF_SRC}="${this.refSrc()}"]`, + (child) => this.undoElRef(child, ref, phxEvent) + ); + if (phxChildrenAdded) { + this.joinNewChildren(); + } + }); + } + refSrc() { + return this.el.id; + } + putRef(elements, phxEvent, eventType, opts = {}) { + const newRef = this.ref++; + const disableWith = this.binding(PHX_DISABLE_WITH); + if (opts.loading) { + const loadingEls = dom_default.all(document, opts.loading).map((el) => { + return { el, lock: true, loading: true }; + }); + elements = elements.concat(loadingEls); + } + for (const { el, lock, loading } of elements) { + if (!lock && !loading) { + throw new Error("putRef requires lock or loading"); + } + el.setAttribute(PHX_REF_SRC, this.refSrc()); + if (loading) { + el.setAttribute(PHX_REF_LOADING, newRef); + } + if (lock) { + el.setAttribute(PHX_REF_LOCK, newRef); + } + if (!loading || opts.submitter && !(el === opts.submitter || el === opts.form)) { + continue; + } + const lockCompletePromise = new Promise((resolve) => { + el.addEventListener(`phx:undo-lock:${newRef}`, () => resolve(detail), { + once: true + }); + }); + const loadingCompletePromise = new Promise((resolve) => { + el.addEventListener( + `phx:undo-loading:${newRef}`, + () => resolve(detail), + { once: true } + ); + }); + el.classList.add(`phx-${eventType}-loading`); + const disableText = el.getAttribute(disableWith); + if (disableText !== null) { + if (!el.getAttribute(PHX_DISABLE_WITH_RESTORE)) { + el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.innerText); + } + if (disableText !== "") { + el.innerText = disableText; + } + el.setAttribute( + PHX_DISABLED, + el.getAttribute(PHX_DISABLED) || el.disabled + ); + el.setAttribute("disabled", ""); + } + const detail = { + event: phxEvent, + eventType, + ref: newRef, + isLoading: loading, + isLocked: lock, + lockElements: elements.filter(({ lock: lock2 }) => lock2).map(({ el: el2 }) => el2), + loadingElements: elements.filter(({ loading: loading2 }) => loading2).map(({ el: el2 }) => el2), + unlock: (els) => { + els = Array.isArray(els) ? els : [els]; + this.undoRefs(newRef, phxEvent, els); + }, + lockComplete: lockCompletePromise, + loadingComplete: loadingCompletePromise, + lock: (lockEl) => { + return new Promise((resolve) => { + if (this.isAcked(newRef)) { + return resolve(detail); + } + lockEl.setAttribute(PHX_REF_LOCK, newRef); + lockEl.setAttribute(PHX_REF_SRC, this.refSrc()); + lockEl.addEventListener( + `phx:lock-stop:${newRef}`, + () => resolve(detail), + { once: true } + ); + }); + } + }; + if (opts.payload) { + detail["payload"] = opts.payload; + } + if (opts.target) { + detail["target"] = opts.target; + } + if (opts.originalEvent) { + detail["originalEvent"] = opts.originalEvent; + } + el.dispatchEvent( + new CustomEvent("phx:push", { + detail, + bubbles: true, + cancelable: false + }) + ); + if (phxEvent) { + el.dispatchEvent( + new CustomEvent(`phx:push:${phxEvent}`, { + detail, + bubbles: true, + cancelable: false + }) + ); + } + } + return [newRef, elements.map(({ el }) => el), opts]; + } + isAcked(ref) { + return this.lastAckRef !== null && this.lastAckRef >= ref; + } + componentID(el) { + const cid = el.getAttribute && el.getAttribute(PHX_COMPONENT); + return cid ? parseInt(cid) : null; + } + targetComponentID(target, targetCtx, opts = {}) { + if (isCid(targetCtx)) { + return targetCtx; + } + const cidOrSelector = opts.target || target.getAttribute(this.binding("target")); + if (isCid(cidOrSelector)) { + return parseInt(cidOrSelector); + } else if (targetCtx && (cidOrSelector !== null || opts.target)) { + return this.closestComponentID(targetCtx); + } else { + return null; + } + } + closestComponentID(targetCtx) { + if (isCid(targetCtx)) { + return targetCtx; + } else if (targetCtx) { + return maybe( + targetCtx.closest(`[${PHX_COMPONENT}]`), + (el) => this.ownsElement(el) && this.componentID(el) + ); + } else { + return null; + } + } + pushHookEvent(el, targetCtx, event, payload) { + if (!this.isConnected()) { + this.log("hook", () => [ + "unable to push hook event. LiveView not connected", + event, + payload + ]); + return Promise.reject( + new Error("unable to push hook event. LiveView not connected") + ); + } + const refGenerator = () => this.putRef([{ el, loading: true, lock: true }], event, "hook", { + payload, + target: targetCtx + }); + return this.pushWithReply(refGenerator, "event", { + type: "hook", + event, + value: payload, + cid: this.closestComponentID(targetCtx) + }).then(({ resp: _resp, reply, ref }) => ({ reply, ref })); + } + extractMeta(el, meta, value) { + const prefix = this.binding("value-"); + for (let i = 0; i < el.attributes.length; i++) { + if (!meta) { + meta = {}; + } + const name = el.attributes[i].name; + if (name.startsWith(prefix)) { + meta[name.replace(prefix, "")] = el.getAttribute(name); + } + } + if (el.value !== void 0 && !(el instanceof HTMLFormElement)) { + if (!meta) { + meta = {}; + } + meta.value = el.value; + if (el.tagName === "INPUT" && CHECKABLE_INPUTS.indexOf(el.type) >= 0 && !el.checked) { + delete meta.value; + } + } + if (value) { + if (!meta) { + meta = {}; + } + for (const key in value) { + meta[key] = value[key]; + } + } + return meta; + } + pushEvent(type, el, targetCtx, phxEvent, meta, opts = {}, onReply) { + this.pushWithReply( + (maybePayload) => this.putRef([{ el, loading: true, lock: true }], phxEvent, type, { + ...opts, + payload: maybePayload?.payload + }), + "event", + { + type, + event: phxEvent, + value: this.extractMeta(el, meta, opts.value), + cid: this.targetComponentID(el, targetCtx, opts) + } + ).then(({ reply }) => onReply && onReply(reply)).catch((error) => logError("Failed to push event", error)); + } + pushFileProgress(fileEl, entryRef, progress, onReply = function() { + }) { + this.liveSocket.withinOwners(fileEl.form, (view, targetCtx) => { + view.pushWithReply(null, "progress", { + event: fileEl.getAttribute(view.binding(PHX_PROGRESS)), + ref: fileEl.getAttribute(PHX_UPLOAD_REF), + entry_ref: entryRef, + progress, + cid: view.targetComponentID(fileEl.form, targetCtx) + }).then(() => onReply()).catch((error) => logError("Failed to push file progress", error)); + }); + } + pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback) { + if (!inputEl.form) { + throw new Error("form events require the input to be inside a form"); + } + let uploads; + const cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx, opts); + const refGenerator = (maybePayload) => { + return this.putRef( + [ + { el: inputEl, loading: true, lock: true }, + { el: inputEl.form, loading: true, lock: true } + ], + phxEvent, + "change", + { ...opts, payload: maybePayload?.payload } + ); + }; + let formData; + const meta = this.extractMeta(inputEl.form, {}, opts.value); + const serializeOpts = {}; + if (inputEl instanceof HTMLButtonElement) { + serializeOpts.submitter = inputEl; + } + if (inputEl.getAttribute(this.binding("change"))) { + formData = serializeForm(inputEl.form, serializeOpts, [inputEl.name]); + } else { + formData = serializeForm(inputEl.form, serializeOpts); + } + if (dom_default.isUploadInput(inputEl) && inputEl.files && inputEl.files.length > 0) { + LiveUploader.trackFiles(inputEl, Array.from(inputEl.files)); + } + uploads = LiveUploader.serializeUploads(inputEl); + const event = { + type: "form", + event: phxEvent, + value: formData, + meta: { + // no target was implicitly sent as "undefined" in LV <= 1.0.5, therefore + // we have to keep it. In 1.0.6 we switched from passing meta as URL encoded data + // to passing it directly in the event, but the JSON encode would drop keys with + // undefined values. + _target: opts._target || "undefined", + ...meta + }, + uploads, + cid + }; + this.pushWithReply(refGenerator, "event", event).then(({ resp }) => { + if (dom_default.isUploadInput(inputEl) && dom_default.isAutoUpload(inputEl)) { + ElementRef.onUnlock(inputEl, () => { + if (LiveUploader.filesAwaitingPreflight(inputEl).length > 0) { + const [ref, _els] = refGenerator(); + this.undoRefs(ref, phxEvent, [inputEl.form]); + this.uploadFiles( + inputEl.form, + phxEvent, + targetCtx, + ref, + cid, + (_uploads) => { + callback && callback(resp); + this.triggerAwaitingSubmit(inputEl.form, phxEvent); + this.undoRefs(ref, phxEvent); + } + ); + } + }); + } else { + callback && callback(resp); + } + }).catch((error) => logError("Failed to push input event", error)); + } + triggerAwaitingSubmit(formEl, phxEvent) { + const awaitingSubmit = this.getScheduledSubmit(formEl); + if (awaitingSubmit) { + const [_el, _ref, _opts, callback] = awaitingSubmit; + this.cancelSubmit(formEl, phxEvent); + callback(); + } + } + getScheduledSubmit(formEl) { + return this.formSubmits.find( + ([el, _ref, _opts, _callback]) => el.isSameNode(formEl) + ); + } + scheduleSubmit(formEl, ref, opts, callback) { + if (this.getScheduledSubmit(formEl)) { + return true; + } + this.formSubmits.push([formEl, ref, opts, callback]); + } + cancelSubmit(formEl, phxEvent) { + this.formSubmits = this.formSubmits.filter( + ([el, ref, _opts, _callback]) => { + if (el.isSameNode(formEl)) { + this.undoRefs(ref, phxEvent); + return false; + } else { + return true; + } + } + ); + } + disableForm(formEl, phxEvent, opts = {}) { + const filterIgnored = (el) => { + const userIgnored = closestPhxBinding( + el, + `${this.binding(PHX_UPDATE)}=ignore`, + el.form + ); + return !(userIgnored || closestPhxBinding(el, "data-phx-update=ignore", el.form)); + }; + const filterDisables = (el) => { + return el.hasAttribute(this.binding(PHX_DISABLE_WITH)); + }; + const filterButton = (el) => el.tagName == "BUTTON"; + const filterInput = (el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName); + const formElements = Array.from(formEl.elements); + const disables = formElements.filter(filterDisables); + const buttons = formElements.filter(filterButton).filter(filterIgnored); + const inputs = formElements.filter(filterInput).filter(filterIgnored); + buttons.forEach((button) => { + button.setAttribute(PHX_DISABLED, button.disabled); + button.disabled = true; + }); + inputs.forEach((input) => { + input.setAttribute(PHX_READONLY, input.readOnly); + input.readOnly = true; + if (input.files) { + input.setAttribute(PHX_DISABLED, input.disabled); + input.disabled = true; + } + }); + const formEls = disables.concat(buttons).concat(inputs).map((el) => { + return { el, loading: true, lock: true }; + }); + const els = [{ el: formEl, loading: true, lock: false }].concat(formEls).reverse(); + return this.putRef(els, phxEvent, "submit", opts); + } + pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply) { + const refGenerator = (maybePayload) => this.disableForm(formEl, phxEvent, { + ...opts, + form: formEl, + payload: maybePayload?.payload, + submitter + }); + dom_default.putPrivate(formEl, "submitter", submitter); + const cid = this.targetComponentID(formEl, targetCtx); + if (LiveUploader.hasUploadsInProgress(formEl)) { + const [ref, _els] = refGenerator(); + const push = () => this.pushFormSubmit( + formEl, + targetCtx, + phxEvent, + submitter, + opts, + onReply + ); + return this.scheduleSubmit(formEl, ref, opts, push); + } else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) { + const [ref, els] = refGenerator(); + const proxyRefGen = () => [ref, els, opts]; + this.uploadFiles(formEl, phxEvent, targetCtx, ref, cid, (_uploads) => { + if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) { + return this.undoRefs(ref, phxEvent); + } + const meta = this.extractMeta(formEl, {}, opts.value); + const formData = serializeForm(formEl, { submitter }); + this.pushWithReply(proxyRefGen, "event", { + type: "form", + event: phxEvent, + value: formData, + meta, + cid + }).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error)); + }); + } else if (!(formEl.hasAttribute(PHX_REF_SRC) && formEl.classList.contains("phx-submit-loading"))) { + const meta = this.extractMeta(formEl, {}, opts.value); + const formData = serializeForm(formEl, { submitter }); + this.pushWithReply(refGenerator, "event", { + type: "form", + event: phxEvent, + value: formData, + meta, + cid + }).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error)); + } + } + uploadFiles(formEl, phxEvent, targetCtx, ref, cid, onComplete) { + const joinCountAtUpload = this.joinCount; + const inputEls = LiveUploader.activeFileInputs(formEl); + let numFileInputsInProgress = inputEls.length; + inputEls.forEach((inputEl) => { + const uploader = new LiveUploader(inputEl, this, () => { + numFileInputsInProgress--; + if (numFileInputsInProgress === 0) { + onComplete(); + } + }); + const entries = uploader.entries().map((entry) => entry.toPreflightPayload()); + if (entries.length === 0) { + numFileInputsInProgress--; + return; + } + const payload = { + ref: inputEl.getAttribute(PHX_UPLOAD_REF), + entries, + cid: this.targetComponentID(inputEl.form, targetCtx) + }; + this.log("upload", () => ["sending preflight request", payload]); + this.pushWithReply(null, "allow_upload", payload).then(({ resp }) => { + this.log("upload", () => ["got preflight response", resp]); + uploader.entries().forEach((entry) => { + if (resp.entries && !resp.entries[entry.ref]) { + this.handleFailedEntryPreflight( + entry.ref, + "failed preflight", + uploader + ); + } + }); + if (resp.error || Object.keys(resp.entries).length === 0) { + this.undoRefs(ref, phxEvent); + const errors = resp.error || []; + errors.map(([entry_ref, reason]) => { + this.handleFailedEntryPreflight(entry_ref, reason, uploader); + }); + } else { + const onError = (callback) => { + this.channel.onError(() => { + if (this.joinCount === joinCountAtUpload) { + callback(); + } + }); + }; + uploader.initAdapterUpload(resp, onError, this.liveSocket); + } + }).catch((error) => logError("Failed to push upload", error)); + }); + } + handleFailedEntryPreflight(uploadRef, reason, uploader) { + if (uploader.isAutoUpload()) { + const entry = uploader.entries().find((entry2) => entry2.ref === uploadRef.toString()); + if (entry) { + entry.cancel(); + } + } else { + uploader.entries().map((entry) => entry.cancel()); + } + this.log("upload", () => [`error for entry ${uploadRef}`, reason]); + } + dispatchUploads(targetCtx, name, filesOrBlobs) { + const targetElement = this.targetCtxElement(targetCtx) || this.el; + const inputs = dom_default.findUploadInputs(targetElement).filter( + (el) => el.name === name + ); + if (inputs.length === 0) { + logError(`no live file inputs found matching the name "${name}"`); + } else if (inputs.length > 1) { + logError(`duplicate live file inputs found matching the name "${name}"`); + } else { + dom_default.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, { + detail: { files: filesOrBlobs } + }); + } + } + targetCtxElement(targetCtx) { + if (isCid(targetCtx)) { + const [target] = dom_default.findComponentNodeList(this.id, targetCtx); + return target; + } else if (targetCtx) { + return targetCtx; + } else { + return null; + } + } + pushFormRecovery(oldForm, newForm, templateDom, callback) { + const phxChange = this.binding("change"); + const phxTarget = newForm.getAttribute(this.binding("target")) || newForm; + const phxEvent = newForm.getAttribute(this.binding(PHX_AUTO_RECOVER)) || newForm.getAttribute(this.binding("change")); + const inputs = Array.from(oldForm.elements).filter( + (el) => dom_default.isFormInput(el) && el.name && !el.hasAttribute(phxChange) + ); + if (inputs.length === 0) { + callback(); + return; + } + inputs.forEach( + (input2) => input2.hasAttribute(PHX_UPLOAD_REF) && LiveUploader.clearFiles(input2) + ); + const input = inputs.find((el) => el.type !== "hidden") || inputs[0]; + let pending = 0; + this.withinTargets( + phxTarget, + (targetView, targetCtx) => { + const cid = this.targetComponentID(newForm, targetCtx); + pending++; + let e = new CustomEvent("phx:form-recovery", { + detail: { sourceElement: oldForm } + }); + js_default.exec(e, "change", phxEvent, this, input, [ + "push", + { + _target: input.name, + targetView, + targetCtx, + newCid: cid, + callback: () => { + pending--; + if (pending === 0) { + callback(); + } + } + } + ]); + }, + templateDom + ); + } + pushLinkPatch(e, href, targetEl, callback) { + const linkRef = this.liveSocket.setPendingLink(href); + const loading = e.isTrusted && e.type !== "popstate"; + const refGen = targetEl ? () => this.putRef( + [{ el: targetEl, loading, lock: true }], + null, + "click" + ) : null; + const fallback = () => this.liveSocket.redirect(window.location.href); + const url = href.startsWith("/") ? `${location.protocol}//${location.host}${href}` : href; + this.pushWithReply(refGen, "live_patch", { url }).then( + ({ resp }) => { + this.liveSocket.requestDOMUpdate(() => { + if (resp.link_redirect) { + this.liveSocket.replaceMain(href, null, callback, linkRef); + } else { + if (this.liveSocket.commitPendingLink(linkRef)) { + this.href = href; + } + this.applyPendingUpdates(); + callback && callback(linkRef); + } + }); + }, + ({ error: _error, timeout: _timeout }) => fallback() + ); + } + getFormsForRecovery() { + if (this.joinCount === 0) { + return {}; + } + const phxChange = this.binding("change"); + return dom_default.all(this.el, `form[${phxChange}]`).filter((form) => form.id).filter((form) => form.elements.length > 0).filter( + (form) => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== "ignore" + ).map((form) => { + const clonedForm = form.cloneNode(true); + morphdom_esm_default(clonedForm, form, { + onBeforeElUpdated: (fromEl, toEl) => { + dom_default.copyPrivates(fromEl, toEl); + return true; + } + }); + const externalElements = document.querySelectorAll( + `[form="${form.id}"]` + ); + Array.from(externalElements).forEach((el) => { + if (form.contains(el)) { + return; + } + const clonedEl = el.cloneNode(true); + morphdom_esm_default(clonedEl, el); + dom_default.copyPrivates(clonedEl, el); + clonedForm.appendChild(clonedEl); + }); + return clonedForm; + }).reduce((acc, form) => { + acc[form.id] = form; + return acc; + }, {}); + } + maybePushComponentsDestroyed(destroyedCIDs) { + let willDestroyCIDs = destroyedCIDs.filter((cid) => { + return dom_default.findComponentNodeList(this.el, cid).length === 0; + }); + const onError = (error) => { + if (!this.isDestroyed()) { + logError("Failed to push components destroyed", error); + } + }; + if (willDestroyCIDs.length > 0) { + willDestroyCIDs.forEach((cid) => this.rendered.resetRender(cid)); + this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }).then(() => { + this.liveSocket.requestDOMUpdate(() => { + let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => { + return dom_default.findComponentNodeList(this.el, cid).length === 0; + }); + if (completelyDestroyCIDs.length > 0) { + this.pushWithReply(null, "cids_destroyed", { + cids: completelyDestroyCIDs + }).then(({ resp }) => { + this.rendered.pruneCIDs(resp.cids); + }).catch(onError); + } + }); + }).catch(onError); + } + } + ownsElement(el) { + let parentViewEl = dom_default.closestViewEl(el); + return el.getAttribute(PHX_PARENT_ID) === this.id || parentViewEl && parentViewEl.id === this.id || !parentViewEl && this.isDead; + } + submitForm(form, targetCtx, phxEvent, submitter, opts = {}) { + dom_default.putPrivate(form, PHX_HAS_SUBMITTED, true); + const inputs = Array.from(form.elements); + inputs.forEach((input) => dom_default.putPrivate(input, PHX_HAS_SUBMITTED, true)); + this.liveSocket.blurActiveElement(this); + this.pushFormSubmit(form, targetCtx, phxEvent, submitter, opts, () => { + this.liveSocket.restorePreviouslyActiveFocus(); + }); + } + binding(kind) { + return this.liveSocket.binding(kind); + } + // phx-portal + pushPortalElementId(id) { + this.portalElementIds.add(id); + } + dropPortalElementId(id) { + this.portalElementIds.delete(id); + } + destroyPortalElements() { + this.portalElementIds.forEach((id) => { + const el = document.getElementById(id); + if (el) { + el.remove(); + } + }); + } + }; + var LiveSocket = class { + constructor(url, phxSocket, opts = {}) { + this.unloaded = false; + if (!phxSocket || phxSocket.constructor.name === "Object") { + throw new Error(` + a phoenix Socket must be provided as the second argument to the LiveSocket constructor. For example: + + import {Socket} from "phoenix" + import {LiveSocket} from "phoenix_live_view" + let liveSocket = new LiveSocket("/live", Socket, {...}) + `); + } + this.socket = new phxSocket(url, opts); + this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX; + this.opts = opts; + this.params = closure2(opts.params || {}); + this.viewLogger = opts.viewLogger; + this.metadataCallbacks = opts.metadata || {}; + this.defaults = Object.assign(clone(DEFAULTS), opts.defaults || {}); + this.prevActive = null; + this.silenced = false; + this.main = null; + this.outgoingMainEl = null; + this.clickStartedAtTarget = null; + this.linkRef = 1; + this.roots = {}; + this.href = window.location.href; + this.pendingLink = null; + this.currentLocation = clone(window.location); + this.hooks = opts.hooks || {}; + this.uploaders = opts.uploaders || {}; + this.loaderTimeout = opts.loaderTimeout || LOADER_TIMEOUT; + this.disconnectedTimeout = opts.disconnectedTimeout || DISCONNECTED_TIMEOUT; + this.reloadWithJitterTimer = null; + this.maxReloads = opts.maxReloads || MAX_RELOADS; + this.reloadJitterMin = opts.reloadJitterMin || RELOAD_JITTER_MIN; + this.reloadJitterMax = opts.reloadJitterMax || RELOAD_JITTER_MAX; + this.failsafeJitter = opts.failsafeJitter || FAILSAFE_JITTER; + this.localStorage = opts.localStorage || window.localStorage; + this.sessionStorage = opts.sessionStorage || window.sessionStorage; + this.boundTopLevelEvents = false; + this.boundEventNames = /* @__PURE__ */ new Set(); + this.blockPhxChangeWhileComposing = opts.blockPhxChangeWhileComposing || false; + this.serverCloseRef = null; + this.domCallbacks = Object.assign( + { + jsQuerySelectorAll: null, + onPatchStart: closure2(), + onPatchEnd: closure2(), + onNodeAdded: closure2(), + onBeforeElUpdated: closure2() + }, + opts.dom || {} + ); + this.transitions = new TransitionSet(); + this.currentHistoryPosition = parseInt(this.sessionStorage.getItem(PHX_LV_HISTORY_POSITION)) || 0; + window.addEventListener("pagehide", (_e) => { + this.unloaded = true; + }); + this.socket.onOpen(() => { + if (this.isUnloaded()) { + window.location.reload(); + } + }); + } + // public + version() { + return "1.1.7"; + } + isProfileEnabled() { + return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true"; + } + isDebugEnabled() { + return this.sessionStorage.getItem(PHX_LV_DEBUG) === "true"; + } + isDebugDisabled() { + return this.sessionStorage.getItem(PHX_LV_DEBUG) === "false"; + } + enableDebug() { + this.sessionStorage.setItem(PHX_LV_DEBUG, "true"); + } + enableProfiling() { + this.sessionStorage.setItem(PHX_LV_PROFILE, "true"); + } + disableDebug() { + this.sessionStorage.setItem(PHX_LV_DEBUG, "false"); + } + disableProfiling() { + this.sessionStorage.removeItem(PHX_LV_PROFILE); + } + enableLatencySim(upperBoundMs) { + this.enableDebug(); + console.log( + "latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable" + ); + this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs); + } + disableLatencySim() { + this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM); + } + getLatencySim() { + const str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM); + return str ? parseInt(str) : null; + } + getSocket() { + return this.socket; + } + connect() { + if (window.location.hostname === "localhost" && !this.isDebugDisabled()) { + this.enableDebug(); + } + const doConnect = () => { + this.resetReloadStatus(); + if (this.joinRootViews()) { + this.bindTopLevelEvents(); + this.socket.connect(); + } else if (this.main) { + this.socket.connect(); + } else { + this.bindTopLevelEvents({ dead: true }); + } + this.joinDeadView(); + }; + if (["complete", "loaded", "interactive"].indexOf(document.readyState) >= 0) { + doConnect(); + } else { + document.addEventListener("DOMContentLoaded", () => doConnect()); + } + } + disconnect(callback) { + clearTimeout(this.reloadWithJitterTimer); + if (this.serverCloseRef) { + this.socket.off(this.serverCloseRef); + this.serverCloseRef = null; + } + this.socket.disconnect(callback); + } + replaceTransport(transport) { + clearTimeout(this.reloadWithJitterTimer); + this.socket.replaceTransport(transport); + this.connect(); + } + execJS(el, encodedJS, eventType = null) { + const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } }); + this.owner(el, (view) => js_default.exec(e, eventType, encodedJS, view, el)); + } + /** + * Returns an object with methods to manipluate the DOM and execute JavaScript. + * The applied changes integrate with server DOM patching. + * + * @returns {import("./js_commands").LiveSocketJSCommands} + */ + js() { + return js_commands_default(this, "js"); + } + // private + unload() { + if (this.unloaded) { + return; + } + if (this.main && this.isConnected()) { + this.log(this.main, "socket", () => ["disconnect for page nav"]); + } + this.unloaded = true; + this.destroyAllViews(); + this.disconnect(); + } + triggerDOM(kind, args) { + this.domCallbacks[kind](...args); + } + time(name, func) { + if (!this.isProfileEnabled() || !console.time) { + return func(); + } + console.time(name); + const result = func(); + console.timeEnd(name); + return result; + } + log(view, kind, msgCallback) { + if (this.viewLogger) { + const [msg, obj] = msgCallback(); + this.viewLogger(view, kind, msg, obj); + } else if (this.isDebugEnabled()) { + const [msg, obj] = msgCallback(); + debug(view, kind, msg, obj); + } + } + requestDOMUpdate(callback) { + this.transitions.after(callback); + } + asyncTransition(promise) { + this.transitions.addAsyncTransition(promise); + } + transition(time, onStart, onDone = function() { + }) { + this.transitions.addTransition(time, onStart, onDone); + } + onChannel(channel, event, cb) { + channel.on(event, (data) => { + const latency = this.getLatencySim(); + if (!latency) { + cb(data); + } else { + setTimeout(() => cb(data), latency); + } + }); + } + reloadWithJitter(view, log) { + clearTimeout(this.reloadWithJitterTimer); + this.disconnect(); + const minMs = this.reloadJitterMin; + const maxMs = this.reloadJitterMax; + let afterMs = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs; + const tries = browser_default.updateLocal( + this.localStorage, + window.location.pathname, + CONSECUTIVE_RELOADS, + 0, + (count) => count + 1 + ); + if (tries >= this.maxReloads) { + afterMs = this.failsafeJitter; + } + this.reloadWithJitterTimer = setTimeout(() => { + if (view.isDestroyed() || view.isConnected()) { + return; + } + view.destroy(); + log ? log() : this.log(view, "join", () => [ + `encountered ${tries} consecutive reloads` + ]); + if (tries >= this.maxReloads) { + this.log(view, "join", () => [ + `exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode` + ]); + } + if (this.hasPendingLink()) { + window.location = this.pendingLink; + } else { + window.location.reload(); + } + }, afterMs); + } + getHookDefinition(name) { + if (!name) { + return; + } + return this.maybeInternalHook(name) || this.hooks[name] || this.maybeRuntimeHook(name); + } + maybeInternalHook(name) { + return name && name.startsWith("Phoenix.") && hooks_default[name.split(".")[1]]; + } + maybeRuntimeHook(name) { + const runtimeHook = document.querySelector( + `script[${PHX_RUNTIME_HOOK}="${CSS.escape(name)}"]` + ); + if (!runtimeHook) { + return; + } + let callbacks = window[`phx_hook_${name}`]; + if (!callbacks || typeof callbacks !== "function") { + logError("a runtime hook must be a function", runtimeHook); + return; + } + const hookDefiniton = callbacks(); + if (hookDefiniton && (typeof hookDefiniton === "object" || typeof hookDefiniton === "function")) { + return hookDefiniton; + } + logError( + "runtime hook must return an object with hook callbacks or an instance of ViewHook", + runtimeHook + ); + } + isUnloaded() { + return this.unloaded; + } + isConnected() { + return this.socket.isConnected(); + } + getBindingPrefix() { + return this.bindingPrefix; + } + binding(kind) { + return `${this.getBindingPrefix()}${kind}`; + } + channel(topic, params) { + return this.socket.channel(topic, params); + } + joinDeadView() { + const body = document.body; + if (body && !this.isPhxView(body) && !this.isPhxView(document.firstElementChild)) { + const view = this.newRootView(body); + view.setHref(this.getHref()); + view.joinDead(); + if (!this.main) { + this.main = view; + } + window.requestAnimationFrame(() => { + view.execNewMounted(); + this.maybeScroll(history.state?.scroll); + }); + } + } + joinRootViews() { + let rootsFound = false; + dom_default.all( + document, + `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, + (rootEl) => { + if (!this.getRootById(rootEl.id)) { + const view = this.newRootView(rootEl); + if (!dom_default.isPhxSticky(rootEl)) { + view.setHref(this.getHref()); + } + view.join(); + if (rootEl.hasAttribute(PHX_MAIN)) { + this.main = view; + } + } + rootsFound = true; + } + ); + return rootsFound; + } + redirect(to, flash, reloadToken) { + if (reloadToken) { + browser_default.setCookie(PHX_RELOAD_STATUS, reloadToken, 60); + } + this.unload(); + browser_default.redirect(to, flash); + } + replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)) { + const liveReferer = this.currentLocation.href; + this.outgoingMainEl = this.outgoingMainEl || this.main.el; + const stickies = dom_default.findPhxSticky(document) || []; + const removeEls = dom_default.all( + this.outgoingMainEl, + `[${this.binding("remove")}]` + ).filter((el) => !dom_default.isChildOfAny(el, stickies)); + const newMainEl = dom_default.cloneNode(this.outgoingMainEl, ""); + this.main.showLoader(this.loaderTimeout); + this.main.destroy(); + this.main = this.newRootView(newMainEl, flash, liveReferer); + this.main.setRedirect(href); + this.transitionRemoves(removeEls); + this.main.join((joinCount, onDone) => { + if (joinCount === 1 && this.commitPendingLink(linkRef)) { + this.requestDOMUpdate(() => { + removeEls.forEach((el) => el.remove()); + stickies.forEach((el) => newMainEl.appendChild(el)); + this.outgoingMainEl.replaceWith(newMainEl); + this.outgoingMainEl = null; + callback && callback(linkRef); + onDone(); + }); + } + }); + } + transitionRemoves(elements, callback) { + const removeAttr = this.binding("remove"); + const silenceEvents = (e) => { + e.preventDefault(); + e.stopImmediatePropagation(); + }; + elements.forEach((el) => { + for (const event of this.boundEventNames) { + el.addEventListener(event, silenceEvents, true); + } + this.execJS(el, el.getAttribute(removeAttr), "remove"); + }); + this.requestDOMUpdate(() => { + elements.forEach((el) => { + for (const event of this.boundEventNames) { + el.removeEventListener(event, silenceEvents, true); + } + }); + callback && callback(); + }); + } + isPhxView(el) { + return el.getAttribute && el.getAttribute(PHX_SESSION) !== null; + } + newRootView(el, flash, liveReferer) { + const view = new View(el, this, null, flash, liveReferer); + this.roots[view.id] = view; + return view; + } + owner(childEl, callback) { + let view; + const viewEl = dom_default.closestViewEl(childEl); + if (viewEl) { + view = this.getViewByEl(viewEl); + } else { + view = this.main; + } + return view && callback ? callback(view) : view; + } + withinOwners(childEl, callback) { + this.owner(childEl, (view) => callback(view, childEl)); + } + getViewByEl(el) { + const rootId = el.getAttribute(PHX_ROOT_ID); + return maybe( + this.getRootById(rootId), + (root) => root.getDescendentByEl(el) + ); + } + getRootById(id) { + return this.roots[id]; + } + destroyAllViews() { + for (const id in this.roots) { + this.roots[id].destroy(); + delete this.roots[id]; + } + this.main = null; + } + destroyViewByEl(el) { + const root = this.getRootById(el.getAttribute(PHX_ROOT_ID)); + if (root && root.id === el.id) { + root.destroy(); + delete this.roots[root.id]; + } else if (root) { + root.destroyDescendent(el.id); + } + } + getActiveElement() { + return document.activeElement; + } + dropActiveElement(view) { + if (this.prevActive && view.ownsElement(this.prevActive)) { + this.prevActive = null; + } + } + restorePreviouslyActiveFocus() { + if (this.prevActive && this.prevActive !== document.body && this.prevActive instanceof HTMLElement) { + this.prevActive.focus(); + } + } + blurActiveElement() { + this.prevActive = this.getActiveElement(); + if (this.prevActive !== document.body && this.prevActive instanceof HTMLElement) { + this.prevActive.blur(); + } + } + /** + * @param {{dead?: boolean}} [options={}] + */ + bindTopLevelEvents({ dead } = {}) { + if (this.boundTopLevelEvents) { + return; + } + this.boundTopLevelEvents = true; + this.serverCloseRef = this.socket.onClose((event) => { + if (event && event.code === 1e3 && this.main) { + return this.reloadWithJitter(this.main); + } + }); + document.body.addEventListener("click", function() { + }); + window.addEventListener( + "pageshow", + (e) => { + if (e.persisted) { + this.getSocket().disconnect(); + this.withPageLoading({ to: window.location.href, kind: "redirect" }); + window.location.reload(); + } + }, + true + ); + if (!dead) { + this.bindNav(); + } + this.bindClicks(); + if (!dead) { + this.bindForms(); + } + this.bind( + { keyup: "keyup", keydown: "keydown" }, + (e, type, view, targetEl, phxEvent, _phxTarget) => { + const matchKey = targetEl.getAttribute(this.binding(PHX_KEY)); + const pressedKey = e.key && e.key.toLowerCase(); + if (matchKey && matchKey.toLowerCase() !== pressedKey) { + return; + } + const data = { key: e.key, ...this.eventMeta(type, e, targetEl) }; + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); + } + ); + this.bind( + { blur: "focusout", focus: "focusin" }, + (e, type, view, targetEl, phxEvent, phxTarget) => { + if (!phxTarget) { + const data = { key: e.key, ...this.eventMeta(type, e, targetEl) }; + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); + } + } + ); + this.bind( + { blur: "blur", focus: "focus" }, + (e, type, view, targetEl, phxEvent, phxTarget) => { + if (phxTarget === "window") { + const data = this.eventMeta(type, e, targetEl); + js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]); + } + } + ); + this.on("dragover", (e) => e.preventDefault()); + this.on("drop", (e) => { + e.preventDefault(); + const dropTargetId = maybe( + closestPhxBinding(e.target, this.binding(PHX_DROP_TARGET)), + (trueTarget) => { + return trueTarget.getAttribute(this.binding(PHX_DROP_TARGET)); + } + ); + const dropTarget = dropTargetId && document.getElementById(dropTargetId); + const files = Array.from(e.dataTransfer.files || []); + if (!dropTarget || !(dropTarget instanceof HTMLInputElement) || dropTarget.disabled || files.length === 0 || !(dropTarget.files instanceof FileList)) { + return; + } + LiveUploader.trackFiles(dropTarget, files, e.dataTransfer); + dropTarget.dispatchEvent(new Event("input", { bubbles: true })); + }); + this.on(PHX_TRACK_UPLOADS, (e) => { + const uploadTarget = e.target; + if (!dom_default.isUploadInput(uploadTarget)) { + return; + } + const files = Array.from(e.detail.files || []).filter( + (f) => f instanceof File || f instanceof Blob + ); + LiveUploader.trackFiles(uploadTarget, files); + uploadTarget.dispatchEvent(new Event("input", { bubbles: true })); + }); + } + eventMeta(eventName, e, targetEl) { + const callback = this.metadataCallbacks[eventName]; + return callback ? callback(e, targetEl) : {}; + } + setPendingLink(href) { + this.linkRef++; + this.pendingLink = href; + this.resetReloadStatus(); + return this.linkRef; + } + // anytime we are navigating or connecting, drop reload cookie in case + // we issue the cookie but the next request was interrupted and the server never dropped it + resetReloadStatus() { + browser_default.deleteCookie(PHX_RELOAD_STATUS); + } + commitPendingLink(linkRef) { + if (this.linkRef !== linkRef) { + return false; + } else { + this.href = this.pendingLink; + this.pendingLink = null; + return true; + } + } + getHref() { + return this.href; + } + hasPendingLink() { + return !!this.pendingLink; + } + bind(events, callback) { + for (const event in events) { + const browserEventName = events[event]; + this.on(browserEventName, (e) => { + const binding = this.binding(event); + const windowBinding = this.binding(`window-${event}`); + const targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding); + if (targetPhxEvent) { + this.debounce(e.target, e, browserEventName, () => { + this.withinOwners(e.target, (view) => { + callback(e, event, view, e.target, targetPhxEvent, null); + }); + }); + } else { + dom_default.all(document, `[${windowBinding}]`, (el) => { + const phxEvent = el.getAttribute(windowBinding); + this.debounce(el, e, browserEventName, () => { + this.withinOwners(el, (view) => { + callback(e, event, view, el, phxEvent, "window"); + }); + }); + }); + } + }); + } + } + bindClicks() { + this.on("mousedown", (e) => this.clickStartedAtTarget = e.target); + this.bindClick("click", "click"); + } + bindClick(eventName, bindingName) { + const click = this.binding(bindingName); + window.addEventListener( + eventName, + (e) => { + let target = null; + if (e.detail === 0) + this.clickStartedAtTarget = e.target; + const clickStartedAtTarget = this.clickStartedAtTarget || e.target; + target = closestPhxBinding(e.target, click); + this.dispatchClickAway(e, clickStartedAtTarget); + this.clickStartedAtTarget = null; + const phxEvent = target && target.getAttribute(click); + if (!phxEvent) { + if (dom_default.isNewPageClick(e, window.location)) { + this.unload(); + } + return; + } + if (target.getAttribute("href") === "#") { + e.preventDefault(); + } + if (target.hasAttribute(PHX_REF_SRC)) { + return; + } + this.debounce(target, e, "click", () => { + this.withinOwners(target, (view) => { + js_default.exec(e, "click", phxEvent, view, target, [ + "push", + { data: this.eventMeta("click", e, target) } + ]); + }); + }); + }, + false + ); + } + dispatchClickAway(e, clickStartedAt) { + const phxClickAway = this.binding("click-away"); + dom_default.all(document, `[${phxClickAway}]`, (el) => { + if (!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))) { + this.withinOwners(el, (view) => { + const phxEvent = el.getAttribute(phxClickAway); + if (js_default.isVisible(el) && js_default.isInViewport(el)) { + js_default.exec(e, "click", phxEvent, view, el, [ + "push", + { data: this.eventMeta("click", e, e.target) } + ]); + } + }); + } + }); + } + bindNav() { + if (!browser_default.canPushState()) { + return; + } + if (history.scrollRestoration) { + history.scrollRestoration = "manual"; + } + let scrollTimer = null; + window.addEventListener("scroll", (_e) => { + clearTimeout(scrollTimer); + scrollTimer = setTimeout(() => { + browser_default.updateCurrentState( + (state) => Object.assign(state, { scroll: window.scrollY }) + ); + }, 100); + }); + window.addEventListener( + "popstate", + (event) => { + if (!this.registerNewLocation(window.location)) { + return; + } + const { type, backType, id, scroll, position } = event.state || {}; + const href = window.location.href; + const isForward = position > this.currentHistoryPosition; + const navType = isForward ? type : backType || type; + this.currentHistoryPosition = position || 0; + this.sessionStorage.setItem( + PHX_LV_HISTORY_POSITION, + this.currentHistoryPosition.toString() + ); + dom_default.dispatchEvent(window, "phx:navigate", { + detail: { + href, + patch: navType === "patch", + pop: true, + direction: isForward ? "forward" : "backward" + } + }); + this.requestDOMUpdate(() => { + const callback = () => { + this.maybeScroll(scroll); + }; + if (this.main.isConnected() && navType === "patch" && id === this.main.id) { + this.main.pushLinkPatch(event, href, null, callback); + } else { + this.replaceMain(href, null, callback); + } + }); + }, + false + ); + window.addEventListener( + "click", + (e) => { + const target = closestPhxBinding(e.target, PHX_LIVE_LINK); + const type = target && target.getAttribute(PHX_LIVE_LINK); + if (!type || !this.isConnected() || !this.main || dom_default.wantsNewTab(e)) { + return; + } + const href = target.href instanceof SVGAnimatedString ? target.href.baseVal : target.href; + const linkState = target.getAttribute(PHX_LINK_STATE); + e.preventDefault(); + e.stopImmediatePropagation(); + if (this.pendingLink === href) { + return; + } + this.requestDOMUpdate(() => { + if (type === "patch") { + this.pushHistoryPatch(e, href, linkState, target); + } else if (type === "redirect") { + this.historyRedirect(e, href, linkState, null, target); + } else { + throw new Error( + `expected ${PHX_LIVE_LINK} to be "patch" or "redirect", got: ${type}` + ); + } + const phxClick = target.getAttribute(this.binding("click")); + if (phxClick) { + this.requestDOMUpdate(() => this.execJS(target, phxClick, "click")); + } + }); + }, + false + ); + } + maybeScroll(scroll) { + if (typeof scroll === "number") { + requestAnimationFrame(() => { + window.scrollTo(0, scroll); + }); + } + } + dispatchEvent(event, payload = {}) { + dom_default.dispatchEvent(window, `phx:${event}`, { detail: payload }); + } + dispatchEvents(events) { + events.forEach(([event, payload]) => this.dispatchEvent(event, payload)); + } + withPageLoading(info, callback) { + dom_default.dispatchEvent(window, "phx:page-loading-start", { detail: info }); + const done = () => dom_default.dispatchEvent(window, "phx:page-loading-stop", { detail: info }); + return callback ? callback(done) : done; + } + pushHistoryPatch(e, href, linkState, targetEl) { + if (!this.isConnected() || !this.main.isMain()) { + return browser_default.redirect(href); + } + this.withPageLoading({ to: href, kind: "patch" }, (done) => { + this.main.pushLinkPatch(e, href, targetEl, (linkRef) => { + this.historyPatch(href, linkState, linkRef); + done(); + }); + }); + } + historyPatch(href, linkState, linkRef = this.setPendingLink(href)) { + if (!this.commitPendingLink(linkRef)) { + return; + } + this.currentHistoryPosition++; + this.sessionStorage.setItem( + PHX_LV_HISTORY_POSITION, + this.currentHistoryPosition.toString() + ); + browser_default.updateCurrentState((state) => ({ ...state, backType: "patch" })); + browser_default.pushState( + linkState, + { + type: "patch", + id: this.main.id, + position: this.currentHistoryPosition + }, + href + ); + dom_default.dispatchEvent(window, "phx:navigate", { + detail: { patch: true, href, pop: false, direction: "forward" } + }); + this.registerNewLocation(window.location); + } + historyRedirect(e, href, linkState, flash, targetEl) { + const clickLoading = targetEl && e.isTrusted && e.type !== "popstate"; + if (clickLoading) { + targetEl.classList.add("phx-click-loading"); + } + if (!this.isConnected() || !this.main.isMain()) { + return browser_default.redirect(href, flash); + } + if (/^\/$|^\/[^\/]+.*$/.test(href)) { + const { protocol, host } = window.location; + href = `${protocol}//${host}${href}`; + } + const scroll = window.scrollY; + this.withPageLoading({ to: href, kind: "redirect" }, (done) => { + this.replaceMain(href, flash, (linkRef) => { + if (linkRef === this.linkRef) { + this.currentHistoryPosition++; + this.sessionStorage.setItem( + PHX_LV_HISTORY_POSITION, + this.currentHistoryPosition.toString() + ); + browser_default.updateCurrentState((state) => ({ + ...state, + backType: "redirect" + })); + browser_default.pushState( + linkState, + { + type: "redirect", + id: this.main.id, + scroll, + position: this.currentHistoryPosition + }, + href + ); + dom_default.dispatchEvent(window, "phx:navigate", { + detail: { href, patch: false, pop: false, direction: "forward" } + }); + this.registerNewLocation(window.location); + } + if (clickLoading) { + targetEl.classList.remove("phx-click-loading"); + } + done(); + }); + }); + } + registerNewLocation(newLocation) { + const { pathname, search } = this.currentLocation; + if (pathname + search === newLocation.pathname + newLocation.search) { + return false; + } else { + this.currentLocation = clone(newLocation); + return true; + } + } + bindForms() { + let iterations = 0; + let externalFormSubmitted = false; + this.on("submit", (e) => { + const phxSubmit = e.target.getAttribute(this.binding("submit")); + const phxChange = e.target.getAttribute(this.binding("change")); + if (!externalFormSubmitted && phxChange && !phxSubmit) { + externalFormSubmitted = true; + e.preventDefault(); + this.withinOwners(e.target, (view) => { + view.disableForm(e.target); + window.requestAnimationFrame(() => { + if (dom_default.isUnloadableFormSubmit(e)) { + this.unload(); + } + e.target.submit(); + }); + }); + } + }); + this.on("submit", (e) => { + const phxEvent = e.target.getAttribute(this.binding("submit")); + if (!phxEvent) { + if (dom_default.isUnloadableFormSubmit(e)) { + this.unload(); + } + return; + } + e.preventDefault(); + e.target.disabled = true; + this.withinOwners(e.target, (view) => { + js_default.exec(e, "submit", phxEvent, view, e.target, [ + "push", + { submitter: e.submitter } + ]); + }); + }); + for (const type of ["change", "input"]) { + this.on(type, (e) => { + if (e instanceof CustomEvent && (e.target instanceof HTMLInputElement || e.target instanceof HTMLSelectElement || e.target instanceof HTMLTextAreaElement) && e.target.form === void 0) { + if (e.detail && e.detail.dispatcher) { + throw new Error( + `dispatching a custom ${type} event is only supported on input elements inside a form` + ); + } + return; + } + const phxChange = this.binding("change"); + const input = e.target; + if (this.blockPhxChangeWhileComposing && e.isComposing) { + const key = `composition-listener-${type}`; + if (!dom_default.private(input, key)) { + dom_default.putPrivate(input, key, true); + input.addEventListener( + "compositionend", + () => { + input.dispatchEvent(new Event(type, { bubbles: true })); + dom_default.deletePrivate(input, key); + }, + { once: true } + ); + } + return; + } + const inputEvent = input.getAttribute(phxChange); + const formEvent = input.form && input.form.getAttribute(phxChange); + const phxEvent = inputEvent || formEvent; + if (!phxEvent) { + return; + } + if (input.type === "number" && input.validity && input.validity.badInput) { + return; + } + const dispatcher = inputEvent ? input : input.form; + const currentIterations = iterations; + iterations++; + const { at, type: lastType } = dom_default.private(input, "prev-iteration") || {}; + if (at === currentIterations - 1 && type === "change" && lastType === "input") { + return; + } + dom_default.putPrivate(input, "prev-iteration", { + at: currentIterations, + type + }); + this.debounce(input, e, type, () => { + this.withinOwners(dispatcher, (view) => { + dom_default.putPrivate(input, PHX_HAS_FOCUSED, true); + js_default.exec(e, "change", phxEvent, view, input, [ + "push", + { _target: e.target.name, dispatcher } + ]); + }); + }); + }); + } + this.on("reset", (e) => { + const form = e.target; + dom_default.resetForm(form); + const input = Array.from(form.elements).find((el) => el.type === "reset"); + if (input) { + window.requestAnimationFrame(() => { + input.dispatchEvent( + new Event("input", { bubbles: true, cancelable: false }) + ); + }); + } + }); + } + debounce(el, event, eventType, callback) { + if (eventType === "blur" || eventType === "focusout") { + return callback(); + } + const phxDebounce = this.binding(PHX_DEBOUNCE); + const phxThrottle = this.binding(PHX_THROTTLE); + const defaultDebounce = this.defaults.debounce.toString(); + const defaultThrottle = this.defaults.throttle.toString(); + this.withinOwners(el, (view) => { + const asyncFilter = () => !view.isDestroyed() && document.body.contains(el); + dom_default.debounce( + el, + event, + phxDebounce, + defaultDebounce, + phxThrottle, + defaultThrottle, + asyncFilter, + () => { + callback(); + } + ); + }); + } + silenceEvents(callback) { + this.silenced = true; + callback(); + this.silenced = false; + } + on(event, callback) { + this.boundEventNames.add(event); + window.addEventListener(event, (e) => { + if (!this.silenced) { + callback(e); + } + }); + } + jsQuerySelectorAll(sourceEl, query, defaultQuery) { + const all = this.domCallbacks.jsQuerySelectorAll; + return all ? all(sourceEl, query, defaultQuery) : defaultQuery(); + } + }; + var TransitionSet = class { + constructor() { + this.transitions = /* @__PURE__ */ new Set(); + this.promises = /* @__PURE__ */ new Set(); + this.pendingOps = []; + } + reset() { + this.transitions.forEach((timer) => { + clearTimeout(timer); + this.transitions.delete(timer); + }); + this.promises.clear(); + this.flushPendingOps(); + } + after(callback) { + if (this.size() === 0) { + callback(); + } else { + this.pushPendingOp(callback); + } + } + addTransition(time, onStart, onDone) { + onStart(); + const timer = setTimeout(() => { + this.transitions.delete(timer); + onDone(); + this.flushPendingOps(); + }, time); + this.transitions.add(timer); + } + addAsyncTransition(promise) { + this.promises.add(promise); + promise.then(() => { + this.promises.delete(promise); + this.flushPendingOps(); + }); + } + pushPendingOp(op) { + this.pendingOps.push(op); + } + size() { + return this.transitions.size + this.promises.size; + } + flushPendingOps() { + if (this.size() > 0) { + return; + } + const op = this.pendingOps.shift(); + if (op) { + op(); + this.flushPendingOps(); + } + } + }; + var LiveSocket2 = LiveSocket; + + // ../_build/dev/phoenix-colocated/myapp/index.js + var hooks = {}; + + // js/app.js + var import_topbar = __toESM(require_topbar()); + var csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content"); + var liveSocket = new LiveSocket2("/live", Socket, { + longPollFallbackMs: 2500, + params: { _csrf_token: csrfToken }, + hooks: { ...hooks } + }); + import_topbar.default.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" }); + window.addEventListener("phx:page-loading-start", (_info) => import_topbar.default.show(300)); + window.addEventListener("phx:page-loading-stop", (_info) => import_topbar.default.hide()); + liveSocket.connect(); + window.liveSocket = liveSocket; + if (true) { + window.addEventListener("phx:live_reload:attached", ({ detail: reloader }) => { + reloader.enableServerLogs(); + let keyDown; + window.addEventListener("keydown", (e) => keyDown = e.key); + window.addEventListener("keyup", (e) => keyDown = null); + window.addEventListener("click", (e) => { + if (keyDown === "c") { + e.preventDefault(); + e.stopImmediatePropagation(); + reloader.openEditorAtCaller(e.target); + } else if (keyDown === "d") { + e.preventDefault(); + e.stopImmediatePropagation(); + reloader.openEditorAtDef(e.target); + } + }, true); + window.liveReloader = reloader; + }); + } +})(); +/** + * @license MIT + * topbar 3.0.0 + * http://buunguyen.github.io/topbar + * Copyright (c) 2024 Buu Nguyen + */ +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vYXNzZXRzL3ZlbmRvci90b3BiYXIuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2h0bWwvcHJpdi9zdGF0aWMvcGhvZW5peF9odG1sLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC91dGlscy5qcyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvY29uc3RhbnRzLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9wdXNoLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC90aW1lci5qcyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvY2hhbm5lbC5qcyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvYWpheC5qcyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXgvYXNzZXRzL2pzL3Bob2VuaXgvbG9uZ3BvbGwuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4L2Fzc2V0cy9qcy9waG9lbml4L3ByZXNlbmNlLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9zZXJpYWxpemVyLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peC9hc3NldHMvanMvcGhvZW5peC9zb2NrZXQuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvY29uc3RhbnRzLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2VudHJ5X3VwbG9hZGVyLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3V0aWxzLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2Jyb3dzZXIuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3VwbG9hZF9lbnRyeS5qcyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXhfbGl2ZV92aWV3L2Fzc2V0cy9qcy9waG9lbml4X2xpdmVfdmlldy9saXZlX3VwbG9hZGVyLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2FyaWEuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvaG9va3MuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZWxlbWVudF9yZWYuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tX3Bvc3RfbW9ycGhfcmVzdG9yZXIuanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9ub2RlX21vZHVsZXMvbW9ycGhkb20vZGlzdC9tb3JwaGRvbS1lc20uanMiLCAiLi4vLi4vLi4vLi4vZGVwcy9waG9lbml4X2xpdmVfdmlldy9hc3NldHMvanMvcGhvZW5peF9saXZlX3ZpZXcvZG9tX3BhdGNoLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3JlbmRlcmVkLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2pzLmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2pzX2NvbW1hbmRzLnRzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L3ZpZXdfaG9vay50cyIsICIuLi8uLi8uLi8uLi9kZXBzL3Bob2VuaXhfbGl2ZV92aWV3L2Fzc2V0cy9qcy9waG9lbml4X2xpdmVfdmlldy92aWV3LmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2xpdmVfc29ja2V0LmpzIiwgIi4uLy4uLy4uLy4uL2RlcHMvcGhvZW5peF9saXZlX3ZpZXcvYXNzZXRzL2pzL3Bob2VuaXhfbGl2ZV92aWV3L2luZGV4LnRzIiwgIi4uLy4uLy4uLy4uL19idWlsZC9kZXYvcGhvZW5peC1jb2xvY2F0ZWQvbXlhcHAvaW5kZXguanMiLCAiLi4vLi4vLi4vLi4vYXNzZXRzL2pzL2FwcC5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAbGljZW5zZSBNSVRcbiAqIHRvcGJhciAzLjAuMFxuICogaHR0cDovL2J1dW5ndXllbi5naXRodWIuaW8vdG9wYmFyXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjQgQnV1IE5ndXllblxuICovXG4oZnVuY3Rpb24gKHdpbmRvdywgZG9jdW1lbnQpIHtcbiAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgdmFyIGNhbnZhcyxcbiAgICBjdXJyZW50UHJvZ3Jlc3MsXG4gICAgc2hvd2luZyxcbiAgICBwcm9ncmVzc1RpbWVySWQgPSBudWxsLFxuICAgIGZhZGVUaW1lcklkID0gbnVsbCxcbiAgICBkZWxheVRpbWVySWQgPSBudWxsLFxuICAgIGFkZEV2ZW50ID0gZnVuY3Rpb24gKGVsZW0sIHR5cGUsIGhhbmRsZXIpIHtcbiAgICAgIGlmIChlbGVtLmFkZEV2ZW50TGlzdGVuZXIpIGVsZW0uYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBoYW5kbGVyLCBmYWxzZSk7XG4gICAgICBlbHNlIGlmIChlbGVtLmF0dGFjaEV2ZW50KSBlbGVtLmF0dGFjaEV2ZW50KFwib25cIiArIHR5cGUsIGhhbmRsZXIpO1xuICAgICAgZWxzZSBlbGVtW1wib25cIiArIHR5cGVdID0gaGFuZGxlcjtcbiAgICB9LFxuICAgIG9wdGlvbnMgPSB7XG4gICAgICBhdXRvUnVuOiB0cnVlLFxuICAgICAgYmFyVGhpY2tuZXNzOiAzLFxuICAgICAgYmFyQ29sb3JzOiB7XG4gICAgICAgIDA6IFwicmdiYSgyNiwgIDE4OCwgMTU2LCAuOSlcIixcbiAgICAgICAgXCIuMjVcIjogXCJyZ2JhKDUyLCAgMTUyLCAyMTksIC45KVwiLFxuICAgICAgICBcIi41MFwiOiBcInJnYmEoMjQxLCAxOTYsIDE1LCAgLjkpXCIsXG4gICAgICAgIFwiLjc1XCI6IFwicmdiYSgyMzAsIDEyNiwgMzQsICAuOSlcIixcbiAgICAgICAgXCIxLjBcIjogXCJyZ2JhKDIxMSwgODQsICAwLCAgIC45KVwiLFxuICAgICAgfSxcbiAgICAgIHNoYWRvd0JsdXI6IDEwLFxuICAgICAgc2hhZG93Q29sb3I6IFwicmdiYSgwLCAgIDAsICAgMCwgICAuNilcIixcbiAgICAgIGNsYXNzTmFtZTogbnVsbCxcbiAgICB9LFxuICAgIHJlcGFpbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICBjYW52YXMud2lkdGggPSB3aW5kb3cuaW5uZXJXaWR0aDtcbiAgICAgIGNhbnZhcy5oZWlnaHQgPSBvcHRpb25zLmJhclRoaWNrbmVzcyAqIDU7IC8vIG5lZWQgc3BhY2UgZm9yIHNoYWRvd1xuXG4gICAgICB2YXIgY3R4ID0gY2FudmFzLmdldENvbnRleHQoXCIyZFwiKTtcbiAgICAgIGN0eC5zaGFkb3dCbHVyID0gb3B0aW9ucy5zaGFkb3dCbHVyO1xuICAgICAgY3R4LnNoYWRvd0NvbG9yID0gb3B0aW9ucy5zaGFkb3dDb2xvcjtcblxuICAgICAgdmFyIGxpbmVHcmFkaWVudCA9IGN0eC5jcmVhdGVMaW5lYXJHcmFkaWVudCgwLCAwLCBjYW52YXMud2lkdGgsIDApO1xuICAgICAgZm9yICh2YXIgc3RvcCBpbiBvcHRpb25zLmJhckNvbG9ycylcbiAgICAgICAgbGluZUdyYWRpZW50LmFkZENvbG9yU3RvcChzdG9wLCBvcHRpb25zLmJhckNvbG9yc1tzdG9wXSk7XG4gICAgICBjdHgubGluZVdpZHRoID0gb3B0aW9ucy5iYXJUaGlja25lc3M7XG4gICAgICBjdHguYmVnaW5QYXRoKCk7XG4gICAgICBjdHgubW92ZVRvKDAsIG9wdGlvbnMuYmFyVGhpY2tuZXNzIC8gMik7XG4gICAgICBjdHgubGluZVRvKFxuICAgICAgICBNYXRoLmNlaWwoY3VycmVudFByb2dyZXNzICogY2FudmFzLndpZHRoKSxcbiAgICAgICAgb3B0aW9ucy5iYXJUaGlja25lc3MgLyAyXG4gICAgICApO1xuICAgICAgY3R4LnN0cm9rZVN0eWxlID0gbGluZUdyYWRpZW50O1xuICAgICAgY3R4LnN0cm9rZSgpO1xuICAgIH0sXG4gICAgY3JlYXRlQ2FudmFzID0gZnVuY3Rpb24gKCkge1xuICAgICAgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImNhbnZhc1wiKTtcbiAgICAgIHZhciBzdHlsZSA9IGNhbnZhcy5zdHlsZTtcbiAgICAgIHN0eWxlLnBvc2l0aW9uID0gXCJmaXhlZFwiO1xuICAgICAgc3R5bGUudG9wID0gc3R5bGUubGVmdCA9IHN0eWxlLnJpZ2h0ID0gc3R5bGUubWFyZ2luID0gc3R5bGUucGFkZGluZyA9IDA7XG4gICAgICBzdHlsZS56SW5kZXggPSAxMDAwMDE7XG4gICAgICBzdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG4gICAgICBpZiAob3B0aW9ucy5jbGFzc05hbWUpIGNhbnZhcy5jbGFzc0xpc3QuYWRkKG9wdGlvbnMuY2xhc3NOYW1lKTtcbiAgICAgIGFkZEV2ZW50KHdpbmRvdywgXCJyZXNpemVcIiwgcmVwYWludCk7XG4gICAgfSxcbiAgICB0b3BiYXIgPSB7XG4gICAgICBjb25maWc6IGZ1bmN0aW9uIChvcHRzKSB7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiBvcHRzKVxuICAgICAgICAgIGlmIChvcHRpb25zLmhhc093blByb3BlcnR5KGtleSkpIG9wdGlvbnNba2V5XSA9IG9wdHNba2V5XTtcbiAgICAgIH0sXG4gICAgICBzaG93OiBmdW5jdGlvbiAoZGVsYXkpIHtcbiAgICAgICAgaWYgKHNob3dpbmcpIHJldHVybjtcbiAgICAgICAgaWYgKGRlbGF5KSB7XG4gICAgICAgICAgaWYgKGRlbGF5VGltZXJJZCkgcmV0dXJuO1xuICAgICAgICAgIGRlbGF5VGltZXJJZCA9IHNldFRpbWVvdXQoKCkgPT4gdG9wYmFyLnNob3coKSwgZGVsYXkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNob3dpbmcgPSB0cnVlO1xuICAgICAgICAgIGlmIChmYWRlVGltZXJJZCAhPT0gbnVsbCkgd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lKGZhZGVUaW1lcklkKTtcbiAgICAgICAgICBpZiAoIWNhbnZhcykgY3JlYXRlQ2FudmFzKCk7XG4gICAgICAgICAgaWYgKCFjYW52YXMucGFyZW50RWxlbWVudCkgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgICAgICAgIGNhbnZhcy5zdHlsZS5vcGFjaXR5ID0gMTtcbiAgICAgICAgICBjYW52YXMuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcbiAgICAgICAgICB0b3BiYXIucHJvZ3Jlc3MoMCk7XG4gICAgICAgICAgaWYgKG9wdGlvbnMuYXV0b1J1bikge1xuICAgICAgICAgICAgKGZ1bmN0aW9uIGxvb3AoKSB7XG4gICAgICAgICAgICAgIHByb2dyZXNzVGltZXJJZCA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUobG9vcCk7XG4gICAgICAgICAgICAgIHRvcGJhci5wcm9ncmVzcyhcbiAgICAgICAgICAgICAgICBcIitcIiArIDAuMDUgKiBNYXRoLnBvdygxIC0gTWF0aC5zcXJ0KGN1cnJlbnRQcm9ncmVzcyksIDIpXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHByb2dyZXNzOiBmdW5jdGlvbiAodG8pIHtcbiAgICAgICAgaWYgKHR5cGVvZiB0byA9PT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIGN1cnJlbnRQcm9ncmVzcztcbiAgICAgICAgaWYgKHR5cGVvZiB0byA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgIHRvID1cbiAgICAgICAgICAgICh0by5pbmRleE9mKFwiK1wiKSA+PSAwIHx8IHRvLmluZGV4T2YoXCItXCIpID49IDBcbiAgICAgICAgICAgICAgPyBjdXJyZW50UHJvZ3Jlc3NcbiAgICAgICAgICAgICAgOiAwKSArIHBhcnNlRmxvYXQodG8pO1xuICAgICAgICB9XG4gICAgICAgIGN1cnJlbnRQcm9ncmVzcyA9IHRvID4gMSA/IDEgOiB0bztcbiAgICAgICAgcmVwYWludCgpO1xuICAgICAgICByZXR1cm4gY3VycmVudFByb2dyZXNzO1xuICAgICAgfSxcbiAgICAgIGhpZGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KGRlbGF5VGltZXJJZCk7XG4gICAgICAgIGRlbGF5VGltZXJJZCA9IG51bGw7XG4gICAgICAgIGlmICghc2hvd2luZykgcmV0dXJuO1xuICAgICAgICBzaG93aW5nID0gZmFsc2U7XG4gICAgICAgIGlmIChwcm9ncmVzc1RpbWVySWQgIT0gbnVsbCkge1xuICAgICAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZShwcm9ncmVzc1RpbWVySWQpO1xuICAgICAgICAgIHByb2dyZXNzVGltZXJJZCA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgKGZ1bmN0aW9uIGxvb3AoKSB7XG4gICAgICAgICAgaWYgKHRvcGJhci5wcm9ncmVzcyhcIisuMVwiKSA+PSAxKSB7XG4gICAgICAgICAgICBjYW52YXMuc3R5bGUub3BhY2l0eSAtPSAwLjA1O1xuICAgICAgICAgICAgaWYgKGNhbnZhcy5zdHlsZS5vcGFjaXR5IDw9IDAuMDUpIHtcbiAgICAgICAgICAgICAgY2FudmFzLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICAgICAgICAgICAgZmFkZVRpbWVySWQgPSBudWxsO1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGZhZGVUaW1lcklkID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShsb29wKTtcbiAgICAgICAgfSkoKTtcbiAgICAgIH0sXG4gICAgfTtcblxuICBpZiAodHlwZW9mIG1vZHVsZSA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgbW9kdWxlLmV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHRvcGJhcjtcbiAgfSBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuICAgIGRlZmluZShmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gdG9wYmFyO1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHRoaXMudG9wYmFyID0gdG9wYmFyO1xuICB9XG59LmNhbGwodGhpcywgd2luZG93LCBkb2N1bWVudCkpO1xuIiwgIlwidXNlIHN0cmljdFwiO1xuXG4oZnVuY3Rpb24oKSB7XG4gIHZhciBQb2x5ZmlsbEV2ZW50ID0gZXZlbnRDb25zdHJ1Y3RvcigpO1xuXG4gIGZ1bmN0aW9uIGV2ZW50Q29uc3RydWN0b3IoKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cuQ3VzdG9tRXZlbnQgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIHdpbmRvdy5DdXN0b21FdmVudDtcbiAgICAvLyBJRTw9OSBTdXBwb3J0XG4gICAgZnVuY3Rpb24gQ3VzdG9tRXZlbnQoZXZlbnQsIHBhcmFtcykge1xuICAgICAgcGFyYW1zID0gcGFyYW1zIHx8IHtidWJibGVzOiBmYWxzZSwgY2FuY2VsYWJsZTogZmFsc2UsIGRldGFpbDogdW5kZWZpbmVkfTtcbiAgICAgIHZhciBldnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudCgnQ3VzdG9tRXZlbnQnKTtcbiAgICAgIGV2dC5pbml0Q3VzdG9tRXZlbnQoZXZlbnQsIHBhcmFtcy5idWJibGVzLCBwYXJhbXMuY2FuY2VsYWJsZSwgcGFyYW1zLmRldGFpbCk7XG4gICAgICByZXR1cm4gZXZ0O1xuICAgIH1cbiAgICBDdXN0b21FdmVudC5wcm90b3R5cGUgPSB3aW5kb3cuRXZlbnQucHJvdG90eXBlO1xuICAgIHJldHVybiBDdXN0b21FdmVudDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGJ1aWxkSGlkZGVuSW5wdXQobmFtZSwgdmFsdWUpIHtcbiAgICB2YXIgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIik7XG4gICAgaW5wdXQudHlwZSA9IFwiaGlkZGVuXCI7XG4gICAgaW5wdXQubmFtZSA9IG5hbWU7XG4gICAgaW5wdXQudmFsdWUgPSB2YWx1ZTtcbiAgICByZXR1cm4gaW5wdXQ7XG4gIH1cblxuICBmdW5jdGlvbiBoYW5kbGVDbGljayhlbGVtZW50LCB0YXJnZXRNb2RpZmllcktleSkge1xuICAgIHZhciB0byA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKFwiZGF0YS10b1wiKSxcbiAgICAgICAgbWV0aG9kID0gYnVpbGRIaWRkZW5JbnB1dChcIl9tZXRob2RcIiwgZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJkYXRhLW1ldGhvZFwiKSksXG4gICAgICAgIGNzcmYgPSBidWlsZEhpZGRlbklucHV0KFwiX2NzcmZfdG9rZW5cIiwgZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJkYXRhLWNzcmZcIikpLFxuICAgICAgICBmb3JtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImZvcm1cIiksXG4gICAgICAgIHN1Ym1pdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiKSxcbiAgICAgICAgdGFyZ2V0ID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJ0YXJnZXRcIik7XG5cbiAgICBmb3JtLm1ldGhvZCA9IChlbGVtZW50LmdldEF0dHJpYnV0ZShcImRhdGEtbWV0aG9kXCIpID09PSBcImdldFwiKSA/IFwiZ2V0XCIgOiBcInBvc3RcIjtcbiAgICBmb3JtLmFjdGlvbiA9IHRvO1xuICAgIGZvcm0uc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiO1xuXG4gICAgaWYgKHRhcmdldCkgZm9ybS50YXJnZXQgPSB0YXJnZXQ7XG4gICAgZWxzZSBpZiAodGFyZ2V0TW9kaWZpZXJLZXkpIGZvcm0udGFyZ2V0ID0gXCJfYmxhbmtcIjtcblxuICAgIGZvcm0uYXBwZW5kQ2hpbGQoY3NyZik7XG4gICAgZm9ybS5hcHBlbmRDaGlsZChtZXRob2QpO1xuICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoZm9ybSk7XG5cbiAgICAvLyBJbnNlcnQgYSBidXR0b24gYW5kIGNsaWNrIGl0IGluc3RlYWQgb2YgdXNpbmcgYGZvcm0uc3VibWl0YFxuICAgIC8vIGJlY2F1c2UgdGhlIGBzdWJtaXRgIGZ1bmN0aW9uIGRvZXMgbm90IGVtaXQgYSBgc3VibWl0YCBldmVudC5cbiAgICBzdWJtaXQudHlwZSA9IFwic3VibWl0XCI7XG4gICAgZm9ybS5hcHBlbmRDaGlsZChzdWJtaXQpO1xuICAgIHN1Ym1pdC5jbGljaygpO1xuICB9XG5cbiAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCBmdW5jdGlvbihlKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBlLnRhcmdldDtcbiAgICBpZiAoZS5kZWZhdWx0UHJldmVudGVkKSByZXR1cm47XG5cbiAgICB3aGlsZSAoZWxlbWVudCAmJiBlbGVtZW50LmdldEF0dHJpYnV0ZSkge1xuICAgICAgdmFyIHBob2VuaXhMaW5rRXZlbnQgPSBuZXcgUG9seWZpbGxFdmVudCgncGhvZW5peC5saW5rLmNsaWNrJywge1xuICAgICAgICBcImJ1YmJsZXNcIjogdHJ1ZSwgXCJjYW5jZWxhYmxlXCI6IHRydWVcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWVsZW1lbnQuZGlzcGF0Y2hFdmVudChwaG9lbml4TGlua0V2ZW50KSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZW1lbnQuZ2V0QXR0cmlidXRlKFwiZGF0YS1tZXRob2RcIikgJiYgZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXRvXCIpKSB7XG4gICAgICAgIGhhbmRsZUNsaWNrKGVsZW1lbnQsIGUubWV0YUtleSB8fCBlLnNoaWZ0S2V5KTtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbGVtZW50ID0gZWxlbWVudC5wYXJlbnROb2RlO1xuICAgICAgfVxuICAgIH1cbiAgfSwgZmFsc2UpO1xuXG4gIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwaG9lbml4LmxpbmsuY2xpY2snLCBmdW5jdGlvbiAoZSkge1xuICAgIHZhciBtZXNzYWdlID0gZS50YXJnZXQuZ2V0QXR0cmlidXRlKFwiZGF0YS1jb25maXJtXCIpO1xuICAgIGlmKG1lc3NhZ2UgJiYgIXdpbmRvdy5jb25maXJtKG1lc3NhZ2UpKSB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuICB9LCBmYWxzZSk7XG59KSgpO1xuIiwgIi8vIHdyYXBzIHZhbHVlIGluIGNsb3N1cmUgb3IgcmV0dXJucyBjbG9zdXJlXG5leHBvcnQgbGV0IGNsb3N1cmUgPSAodmFsdWUpID0+IHtcbiAgaWYodHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIpe1xuICAgIHJldHVybiB2YWx1ZVxuICB9IGVsc2Uge1xuICAgIGxldCBjbG9zdXJlID0gZnVuY3Rpb24gKCl7IHJldHVybiB2YWx1ZSB9XG4gICAgcmV0dXJuIGNsb3N1cmVcbiAgfVxufVxuIiwgImV4cG9ydCBjb25zdCBnbG9iYWxTZWxmID0gdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCIgPyBzZWxmIDogbnVsbFxuZXhwb3J0IGNvbnN0IHBoeFdpbmRvdyA9IHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgPyB3aW5kb3cgOiBudWxsXG5leHBvcnQgY29uc3QgZ2xvYmFsID0gZ2xvYmFsU2VsZiB8fCBwaHhXaW5kb3cgfHwgZ2xvYmFsVGhpc1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfVlNOID0gXCIyLjAuMFwiXG5leHBvcnQgY29uc3QgU09DS0VUX1NUQVRFUyA9IHtjb25uZWN0aW5nOiAwLCBvcGVuOiAxLCBjbG9zaW5nOiAyLCBjbG9zZWQ6IDN9XG5leHBvcnQgY29uc3QgREVGQVVMVF9USU1FT1VUID0gMTAwMDBcbmV4cG9ydCBjb25zdCBXU19DTE9TRV9OT1JNQUwgPSAxMDAwXG5leHBvcnQgY29uc3QgQ0hBTk5FTF9TVEFURVMgPSB7XG4gIGNsb3NlZDogXCJjbG9zZWRcIixcbiAgZXJyb3JlZDogXCJlcnJvcmVkXCIsXG4gIGpvaW5lZDogXCJqb2luZWRcIixcbiAgam9pbmluZzogXCJqb2luaW5nXCIsXG4gIGxlYXZpbmc6IFwibGVhdmluZ1wiLFxufVxuZXhwb3J0IGNvbnN0IENIQU5ORUxfRVZFTlRTID0ge1xuICBjbG9zZTogXCJwaHhfY2xvc2VcIixcbiAgZXJyb3I6IFwicGh4X2Vycm9yXCIsXG4gIGpvaW46IFwicGh4X2pvaW5cIixcbiAgcmVwbHk6IFwicGh4X3JlcGx5XCIsXG4gIGxlYXZlOiBcInBoeF9sZWF2ZVwiXG59XG5cbmV4cG9ydCBjb25zdCBUUkFOU1BPUlRTID0ge1xuICBsb25ncG9sbDogXCJsb25ncG9sbFwiLFxuICB3ZWJzb2NrZXQ6IFwid2Vic29ja2V0XCJcbn1cbmV4cG9ydCBjb25zdCBYSFJfU1RBVEVTID0ge1xuICBjb21wbGV0ZTogNFxufVxuZXhwb3J0IGNvbnN0IEFVVEhfVE9LRU5fUFJFRklYID0gXCJiYXNlNjR1cmwuYmVhcmVyLnBoeC5cIlxuIiwgIi8qKlxuICogSW5pdGlhbGl6ZXMgdGhlIFB1c2hcbiAqIEBwYXJhbSB7Q2hhbm5lbH0gY2hhbm5lbCAtIFRoZSBDaGFubmVsXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnQgLSBUaGUgZXZlbnQsIGZvciBleGFtcGxlIGBcInBoeF9qb2luXCJgXG4gKiBAcGFyYW0ge09iamVjdH0gcGF5bG9hZCAtIFRoZSBwYXlsb2FkLCBmb3IgZXhhbXBsZSBge3VzZXJfaWQ6IDEyM31gXG4gKiBAcGFyYW0ge251bWJlcn0gdGltZW91dCAtIFRoZSBwdXNoIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFB1c2gge1xuICBjb25zdHJ1Y3RvcihjaGFubmVsLCBldmVudCwgcGF5bG9hZCwgdGltZW91dCl7XG4gICAgdGhpcy5jaGFubmVsID0gY2hhbm5lbFxuICAgIHRoaXMuZXZlbnQgPSBldmVudFxuICAgIHRoaXMucGF5bG9hZCA9IHBheWxvYWQgfHwgZnVuY3Rpb24gKCl7IHJldHVybiB7fSB9XG4gICAgdGhpcy5yZWNlaXZlZFJlc3AgPSBudWxsXG4gICAgdGhpcy50aW1lb3V0ID0gdGltZW91dFxuICAgIHRoaXMudGltZW91dFRpbWVyID0gbnVsbFxuICAgIHRoaXMucmVjSG9va3MgPSBbXVxuICAgIHRoaXMuc2VudCA9IGZhbHNlXG4gIH1cblxuICAvKipcbiAgICpcbiAgICogQHBhcmFtIHtudW1iZXJ9IHRpbWVvdXRcbiAgICovXG4gIHJlc2VuZCh0aW1lb3V0KXtcbiAgICB0aGlzLnRpbWVvdXQgPSB0aW1lb3V0XG4gICAgdGhpcy5yZXNldCgpXG4gICAgdGhpcy5zZW5kKClcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKi9cbiAgc2VuZCgpe1xuICAgIGlmKHRoaXMuaGFzUmVjZWl2ZWQoXCJ0aW1lb3V0XCIpKXsgcmV0dXJuIH1cbiAgICB0aGlzLnN0YXJ0VGltZW91dCgpXG4gICAgdGhpcy5zZW50ID0gdHJ1ZVxuICAgIHRoaXMuY2hhbm5lbC5zb2NrZXQucHVzaCh7XG4gICAgICB0b3BpYzogdGhpcy5jaGFubmVsLnRvcGljLFxuICAgICAgZXZlbnQ6IHRoaXMuZXZlbnQsXG4gICAgICBwYXlsb2FkOiB0aGlzLnBheWxvYWQoKSxcbiAgICAgIHJlZjogdGhpcy5yZWYsXG4gICAgICBqb2luX3JlZjogdGhpcy5jaGFubmVsLmpvaW5SZWYoKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICpcbiAgICogQHBhcmFtIHsqfSBzdGF0dXNcbiAgICogQHBhcmFtIHsqfSBjYWxsYmFja1xuICAgKi9cbiAgcmVjZWl2ZShzdGF0dXMsIGNhbGxiYWNrKXtcbiAgICBpZih0aGlzLmhhc1JlY2VpdmVkKHN0YXR1cykpe1xuICAgICAgY2FsbGJhY2sodGhpcy5yZWNlaXZlZFJlc3AucmVzcG9uc2UpXG4gICAgfVxuXG4gICAgdGhpcy5yZWNIb29rcy5wdXNoKHtzdGF0dXMsIGNhbGxiYWNrfSlcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICByZXNldCgpe1xuICAgIHRoaXMuY2FuY2VsUmVmRXZlbnQoKVxuICAgIHRoaXMucmVmID0gbnVsbFxuICAgIHRoaXMucmVmRXZlbnQgPSBudWxsXG4gICAgdGhpcy5yZWNlaXZlZFJlc3AgPSBudWxsXG4gICAgdGhpcy5zZW50ID0gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgbWF0Y2hSZWNlaXZlKHtzdGF0dXMsIHJlc3BvbnNlLCBfcmVmfSl7XG4gICAgdGhpcy5yZWNIb29rcy5maWx0ZXIoaCA9PiBoLnN0YXR1cyA9PT0gc3RhdHVzKVxuICAgICAgLmZvckVhY2goaCA9PiBoLmNhbGxiYWNrKHJlc3BvbnNlKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY2FuY2VsUmVmRXZlbnQoKXtcbiAgICBpZighdGhpcy5yZWZFdmVudCl7IHJldHVybiB9XG4gICAgdGhpcy5jaGFubmVsLm9mZih0aGlzLnJlZkV2ZW50KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBjYW5jZWxUaW1lb3V0KCl7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dFRpbWVyKVxuICAgIHRoaXMudGltZW91dFRpbWVyID0gbnVsbFxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBzdGFydFRpbWVvdXQoKXtcbiAgICBpZih0aGlzLnRpbWVvdXRUaW1lcil7IHRoaXMuY2FuY2VsVGltZW91dCgpIH1cbiAgICB0aGlzLnJlZiA9IHRoaXMuY2hhbm5lbC5zb2NrZXQubWFrZVJlZigpXG4gICAgdGhpcy5yZWZFdmVudCA9IHRoaXMuY2hhbm5lbC5yZXBseUV2ZW50TmFtZSh0aGlzLnJlZilcblxuICAgIHRoaXMuY2hhbm5lbC5vbih0aGlzLnJlZkV2ZW50LCBwYXlsb2FkID0+IHtcbiAgICAgIHRoaXMuY2FuY2VsUmVmRXZlbnQoKVxuICAgICAgdGhpcy5jYW5jZWxUaW1lb3V0KClcbiAgICAgIHRoaXMucmVjZWl2ZWRSZXNwID0gcGF5bG9hZFxuICAgICAgdGhpcy5tYXRjaFJlY2VpdmUocGF5bG9hZClcbiAgICB9KVxuXG4gICAgdGhpcy50aW1lb3V0VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudHJpZ2dlcihcInRpbWVvdXRcIiwge30pXG4gICAgfSwgdGhpcy50aW1lb3V0KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBoYXNSZWNlaXZlZChzdGF0dXMpe1xuICAgIHJldHVybiB0aGlzLnJlY2VpdmVkUmVzcCAmJiB0aGlzLnJlY2VpdmVkUmVzcC5zdGF0dXMgPT09IHN0YXR1c1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICB0cmlnZ2VyKHN0YXR1cywgcmVzcG9uc2Upe1xuICAgIHRoaXMuY2hhbm5lbC50cmlnZ2VyKHRoaXMucmVmRXZlbnQsIHtzdGF0dXMsIHJlc3BvbnNlfSlcbiAgfVxufVxuIiwgIi8qKlxuICpcbiAqIENyZWF0ZXMgYSB0aW1lciB0aGF0IGFjY2VwdHMgYSBgdGltZXJDYWxjYCBmdW5jdGlvbiB0byBwZXJmb3JtXG4gKiBjYWxjdWxhdGVkIHRpbWVvdXQgcmV0cmllcywgc3VjaCBhcyBleHBvbmVudGlhbCBiYWNrb2ZmLlxuICpcbiAqIEBleGFtcGxlXG4gKiBsZXQgcmVjb25uZWN0VGltZXIgPSBuZXcgVGltZXIoKCkgPT4gdGhpcy5jb25uZWN0KCksIGZ1bmN0aW9uKHRyaWVzKXtcbiAqICAgcmV0dXJuIFsxMDAwLCA1MDAwLCAxMDAwMF1bdHJpZXMgLSAxXSB8fCAxMDAwMFxuICogfSlcbiAqIHJlY29ubmVjdFRpbWVyLnNjaGVkdWxlVGltZW91dCgpIC8vIGZpcmVzIGFmdGVyIDEwMDBcbiAqIHJlY29ubmVjdFRpbWVyLnNjaGVkdWxlVGltZW91dCgpIC8vIGZpcmVzIGFmdGVyIDUwMDBcbiAqIHJlY29ubmVjdFRpbWVyLnJlc2V0KClcbiAqIHJlY29ubmVjdFRpbWVyLnNjaGVkdWxlVGltZW91dCgpIC8vIGZpcmVzIGFmdGVyIDEwMDBcbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHBhcmFtIHtGdW5jdGlvbn0gdGltZXJDYWxjXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRpbWVyIHtcbiAgY29uc3RydWN0b3IoY2FsbGJhY2ssIHRpbWVyQ2FsYyl7XG4gICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrXG4gICAgdGhpcy50aW1lckNhbGMgPSB0aW1lckNhbGNcbiAgICB0aGlzLnRpbWVyID0gbnVsbFxuICAgIHRoaXMudHJpZXMgPSAwXG4gIH1cblxuICByZXNldCgpe1xuICAgIHRoaXMudHJpZXMgPSAwXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZXIpXG4gIH1cblxuICAvKipcbiAgICogQ2FuY2VscyBhbnkgcHJldmlvdXMgc2NoZWR1bGVUaW1lb3V0IGFuZCBzY2hlZHVsZXMgY2FsbGJhY2tcbiAgICovXG4gIHNjaGVkdWxlVGltZW91dCgpe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyKVxuXG4gICAgdGhpcy50aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy50cmllcyA9IHRoaXMudHJpZXMgKyAxXG4gICAgICB0aGlzLmNhbGxiYWNrKClcbiAgICB9LCB0aGlzLnRpbWVyQ2FsYyh0aGlzLnRyaWVzICsgMSkpXG4gIH1cbn1cbiIsICJpbXBvcnQge2Nsb3N1cmV9IGZyb20gXCIuL3V0aWxzXCJcbmltcG9ydCB7XG4gIENIQU5ORUxfRVZFTlRTLFxuICBDSEFOTkVMX1NUQVRFUyxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuaW1wb3J0IFB1c2ggZnJvbSBcIi4vcHVzaFwiXG5pbXBvcnQgVGltZXIgZnJvbSBcIi4vdGltZXJcIlxuXG4vKipcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdG9waWNcbiAqIEBwYXJhbSB7KE9iamVjdHxmdW5jdGlvbil9IHBhcmFtc1xuICogQHBhcmFtIHtTb2NrZXR9IHNvY2tldFxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDaGFubmVsIHtcbiAgY29uc3RydWN0b3IodG9waWMsIHBhcmFtcywgc29ja2V0KXtcbiAgICB0aGlzLnN0YXRlID0gQ0hBTk5FTF9TVEFURVMuY2xvc2VkXG4gICAgdGhpcy50b3BpYyA9IHRvcGljXG4gICAgdGhpcy5wYXJhbXMgPSBjbG9zdXJlKHBhcmFtcyB8fCB7fSlcbiAgICB0aGlzLnNvY2tldCA9IHNvY2tldFxuICAgIHRoaXMuYmluZGluZ3MgPSBbXVxuICAgIHRoaXMuYmluZGluZ1JlZiA9IDBcbiAgICB0aGlzLnRpbWVvdXQgPSB0aGlzLnNvY2tldC50aW1lb3V0XG4gICAgdGhpcy5qb2luZWRPbmNlID0gZmFsc2VcbiAgICB0aGlzLmpvaW5QdXNoID0gbmV3IFB1c2godGhpcywgQ0hBTk5FTF9FVkVOVFMuam9pbiwgdGhpcy5wYXJhbXMsIHRoaXMudGltZW91dClcbiAgICB0aGlzLnB1c2hCdWZmZXIgPSBbXVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VSZWZzID0gW11cblxuICAgIHRoaXMucmVqb2luVGltZXIgPSBuZXcgVGltZXIoKCkgPT4ge1xuICAgICAgaWYodGhpcy5zb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMucmVqb2luKCkgfVxuICAgIH0sIHRoaXMuc29ja2V0LnJlam9pbkFmdGVyTXMpXG4gICAgdGhpcy5zdGF0ZUNoYW5nZVJlZnMucHVzaCh0aGlzLnNvY2tldC5vbkVycm9yKCgpID0+IHRoaXMucmVqb2luVGltZXIucmVzZXQoKSkpXG4gICAgdGhpcy5zdGF0ZUNoYW5nZVJlZnMucHVzaCh0aGlzLnNvY2tldC5vbk9wZW4oKCkgPT4ge1xuICAgICAgdGhpcy5yZWpvaW5UaW1lci5yZXNldCgpXG4gICAgICBpZih0aGlzLmlzRXJyb3JlZCgpKXsgdGhpcy5yZWpvaW4oKSB9XG4gICAgfSlcbiAgICApXG4gICAgdGhpcy5qb2luUHVzaC5yZWNlaXZlKFwib2tcIiwgKCkgPT4ge1xuICAgICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmpvaW5lZFxuICAgICAgdGhpcy5yZWpvaW5UaW1lci5yZXNldCgpXG4gICAgICB0aGlzLnB1c2hCdWZmZXIuZm9yRWFjaChwdXNoRXZlbnQgPT4gcHVzaEV2ZW50LnNlbmQoKSlcbiAgICAgIHRoaXMucHVzaEJ1ZmZlciA9IFtdXG4gICAgfSlcbiAgICB0aGlzLmpvaW5QdXNoLnJlY2VpdmUoXCJlcnJvclwiLCAoKSA9PiB7XG4gICAgICB0aGlzLnN0YXRlID0gQ0hBTk5FTF9TVEFURVMuZXJyb3JlZFxuICAgICAgaWYodGhpcy5zb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMucmVqb2luVGltZXIuc2NoZWR1bGVUaW1lb3V0KCkgfVxuICAgIH0pXG4gICAgdGhpcy5vbkNsb3NlKCgpID0+IHtcbiAgICAgIHRoaXMucmVqb2luVGltZXIucmVzZXQoKVxuICAgICAgaWYodGhpcy5zb2NrZXQuaGFzTG9nZ2VyKCkpIHRoaXMuc29ja2V0LmxvZyhcImNoYW5uZWxcIiwgYGNsb3NlICR7dGhpcy50b3BpY30gJHt0aGlzLmpvaW5SZWYoKX1gKVxuICAgICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmNsb3NlZFxuICAgICAgdGhpcy5zb2NrZXQucmVtb3ZlKHRoaXMpXG4gICAgfSlcbiAgICB0aGlzLm9uRXJyb3IocmVhc29uID0+IHtcbiAgICAgIGlmKHRoaXMuc29ja2V0Lmhhc0xvZ2dlcigpKSB0aGlzLnNvY2tldC5sb2coXCJjaGFubmVsXCIsIGBlcnJvciAke3RoaXMudG9waWN9YCwgcmVhc29uKVxuICAgICAgaWYodGhpcy5pc0pvaW5pbmcoKSl7IHRoaXMuam9pblB1c2gucmVzZXQoKSB9XG4gICAgICB0aGlzLnN0YXRlID0gQ0hBTk5FTF9TVEFURVMuZXJyb3JlZFxuICAgICAgaWYodGhpcy5zb2NrZXQuaXNDb25uZWN0ZWQoKSl7IHRoaXMucmVqb2luVGltZXIuc2NoZWR1bGVUaW1lb3V0KCkgfVxuICAgIH0pXG4gICAgdGhpcy5qb2luUHVzaC5yZWNlaXZlKFwidGltZW91dFwiLCAoKSA9PiB7XG4gICAgICBpZih0aGlzLnNvY2tldC5oYXNMb2dnZXIoKSkgdGhpcy5zb2NrZXQubG9nKFwiY2hhbm5lbFwiLCBgdGltZW91dCAke3RoaXMudG9waWN9ICgke3RoaXMuam9pblJlZigpfSlgLCB0aGlzLmpvaW5QdXNoLnRpbWVvdXQpXG4gICAgICBsZXQgbGVhdmVQdXNoID0gbmV3IFB1c2godGhpcywgQ0hBTk5FTF9FVkVOVFMubGVhdmUsIGNsb3N1cmUoe30pLCB0aGlzLnRpbWVvdXQpXG4gICAgICBsZWF2ZVB1c2guc2VuZCgpXG4gICAgICB0aGlzLnN0YXRlID0gQ0hBTk5FTF9TVEFURVMuZXJyb3JlZFxuICAgICAgdGhpcy5qb2luUHVzaC5yZXNldCgpXG4gICAgICBpZih0aGlzLnNvY2tldC5pc0Nvbm5lY3RlZCgpKXsgdGhpcy5yZWpvaW5UaW1lci5zY2hlZHVsZVRpbWVvdXQoKSB9XG4gICAgfSlcbiAgICB0aGlzLm9uKENIQU5ORUxfRVZFTlRTLnJlcGx5LCAocGF5bG9hZCwgcmVmKSA9PiB7XG4gICAgICB0aGlzLnRyaWdnZXIodGhpcy5yZXBseUV2ZW50TmFtZShyZWYpLCBwYXlsb2FkKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogSm9pbiB0aGUgY2hhbm5lbFxuICAgKiBAcGFyYW0ge2ludGVnZXJ9IHRpbWVvdXRcbiAgICogQHJldHVybnMge1B1c2h9XG4gICAqL1xuICBqb2luKHRpbWVvdXQgPSB0aGlzLnRpbWVvdXQpe1xuICAgIGlmKHRoaXMuam9pbmVkT25jZSl7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ0cmllZCB0byBqb2luIG11bHRpcGxlIHRpbWVzLiAnam9pbicgY2FuIG9ubHkgYmUgY2FsbGVkIGEgc2luZ2xlIHRpbWUgcGVyIGNoYW5uZWwgaW5zdGFuY2VcIilcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50aW1lb3V0ID0gdGltZW91dFxuICAgICAgdGhpcy5qb2luZWRPbmNlID0gdHJ1ZVxuICAgICAgdGhpcy5yZWpvaW4oKVxuICAgICAgcmV0dXJuIHRoaXMuam9pblB1c2hcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSG9vayBpbnRvIGNoYW5uZWwgY2xvc2VcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICovXG4gIG9uQ2xvc2UoY2FsbGJhY2spe1xuICAgIHRoaXMub24oQ0hBTk5FTF9FVkVOVFMuY2xvc2UsIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIEhvb2sgaW50byBjaGFubmVsIGVycm9yc1xuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgKi9cbiAgb25FcnJvcihjYWxsYmFjayl7XG4gICAgcmV0dXJuIHRoaXMub24oQ0hBTk5FTF9FVkVOVFMuZXJyb3IsIHJlYXNvbiA9PiBjYWxsYmFjayhyZWFzb24pKVxuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZXMgb24gY2hhbm5lbCBldmVudHNcbiAgICpcbiAgICogU3Vic2NyaXB0aW9uIHJldHVybnMgYSByZWYgY291bnRlciwgd2hpY2ggY2FuIGJlIHVzZWQgbGF0ZXIgdG9cbiAgICogdW5zdWJzY3JpYmUgdGhlIGV4YWN0IGV2ZW50IGxpc3RlbmVyXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGNvbnN0IHJlZjEgPSBjaGFubmVsLm9uKFwiZXZlbnRcIiwgZG9fc3R1ZmYpXG4gICAqIGNvbnN0IHJlZjIgPSBjaGFubmVsLm9uKFwiZXZlbnRcIiwgZG9fb3RoZXJfc3R1ZmYpXG4gICAqIGNoYW5uZWwub2ZmKFwiZXZlbnRcIiwgcmVmMSlcbiAgICogLy8gU2luY2UgdW5zdWJzY3JpcHRpb24sIGRvX3N0dWZmIHdvbid0IGZpcmUsXG4gICAqIC8vIHdoaWxlIGRvX290aGVyX3N0dWZmIHdpbGwga2VlcCBmaXJpbmcgb24gdGhlIFwiZXZlbnRcIlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge2ludGVnZXJ9IHJlZlxuICAgKi9cbiAgb24oZXZlbnQsIGNhbGxiYWNrKXtcbiAgICBsZXQgcmVmID0gdGhpcy5iaW5kaW5nUmVmKytcbiAgICB0aGlzLmJpbmRpbmdzLnB1c2goe2V2ZW50LCByZWYsIGNhbGxiYWNrfSlcbiAgICByZXR1cm4gcmVmXG4gIH1cblxuICAvKipcbiAgICogVW5zdWJzY3JpYmVzIG9mZiBvZiBjaGFubmVsIGV2ZW50c1xuICAgKlxuICAgKiBVc2UgdGhlIHJlZiByZXR1cm5lZCBmcm9tIGEgY2hhbm5lbC5vbigpIHRvIHVuc3Vic2NyaWJlIG9uZVxuICAgKiBoYW5kbGVyLCBvciBwYXNzIG5vdGhpbmcgZm9yIHRoZSByZWYgdG8gdW5zdWJzY3JpYmUgYWxsXG4gICAqIGhhbmRsZXJzIGZvciB0aGUgZ2l2ZW4gZXZlbnQuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC8vIFVuc3Vic2NyaWJlIHRoZSBkb19zdHVmZiBoYW5kbGVyXG4gICAqIGNvbnN0IHJlZjEgPSBjaGFubmVsLm9uKFwiZXZlbnRcIiwgZG9fc3R1ZmYpXG4gICAqIGNoYW5uZWwub2ZmKFwiZXZlbnRcIiwgcmVmMSlcbiAgICpcbiAgICogLy8gVW5zdWJzY3JpYmUgYWxsIGhhbmRsZXJzIGZyb20gZXZlbnRcbiAgICogY2hhbm5lbC5vZmYoXCJldmVudFwiKVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSByZWZcbiAgICovXG4gIG9mZihldmVudCwgcmVmKXtcbiAgICB0aGlzLmJpbmRpbmdzID0gdGhpcy5iaW5kaW5ncy5maWx0ZXIoKGJpbmQpID0+IHtcbiAgICAgIHJldHVybiAhKGJpbmQuZXZlbnQgPT09IGV2ZW50ICYmICh0eXBlb2YgcmVmID09PSBcInVuZGVmaW5lZFwiIHx8IHJlZiA9PT0gYmluZC5yZWYpKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGNhblB1c2goKXsgcmV0dXJuIHRoaXMuc29ja2V0LmlzQ29ubmVjdGVkKCkgJiYgdGhpcy5pc0pvaW5lZCgpIH1cblxuICAvKipcbiAgICogU2VuZHMgYSBtZXNzYWdlIGBldmVudGAgdG8gcGhvZW5peCB3aXRoIHRoZSBwYXlsb2FkIGBwYXlsb2FkYC5cbiAgICogUGhvZW5peCByZWNlaXZlcyB0aGlzIGluIHRoZSBgaGFuZGxlX2luKGV2ZW50LCBwYXlsb2FkLCBzb2NrZXQpYFxuICAgKiBmdW5jdGlvbi4gaWYgcGhvZW5peCByZXBsaWVzIG9yIGl0IHRpbWVzIG91dCAoZGVmYXVsdCAxMDAwMG1zKSxcbiAgICogdGhlbiBvcHRpb25hbGx5IHRoZSByZXBseSBjYW4gYmUgcmVjZWl2ZWQuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGNoYW5uZWwucHVzaChcImV2ZW50XCIpXG4gICAqICAgLnJlY2VpdmUoXCJva1wiLCBwYXlsb2FkID0+IGNvbnNvbGUubG9nKFwicGhvZW5peCByZXBsaWVkOlwiLCBwYXlsb2FkKSlcbiAgICogICAucmVjZWl2ZShcImVycm9yXCIsIGVyciA9PiBjb25zb2xlLmxvZyhcInBob2VuaXggZXJyb3JlZFwiLCBlcnIpKVxuICAgKiAgIC5yZWNlaXZlKFwidGltZW91dFwiLCAoKSA9PiBjb25zb2xlLmxvZyhcInRpbWVkIG91dCBwdXNoaW5nXCIpKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRcbiAgICogQHBhcmFtIHtPYmplY3R9IHBheWxvYWRcbiAgICogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0XVxuICAgKiBAcmV0dXJucyB7UHVzaH1cbiAgICovXG4gIHB1c2goZXZlbnQsIHBheWxvYWQsIHRpbWVvdXQgPSB0aGlzLnRpbWVvdXQpe1xuICAgIHBheWxvYWQgPSBwYXlsb2FkIHx8IHt9XG4gICAgaWYoIXRoaXMuam9pbmVkT25jZSl7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHRyaWVkIHRvIHB1c2ggJyR7ZXZlbnR9JyB0byAnJHt0aGlzLnRvcGljfScgYmVmb3JlIGpvaW5pbmcuIFVzZSBjaGFubmVsLmpvaW4oKSBiZWZvcmUgcHVzaGluZyBldmVudHNgKVxuICAgIH1cbiAgICBsZXQgcHVzaEV2ZW50ID0gbmV3IFB1c2godGhpcywgZXZlbnQsIGZ1bmN0aW9uICgpeyByZXR1cm4gcGF5bG9hZCB9LCB0aW1lb3V0KVxuICAgIGlmKHRoaXMuY2FuUHVzaCgpKXtcbiAgICAgIHB1c2hFdmVudC5zZW5kKClcbiAgICB9IGVsc2Uge1xuICAgICAgcHVzaEV2ZW50LnN0YXJ0VGltZW91dCgpXG4gICAgICB0aGlzLnB1c2hCdWZmZXIucHVzaChwdXNoRXZlbnQpXG4gICAgfVxuXG4gICAgcmV0dXJuIHB1c2hFdmVudFxuICB9XG5cbiAgLyoqIExlYXZlcyB0aGUgY2hhbm5lbFxuICAgKlxuICAgKiBVbnN1YnNjcmliZXMgZnJvbSBzZXJ2ZXIgZXZlbnRzLCBhbmRcbiAgICogaW5zdHJ1Y3RzIGNoYW5uZWwgdG8gdGVybWluYXRlIG9uIHNlcnZlclxuICAgKlxuICAgKiBUcmlnZ2VycyBvbkNsb3NlKCkgaG9va3NcbiAgICpcbiAgICogVG8gcmVjZWl2ZSBsZWF2ZSBhY2tub3dsZWRnZW1lbnRzLCB1c2UgdGhlIGByZWNlaXZlYFxuICAgKiBob29rIHRvIGJpbmQgdG8gdGhlIHNlcnZlciBhY2ssIGllOlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBjaGFubmVsLmxlYXZlKCkucmVjZWl2ZShcIm9rXCIsICgpID0+IGFsZXJ0KFwibGVmdCFcIikgKVxuICAgKlxuICAgKiBAcGFyYW0ge2ludGVnZXJ9IHRpbWVvdXRcbiAgICogQHJldHVybnMge1B1c2h9XG4gICAqL1xuICBsZWF2ZSh0aW1lb3V0ID0gdGhpcy50aW1lb3V0KXtcbiAgICB0aGlzLnJlam9pblRpbWVyLnJlc2V0KClcbiAgICB0aGlzLmpvaW5QdXNoLmNhbmNlbFRpbWVvdXQoKVxuXG4gICAgdGhpcy5zdGF0ZSA9IENIQU5ORUxfU1RBVEVTLmxlYXZpbmdcbiAgICBsZXQgb25DbG9zZSA9ICgpID0+IHtcbiAgICAgIGlmKHRoaXMuc29ja2V0Lmhhc0xvZ2dlcigpKSB0aGlzLnNvY2tldC5sb2coXCJjaGFubmVsXCIsIGBsZWF2ZSAke3RoaXMudG9waWN9YClcbiAgICAgIHRoaXMudHJpZ2dlcihDSEFOTkVMX0VWRU5UUy5jbG9zZSwgXCJsZWF2ZVwiKVxuICAgIH1cbiAgICBsZXQgbGVhdmVQdXNoID0gbmV3IFB1c2godGhpcywgQ0hBTk5FTF9FVkVOVFMubGVhdmUsIGNsb3N1cmUoe30pLCB0aW1lb3V0KVxuICAgIGxlYXZlUHVzaC5yZWNlaXZlKFwib2tcIiwgKCkgPT4gb25DbG9zZSgpKVxuICAgICAgLnJlY2VpdmUoXCJ0aW1lb3V0XCIsICgpID0+IG9uQ2xvc2UoKSlcbiAgICBsZWF2ZVB1c2guc2VuZCgpXG4gICAgaWYoIXRoaXMuY2FuUHVzaCgpKXsgbGVhdmVQdXNoLnRyaWdnZXIoXCJva1wiLCB7fSkgfVxuXG4gICAgcmV0dXJuIGxlYXZlUHVzaFxuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRhYmxlIG1lc3NhZ2UgaG9va1xuICAgKlxuICAgKiBSZWNlaXZlcyBhbGwgZXZlbnRzIGZvciBzcGVjaWFsaXplZCBtZXNzYWdlIGhhbmRsaW5nXG4gICAqIGJlZm9yZSBkaXNwYXRjaGluZyB0byB0aGUgY2hhbm5lbCBjYWxsYmFja3MuXG4gICAqXG4gICAqIE11c3QgcmV0dXJuIHRoZSBwYXlsb2FkLCBtb2RpZmllZCBvciB1bm1vZGlmaWVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudFxuICAgKiBAcGFyYW0ge09iamVjdH0gcGF5bG9hZFxuICAgKiBAcGFyYW0ge2ludGVnZXJ9IHJlZlxuICAgKiBAcmV0dXJucyB7T2JqZWN0fVxuICAgKi9cbiAgb25NZXNzYWdlKF9ldmVudCwgcGF5bG9hZCwgX3JlZil7IHJldHVybiBwYXlsb2FkIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGlzTWVtYmVyKHRvcGljLCBldmVudCwgcGF5bG9hZCwgam9pblJlZil7XG4gICAgaWYodGhpcy50b3BpYyAhPT0gdG9waWMpeyByZXR1cm4gZmFsc2UgfVxuXG4gICAgaWYoam9pblJlZiAmJiBqb2luUmVmICE9PSB0aGlzLmpvaW5SZWYoKSl7XG4gICAgICBpZih0aGlzLnNvY2tldC5oYXNMb2dnZXIoKSkgdGhpcy5zb2NrZXQubG9nKFwiY2hhbm5lbFwiLCBcImRyb3BwaW5nIG91dGRhdGVkIG1lc3NhZ2VcIiwge3RvcGljLCBldmVudCwgcGF5bG9hZCwgam9pblJlZn0pXG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGpvaW5SZWYoKXsgcmV0dXJuIHRoaXMuam9pblB1c2gucmVmIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHJlam9pbih0aW1lb3V0ID0gdGhpcy50aW1lb3V0KXtcbiAgICBpZih0aGlzLmlzTGVhdmluZygpKXsgcmV0dXJuIH1cbiAgICB0aGlzLnNvY2tldC5sZWF2ZU9wZW5Ub3BpYyh0aGlzLnRvcGljKVxuICAgIHRoaXMuc3RhdGUgPSBDSEFOTkVMX1NUQVRFUy5qb2luaW5nXG4gICAgdGhpcy5qb2luUHVzaC5yZXNlbmQodGltZW91dClcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgdHJpZ2dlcihldmVudCwgcGF5bG9hZCwgcmVmLCBqb2luUmVmKXtcbiAgICBsZXQgaGFuZGxlZFBheWxvYWQgPSB0aGlzLm9uTWVzc2FnZShldmVudCwgcGF5bG9hZCwgcmVmLCBqb2luUmVmKVxuICAgIGlmKHBheWxvYWQgJiYgIWhhbmRsZWRQYXlsb2FkKXsgdGhyb3cgbmV3IEVycm9yKFwiY2hhbm5lbCBvbk1lc3NhZ2UgY2FsbGJhY2tzIG11c3QgcmV0dXJuIHRoZSBwYXlsb2FkLCBtb2RpZmllZCBvciB1bm1vZGlmaWVkXCIpIH1cblxuICAgIGxldCBldmVudEJpbmRpbmdzID0gdGhpcy5iaW5kaW5ncy5maWx0ZXIoYmluZCA9PiBiaW5kLmV2ZW50ID09PSBldmVudClcblxuICAgIGZvcihsZXQgaSA9IDA7IGkgPCBldmVudEJpbmRpbmdzLmxlbmd0aDsgaSsrKXtcbiAgICAgIGxldCBiaW5kID0gZXZlbnRCaW5kaW5nc1tpXVxuICAgICAgYmluZC5jYWxsYmFjayhoYW5kbGVkUGF5bG9hZCwgcmVmLCBqb2luUmVmIHx8IHRoaXMuam9pblJlZigpKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcmVwbHlFdmVudE5hbWUocmVmKXsgcmV0dXJuIGBjaGFuX3JlcGx5XyR7cmVmfWAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaXNDbG9zZWQoKXsgcmV0dXJuIHRoaXMuc3RhdGUgPT09IENIQU5ORUxfU1RBVEVTLmNsb3NlZCB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBpc0Vycm9yZWQoKXsgcmV0dXJuIHRoaXMuc3RhdGUgPT09IENIQU5ORUxfU1RBVEVTLmVycm9yZWQgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaXNKb2luZWQoKXsgcmV0dXJuIHRoaXMuc3RhdGUgPT09IENIQU5ORUxfU1RBVEVTLmpvaW5lZCB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBpc0pvaW5pbmcoKXsgcmV0dXJuIHRoaXMuc3RhdGUgPT09IENIQU5ORUxfU1RBVEVTLmpvaW5pbmcgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgaXNMZWF2aW5nKCl7IHJldHVybiB0aGlzLnN0YXRlID09PSBDSEFOTkVMX1NUQVRFUy5sZWF2aW5nIH1cbn1cbiIsICJpbXBvcnQge1xuICBnbG9iYWwsXG4gIFhIUl9TVEFURVNcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCJcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQWpheCB7XG5cbiAgc3RhdGljIHJlcXVlc3QobWV0aG9kLCBlbmRQb2ludCwgaGVhZGVycywgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjayl7XG4gICAgaWYoZ2xvYmFsLlhEb21haW5SZXF1ZXN0KXtcbiAgICAgIGxldCByZXEgPSBuZXcgZ2xvYmFsLlhEb21haW5SZXF1ZXN0KCkgLy8gSUU4LCBJRTlcbiAgICAgIHJldHVybiB0aGlzLnhkb21haW5SZXF1ZXN0KHJlcSwgbWV0aG9kLCBlbmRQb2ludCwgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjaylcbiAgICB9IGVsc2UgaWYoZ2xvYmFsLlhNTEh0dHBSZXF1ZXN0KXtcbiAgICAgIGxldCByZXEgPSBuZXcgZ2xvYmFsLlhNTEh0dHBSZXF1ZXN0KCkgLy8gSUU3KywgRmlyZWZveCwgQ2hyb21lLCBPcGVyYSwgU2FmYXJpXG4gICAgICByZXR1cm4gdGhpcy54aHJSZXF1ZXN0KHJlcSwgbWV0aG9kLCBlbmRQb2ludCwgaGVhZGVycywgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjaylcbiAgICB9IGVsc2UgaWYoZ2xvYmFsLmZldGNoICYmIGdsb2JhbC5BYm9ydENvbnRyb2xsZXIpe1xuICAgICAgLy8gRmV0Y2ggd2l0aCBBYm9ydENvbnRyb2xsZXIgZm9yIG1vZGVybiBicm93c2Vyc1xuICAgICAgcmV0dXJuIHRoaXMuZmV0Y2hSZXF1ZXN0KG1ldGhvZCwgZW5kUG9pbnQsIGhlYWRlcnMsIGJvZHksIHRpbWVvdXQsIG9udGltZW91dCwgY2FsbGJhY2spXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHN1aXRhYmxlIFhNTEh0dHBSZXF1ZXN0IGltcGxlbWVudGF0aW9uIGZvdW5kXCIpXG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGZldGNoUmVxdWVzdChtZXRob2QsIGVuZFBvaW50LCBoZWFkZXJzLCBib2R5LCB0aW1lb3V0LCBvbnRpbWVvdXQsIGNhbGxiYWNrKXtcbiAgICBsZXQgb3B0aW9ucyA9IHtcbiAgICAgIG1ldGhvZCxcbiAgICAgIGhlYWRlcnMsXG4gICAgICBib2R5LFxuICAgIH1cbiAgICBsZXQgY29udHJvbGxlciA9IG51bGxcbiAgICBpZih0aW1lb3V0KXtcbiAgICAgIGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKClcbiAgICAgIGNvbnN0IF90aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgdGltZW91dClcbiAgICAgIG9wdGlvbnMuc2lnbmFsID0gY29udHJvbGxlci5zaWduYWxcbiAgICB9XG4gICAgZ2xvYmFsLmZldGNoKGVuZFBvaW50LCBvcHRpb25zKVxuICAgICAgLnRoZW4ocmVzcG9uc2UgPT4gcmVzcG9uc2UudGV4dCgpKVxuICAgICAgLnRoZW4oZGF0YSA9PiB0aGlzLnBhcnNlSlNPTihkYXRhKSlcbiAgICAgIC50aGVuKGRhdGEgPT4gY2FsbGJhY2sgJiYgY2FsbGJhY2soZGF0YSkpXG4gICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgaWYoZXJyLm5hbWUgPT09IFwiQWJvcnRFcnJvclwiICYmIG9udGltZW91dCl7XG4gICAgICAgICAgb250aW1lb3V0KClcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhudWxsKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIHJldHVybiBjb250cm9sbGVyXG4gIH1cblxuICBzdGF0aWMgeGRvbWFpblJlcXVlc3QocmVxLCBtZXRob2QsIGVuZFBvaW50LCBib2R5LCB0aW1lb3V0LCBvbnRpbWVvdXQsIGNhbGxiYWNrKXtcbiAgICByZXEudGltZW91dCA9IHRpbWVvdXRcbiAgICByZXEub3BlbihtZXRob2QsIGVuZFBvaW50KVxuICAgIHJlcS5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICBsZXQgcmVzcG9uc2UgPSB0aGlzLnBhcnNlSlNPTihyZXEucmVzcG9uc2VUZXh0KVxuICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2socmVzcG9uc2UpXG4gICAgfVxuICAgIGlmKG9udGltZW91dCl7IHJlcS5vbnRpbWVvdXQgPSBvbnRpbWVvdXQgfVxuXG4gICAgLy8gV29yayBhcm91bmQgYnVnIGluIElFOSB0aGF0IHJlcXVpcmVzIGFuIGF0dGFjaGVkIG9ucHJvZ3Jlc3MgaGFuZGxlclxuICAgIHJlcS5vbnByb2dyZXNzID0gKCkgPT4geyB9XG5cbiAgICByZXEuc2VuZChib2R5KVxuICAgIHJldHVybiByZXFcbiAgfVxuXG4gIHN0YXRpYyB4aHJSZXF1ZXN0KHJlcSwgbWV0aG9kLCBlbmRQb2ludCwgaGVhZGVycywgYm9keSwgdGltZW91dCwgb250aW1lb3V0LCBjYWxsYmFjayl7XG4gICAgcmVxLm9wZW4obWV0aG9kLCBlbmRQb2ludCwgdHJ1ZSlcbiAgICByZXEudGltZW91dCA9IHRpbWVvdXRcbiAgICBmb3IobGV0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhoZWFkZXJzKSl7XG4gICAgICByZXEuc2V0UmVxdWVzdEhlYWRlcihrZXksIHZhbHVlKVxuICAgIH1cbiAgICByZXEub25lcnJvciA9ICgpID0+IGNhbGxiYWNrICYmIGNhbGxiYWNrKG51bGwpXG4gICAgcmVxLm9ucmVhZHlzdGF0ZWNoYW5nZSA9ICgpID0+IHtcbiAgICAgIGlmKHJlcS5yZWFkeVN0YXRlID09PSBYSFJfU1RBVEVTLmNvbXBsZXRlICYmIGNhbGxiYWNrKXtcbiAgICAgICAgbGV0IHJlc3BvbnNlID0gdGhpcy5wYXJzZUpTT04ocmVxLnJlc3BvbnNlVGV4dClcbiAgICAgICAgY2FsbGJhY2socmVzcG9uc2UpXG4gICAgICB9XG4gICAgfVxuICAgIGlmKG9udGltZW91dCl7IHJlcS5vbnRpbWVvdXQgPSBvbnRpbWVvdXQgfVxuXG4gICAgcmVxLnNlbmQoYm9keSlcbiAgICByZXR1cm4gcmVxXG4gIH1cblxuICBzdGF0aWMgcGFyc2VKU09OKHJlc3Ape1xuICAgIGlmKCFyZXNwIHx8IHJlc3AgPT09IFwiXCIpeyByZXR1cm4gbnVsbCB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVzcClcbiAgICB9IGNhdGNoIHtcbiAgICAgIGNvbnNvbGUgJiYgY29uc29sZS5sb2coXCJmYWlsZWQgdG8gcGFyc2UgSlNPTiByZXNwb25zZVwiLCByZXNwKVxuICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgc2VyaWFsaXplKG9iaiwgcGFyZW50S2V5KXtcbiAgICBsZXQgcXVlcnlTdHIgPSBbXVxuICAgIGZvcih2YXIga2V5IGluIG9iail7XG4gICAgICBpZighT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSl7IGNvbnRpbnVlIH1cbiAgICAgIGxldCBwYXJhbUtleSA9IHBhcmVudEtleSA/IGAke3BhcmVudEtleX1bJHtrZXl9XWAgOiBrZXlcbiAgICAgIGxldCBwYXJhbVZhbCA9IG9ialtrZXldXG4gICAgICBpZih0eXBlb2YgcGFyYW1WYWwgPT09IFwib2JqZWN0XCIpe1xuICAgICAgICBxdWVyeVN0ci5wdXNoKHRoaXMuc2VyaWFsaXplKHBhcmFtVmFsLCBwYXJhbUtleSkpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBxdWVyeVN0ci5wdXNoKGVuY29kZVVSSUNvbXBvbmVudChwYXJhbUtleSkgKyBcIj1cIiArIGVuY29kZVVSSUNvbXBvbmVudChwYXJhbVZhbCkpXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBxdWVyeVN0ci5qb2luKFwiJlwiKVxuICB9XG5cbiAgc3RhdGljIGFwcGVuZFBhcmFtcyh1cmwsIHBhcmFtcyl7XG4gICAgaWYoT2JqZWN0LmtleXMocGFyYW1zKS5sZW5ndGggPT09IDApeyByZXR1cm4gdXJsIH1cblxuICAgIGxldCBwcmVmaXggPSB1cmwubWF0Y2goL1xcPy8pID8gXCImXCIgOiBcIj9cIlxuICAgIHJldHVybiBgJHt1cmx9JHtwcmVmaXh9JHt0aGlzLnNlcmlhbGl6ZShwYXJhbXMpfWBcbiAgfVxufVxuIiwgImltcG9ydCB7XG4gIFNPQ0tFVF9TVEFURVMsXG4gIFRSQU5TUE9SVFMsXG4gIEFVVEhfVE9LRU5fUFJFRklYXG59IGZyb20gXCIuL2NvbnN0YW50c1wiXG5cbmltcG9ydCBBamF4IGZyb20gXCIuL2FqYXhcIlxuXG5sZXQgYXJyYXlCdWZmZXJUb0Jhc2U2NCA9IChidWZmZXIpID0+IHtcbiAgbGV0IGJpbmFyeSA9IFwiXCJcbiAgbGV0IGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoYnVmZmVyKVxuICBsZXQgbGVuID0gYnl0ZXMuYnl0ZUxlbmd0aFxuICBmb3IobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspeyBiaW5hcnkgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSkgfVxuICByZXR1cm4gYnRvYShiaW5hcnkpXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExvbmdQb2xsIHtcblxuICBjb25zdHJ1Y3RvcihlbmRQb2ludCwgcHJvdG9jb2xzKXtcbiAgICAvLyB3ZSBvbmx5IHN1cHBvcnQgc3VicHJvdG9jb2xzIGZvciBhdXRoVG9rZW5cbiAgICAvLyBbXCJwaG9lbml4XCIsIFwiYmFzZTY0dXJsLmJlYXJlci5waHguQkFTRTY0X0VOQ09ERURfVE9LRU5cIl1cbiAgICBpZihwcm90b2NvbHMgJiYgcHJvdG9jb2xzLmxlbmd0aCA9PT0gMiAmJiBwcm90b2NvbHNbMV0uc3RhcnRzV2l0aChBVVRIX1RPS0VOX1BSRUZJWCkpe1xuICAgICAgdGhpcy5hdXRoVG9rZW4gPSBhdG9iKHByb3RvY29sc1sxXS5zbGljZShBVVRIX1RPS0VOX1BSRUZJWC5sZW5ndGgpKVxuICAgIH1cbiAgICB0aGlzLmVuZFBvaW50ID0gbnVsbFxuICAgIHRoaXMudG9rZW4gPSBudWxsXG4gICAgdGhpcy5za2lwSGVhcnRiZWF0ID0gdHJ1ZVxuICAgIHRoaXMucmVxcyA9IG5ldyBTZXQoKVxuICAgIHRoaXMuYXdhaXRpbmdCYXRjaEFjayA9IGZhbHNlXG4gICAgdGhpcy5jdXJyZW50QmF0Y2ggPSBudWxsXG4gICAgdGhpcy5jdXJyZW50QmF0Y2hUaW1lciA9IG51bGxcbiAgICB0aGlzLmJhdGNoQnVmZmVyID0gW11cbiAgICB0aGlzLm9ub3BlbiA9IGZ1bmN0aW9uICgpeyB9IC8vIG5vb3BcbiAgICB0aGlzLm9uZXJyb3IgPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgdGhpcy5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgdGhpcy5vbmNsb3NlID0gZnVuY3Rpb24gKCl7IH0gLy8gbm9vcFxuICAgIHRoaXMucG9sbEVuZHBvaW50ID0gdGhpcy5ub3JtYWxpemVFbmRwb2ludChlbmRQb2ludClcbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBTT0NLRVRfU1RBVEVTLmNvbm5lY3RpbmdcbiAgICAvLyB3ZSBtdXN0IHdhaXQgZm9yIHRoZSBjYWxsZXIgdG8gZmluaXNoIHNldHRpbmcgdXAgb3VyIGNhbGxiYWNrcyBhbmQgdGltZW91dCBwcm9wZXJ0aWVzXG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnBvbGwoKSwgMClcbiAgfVxuXG4gIG5vcm1hbGl6ZUVuZHBvaW50KGVuZFBvaW50KXtcbiAgICByZXR1cm4gKGVuZFBvaW50XG4gICAgICAucmVwbGFjZShcIndzOi8vXCIsIFwiaHR0cDovL1wiKVxuICAgICAgLnJlcGxhY2UoXCJ3c3M6Ly9cIiwgXCJodHRwczovL1wiKVxuICAgICAgLnJlcGxhY2UobmV3IFJlZ0V4cChcIiguKilcXC9cIiArIFRSQU5TUE9SVFMud2Vic29ja2V0KSwgXCIkMS9cIiArIFRSQU5TUE9SVFMubG9uZ3BvbGwpKVxuICB9XG5cbiAgZW5kcG9pbnRVUkwoKXtcbiAgICByZXR1cm4gQWpheC5hcHBlbmRQYXJhbXModGhpcy5wb2xsRW5kcG9pbnQsIHt0b2tlbjogdGhpcy50b2tlbn0pXG4gIH1cblxuICBjbG9zZUFuZFJldHJ5KGNvZGUsIHJlYXNvbiwgd2FzQ2xlYW4pe1xuICAgIHRoaXMuY2xvc2UoY29kZSwgcmVhc29uLCB3YXNDbGVhbilcbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBTT0NLRVRfU1RBVEVTLmNvbm5lY3RpbmdcbiAgfVxuXG4gIG9udGltZW91dCgpe1xuICAgIHRoaXMub25lcnJvcihcInRpbWVvdXRcIilcbiAgICB0aGlzLmNsb3NlQW5kUmV0cnkoMTAwNSwgXCJ0aW1lb3V0XCIsIGZhbHNlKVxuICB9XG5cbiAgaXNBY3RpdmUoKXsgcmV0dXJuIHRoaXMucmVhZHlTdGF0ZSA9PT0gU09DS0VUX1NUQVRFUy5vcGVuIHx8IHRoaXMucmVhZHlTdGF0ZSA9PT0gU09DS0VUX1NUQVRFUy5jb25uZWN0aW5nIH1cblxuICBwb2xsKCl7XG4gICAgY29uc3QgaGVhZGVycyA9IHtcIkFjY2VwdFwiOiBcImFwcGxpY2F0aW9uL2pzb25cIn1cbiAgICBpZih0aGlzLmF1dGhUb2tlbil7XG4gICAgICBoZWFkZXJzW1wiWC1QaG9lbml4LUF1dGhUb2tlblwiXSA9IHRoaXMuYXV0aFRva2VuXG4gICAgfVxuICAgIHRoaXMuYWpheChcIkdFVFwiLCBoZWFkZXJzLCBudWxsLCAoKSA9PiB0aGlzLm9udGltZW91dCgpLCByZXNwID0+IHtcbiAgICAgIGlmKHJlc3Ape1xuICAgICAgICB2YXIge3N0YXR1cywgdG9rZW4sIG1lc3NhZ2VzfSA9IHJlc3BcbiAgICAgICAgdGhpcy50b2tlbiA9IHRva2VuXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdGF0dXMgPSAwXG4gICAgICB9XG5cbiAgICAgIHN3aXRjaChzdGF0dXMpe1xuICAgICAgICBjYXNlIDIwMDpcbiAgICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKG1zZyA9PiB7XG4gICAgICAgICAgICAvLyBUYXNrcyBhcmUgd2hhdCB0aGluZ3MgbGlrZSBldmVudCBoYW5kbGVycywgc2V0VGltZW91dCBjYWxsYmFja3MsXG4gICAgICAgICAgICAvLyBwcm9taXNlIHJlc29sdmVzIGFuZCBtb3JlIGFyZSBydW4gd2l0aGluLlxuICAgICAgICAgICAgLy8gSW4gbW9kZXJuIGJyb3dzZXJzLCB0aGVyZSBhcmUgdHdvIGRpZmZlcmVudCBraW5kcyBvZiB0YXNrcyxcbiAgICAgICAgICAgIC8vIG1pY3JvdGFza3MgYW5kIG1hY3JvdGFza3MuXG4gICAgICAgICAgICAvLyBNaWNyb3Rhc2tzIGFyZSBtYWlubHkgdXNlZCBmb3IgUHJvbWlzZXMsIHdoaWxlIG1hY3JvdGFza3MgYXJlXG4gICAgICAgICAgICAvLyB1c2VkIGZvciBldmVyeXRoaW5nIGVsc2UuXG4gICAgICAgICAgICAvLyBNaWNyb3Rhc2tzIGFsd2F5cyBoYXZlIHByaW9yaXR5IG92ZXIgbWFjcm90YXNrcy4gSWYgdGhlIEpTIGVuZ2luZVxuICAgICAgICAgICAgLy8gaXMgbG9va2luZyBmb3IgYSB0YXNrIHRvIHJ1biwgaXQgd2lsbCBhbHdheXMgdHJ5IHRvIGVtcHR5IHRoZVxuICAgICAgICAgICAgLy8gbWljcm90YXNrIHF1ZXVlIGJlZm9yZSBhdHRlbXB0aW5nIHRvIHJ1biBhbnl0aGluZyBmcm9tIHRoZVxuICAgICAgICAgICAgLy8gbWFjcm90YXNrIHF1ZXVlLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIEZvciB0aGUgV2ViU29ja2V0IHRyYW5zcG9ydCwgbWVzc2FnZXMgYWx3YXlzIGFycml2ZSBpbiB0aGVpciBvd25cbiAgICAgICAgICAgIC8vIGV2ZW50LiBUaGlzIG1lYW5zIHRoYXQgaWYgYW55IHByb21pc2VzIGFyZSByZXNvbHZlZCBmcm9tIHdpdGhpbixcbiAgICAgICAgICAgIC8vIHRoZWlyIGNhbGxiYWNrcyB3aWxsIGFsd2F5cyBmaW5pc2ggZXhlY3V0aW9uIGJ5IHRoZSB0aW1lIHRoZVxuICAgICAgICAgICAgLy8gbmV4dCBtZXNzYWdlIGV2ZW50IGhhbmRsZXIgaXMgcnVuLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIEluIG9yZGVyIHRvIGVtdWxhdGUgdGhpcyBiZWhhdmlvdXIsIHdlIG5lZWQgdG8gbWFrZSBzdXJlIGVhY2hcbiAgICAgICAgICAgIC8vIG9ubWVzc2FnZSBoYW5kbGVyIGlzIHJ1biB3aXRoaW4gaXRzIG93biBtYWNyb3Rhc2suXG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMub25tZXNzYWdlKHtkYXRhOiBtc2d9KSwgMClcbiAgICAgICAgICB9KVxuICAgICAgICAgIHRoaXMucG9sbCgpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyMDQ6XG4gICAgICAgICAgdGhpcy5wb2xsKClcbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQxMDpcbiAgICAgICAgICB0aGlzLnJlYWR5U3RhdGUgPSBTT0NLRVRfU1RBVEVTLm9wZW5cbiAgICAgICAgICB0aGlzLm9ub3Blbih7fSlcbiAgICAgICAgICB0aGlzLnBvbGwoKVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgNDAzOlxuICAgICAgICAgIHRoaXMub25lcnJvcig0MDMpXG4gICAgICAgICAgdGhpcy5jbG9zZSgxMDA4LCBcImZvcmJpZGRlblwiLCBmYWxzZSlcbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDA6XG4gICAgICAgIGNhc2UgNTAwOlxuICAgICAgICAgIHRoaXMub25lcnJvcig1MDApXG4gICAgICAgICAgdGhpcy5jbG9zZUFuZFJldHJ5KDEwMTEsIFwiaW50ZXJuYWwgc2VydmVyIGVycm9yXCIsIDUwMClcbiAgICAgICAgICBicmVha1xuICAgICAgICBkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoYHVuaGFuZGxlZCBwb2xsIHN0YXR1cyAke3N0YXR1c31gKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvLyB3ZSBjb2xsZWN0IGFsbCBwdXNoZXMgd2l0aGluIHRoZSBjdXJyZW50IGV2ZW50IGxvb3AgYnlcbiAgLy8gc2V0VGltZW91dCAwLCB3aGljaCBvcHRpbWl6ZXMgYmFjay10by1iYWNrIHByb2NlZHVyYWxcbiAgLy8gcHVzaGVzIGFnYWluc3QgYW4gZW1wdHkgYnVmZmVyXG5cbiAgc2VuZChib2R5KXtcbiAgICBpZih0eXBlb2YoYm9keSkgIT09IFwic3RyaW5nXCIpeyBib2R5ID0gYXJyYXlCdWZmZXJUb0Jhc2U2NChib2R5KSB9XG4gICAgaWYodGhpcy5jdXJyZW50QmF0Y2gpe1xuICAgICAgdGhpcy5jdXJyZW50QmF0Y2gucHVzaChib2R5KVxuICAgIH0gZWxzZSBpZih0aGlzLmF3YWl0aW5nQmF0Y2hBY2spe1xuICAgICAgdGhpcy5iYXRjaEJ1ZmZlci5wdXNoKGJvZHkpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3VycmVudEJhdGNoID0gW2JvZHldXG4gICAgICB0aGlzLmN1cnJlbnRCYXRjaFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuYmF0Y2hTZW5kKHRoaXMuY3VycmVudEJhdGNoKVxuICAgICAgICB0aGlzLmN1cnJlbnRCYXRjaCA9IG51bGxcbiAgICAgIH0sIDApXG4gICAgfVxuICB9XG5cbiAgYmF0Y2hTZW5kKG1lc3NhZ2VzKXtcbiAgICB0aGlzLmF3YWl0aW5nQmF0Y2hBY2sgPSB0cnVlXG4gICAgdGhpcy5hamF4KFwiUE9TVFwiLCB7XCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi94LW5kanNvblwifSwgbWVzc2FnZXMuam9pbihcIlxcblwiKSwgKCkgPT4gdGhpcy5vbmVycm9yKFwidGltZW91dFwiKSwgcmVzcCA9PiB7XG4gICAgICB0aGlzLmF3YWl0aW5nQmF0Y2hBY2sgPSBmYWxzZVxuICAgICAgaWYoIXJlc3AgfHwgcmVzcC5zdGF0dXMgIT09IDIwMCl7XG4gICAgICAgIHRoaXMub25lcnJvcihyZXNwICYmIHJlc3Auc3RhdHVzKVxuICAgICAgICB0aGlzLmNsb3NlQW5kUmV0cnkoMTAxMSwgXCJpbnRlcm5hbCBzZXJ2ZXIgZXJyb3JcIiwgZmFsc2UpXG4gICAgICB9IGVsc2UgaWYodGhpcy5iYXRjaEJ1ZmZlci5sZW5ndGggPiAwKXtcbiAgICAgICAgdGhpcy5iYXRjaFNlbmQodGhpcy5iYXRjaEJ1ZmZlcilcbiAgICAgICAgdGhpcy5iYXRjaEJ1ZmZlciA9IFtdXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIGNsb3NlKGNvZGUsIHJlYXNvbiwgd2FzQ2xlYW4pe1xuICAgIGZvcihsZXQgcmVxIG9mIHRoaXMucmVxcyl7IHJlcS5hYm9ydCgpIH1cbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBTT0NLRVRfU1RBVEVTLmNsb3NlZFxuICAgIGxldCBvcHRzID0gT2JqZWN0LmFzc2lnbih7Y29kZTogMTAwMCwgcmVhc29uOiB1bmRlZmluZWQsIHdhc0NsZWFuOiB0cnVlfSwge2NvZGUsIHJlYXNvbiwgd2FzQ2xlYW59KVxuICAgIHRoaXMuYmF0Y2hCdWZmZXIgPSBbXVxuICAgIGNsZWFyVGltZW91dCh0aGlzLmN1cnJlbnRCYXRjaFRpbWVyKVxuICAgIHRoaXMuY3VycmVudEJhdGNoVGltZXIgPSBudWxsXG4gICAgaWYodHlwZW9mKENsb3NlRXZlbnQpICE9PSBcInVuZGVmaW5lZFwiKXtcbiAgICAgIHRoaXMub25jbG9zZShuZXcgQ2xvc2VFdmVudChcImNsb3NlXCIsIG9wdHMpKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm9uY2xvc2Uob3B0cylcbiAgICB9XG4gIH1cblxuICBhamF4KG1ldGhvZCwgaGVhZGVycywgYm9keSwgb25DYWxsZXJUaW1lb3V0LCBjYWxsYmFjayl7XG4gICAgbGV0IHJlcVxuICAgIGxldCBvbnRpbWVvdXQgPSAoKSA9PiB7XG4gICAgICB0aGlzLnJlcXMuZGVsZXRlKHJlcSlcbiAgICAgIG9uQ2FsbGVyVGltZW91dCgpXG4gICAgfVxuICAgIHJlcSA9IEFqYXgucmVxdWVzdChtZXRob2QsIHRoaXMuZW5kcG9pbnRVUkwoKSwgaGVhZGVycywgYm9keSwgdGhpcy50aW1lb3V0LCBvbnRpbWVvdXQsIHJlc3AgPT4ge1xuICAgICAgdGhpcy5yZXFzLmRlbGV0ZShyZXEpXG4gICAgICBpZih0aGlzLmlzQWN0aXZlKCkpeyBjYWxsYmFjayhyZXNwKSB9XG4gICAgfSlcbiAgICB0aGlzLnJlcXMuYWRkKHJlcSlcbiAgfVxufVxuIiwgIi8qKlxuICogSW5pdGlhbGl6ZXMgdGhlIFByZXNlbmNlXG4gKiBAcGFyYW0ge0NoYW5uZWx9IGNoYW5uZWwgLSBUaGUgQ2hhbm5lbFxuICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBUaGUgb3B0aW9ucyxcbiAqICAgICAgICBmb3IgZXhhbXBsZSBge2V2ZW50czoge3N0YXRlOiBcInN0YXRlXCIsIGRpZmY6IFwiZGlmZlwifX1gXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFByZXNlbmNlIHtcblxuICBjb25zdHJ1Y3RvcihjaGFubmVsLCBvcHRzID0ge30pe1xuICAgIGxldCBldmVudHMgPSBvcHRzLmV2ZW50cyB8fCB7c3RhdGU6IFwicHJlc2VuY2Vfc3RhdGVcIiwgZGlmZjogXCJwcmVzZW5jZV9kaWZmXCJ9XG4gICAgdGhpcy5zdGF0ZSA9IHt9XG4gICAgdGhpcy5wZW5kaW5nRGlmZnMgPSBbXVxuICAgIHRoaXMuY2hhbm5lbCA9IGNoYW5uZWxcbiAgICB0aGlzLmpvaW5SZWYgPSBudWxsXG4gICAgdGhpcy5jYWxsZXIgPSB7XG4gICAgICBvbkpvaW46IGZ1bmN0aW9uICgpeyB9LFxuICAgICAgb25MZWF2ZTogZnVuY3Rpb24gKCl7IH0sXG4gICAgICBvblN5bmM6IGZ1bmN0aW9uICgpeyB9XG4gICAgfVxuXG4gICAgdGhpcy5jaGFubmVsLm9uKGV2ZW50cy5zdGF0ZSwgbmV3U3RhdGUgPT4ge1xuICAgICAgbGV0IHtvbkpvaW4sIG9uTGVhdmUsIG9uU3luY30gPSB0aGlzLmNhbGxlclxuXG4gICAgICB0aGlzLmpvaW5SZWYgPSB0aGlzLmNoYW5uZWwuam9pblJlZigpXG4gICAgICB0aGlzLnN0YXRlID0gUHJlc2VuY2Uuc3luY1N0YXRlKHRoaXMuc3RhdGUsIG5ld1N0YXRlLCBvbkpvaW4sIG9uTGVhdmUpXG5cbiAgICAgIHRoaXMucGVuZGluZ0RpZmZzLmZvckVhY2goZGlmZiA9PiB7XG4gICAgICAgIHRoaXMuc3RhdGUgPSBQcmVzZW5jZS5zeW5jRGlmZih0aGlzLnN0YXRlLCBkaWZmLCBvbkpvaW4sIG9uTGVhdmUpXG4gICAgICB9KVxuICAgICAgdGhpcy5wZW5kaW5nRGlmZnMgPSBbXVxuICAgICAgb25TeW5jKClcbiAgICB9KVxuXG4gICAgdGhpcy5jaGFubmVsLm9uKGV2ZW50cy5kaWZmLCBkaWZmID0+IHtcbiAgICAgIGxldCB7b25Kb2luLCBvbkxlYXZlLCBvblN5bmN9ID0gdGhpcy5jYWxsZXJcblxuICAgICAgaWYodGhpcy5pblBlbmRpbmdTeW5jU3RhdGUoKSl7XG4gICAgICAgIHRoaXMucGVuZGluZ0RpZmZzLnB1c2goZGlmZilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc3RhdGUgPSBQcmVzZW5jZS5zeW5jRGlmZih0aGlzLnN0YXRlLCBkaWZmLCBvbkpvaW4sIG9uTGVhdmUpXG4gICAgICAgIG9uU3luYygpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIG9uSm9pbihjYWxsYmFjayl7IHRoaXMuY2FsbGVyLm9uSm9pbiA9IGNhbGxiYWNrIH1cblxuICBvbkxlYXZlKGNhbGxiYWNrKXsgdGhpcy5jYWxsZXIub25MZWF2ZSA9IGNhbGxiYWNrIH1cblxuICBvblN5bmMoY2FsbGJhY2speyB0aGlzLmNhbGxlci5vblN5bmMgPSBjYWxsYmFjayB9XG5cbiAgbGlzdChieSl7IHJldHVybiBQcmVzZW5jZS5saXN0KHRoaXMuc3RhdGUsIGJ5KSB9XG5cbiAgaW5QZW5kaW5nU3luY1N0YXRlKCl7XG4gICAgcmV0dXJuICF0aGlzLmpvaW5SZWYgfHwgKHRoaXMuam9pblJlZiAhPT0gdGhpcy5jaGFubmVsLmpvaW5SZWYoKSlcbiAgfVxuXG4gIC8vIGxvd2VyLWxldmVsIHB1YmxpYyBzdGF0aWMgQVBJXG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gc3luYyB0aGUgbGlzdCBvZiBwcmVzZW5jZXMgb24gdGhlIHNlcnZlclxuICAgKiB3aXRoIHRoZSBjbGllbnQncyBzdGF0ZS4gQW4gb3B0aW9uYWwgYG9uSm9pbmAgYW5kIGBvbkxlYXZlYCBjYWxsYmFjayBjYW5cbiAgICogYmUgcHJvdmlkZWQgdG8gcmVhY3QgdG8gY2hhbmdlcyBpbiB0aGUgY2xpZW50J3MgbG9jYWwgcHJlc2VuY2VzIGFjcm9zc1xuICAgKiBkaXNjb25uZWN0cyBhbmQgcmVjb25uZWN0cyB3aXRoIHRoZSBzZXJ2ZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcmVzZW5jZX1cbiAgICovXG4gIHN0YXRpYyBzeW5jU3RhdGUoY3VycmVudFN0YXRlLCBuZXdTdGF0ZSwgb25Kb2luLCBvbkxlYXZlKXtcbiAgICBsZXQgc3RhdGUgPSB0aGlzLmNsb25lKGN1cnJlbnRTdGF0ZSlcbiAgICBsZXQgam9pbnMgPSB7fVxuICAgIGxldCBsZWF2ZXMgPSB7fVxuXG4gICAgdGhpcy5tYXAoc3RhdGUsIChrZXksIHByZXNlbmNlKSA9PiB7XG4gICAgICBpZighbmV3U3RhdGVba2V5XSl7XG4gICAgICAgIGxlYXZlc1trZXldID0gcHJlc2VuY2VcbiAgICAgIH1cbiAgICB9KVxuICAgIHRoaXMubWFwKG5ld1N0YXRlLCAoa2V5LCBuZXdQcmVzZW5jZSkgPT4ge1xuICAgICAgbGV0IGN1cnJlbnRQcmVzZW5jZSA9IHN0YXRlW2tleV1cbiAgICAgIGlmKGN1cnJlbnRQcmVzZW5jZSl7XG4gICAgICAgIGxldCBuZXdSZWZzID0gbmV3UHJlc2VuY2UubWV0YXMubWFwKG0gPT4gbS5waHhfcmVmKVxuICAgICAgICBsZXQgY3VyUmVmcyA9IGN1cnJlbnRQcmVzZW5jZS5tZXRhcy5tYXAobSA9PiBtLnBoeF9yZWYpXG4gICAgICAgIGxldCBqb2luZWRNZXRhcyA9IG5ld1ByZXNlbmNlLm1ldGFzLmZpbHRlcihtID0+IGN1clJlZnMuaW5kZXhPZihtLnBoeF9yZWYpIDwgMClcbiAgICAgICAgbGV0IGxlZnRNZXRhcyA9IGN1cnJlbnRQcmVzZW5jZS5tZXRhcy5maWx0ZXIobSA9PiBuZXdSZWZzLmluZGV4T2YobS5waHhfcmVmKSA8IDApXG4gICAgICAgIGlmKGpvaW5lZE1ldGFzLmxlbmd0aCA+IDApe1xuICAgICAgICAgIGpvaW5zW2tleV0gPSBuZXdQcmVzZW5jZVxuICAgICAgICAgIGpvaW5zW2tleV0ubWV0YXMgPSBqb2luZWRNZXRhc1xuICAgICAgICB9XG4gICAgICAgIGlmKGxlZnRNZXRhcy5sZW5ndGggPiAwKXtcbiAgICAgICAgICBsZWF2ZXNba2V5XSA9IHRoaXMuY2xvbmUoY3VycmVudFByZXNlbmNlKVxuICAgICAgICAgIGxlYXZlc1trZXldLm1ldGFzID0gbGVmdE1ldGFzXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGpvaW5zW2tleV0gPSBuZXdQcmVzZW5jZVxuICAgICAgfVxuICAgIH0pXG4gICAgcmV0dXJuIHRoaXMuc3luY0RpZmYoc3RhdGUsIHtqb2luczogam9pbnMsIGxlYXZlczogbGVhdmVzfSwgb25Kb2luLCBvbkxlYXZlKVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIFVzZWQgdG8gc3luYyBhIGRpZmYgb2YgcHJlc2VuY2Ugam9pbiBhbmQgbGVhdmVcbiAgICogZXZlbnRzIGZyb20gdGhlIHNlcnZlciwgYXMgdGhleSBoYXBwZW4uIExpa2UgYHN5bmNTdGF0ZWAsIGBzeW5jRGlmZmBcbiAgICogYWNjZXB0cyBvcHRpb25hbCBgb25Kb2luYCBhbmQgYG9uTGVhdmVgIGNhbGxiYWNrcyB0byByZWFjdCB0byBhIHVzZXJcbiAgICogam9pbmluZyBvciBsZWF2aW5nIGZyb20gYSBkZXZpY2UuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcmVzZW5jZX1cbiAgICovXG4gIHN0YXRpYyBzeW5jRGlmZihzdGF0ZSwgZGlmZiwgb25Kb2luLCBvbkxlYXZlKXtcbiAgICBsZXQge2pvaW5zLCBsZWF2ZXN9ID0gdGhpcy5jbG9uZShkaWZmKVxuICAgIGlmKCFvbkpvaW4peyBvbkpvaW4gPSBmdW5jdGlvbiAoKXsgfSB9XG4gICAgaWYoIW9uTGVhdmUpeyBvbkxlYXZlID0gZnVuY3Rpb24gKCl7IH0gfVxuXG4gICAgdGhpcy5tYXAoam9pbnMsIChrZXksIG5ld1ByZXNlbmNlKSA9PiB7XG4gICAgICBsZXQgY3VycmVudFByZXNlbmNlID0gc3RhdGVba2V5XVxuICAgICAgc3RhdGVba2V5XSA9IHRoaXMuY2xvbmUobmV3UHJlc2VuY2UpXG4gICAgICBpZihjdXJyZW50UHJlc2VuY2Upe1xuICAgICAgICBsZXQgam9pbmVkUmVmcyA9IHN0YXRlW2tleV0ubWV0YXMubWFwKG0gPT4gbS5waHhfcmVmKVxuICAgICAgICBsZXQgY3VyTWV0YXMgPSBjdXJyZW50UHJlc2VuY2UubWV0YXMuZmlsdGVyKG0gPT4gam9pbmVkUmVmcy5pbmRleE9mKG0ucGh4X3JlZikgPCAwKVxuICAgICAgICBzdGF0ZVtrZXldLm1ldGFzLnVuc2hpZnQoLi4uY3VyTWV0YXMpXG4gICAgICB9XG4gICAgICBvbkpvaW4oa2V5LCBjdXJyZW50UHJlc2VuY2UsIG5ld1ByZXNlbmNlKVxuICAgIH0pXG4gICAgdGhpcy5tYXAobGVhdmVzLCAoa2V5LCBsZWZ0UHJlc2VuY2UpID0+IHtcbiAgICAgIGxldCBjdXJyZW50UHJlc2VuY2UgPSBzdGF0ZVtrZXldXG4gICAgICBpZighY3VycmVudFByZXNlbmNlKXsgcmV0dXJuIH1cbiAgICAgIGxldCByZWZzVG9SZW1vdmUgPSBsZWZ0UHJlc2VuY2UubWV0YXMubWFwKG0gPT4gbS5waHhfcmVmKVxuICAgICAgY3VycmVudFByZXNlbmNlLm1ldGFzID0gY3VycmVudFByZXNlbmNlLm1ldGFzLmZpbHRlcihwID0+IHtcbiAgICAgICAgcmV0dXJuIHJlZnNUb1JlbW92ZS5pbmRleE9mKHAucGh4X3JlZikgPCAwXG4gICAgICB9KVxuICAgICAgb25MZWF2ZShrZXksIGN1cnJlbnRQcmVzZW5jZSwgbGVmdFByZXNlbmNlKVxuICAgICAgaWYoY3VycmVudFByZXNlbmNlLm1ldGFzLmxlbmd0aCA9PT0gMCl7XG4gICAgICAgIGRlbGV0ZSBzdGF0ZVtrZXldXG4gICAgICB9XG4gICAgfSlcbiAgICByZXR1cm4gc3RhdGVcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBwcmVzZW5jZXMsIHdpdGggc2VsZWN0ZWQgbWV0YWRhdGEuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwcmVzZW5jZXNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2hvb3NlclxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJlc2VuY2V9XG4gICAqL1xuICBzdGF0aWMgbGlzdChwcmVzZW5jZXMsIGNob29zZXIpe1xuICAgIGlmKCFjaG9vc2VyKXsgY2hvb3NlciA9IGZ1bmN0aW9uIChrZXksIHByZXMpeyByZXR1cm4gcHJlcyB9IH1cblxuICAgIHJldHVybiB0aGlzLm1hcChwcmVzZW5jZXMsIChrZXksIHByZXNlbmNlKSA9PiB7XG4gICAgICByZXR1cm4gY2hvb3NlcihrZXksIHByZXNlbmNlKVxuICAgIH0pXG4gIH1cblxuICAvLyBwcml2YXRlXG5cbiAgc3RhdGljIG1hcChvYmosIGZ1bmMpe1xuICAgIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhvYmopLm1hcChrZXkgPT4gZnVuYyhrZXksIG9ialtrZXldKSlcbiAgfVxuXG4gIHN0YXRpYyBjbG9uZShvYmopeyByZXR1cm4gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShvYmopKSB9XG59XG4iLCAiLyogVGhlIGRlZmF1bHQgc2VyaWFsaXplciBmb3IgZW5jb2RpbmcgYW5kIGRlY29kaW5nIG1lc3NhZ2VzICovXG5pbXBvcnQge1xuICBDSEFOTkVMX0VWRU5UU1xufSBmcm9tIFwiLi9jb25zdGFudHNcIlxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIEhFQURFUl9MRU5HVEg6IDEsXG4gIE1FVEFfTEVOR1RIOiA0LFxuICBLSU5EUzoge3B1c2g6IDAsIHJlcGx5OiAxLCBicm9hZGNhc3Q6IDJ9LFxuXG4gIGVuY29kZShtc2csIGNhbGxiYWNrKXtcbiAgICBpZihtc2cucGF5bG9hZC5jb25zdHJ1Y3RvciA9PT0gQXJyYXlCdWZmZXIpe1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKHRoaXMuYmluYXJ5RW5jb2RlKG1zZykpXG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBwYXlsb2FkID0gW21zZy5qb2luX3JlZiwgbXNnLnJlZiwgbXNnLnRvcGljLCBtc2cuZXZlbnQsIG1zZy5wYXlsb2FkXVxuICAgICAgcmV0dXJuIGNhbGxiYWNrKEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKVxuICAgIH1cbiAgfSxcblxuICBkZWNvZGUocmF3UGF5bG9hZCwgY2FsbGJhY2spe1xuICAgIGlmKHJhd1BheWxvYWQuY29uc3RydWN0b3IgPT09IEFycmF5QnVmZmVyKXtcbiAgICAgIHJldHVybiBjYWxsYmFjayh0aGlzLmJpbmFyeURlY29kZShyYXdQYXlsb2FkKSlcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IFtqb2luX3JlZiwgcmVmLCB0b3BpYywgZXZlbnQsIHBheWxvYWRdID0gSlNPTi5wYXJzZShyYXdQYXlsb2FkKVxuICAgICAgcmV0dXJuIGNhbGxiYWNrKHtqb2luX3JlZiwgcmVmLCB0b3BpYywgZXZlbnQsIHBheWxvYWR9KVxuICAgIH1cbiAgfSxcblxuICAvLyBwcml2YXRlXG5cbiAgYmluYXJ5RW5jb2RlKG1lc3NhZ2Upe1xuICAgIGxldCB7am9pbl9yZWYsIHJlZiwgZXZlbnQsIHRvcGljLCBwYXlsb2FkfSA9IG1lc3NhZ2VcbiAgICBsZXQgbWV0YUxlbmd0aCA9IHRoaXMuTUVUQV9MRU5HVEggKyBqb2luX3JlZi5sZW5ndGggKyByZWYubGVuZ3RoICsgdG9waWMubGVuZ3RoICsgZXZlbnQubGVuZ3RoXG4gICAgbGV0IGhlYWRlciA9IG5ldyBBcnJheUJ1ZmZlcih0aGlzLkhFQURFUl9MRU5HVEggKyBtZXRhTGVuZ3RoKVxuICAgIGxldCB2aWV3ID0gbmV3IERhdGFWaWV3KGhlYWRlcilcbiAgICBsZXQgb2Zmc2V0ID0gMFxuXG4gICAgdmlldy5zZXRVaW50OChvZmZzZXQrKywgdGhpcy5LSU5EUy5wdXNoKSAvLyBraW5kXG4gICAgdmlldy5zZXRVaW50OChvZmZzZXQrKywgam9pbl9yZWYubGVuZ3RoKVxuICAgIHZpZXcuc2V0VWludDgob2Zmc2V0KyssIHJlZi5sZW5ndGgpXG4gICAgdmlldy5zZXRVaW50OChvZmZzZXQrKywgdG9waWMubGVuZ3RoKVxuICAgIHZpZXcuc2V0VWludDgob2Zmc2V0KyssIGV2ZW50Lmxlbmd0aClcbiAgICBBcnJheS5mcm9tKGpvaW5fcmVmLCBjaGFyID0+IHZpZXcuc2V0VWludDgob2Zmc2V0KyssIGNoYXIuY2hhckNvZGVBdCgwKSkpXG4gICAgQXJyYXkuZnJvbShyZWYsIGNoYXIgPT4gdmlldy5zZXRVaW50OChvZmZzZXQrKywgY2hhci5jaGFyQ29kZUF0KDApKSlcbiAgICBBcnJheS5mcm9tKHRvcGljLCBjaGFyID0+IHZpZXcuc2V0VWludDgob2Zmc2V0KyssIGNoYXIuY2hhckNvZGVBdCgwKSkpXG4gICAgQXJyYXkuZnJvbShldmVudCwgY2hhciA9PiB2aWV3LnNldFVpbnQ4KG9mZnNldCsrLCBjaGFyLmNoYXJDb2RlQXQoMCkpKVxuXG4gICAgdmFyIGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkoaGVhZGVyLmJ5dGVMZW5ndGggKyBwYXlsb2FkLmJ5dGVMZW5ndGgpXG4gICAgY29tYmluZWQuc2V0KG5ldyBVaW50OEFycmF5KGhlYWRlciksIDApXG4gICAgY29tYmluZWQuc2V0KG5ldyBVaW50OEFycmF5KHBheWxvYWQpLCBoZWFkZXIuYnl0ZUxlbmd0aClcblxuICAgIHJldHVybiBjb21iaW5lZC5idWZmZXJcbiAgfSxcblxuICBiaW5hcnlEZWNvZGUoYnVmZmVyKXtcbiAgICBsZXQgdmlldyA9IG5ldyBEYXRhVmlldyhidWZmZXIpXG4gICAgbGV0IGtpbmQgPSB2aWV3LmdldFVpbnQ4KDApXG4gICAgbGV0IGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoKVxuICAgIHN3aXRjaChraW5kKXtcbiAgICAgIGNhc2UgdGhpcy5LSU5EUy5wdXNoOiByZXR1cm4gdGhpcy5kZWNvZGVQdXNoKGJ1ZmZlciwgdmlldywgZGVjb2RlcilcbiAgICAgIGNhc2UgdGhpcy5LSU5EUy5yZXBseTogcmV0dXJuIHRoaXMuZGVjb2RlUmVwbHkoYnVmZmVyLCB2aWV3LCBkZWNvZGVyKVxuICAgICAgY2FzZSB0aGlzLktJTkRTLmJyb2FkY2FzdDogcmV0dXJuIHRoaXMuZGVjb2RlQnJvYWRjYXN0KGJ1ZmZlciwgdmlldywgZGVjb2RlcilcbiAgICB9XG4gIH0sXG5cbiAgZGVjb2RlUHVzaChidWZmZXIsIHZpZXcsIGRlY29kZXIpe1xuICAgIGxldCBqb2luUmVmU2l6ZSA9IHZpZXcuZ2V0VWludDgoMSlcbiAgICBsZXQgdG9waWNTaXplID0gdmlldy5nZXRVaW50OCgyKVxuICAgIGxldCBldmVudFNpemUgPSB2aWV3LmdldFVpbnQ4KDMpXG4gICAgbGV0IG9mZnNldCA9IHRoaXMuSEVBREVSX0xFTkdUSCArIHRoaXMuTUVUQV9MRU5HVEggLSAxIC8vIHB1c2hlcyBoYXZlIG5vIHJlZlxuICAgIGxldCBqb2luUmVmID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgam9pblJlZlNpemUpKVxuICAgIG9mZnNldCA9IG9mZnNldCArIGpvaW5SZWZTaXplXG4gICAgbGV0IHRvcGljID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgdG9waWNTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyB0b3BpY1NpemVcbiAgICBsZXQgZXZlbnQgPSBkZWNvZGVyLmRlY29kZShidWZmZXIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBldmVudFNpemUpKVxuICAgIG9mZnNldCA9IG9mZnNldCArIGV2ZW50U2l6ZVxuICAgIGxldCBkYXRhID0gYnVmZmVyLnNsaWNlKG9mZnNldCwgYnVmZmVyLmJ5dGVMZW5ndGgpXG4gICAgcmV0dXJuIHtqb2luX3JlZjogam9pblJlZiwgcmVmOiBudWxsLCB0b3BpYzogdG9waWMsIGV2ZW50OiBldmVudCwgcGF5bG9hZDogZGF0YX1cbiAgfSxcblxuICBkZWNvZGVSZXBseShidWZmZXIsIHZpZXcsIGRlY29kZXIpe1xuICAgIGxldCBqb2luUmVmU2l6ZSA9IHZpZXcuZ2V0VWludDgoMSlcbiAgICBsZXQgcmVmU2l6ZSA9IHZpZXcuZ2V0VWludDgoMilcbiAgICBsZXQgdG9waWNTaXplID0gdmlldy5nZXRVaW50OCgzKVxuICAgIGxldCBldmVudFNpemUgPSB2aWV3LmdldFVpbnQ4KDQpXG4gICAgbGV0IG9mZnNldCA9IHRoaXMuSEVBREVSX0xFTkdUSCArIHRoaXMuTUVUQV9MRU5HVEhcbiAgICBsZXQgam9pblJlZiA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIGpvaW5SZWZTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyBqb2luUmVmU2l6ZVxuICAgIGxldCByZWYgPSBkZWNvZGVyLmRlY29kZShidWZmZXIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyByZWZTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyByZWZTaXplXG4gICAgbGV0IHRvcGljID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgdG9waWNTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyB0b3BpY1NpemVcbiAgICBsZXQgZXZlbnQgPSBkZWNvZGVyLmRlY29kZShidWZmZXIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBldmVudFNpemUpKVxuICAgIG9mZnNldCA9IG9mZnNldCArIGV2ZW50U2l6ZVxuICAgIGxldCBkYXRhID0gYnVmZmVyLnNsaWNlKG9mZnNldCwgYnVmZmVyLmJ5dGVMZW5ndGgpXG4gICAgbGV0IHBheWxvYWQgPSB7c3RhdHVzOiBldmVudCwgcmVzcG9uc2U6IGRhdGF9XG4gICAgcmV0dXJuIHtqb2luX3JlZjogam9pblJlZiwgcmVmOiByZWYsIHRvcGljOiB0b3BpYywgZXZlbnQ6IENIQU5ORUxfRVZFTlRTLnJlcGx5LCBwYXlsb2FkOiBwYXlsb2FkfVxuICB9LFxuXG4gIGRlY29kZUJyb2FkY2FzdChidWZmZXIsIHZpZXcsIGRlY29kZXIpe1xuICAgIGxldCB0b3BpY1NpemUgPSB2aWV3LmdldFVpbnQ4KDEpXG4gICAgbGV0IGV2ZW50U2l6ZSA9IHZpZXcuZ2V0VWludDgoMilcbiAgICBsZXQgb2Zmc2V0ID0gdGhpcy5IRUFERVJfTEVOR1RIICsgMlxuICAgIGxldCB0b3BpYyA9IGRlY29kZXIuZGVjb2RlKGJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIHRvcGljU2l6ZSkpXG4gICAgb2Zmc2V0ID0gb2Zmc2V0ICsgdG9waWNTaXplXG4gICAgbGV0IGV2ZW50ID0gZGVjb2Rlci5kZWNvZGUoYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgZXZlbnRTaXplKSlcbiAgICBvZmZzZXQgPSBvZmZzZXQgKyBldmVudFNpemVcbiAgICBsZXQgZGF0YSA9IGJ1ZmZlci5zbGljZShvZmZzZXQsIGJ1ZmZlci5ieXRlTGVuZ3RoKVxuXG4gICAgcmV0dXJuIHtqb2luX3JlZjogbnVsbCwgcmVmOiBudWxsLCB0b3BpYzogdG9waWMsIGV2ZW50OiBldmVudCwgcGF5bG9hZDogZGF0YX1cbiAgfVxufVxuIiwgImltcG9ydCB7XG4gIGdsb2JhbCxcbiAgcGh4V2luZG93LFxuICBDSEFOTkVMX0VWRU5UUyxcbiAgREVGQVVMVF9USU1FT1VULFxuICBERUZBVUxUX1ZTTixcbiAgU09DS0VUX1NUQVRFUyxcbiAgVFJBTlNQT1JUUyxcbiAgV1NfQ0xPU0VfTk9STUFMLFxuICBBVVRIX1RPS0VOX1BSRUZJWFxufSBmcm9tIFwiLi9jb25zdGFudHNcIlxuXG5pbXBvcnQge1xuICBjbG9zdXJlXG59IGZyb20gXCIuL3V0aWxzXCJcblxuaW1wb3J0IEFqYXggZnJvbSBcIi4vYWpheFwiXG5pbXBvcnQgQ2hhbm5lbCBmcm9tIFwiLi9jaGFubmVsXCJcbmltcG9ydCBMb25nUG9sbCBmcm9tIFwiLi9sb25ncG9sbFwiXG5pbXBvcnQgU2VyaWFsaXplciBmcm9tIFwiLi9zZXJpYWxpemVyXCJcbmltcG9ydCBUaW1lciBmcm9tIFwiLi90aW1lclwiXG5cbi8qKiBJbml0aWFsaXplcyB0aGUgU29ja2V0ICpcbiAqXG4gKiBGb3IgSUU4IHN1cHBvcnQgdXNlIGFuIEVTNS1zaGltIChodHRwczovL2dpdGh1Yi5jb20vZXMtc2hpbXMvZXM1LXNoaW0pXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGVuZFBvaW50IC0gVGhlIHN0cmluZyBXZWJTb2NrZXQgZW5kcG9pbnQsIGllLCBgXCJ3czovL2V4YW1wbGUuY29tL3NvY2tldFwiYCxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgXCJ3c3M6Ly9leGFtcGxlLmNvbVwiYFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBcIi9zb2NrZXRcImAgKGluaGVyaXRlZCBob3N0ICYgcHJvdG9jb2wpXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdHNdIC0gT3B0aW9uYWwgY29uZmlndXJhdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMudHJhbnNwb3J0XSAtIFRoZSBXZWJzb2NrZXQgVHJhbnNwb3J0LCBmb3IgZXhhbXBsZSBXZWJTb2NrZXQgb3IgUGhvZW5peC5Mb25nUG9sbC5cbiAqXG4gKiBEZWZhdWx0cyB0byBXZWJTb2NrZXQgd2l0aCBhdXRvbWF0aWMgTG9uZ1BvbGwgZmFsbGJhY2sgaWYgV2ViU29ja2V0IGlzIG5vdCBkZWZpbmVkLlxuICogVG8gZmFsbGJhY2sgdG8gTG9uZ1BvbGwgd2hlbiBXZWJTb2NrZXQgYXR0ZW1wdHMgZmFpbCwgdXNlIGBsb25nUG9sbEZhbGxiYWNrTXM6IDI1MDBgLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy5sb25nUG9sbEZhbGxiYWNrTXNdIC0gVGhlIG1pbGxpc2Vjb25kIHRpbWUgdG8gYXR0ZW1wdCB0aGUgcHJpbWFyeSB0cmFuc3BvcnRcbiAqIGJlZm9yZSBmYWxsaW5nIGJhY2sgdG8gdGhlIExvbmdQb2xsIHRyYW5zcG9ydC4gRGlzYWJsZWQgYnkgZGVmYXVsdC5cbiAqXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmRlYnVnXSAtIFdoZW4gdHJ1ZSwgZW5hYmxlcyBkZWJ1ZyBsb2dnaW5nLiBEZWZhdWx0IGZhbHNlLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRzLmVuY29kZV0gLSBUaGUgZnVuY3Rpb24gdG8gZW5jb2RlIG91dGdvaW5nIG1lc3NhZ2VzLlxuICpcbiAqIERlZmF1bHRzIHRvIEpTT04gZW5jb2Rlci5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBbb3B0cy5kZWNvZGVdIC0gVGhlIGZ1bmN0aW9uIHRvIGRlY29kZSBpbmNvbWluZyBtZXNzYWdlcy5cbiAqXG4gKiBEZWZhdWx0cyB0byBKU09OOlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIChwYXlsb2FkLCBjYWxsYmFjaykgPT4gY2FsbGJhY2soSlNPTi5wYXJzZShwYXlsb2FkKSlcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0cy50aW1lb3V0XSAtIFRoZSBkZWZhdWx0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIHRvIHRyaWdnZXIgcHVzaCB0aW1lb3V0cy5cbiAqXG4gKiBEZWZhdWx0cyBgREVGQVVMVF9USU1FT1VUYFxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLmhlYXJ0YmVhdEludGVydmFsTXNdIC0gVGhlIG1pbGxpc2VjIGludGVydmFsIHRvIHNlbmQgYSBoZWFydGJlYXQgbWVzc2FnZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMucmVjb25uZWN0QWZ0ZXJNc10gLSBUaGUgb3B0aW9uYWwgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZVxuICogc29ja2V0IHJlY29ubmVjdCBpbnRlcnZhbCwgaW4gbWlsbGlzZWNvbmRzLlxuICpcbiAqIERlZmF1bHRzIHRvIHN0ZXBwZWQgYmFja29mZiBvZjpcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiBmdW5jdGlvbih0cmllcyl7XG4gKiAgIHJldHVybiBbMTAsIDUwLCAxMDAsIDE1MCwgMjAwLCAyNTAsIDUwMCwgMTAwMCwgMjAwMF1bdHJpZXMgLSAxXSB8fCA1MDAwXG4gKiB9XG4gKiBgYGBgXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMucmVqb2luQWZ0ZXJNc10gLSBUaGUgb3B0aW9uYWwgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBtaWxsaXNlY1xuICogcmVqb2luIGludGVydmFsIGZvciBpbmRpdmlkdWFsIGNoYW5uZWxzLlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIGZ1bmN0aW9uKHRyaWVzKXtcbiAqICAgcmV0dXJuIFsxMDAwLCAyMDAwLCA1MDAwXVt0cmllcyAtIDFdIHx8IDEwMDAwXG4gKiB9XG4gKiBgYGBgXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29wdHMubG9nZ2VyXSAtIFRoZSBvcHRpb25hbCBmdW5jdGlvbiBmb3Igc3BlY2lhbGl6ZWQgbG9nZ2luZywgaWU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogZnVuY3Rpb24oa2luZCwgbXNnLCBkYXRhKSB7XG4gKiAgIGNvbnNvbGUubG9nKGAke2tpbmR9OiAke21zZ31gLCBkYXRhKVxuICogfVxuICogYGBgXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRzLmxvbmdwb2xsZXJUaW1lb3V0XSAtIFRoZSBtYXhpbXVtIHRpbWVvdXQgb2YgYSBsb25nIHBvbGwgQUpBWCByZXF1ZXN0LlxuICpcbiAqIERlZmF1bHRzIHRvIDIwcyAoZG91YmxlIHRoZSBzZXJ2ZXIgbG9uZyBwb2xsIHRpbWVyKS5cbiAqXG4gKiBAcGFyYW0geyhPYmplY3R8ZnVuY3Rpb24pfSBbb3B0cy5wYXJhbXNdIC0gVGhlIG9wdGlvbmFsIHBhcmFtcyB0byBwYXNzIHdoZW4gY29ubmVjdGluZ1xuICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmF1dGhUb2tlbl0gLSB0aGUgb3B0aW9uYWwgYXV0aGVudGljYXRpb24gdG9rZW4gdG8gYmUgZXhwb3NlZCBvbiB0aGUgc2VydmVyXG4gKiB1bmRlciB0aGUgYDphdXRoX3Rva2VuYCBjb25uZWN0X2luZm8ga2V5LlxuICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmJpbmFyeVR5cGVdIC0gVGhlIGJpbmFyeSB0eXBlIHRvIHVzZSBmb3IgYmluYXJ5IFdlYlNvY2tldCBmcmFtZXMuXG4gKlxuICogRGVmYXVsdHMgdG8gXCJhcnJheWJ1ZmZlclwiXG4gKlxuICogQHBhcmFtIHt2c259IFtvcHRzLnZzbl0gLSBUaGUgc2VyaWFsaXplcidzIHByb3RvY29sIHZlcnNpb24gdG8gc2VuZCBvbiBjb25uZWN0LlxuICpcbiAqIERlZmF1bHRzIHRvIERFRkFVTFRfVlNOLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5zZXNzaW9uU3RvcmFnZV0gLSBBbiBvcHRpb25hbCBTdG9yYWdlIGNvbXBhdGlibGUgb2JqZWN0XG4gKiBQaG9lbml4IHVzZXMgc2Vzc2lvblN0b3JhZ2UgZm9yIGxvbmdwb2xsIGZhbGxiYWNrIGhpc3RvcnkuIE92ZXJyaWRpbmcgdGhlIHN0b3JlIGlzXG4gKiB1c2VmdWwgd2hlbiBQaG9lbml4IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBzZXNzaW9uU3RvcmFnZWAuIEZvciBleGFtcGxlLCBUaGlzIGNvdWxkXG4gKiBoYXBwZW4gaWYgYSBzaXRlIGxvYWRzIGEgY3Jvc3MtZG9tYWluIGNoYW5uZWwgaW4gYW4gaWZyYW1lLiBFeGFtcGxlIHVzYWdlOlxuICpcbiAqICAgICBjbGFzcyBJbk1lbW9yeVN0b3JhZ2Uge1xuICogICAgICAgY29uc3RydWN0b3IoKSB7IHRoaXMuc3RvcmFnZSA9IHt9IH1cbiAqICAgICAgIGdldEl0ZW0oa2V5TmFtZSkgeyByZXR1cm4gdGhpcy5zdG9yYWdlW2tleU5hbWVdIHx8IG51bGwgfVxuICogICAgICAgcmVtb3ZlSXRlbShrZXlOYW1lKSB7IGRlbGV0ZSB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gfVxuICogICAgICAgc2V0SXRlbShrZXlOYW1lLCBrZXlWYWx1ZSkgeyB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gPSBrZXlWYWx1ZSB9XG4gKiAgICAgfVxuICpcbiovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTb2NrZXQge1xuICBjb25zdHJ1Y3RvcihlbmRQb2ludCwgb3B0cyA9IHt9KXtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzID0ge29wZW46IFtdLCBjbG9zZTogW10sIGVycm9yOiBbXSwgbWVzc2FnZTogW119XG4gICAgdGhpcy5jaGFubmVscyA9IFtdXG4gICAgdGhpcy5zZW5kQnVmZmVyID0gW11cbiAgICB0aGlzLnJlZiA9IDBcbiAgICB0aGlzLnRpbWVvdXQgPSBvcHRzLnRpbWVvdXQgfHwgREVGQVVMVF9USU1FT1VUXG4gICAgdGhpcy50cmFuc3BvcnQgPSBvcHRzLnRyYW5zcG9ydCB8fCBnbG9iYWwuV2ViU29ja2V0IHx8IExvbmdQb2xsXG4gICAgdGhpcy5wcmltYXJ5UGFzc2VkSGVhbHRoQ2hlY2sgPSBmYWxzZVxuICAgIHRoaXMubG9uZ1BvbGxGYWxsYmFja01zID0gb3B0cy5sb25nUG9sbEZhbGxiYWNrTXNcbiAgICB0aGlzLmZhbGxiYWNrVGltZXIgPSBudWxsXG4gICAgdGhpcy5zZXNzaW9uU3RvcmUgPSBvcHRzLnNlc3Npb25TdG9yYWdlIHx8IChnbG9iYWwgJiYgZ2xvYmFsLnNlc3Npb25TdG9yYWdlKVxuICAgIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9ucyA9IDBcbiAgICB0aGlzLmRlZmF1bHRFbmNvZGVyID0gU2VyaWFsaXplci5lbmNvZGUuYmluZChTZXJpYWxpemVyKVxuICAgIHRoaXMuZGVmYXVsdERlY29kZXIgPSBTZXJpYWxpemVyLmRlY29kZS5iaW5kKFNlcmlhbGl6ZXIpXG4gICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gZmFsc2VcbiAgICB0aGlzLmRpc2Nvbm5lY3RpbmcgPSBmYWxzZVxuICAgIHRoaXMuYmluYXJ5VHlwZSA9IG9wdHMuYmluYXJ5VHlwZSB8fCBcImFycmF5YnVmZmVyXCJcbiAgICB0aGlzLmNvbm5lY3RDbG9jayA9IDFcbiAgICBpZih0aGlzLnRyYW5zcG9ydCAhPT0gTG9uZ1BvbGwpe1xuICAgICAgdGhpcy5lbmNvZGUgPSBvcHRzLmVuY29kZSB8fCB0aGlzLmRlZmF1bHRFbmNvZGVyXG4gICAgICB0aGlzLmRlY29kZSA9IG9wdHMuZGVjb2RlIHx8IHRoaXMuZGVmYXVsdERlY29kZXJcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5lbmNvZGUgPSB0aGlzLmRlZmF1bHRFbmNvZGVyXG4gICAgICB0aGlzLmRlY29kZSA9IHRoaXMuZGVmYXVsdERlY29kZXJcbiAgICB9XG4gICAgbGV0IGF3YWl0aW5nQ29ubmVjdGlvbk9uUGFnZVNob3cgPSBudWxsXG4gICAgaWYocGh4V2luZG93ICYmIHBoeFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKXtcbiAgICAgIHBoeFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGFnZWhpZGVcIiwgX2UgPT4ge1xuICAgICAgICBpZih0aGlzLmNvbm4pe1xuICAgICAgICAgIHRoaXMuZGlzY29ubmVjdCgpXG4gICAgICAgICAgYXdhaXRpbmdDb25uZWN0aW9uT25QYWdlU2hvdyA9IHRoaXMuY29ubmVjdENsb2NrXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICBwaHhXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBhZ2VzaG93XCIsIF9lID0+IHtcbiAgICAgICAgaWYoYXdhaXRpbmdDb25uZWN0aW9uT25QYWdlU2hvdyA9PT0gdGhpcy5jb25uZWN0Q2xvY2spe1xuICAgICAgICAgIGF3YWl0aW5nQ29ubmVjdGlvbk9uUGFnZVNob3cgPSBudWxsXG4gICAgICAgICAgdGhpcy5jb25uZWN0KClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG4gICAgdGhpcy5oZWFydGJlYXRJbnRlcnZhbE1zID0gb3B0cy5oZWFydGJlYXRJbnRlcnZhbE1zIHx8IDMwMDAwXG4gICAgdGhpcy5yZWpvaW5BZnRlck1zID0gKHRyaWVzKSA9PiB7XG4gICAgICBpZihvcHRzLnJlam9pbkFmdGVyTXMpe1xuICAgICAgICByZXR1cm4gb3B0cy5yZWpvaW5BZnRlck1zKHRyaWVzKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFsxMDAwLCAyMDAwLCA1MDAwXVt0cmllcyAtIDFdIHx8IDEwMDAwXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVjb25uZWN0QWZ0ZXJNcyA9ICh0cmllcykgPT4ge1xuICAgICAgaWYob3B0cy5yZWNvbm5lY3RBZnRlck1zKXtcbiAgICAgICAgcmV0dXJuIG9wdHMucmVjb25uZWN0QWZ0ZXJNcyh0cmllcylcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBbMTAsIDUwLCAxMDAsIDE1MCwgMjAwLCAyNTAsIDUwMCwgMTAwMCwgMjAwMF1bdHJpZXMgLSAxXSB8fCA1MDAwXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMubG9nZ2VyID0gb3B0cy5sb2dnZXIgfHwgbnVsbFxuICAgIGlmKCF0aGlzLmxvZ2dlciAmJiBvcHRzLmRlYnVnKXtcbiAgICAgIHRoaXMubG9nZ2VyID0gKGtpbmQsIG1zZywgZGF0YSkgPT4geyBjb25zb2xlLmxvZyhgJHtraW5kfTogJHttc2d9YCwgZGF0YSkgfVxuICAgIH1cbiAgICB0aGlzLmxvbmdwb2xsZXJUaW1lb3V0ID0gb3B0cy5sb25ncG9sbGVyVGltZW91dCB8fCAyMDAwMFxuICAgIHRoaXMucGFyYW1zID0gY2xvc3VyZShvcHRzLnBhcmFtcyB8fCB7fSlcbiAgICB0aGlzLmVuZFBvaW50ID0gYCR7ZW5kUG9pbnR9LyR7VFJBTlNQT1JUUy53ZWJzb2NrZXR9YFxuICAgIHRoaXMudnNuID0gb3B0cy52c24gfHwgREVGQVVMVF9WU05cbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVvdXRUaW1lciA9IG51bGxcbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVyID0gbnVsbFxuICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IG51bGxcbiAgICB0aGlzLnJlY29ubmVjdFRpbWVyID0gbmV3IFRpbWVyKCgpID0+IHtcbiAgICAgIHRoaXMudGVhcmRvd24oKCkgPT4gdGhpcy5jb25uZWN0KCkpXG4gICAgfSwgdGhpcy5yZWNvbm5lY3RBZnRlck1zKVxuICAgIHRoaXMuYXV0aFRva2VuID0gb3B0cy5hdXRoVG9rZW5cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBMb25nUG9sbCB0cmFuc3BvcnQgcmVmZXJlbmNlXG4gICAqL1xuICBnZXRMb25nUG9sbFRyYW5zcG9ydCgpeyByZXR1cm4gTG9uZ1BvbGwgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0cyBhbmQgcmVwbGFjZXMgdGhlIGFjdGl2ZSB0cmFuc3BvcnRcbiAgICpcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gbmV3VHJhbnNwb3J0IC0gVGhlIG5ldyB0cmFuc3BvcnQgY2xhc3MgdG8gaW5zdGFudGlhdGVcbiAgICpcbiAgICovXG4gIHJlcGxhY2VUcmFuc3BvcnQobmV3VHJhbnNwb3J0KXtcbiAgICB0aGlzLmNvbm5lY3RDbG9jaysrXG4gICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gdHJ1ZVxuICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgdGhpcy5yZWNvbm5lY3RUaW1lci5yZXNldCgpXG4gICAgaWYodGhpcy5jb25uKXtcbiAgICAgIHRoaXMuY29ubi5jbG9zZSgpXG4gICAgICB0aGlzLmNvbm4gPSBudWxsXG4gICAgfVxuICAgIHRoaXMudHJhbnNwb3J0ID0gbmV3VHJhbnNwb3J0XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc29ja2V0IHByb3RvY29sXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBwcm90b2NvbCgpeyByZXR1cm4gbG9jYXRpb24ucHJvdG9jb2wubWF0Y2goL15odHRwcy8pID8gXCJ3c3NcIiA6IFwid3NcIiB9XG5cbiAgLyoqXG4gICAqIFRoZSBmdWxseSBxdWFsaWZpZWQgc29ja2V0IHVybFxuICAgKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgZW5kUG9pbnRVUkwoKXtcbiAgICBsZXQgdXJpID0gQWpheC5hcHBlbmRQYXJhbXMoXG4gICAgICBBamF4LmFwcGVuZFBhcmFtcyh0aGlzLmVuZFBvaW50LCB0aGlzLnBhcmFtcygpKSwge3ZzbjogdGhpcy52c259KVxuICAgIGlmKHVyaS5jaGFyQXQoMCkgIT09IFwiL1wiKXsgcmV0dXJuIHVyaSB9XG4gICAgaWYodXJpLmNoYXJBdCgxKSA9PT0gXCIvXCIpeyByZXR1cm4gYCR7dGhpcy5wcm90b2NvbCgpfToke3VyaX1gIH1cblxuICAgIHJldHVybiBgJHt0aGlzLnByb3RvY29sKCl9Oi8vJHtsb2NhdGlvbi5ob3N0fSR7dXJpfWBcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0cyB0aGUgc29ja2V0XG4gICAqXG4gICAqIFNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvQ2xvc2VFdmVudCNTdGF0dXNfY29kZXMgZm9yIHZhbGlkIHN0YXR1cyBjb2Rlcy5cbiAgICpcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgLSBPcHRpb25hbCBjYWxsYmFjayB3aGljaCBpcyBjYWxsZWQgYWZ0ZXIgc29ja2V0IGlzIGRpc2Nvbm5lY3RlZC5cbiAgICogQHBhcmFtIHtpbnRlZ2VyfSBjb2RlIC0gQSBzdGF0dXMgY29kZSBmb3IgZGlzY29ubmVjdGlvbiAoT3B0aW9uYWwpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIC0gQSB0ZXh0dWFsIGRlc2NyaXB0aW9uIG9mIHRoZSByZWFzb24gdG8gZGlzY29ubmVjdC4gKE9wdGlvbmFsKVxuICAgKi9cbiAgZGlzY29ubmVjdChjYWxsYmFjaywgY29kZSwgcmVhc29uKXtcbiAgICB0aGlzLmNvbm5lY3RDbG9jaysrXG4gICAgdGhpcy5kaXNjb25uZWN0aW5nID0gdHJ1ZVxuICAgIHRoaXMuY2xvc2VXYXNDbGVhbiA9IHRydWVcbiAgICBjbGVhclRpbWVvdXQodGhpcy5mYWxsYmFja1RpbWVyKVxuICAgIHRoaXMucmVjb25uZWN0VGltZXIucmVzZXQoKVxuICAgIHRoaXMudGVhcmRvd24oKCkgPT4ge1xuICAgICAgdGhpcy5kaXNjb25uZWN0aW5nID0gZmFsc2VcbiAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKClcbiAgICB9LCBjb2RlLCByZWFzb24pXG4gIH1cblxuICAvKipcbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyAtIFRoZSBwYXJhbXMgdG8gc2VuZCB3aGVuIGNvbm5lY3RpbmcsIGZvciBleGFtcGxlIGB7dXNlcl9pZDogdXNlclRva2VufWBcbiAgICpcbiAgICogUGFzc2luZyBwYXJhbXMgdG8gY29ubmVjdCBpcyBkZXByZWNhdGVkOyBwYXNzIHRoZW0gaW4gdGhlIFNvY2tldCBjb25zdHJ1Y3RvciBpbnN0ZWFkOlxuICAgKiBgbmV3IFNvY2tldChcIi9zb2NrZXRcIiwge3BhcmFtczoge3VzZXJfaWQ6IHVzZXJUb2tlbn19KWAuXG4gICAqL1xuICBjb25uZWN0KHBhcmFtcyl7XG4gICAgaWYocGFyYW1zKXtcbiAgICAgIGNvbnNvbGUgJiYgY29uc29sZS5sb2coXCJwYXNzaW5nIHBhcmFtcyB0byBjb25uZWN0IGlzIGRlcHJlY2F0ZWQuIEluc3RlYWQgcGFzcyA6cGFyYW1zIHRvIHRoZSBTb2NrZXQgY29uc3RydWN0b3JcIilcbiAgICAgIHRoaXMucGFyYW1zID0gY2xvc3VyZShwYXJhbXMpXG4gICAgfVxuICAgIGlmKHRoaXMuY29ubiAmJiAhdGhpcy5kaXNjb25uZWN0aW5nKXsgcmV0dXJuIH1cbiAgICBpZih0aGlzLmxvbmdQb2xsRmFsbGJhY2tNcyAmJiB0aGlzLnRyYW5zcG9ydCAhPT0gTG9uZ1BvbGwpe1xuICAgICAgdGhpcy5jb25uZWN0V2l0aEZhbGxiYWNrKExvbmdQb2xsLCB0aGlzLmxvbmdQb2xsRmFsbGJhY2tNcylcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50cmFuc3BvcnRDb25uZWN0KClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTG9ncyB0aGUgbWVzc2FnZS4gT3ZlcnJpZGUgYHRoaXMubG9nZ2VyYCBmb3Igc3BlY2lhbGl6ZWQgbG9nZ2luZy4gbm9vcHMgYnkgZGVmYXVsdFxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2luZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbXNnXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXG4gICAqL1xuICBsb2coa2luZCwgbXNnLCBkYXRhKXsgdGhpcy5sb2dnZXIgJiYgdGhpcy5sb2dnZXIoa2luZCwgbXNnLCBkYXRhKSB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhIGxvZ2dlciBoYXMgYmVlbiBzZXQgb24gdGhpcyBzb2NrZXQuXG4gICAqL1xuICBoYXNMb2dnZXIoKXsgcmV0dXJuIHRoaXMubG9nZ2VyICE9PSBudWxsIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGNhbGxiYWNrcyBmb3IgY29ubmVjdGlvbiBvcGVuIGV2ZW50c1xuICAgKlxuICAgKiBAZXhhbXBsZSBzb2NrZXQub25PcGVuKGZ1bmN0aW9uKCl7IGNvbnNvbGUuaW5mbyhcInRoZSBzb2NrZXQgd2FzIG9wZW5lZFwiKSB9KVxuICAgKlxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgKi9cbiAgb25PcGVuKGNhbGxiYWNrKXtcbiAgICBsZXQgcmVmID0gdGhpcy5tYWtlUmVmKClcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzLm9wZW4ucHVzaChbcmVmLCBjYWxsYmFja10pXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBjYWxsYmFja3MgZm9yIGNvbm5lY3Rpb24gY2xvc2UgZXZlbnRzXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAqL1xuICBvbkNsb3NlKGNhbGxiYWNrKXtcbiAgICBsZXQgcmVmID0gdGhpcy5tYWtlUmVmKClcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzLmNsb3NlLnB1c2goW3JlZiwgY2FsbGJhY2tdKVxuICAgIHJldHVybiByZWZcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlcnMgY2FsbGJhY2tzIGZvciBjb25uZWN0aW9uIGVycm9yIGV2ZW50c1xuICAgKlxuICAgKiBAZXhhbXBsZSBzb2NrZXQub25FcnJvcihmdW5jdGlvbihlcnJvcil7IGFsZXJ0KFwiQW4gZXJyb3Igb2NjdXJyZWRcIikgfSlcbiAgICpcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICovXG4gIG9uRXJyb3IoY2FsbGJhY2spe1xuICAgIGxldCByZWYgPSB0aGlzLm1ha2VSZWYoKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3MuZXJyb3IucHVzaChbcmVmLCBjYWxsYmFja10pXG4gICAgcmV0dXJuIHJlZlxuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBjYWxsYmFja3MgZm9yIGNvbm5lY3Rpb24gbWVzc2FnZSBldmVudHNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICovXG4gIG9uTWVzc2FnZShjYWxsYmFjayl7XG4gICAgbGV0IHJlZiA9IHRoaXMubWFrZVJlZigpXG4gICAgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5tZXNzYWdlLnB1c2goW3JlZiwgY2FsbGJhY2tdKVxuICAgIHJldHVybiByZWZcbiAgfVxuXG4gIC8qKlxuICAgKiBQaW5ncyB0aGUgc2VydmVyIGFuZCBpbnZva2VzIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBSVFQgaW4gbWlsbGlzZWNvbmRzXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgcGluZyB3YXMgcHVzaGVkIG9yIGZhbHNlIGlmIHVuYWJsZSB0byBiZSBwdXNoZWQuXG4gICAqL1xuICBwaW5nKGNhbGxiYWNrKXtcbiAgICBpZighdGhpcy5pc0Nvbm5lY3RlZCgpKXsgcmV0dXJuIGZhbHNlIH1cbiAgICBsZXQgcmVmID0gdGhpcy5tYWtlUmVmKClcbiAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgIHRoaXMucHVzaCh7dG9waWM6IFwicGhvZW5peFwiLCBldmVudDogXCJoZWFydGJlYXRcIiwgcGF5bG9hZDoge30sIHJlZjogcmVmfSlcbiAgICBsZXQgb25Nc2dSZWYgPSB0aGlzLm9uTWVzc2FnZShtc2cgPT4ge1xuICAgICAgaWYobXNnLnJlZiA9PT0gcmVmKXtcbiAgICAgICAgdGhpcy5vZmYoW29uTXNnUmVmXSlcbiAgICAgICAgY2FsbGJhY2soRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSlcbiAgICAgIH1cbiAgICB9KVxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG5cbiAgdHJhbnNwb3J0Q29ubmVjdCgpe1xuICAgIHRoaXMuY29ubmVjdENsb2NrKytcbiAgICB0aGlzLmNsb3NlV2FzQ2xlYW4gPSBmYWxzZVxuICAgIGxldCBwcm90b2NvbHMgPSB1bmRlZmluZWRcbiAgICAvLyBTZWMtV2ViU29ja2V0LVByb3RvY29sIGJhc2VkIHRva2VuXG4gICAgLy8gKGxvbmdwb2xsIHVzZXMgQXV0aG9yaXphdGlvbiBoZWFkZXIgaW5zdGVhZClcbiAgICBpZih0aGlzLmF1dGhUb2tlbil7XG4gICAgICBwcm90b2NvbHMgPSBbXCJwaG9lbml4XCIsIGAke0FVVEhfVE9LRU5fUFJFRklYfSR7YnRvYSh0aGlzLmF1dGhUb2tlbikucmVwbGFjZSgvPS9nLCBcIlwiKX1gXVxuICAgIH1cbiAgICB0aGlzLmNvbm4gPSBuZXcgdGhpcy50cmFuc3BvcnQodGhpcy5lbmRQb2ludFVSTCgpLCBwcm90b2NvbHMpXG4gICAgdGhpcy5jb25uLmJpbmFyeVR5cGUgPSB0aGlzLmJpbmFyeVR5cGVcbiAgICB0aGlzLmNvbm4udGltZW91dCA9IHRoaXMubG9uZ3BvbGxlclRpbWVvdXRcbiAgICB0aGlzLmNvbm4ub25vcGVuID0gKCkgPT4gdGhpcy5vbkNvbm5PcGVuKClcbiAgICB0aGlzLmNvbm4ub25lcnJvciA9IGVycm9yID0+IHRoaXMub25Db25uRXJyb3IoZXJyb3IpXG4gICAgdGhpcy5jb25uLm9ubWVzc2FnZSA9IGV2ZW50ID0+IHRoaXMub25Db25uTWVzc2FnZShldmVudClcbiAgICB0aGlzLmNvbm4ub25jbG9zZSA9IGV2ZW50ID0+IHRoaXMub25Db25uQ2xvc2UoZXZlbnQpXG4gIH1cblxuICBnZXRTZXNzaW9uKGtleSl7IHJldHVybiB0aGlzLnNlc3Npb25TdG9yZSAmJiB0aGlzLnNlc3Npb25TdG9yZS5nZXRJdGVtKGtleSkgfVxuXG4gIHN0b3JlU2Vzc2lvbihrZXksIHZhbCl7IHRoaXMuc2Vzc2lvblN0b3JlICYmIHRoaXMuc2Vzc2lvblN0b3JlLnNldEl0ZW0oa2V5LCB2YWwpIH1cblxuICBjb25uZWN0V2l0aEZhbGxiYWNrKGZhbGxiYWNrVHJhbnNwb3J0LCBmYWxsYmFja1RocmVzaG9sZCA9IDI1MDApe1xuICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgbGV0IGVzdGFibGlzaGVkID0gZmFsc2VcbiAgICBsZXQgcHJpbWFyeVRyYW5zcG9ydCA9IHRydWVcbiAgICBsZXQgb3BlblJlZiwgZXJyb3JSZWZcbiAgICBsZXQgZmFsbGJhY2sgPSAocmVhc29uKSA9PiB7XG4gICAgICB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBgZmFsbGluZyBiYWNrIHRvICR7ZmFsbGJhY2tUcmFuc3BvcnQubmFtZX0uLi5gLCByZWFzb24pXG4gICAgICB0aGlzLm9mZihbb3BlblJlZiwgZXJyb3JSZWZdKVxuICAgICAgcHJpbWFyeVRyYW5zcG9ydCA9IGZhbHNlXG4gICAgICB0aGlzLnJlcGxhY2VUcmFuc3BvcnQoZmFsbGJhY2tUcmFuc3BvcnQpXG4gICAgICB0aGlzLnRyYW5zcG9ydENvbm5lY3QoKVxuICAgIH1cbiAgICBpZih0aGlzLmdldFNlc3Npb24oYHBoeDpmYWxsYmFjazoke2ZhbGxiYWNrVHJhbnNwb3J0Lm5hbWV9YCkpeyByZXR1cm4gZmFsbGJhY2soXCJtZW1vcml6ZWRcIikgfVxuXG4gICAgdGhpcy5mYWxsYmFja1RpbWVyID0gc2V0VGltZW91dChmYWxsYmFjaywgZmFsbGJhY2tUaHJlc2hvbGQpXG5cbiAgICBlcnJvclJlZiA9IHRoaXMub25FcnJvcihyZWFzb24gPT4ge1xuICAgICAgdGhpcy5sb2coXCJ0cmFuc3BvcnRcIiwgXCJlcnJvclwiLCByZWFzb24pXG4gICAgICBpZihwcmltYXJ5VHJhbnNwb3J0ICYmICFlc3RhYmxpc2hlZCl7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmZhbGxiYWNrVGltZXIpXG4gICAgICAgIGZhbGxiYWNrKHJlYXNvbilcbiAgICAgIH1cbiAgICB9KVxuICAgIHRoaXMub25PcGVuKCgpID0+IHtcbiAgICAgIGVzdGFibGlzaGVkID0gdHJ1ZVxuICAgICAgaWYoIXByaW1hcnlUcmFuc3BvcnQpe1xuICAgICAgICAvLyBvbmx5IG1lbW9yaXplIExQIGlmIHdlIG5ldmVyIGNvbm5lY3RlZCB0byBwcmltYXJ5XG4gICAgICAgIGlmKCF0aGlzLnByaW1hcnlQYXNzZWRIZWFsdGhDaGVjayl7IHRoaXMuc3RvcmVTZXNzaW9uKGBwaHg6ZmFsbGJhY2s6JHtmYWxsYmFja1RyYW5zcG9ydC5uYW1lfWAsIFwidHJ1ZVwiKSB9XG4gICAgICAgIHJldHVybiB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBgZXN0YWJsaXNoZWQgJHtmYWxsYmFja1RyYW5zcG9ydC5uYW1lfSBmYWxsYmFja2ApXG4gICAgICB9XG4gICAgICAvLyBpZiB3ZSd2ZSBlc3RhYmxpc2hlZCBwcmltYXJ5LCBnaXZlIHRoZSBmYWxsYmFjayBhIG5ldyBwZXJpb2QgdG8gYXR0ZW1wdCBwaW5nXG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5mYWxsYmFja1RpbWVyKVxuICAgICAgdGhpcy5mYWxsYmFja1RpbWVyID0gc2V0VGltZW91dChmYWxsYmFjaywgZmFsbGJhY2tUaHJlc2hvbGQpXG4gICAgICB0aGlzLnBpbmcocnR0ID0+IHtcbiAgICAgICAgdGhpcy5sb2coXCJ0cmFuc3BvcnRcIiwgXCJjb25uZWN0ZWQgdG8gcHJpbWFyeSBhZnRlclwiLCBydHQpXG4gICAgICAgIHRoaXMucHJpbWFyeVBhc3NlZEhlYWx0aENoZWNrID0gdHJ1ZVxuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5mYWxsYmFja1RpbWVyKVxuICAgICAgfSlcbiAgICB9KVxuICAgIHRoaXMudHJhbnNwb3J0Q29ubmVjdCgpXG4gIH1cblxuICBjbGVhckhlYXJ0YmVhdHMoKXtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5oZWFydGJlYXRUaW1lcilcbiAgICBjbGVhclRpbWVvdXQodGhpcy5oZWFydGJlYXRUaW1lb3V0VGltZXIpXG4gIH1cblxuICBvbkNvbm5PcGVuKCl7XG4gICAgaWYodGhpcy5oYXNMb2dnZXIoKSkgdGhpcy5sb2coXCJ0cmFuc3BvcnRcIiwgYCR7dGhpcy50cmFuc3BvcnQubmFtZX0gY29ubmVjdGVkIHRvICR7dGhpcy5lbmRQb2ludFVSTCgpfWApXG4gICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gZmFsc2VcbiAgICB0aGlzLmRpc2Nvbm5lY3RpbmcgPSBmYWxzZVxuICAgIHRoaXMuZXN0YWJsaXNoZWRDb25uZWN0aW9ucysrXG4gICAgdGhpcy5mbHVzaFNlbmRCdWZmZXIoKVxuICAgIHRoaXMucmVjb25uZWN0VGltZXIucmVzZXQoKVxuICAgIHRoaXMucmVzZXRIZWFydGJlYXQoKVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3Mub3Blbi5mb3JFYWNoKChbLCBjYWxsYmFja10pID0+IGNhbGxiYWNrKCkpXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG5cbiAgaGVhcnRiZWF0VGltZW91dCgpe1xuICAgIGlmKHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZil7XG4gICAgICB0aGlzLnBlbmRpbmdIZWFydGJlYXRSZWYgPSBudWxsXG4gICAgICBpZih0aGlzLmhhc0xvZ2dlcigpKXsgdGhpcy5sb2coXCJ0cmFuc3BvcnRcIiwgXCJoZWFydGJlYXQgdGltZW91dC4gQXR0ZW1wdGluZyB0byByZS1lc3RhYmxpc2ggY29ubmVjdGlvblwiKSB9XG4gICAgICB0aGlzLnRyaWdnZXJDaGFuRXJyb3IoKVxuICAgICAgdGhpcy5jbG9zZVdhc0NsZWFuID0gZmFsc2VcbiAgICAgIHRoaXMudGVhcmRvd24oKCkgPT4gdGhpcy5yZWNvbm5lY3RUaW1lci5zY2hlZHVsZVRpbWVvdXQoKSwgV1NfQ0xPU0VfTk9STUFMLCBcImhlYXJ0YmVhdCB0aW1lb3V0XCIpXG4gICAgfVxuICB9XG5cbiAgcmVzZXRIZWFydGJlYXQoKXtcbiAgICBpZih0aGlzLmNvbm4gJiYgdGhpcy5jb25uLnNraXBIZWFydGJlYXQpeyByZXR1cm4gfVxuICAgIHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiA9IG51bGxcbiAgICB0aGlzLmNsZWFySGVhcnRiZWF0cygpXG4gICAgdGhpcy5oZWFydGJlYXRUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZW5kSGVhcnRiZWF0KCksIHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWxNcylcbiAgfVxuXG4gIHRlYXJkb3duKGNhbGxiYWNrLCBjb2RlLCByZWFzb24pe1xuICAgIGlmKCF0aGlzLmNvbm4pe1xuICAgICAgcmV0dXJuIGNhbGxiYWNrICYmIGNhbGxiYWNrKClcbiAgICB9XG4gICAgbGV0IGNvbm5lY3RDbG9jayA9IHRoaXMuY29ubmVjdENsb2NrXG5cbiAgICB0aGlzLndhaXRGb3JCdWZmZXJEb25lKCgpID0+IHtcbiAgICAgIGlmKGNvbm5lY3RDbG9jayAhPT0gdGhpcy5jb25uZWN0Q2xvY2speyByZXR1cm4gfVxuICAgICAgaWYodGhpcy5jb25uKXtcbiAgICAgICAgaWYoY29kZSl7IHRoaXMuY29ubi5jbG9zZShjb2RlLCByZWFzb24gfHwgXCJcIikgfSBlbHNlIHsgdGhpcy5jb25uLmNsb3NlKCkgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLndhaXRGb3JTb2NrZXRDbG9zZWQoKCkgPT4ge1xuICAgICAgICBpZihjb25uZWN0Q2xvY2sgIT09IHRoaXMuY29ubmVjdENsb2NrKXsgcmV0dXJuIH1cbiAgICAgICAgaWYodGhpcy5jb25uKXtcbiAgICAgICAgICB0aGlzLmNvbm4ub25vcGVuID0gZnVuY3Rpb24gKCl7IH0gLy8gbm9vcFxuICAgICAgICAgIHRoaXMuY29ubi5vbmVycm9yID0gZnVuY3Rpb24gKCl7IH0gLy8gbm9vcFxuICAgICAgICAgIHRoaXMuY29ubi5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgICAgICAgdGhpcy5jb25uLm9uY2xvc2UgPSBmdW5jdGlvbiAoKXsgfSAvLyBub29wXG4gICAgICAgICAgdGhpcy5jb25uID0gbnVsbFxuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soKVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgd2FpdEZvckJ1ZmZlckRvbmUoY2FsbGJhY2ssIHRyaWVzID0gMSl7XG4gICAgaWYodHJpZXMgPT09IDUgfHwgIXRoaXMuY29ubiB8fCAhdGhpcy5jb25uLmJ1ZmZlcmVkQW1vdW50KXtcbiAgICAgIGNhbGxiYWNrKClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy53YWl0Rm9yQnVmZmVyRG9uZShjYWxsYmFjaywgdHJpZXMgKyAxKVxuICAgIH0sIDE1MCAqIHRyaWVzKVxuICB9XG5cbiAgd2FpdEZvclNvY2tldENsb3NlZChjYWxsYmFjaywgdHJpZXMgPSAxKXtcbiAgICBpZih0cmllcyA9PT0gNSB8fCAhdGhpcy5jb25uIHx8IHRoaXMuY29ubi5yZWFkeVN0YXRlID09PSBTT0NLRVRfU1RBVEVTLmNsb3NlZCl7XG4gICAgICBjYWxsYmFjaygpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMud2FpdEZvclNvY2tldENsb3NlZChjYWxsYmFjaywgdHJpZXMgKyAxKVxuICAgIH0sIDE1MCAqIHRyaWVzKVxuICB9XG5cbiAgb25Db25uQ2xvc2UoZXZlbnQpe1xuICAgIGxldCBjbG9zZUNvZGUgPSBldmVudCAmJiBldmVudC5jb2RlXG4gICAgaWYodGhpcy5oYXNMb2dnZXIoKSkgdGhpcy5sb2coXCJ0cmFuc3BvcnRcIiwgXCJjbG9zZVwiLCBldmVudClcbiAgICB0aGlzLnRyaWdnZXJDaGFuRXJyb3IoKVxuICAgIHRoaXMuY2xlYXJIZWFydGJlYXRzKClcbiAgICBpZighdGhpcy5jbG9zZVdhc0NsZWFuICYmIGNsb3NlQ29kZSAhPT0gMTAwMCl7XG4gICAgICB0aGlzLnJlY29ubmVjdFRpbWVyLnNjaGVkdWxlVGltZW91dCgpXG4gICAgfVxuICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3MuY2xvc2UuZm9yRWFjaCgoWywgY2FsbGJhY2tdKSA9PiBjYWxsYmFjayhldmVudCkpXG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIG9uQ29ubkVycm9yKGVycm9yKXtcbiAgICBpZih0aGlzLmhhc0xvZ2dlcigpKSB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBlcnJvcilcbiAgICBsZXQgdHJhbnNwb3J0QmVmb3JlID0gdGhpcy50cmFuc3BvcnRcbiAgICBsZXQgZXN0YWJsaXNoZWRCZWZvcmUgPSB0aGlzLmVzdGFibGlzaGVkQ29ubmVjdGlvbnNcbiAgICB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzLmVycm9yLmZvckVhY2goKFssIGNhbGxiYWNrXSkgPT4ge1xuICAgICAgY2FsbGJhY2soZXJyb3IsIHRyYW5zcG9ydEJlZm9yZSwgZXN0YWJsaXNoZWRCZWZvcmUpXG4gICAgfSlcbiAgICBpZih0cmFuc3BvcnRCZWZvcmUgPT09IHRoaXMudHJhbnNwb3J0IHx8IGVzdGFibGlzaGVkQmVmb3JlID4gMCl7XG4gICAgICB0aGlzLnRyaWdnZXJDaGFuRXJyb3IoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgdHJpZ2dlckNoYW5FcnJvcigpe1xuICAgIHRoaXMuY2hhbm5lbHMuZm9yRWFjaChjaGFubmVsID0+IHtcbiAgICAgIGlmKCEoY2hhbm5lbC5pc0Vycm9yZWQoKSB8fCBjaGFubmVsLmlzTGVhdmluZygpIHx8IGNoYW5uZWwuaXNDbG9zZWQoKSkpe1xuICAgICAgICBjaGFubmVsLnRyaWdnZXIoQ0hBTk5FTF9FVkVOVFMuZXJyb3IpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgY29ubmVjdGlvblN0YXRlKCl7XG4gICAgc3dpdGNoKHRoaXMuY29ubiAmJiB0aGlzLmNvbm4ucmVhZHlTdGF0ZSl7XG4gICAgICBjYXNlIFNPQ0tFVF9TVEFURVMuY29ubmVjdGluZzogcmV0dXJuIFwiY29ubmVjdGluZ1wiXG4gICAgICBjYXNlIFNPQ0tFVF9TVEFURVMub3BlbjogcmV0dXJuIFwib3BlblwiXG4gICAgICBjYXNlIFNPQ0tFVF9TVEFURVMuY2xvc2luZzogcmV0dXJuIFwiY2xvc2luZ1wiXG4gICAgICBkZWZhdWx0OiByZXR1cm4gXCJjbG9zZWRcIlxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICovXG4gIGlzQ29ubmVjdGVkKCl7IHJldHVybiB0aGlzLmNvbm5lY3Rpb25TdGF0ZSgpID09PSBcIm9wZW5cIiB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqXG4gICAqIEBwYXJhbSB7Q2hhbm5lbH1cbiAgICovXG4gIHJlbW92ZShjaGFubmVsKXtcbiAgICB0aGlzLm9mZihjaGFubmVsLnN0YXRlQ2hhbmdlUmVmcylcbiAgICB0aGlzLmNoYW5uZWxzID0gdGhpcy5jaGFubmVscy5maWx0ZXIoYyA9PiBjICE9PSBjaGFubmVsKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYG9uT3BlbmAsIGBvbkNsb3NlYCwgYG9uRXJyb3IsYCBhbmQgYG9uTWVzc2FnZWAgcmVnaXN0cmF0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHtyZWZzfSAtIGxpc3Qgb2YgcmVmcyByZXR1cm5lZCBieSBjYWxscyB0b1xuICAgKiAgICAgICAgICAgICAgICAgYG9uT3BlbmAsIGBvbkNsb3NlYCwgYG9uRXJyb3IsYCBhbmQgYG9uTWVzc2FnZWBcbiAgICovXG4gIG9mZihyZWZzKXtcbiAgICBmb3IobGV0IGtleSBpbiB0aGlzLnN0YXRlQ2hhbmdlQ2FsbGJhY2tzKXtcbiAgICAgIHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3Nba2V5XSA9IHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3Nba2V5XS5maWx0ZXIoKFtyZWZdKSA9PiB7XG4gICAgICAgIHJldHVybiByZWZzLmluZGV4T2YocmVmKSA9PT0gLTFcbiAgICAgIH0pXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYXRlcyBhIG5ldyBjaGFubmVsIGZvciB0aGUgZ2l2ZW4gdG9waWNcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcGljXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjaGFuUGFyYW1zIC0gUGFyYW1ldGVycyBmb3IgdGhlIGNoYW5uZWxcbiAgICogQHJldHVybnMge0NoYW5uZWx9XG4gICAqL1xuICBjaGFubmVsKHRvcGljLCBjaGFuUGFyYW1zID0ge30pe1xuICAgIGxldCBjaGFuID0gbmV3IENoYW5uZWwodG9waWMsIGNoYW5QYXJhbXMsIHRoaXMpXG4gICAgdGhpcy5jaGFubmVscy5wdXNoKGNoYW4pXG4gICAgcmV0dXJuIGNoYW5cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICAgKi9cbiAgcHVzaChkYXRhKXtcbiAgICBpZih0aGlzLmhhc0xvZ2dlcigpKXtcbiAgICAgIGxldCB7dG9waWMsIGV2ZW50LCBwYXlsb2FkLCByZWYsIGpvaW5fcmVmfSA9IGRhdGFcbiAgICAgIHRoaXMubG9nKFwicHVzaFwiLCBgJHt0b3BpY30gJHtldmVudH0gKCR7am9pbl9yZWZ9LCAke3JlZn0pYCwgcGF5bG9hZClcbiAgICB9XG5cbiAgICBpZih0aGlzLmlzQ29ubmVjdGVkKCkpe1xuICAgICAgdGhpcy5lbmNvZGUoZGF0YSwgcmVzdWx0ID0+IHRoaXMuY29ubi5zZW5kKHJlc3VsdCkpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2VuZEJ1ZmZlci5wdXNoKCgpID0+IHRoaXMuZW5jb2RlKGRhdGEsIHJlc3VsdCA9PiB0aGlzLmNvbm4uc2VuZChyZXN1bHQpKSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBuZXh0IG1lc3NhZ2UgcmVmLCBhY2NvdW50aW5nIGZvciBvdmVyZmxvd3NcbiAgICogQHJldHVybnMge3N0cmluZ31cbiAgICovXG4gIG1ha2VSZWYoKXtcbiAgICBsZXQgbmV3UmVmID0gdGhpcy5yZWYgKyAxXG4gICAgaWYobmV3UmVmID09PSB0aGlzLnJlZil7IHRoaXMucmVmID0gMCB9IGVsc2UgeyB0aGlzLnJlZiA9IG5ld1JlZiB9XG5cbiAgICByZXR1cm4gdGhpcy5yZWYudG9TdHJpbmcoKVxuICB9XG5cbiAgc2VuZEhlYXJ0YmVhdCgpe1xuICAgIGlmKHRoaXMucGVuZGluZ0hlYXJ0YmVhdFJlZiAmJiAhdGhpcy5pc0Nvbm5lY3RlZCgpKXsgcmV0dXJuIH1cbiAgICB0aGlzLnBlbmRpbmdIZWFydGJlYXRSZWYgPSB0aGlzLm1ha2VSZWYoKVxuICAgIHRoaXMucHVzaCh7dG9waWM6IFwicGhvZW5peFwiLCBldmVudDogXCJoZWFydGJlYXRcIiwgcGF5bG9hZDoge30sIHJlZjogdGhpcy5wZW5kaW5nSGVhcnRiZWF0UmVmfSlcbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVvdXRUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5oZWFydGJlYXRUaW1lb3V0KCksIHRoaXMuaGVhcnRiZWF0SW50ZXJ2YWxNcylcbiAgfVxuXG4gIGZsdXNoU2VuZEJ1ZmZlcigpe1xuICAgIGlmKHRoaXMuaXNDb25uZWN0ZWQoKSAmJiB0aGlzLnNlbmRCdWZmZXIubGVuZ3RoID4gMCl7XG4gICAgICB0aGlzLnNlbmRCdWZmZXIuZm9yRWFjaChjYWxsYmFjayA9PiBjYWxsYmFjaygpKVxuICAgICAgdGhpcy5zZW5kQnVmZmVyID0gW11cbiAgICB9XG4gIH1cblxuICBvbkNvbm5NZXNzYWdlKHJhd01lc3NhZ2Upe1xuICAgIHRoaXMuZGVjb2RlKHJhd01lc3NhZ2UuZGF0YSwgbXNnID0+IHtcbiAgICAgIGxldCB7dG9waWMsIGV2ZW50LCBwYXlsb2FkLCByZWYsIGpvaW5fcmVmfSA9IG1zZ1xuICAgICAgaWYocmVmICYmIHJlZiA9PT0gdGhpcy5wZW5kaW5nSGVhcnRiZWF0UmVmKXtcbiAgICAgICAgdGhpcy5jbGVhckhlYXJ0YmVhdHMoKVxuICAgICAgICB0aGlzLnBlbmRpbmdIZWFydGJlYXRSZWYgPSBudWxsXG4gICAgICAgIHRoaXMuaGVhcnRiZWF0VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHRoaXMuc2VuZEhlYXJ0YmVhdCgpLCB0aGlzLmhlYXJ0YmVhdEludGVydmFsTXMpXG4gICAgICB9XG5cbiAgICAgIGlmKHRoaXMuaGFzTG9nZ2VyKCkpIHRoaXMubG9nKFwicmVjZWl2ZVwiLCBgJHtwYXlsb2FkLnN0YXR1cyB8fCBcIlwifSAke3RvcGljfSAke2V2ZW50fSAke3JlZiAmJiBcIihcIiArIHJlZiArIFwiKVwiIHx8IFwiXCJ9YCwgcGF5bG9hZClcblxuICAgICAgZm9yKGxldCBpID0gMDsgaSA8IHRoaXMuY2hhbm5lbHMubGVuZ3RoOyBpKyspe1xuICAgICAgICBjb25zdCBjaGFubmVsID0gdGhpcy5jaGFubmVsc1tpXVxuICAgICAgICBpZighY2hhbm5lbC5pc01lbWJlcih0b3BpYywgZXZlbnQsIHBheWxvYWQsIGpvaW5fcmVmKSl7IGNvbnRpbnVlIH1cbiAgICAgICAgY2hhbm5lbC50cmlnZ2VyKGV2ZW50LCBwYXlsb2FkLCByZWYsIGpvaW5fcmVmKVxuICAgICAgfVxuXG4gICAgICBmb3IobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGF0ZUNoYW5nZUNhbGxiYWNrcy5tZXNzYWdlLmxlbmd0aDsgaSsrKXtcbiAgICAgICAgbGV0IFssIGNhbGxiYWNrXSA9IHRoaXMuc3RhdGVDaGFuZ2VDYWxsYmFja3MubWVzc2FnZVtpXVxuICAgICAgICBjYWxsYmFjayhtc2cpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIGxlYXZlT3BlblRvcGljKHRvcGljKXtcbiAgICBsZXQgZHVwQ2hhbm5lbCA9IHRoaXMuY2hhbm5lbHMuZmluZChjID0+IGMudG9waWMgPT09IHRvcGljICYmIChjLmlzSm9pbmVkKCkgfHwgYy5pc0pvaW5pbmcoKSkpXG4gICAgaWYoZHVwQ2hhbm5lbCl7XG4gICAgICBpZih0aGlzLmhhc0xvZ2dlcigpKSB0aGlzLmxvZyhcInRyYW5zcG9ydFwiLCBgbGVhdmluZyBkdXBsaWNhdGUgdG9waWMgXCIke3RvcGljfVwiYClcbiAgICAgIGR1cENoYW5uZWwubGVhdmUoKVxuICAgIH1cbiAgfVxufVxuIiwgImV4cG9ydCBjb25zdCBDT05TRUNVVElWRV9SRUxPQURTID0gXCJjb25zZWN1dGl2ZS1yZWxvYWRzXCI7XG5leHBvcnQgY29uc3QgTUFYX1JFTE9BRFMgPSAxMDtcbmV4cG9ydCBjb25zdCBSRUxPQURfSklUVEVSX01JTiA9IDUwMDA7XG5leHBvcnQgY29uc3QgUkVMT0FEX0pJVFRFUl9NQVggPSAxMDAwMDtcbmV4cG9ydCBjb25zdCBGQUlMU0FGRV9KSVRURVIgPSAzMDAwMDtcbmV4cG9ydCBjb25zdCBQSFhfRVZFTlRfQ0xBU1NFUyA9IFtcbiAgXCJwaHgtY2xpY2stbG9hZGluZ1wiLFxuICBcInBoeC1jaGFuZ2UtbG9hZGluZ1wiLFxuICBcInBoeC1zdWJtaXQtbG9hZGluZ1wiLFxuICBcInBoeC1rZXlkb3duLWxvYWRpbmdcIixcbiAgXCJwaHgta2V5dXAtbG9hZGluZ1wiLFxuICBcInBoeC1ibHVyLWxvYWRpbmdcIixcbiAgXCJwaHgtZm9jdXMtbG9hZGluZ1wiLFxuICBcInBoeC1ob29rLWxvYWRpbmdcIixcbl07XG5leHBvcnQgY29uc3QgUEhYX0NPTVBPTkVOVCA9IFwiZGF0YS1waHgtY29tcG9uZW50XCI7XG5leHBvcnQgY29uc3QgUEhYX1ZJRVdfUkVGID0gXCJkYXRhLXBoeC12aWV3XCI7XG5leHBvcnQgY29uc3QgUEhYX0xJVkVfTElOSyA9IFwiZGF0YS1waHgtbGlua1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9UUkFDS19TVEFUSUMgPSBcInRyYWNrLXN0YXRpY1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9MSU5LX1NUQVRFID0gXCJkYXRhLXBoeC1saW5rLXN0YXRlXCI7XG5leHBvcnQgY29uc3QgUEhYX1JFRl9MT0FESU5HID0gXCJkYXRhLXBoeC1yZWYtbG9hZGluZ1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9SRUZfU1JDID0gXCJkYXRhLXBoeC1yZWYtc3JjXCI7XG5leHBvcnQgY29uc3QgUEhYX1JFRl9MT0NLID0gXCJkYXRhLXBoeC1yZWYtbG9ja1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9QRU5ESU5HX1JFRlMgPSBcInBoeC1wZW5kaW5nLXJlZnNcIjtcbmV4cG9ydCBjb25zdCBQSFhfVFJBQ0tfVVBMT0FEUyA9IFwidHJhY2stdXBsb2Fkc1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9VUExPQURfUkVGID0gXCJkYXRhLXBoeC11cGxvYWQtcmVmXCI7XG5leHBvcnQgY29uc3QgUEhYX1BSRUZMSUdIVEVEX1JFRlMgPSBcImRhdGEtcGh4LXByZWZsaWdodGVkLXJlZnNcIjtcbmV4cG9ydCBjb25zdCBQSFhfRE9ORV9SRUZTID0gXCJkYXRhLXBoeC1kb25lLXJlZnNcIjtcbmV4cG9ydCBjb25zdCBQSFhfRFJPUF9UQVJHRVQgPSBcImRyb3AtdGFyZ2V0XCI7XG5leHBvcnQgY29uc3QgUEhYX0FDVElWRV9FTlRSWV9SRUZTID0gXCJkYXRhLXBoeC1hY3RpdmUtcmVmc1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9MSVZFX0ZJTEVfVVBEQVRFRCA9IFwicGh4OmxpdmUtZmlsZTp1cGRhdGVkXCI7XG5leHBvcnQgY29uc3QgUEhYX1NLSVAgPSBcImRhdGEtcGh4LXNraXBcIjtcbmV4cG9ydCBjb25zdCBQSFhfTUFHSUNfSUQgPSBcImRhdGEtcGh4LWlkXCI7XG5leHBvcnQgY29uc3QgUEhYX1BSVU5FID0gXCJkYXRhLXBoeC1wcnVuZVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9DT05ORUNURURfQ0xBU1MgPSBcInBoeC1jb25uZWN0ZWRcIjtcbmV4cG9ydCBjb25zdCBQSFhfTE9BRElOR19DTEFTUyA9IFwicGh4LWxvYWRpbmdcIjtcbmV4cG9ydCBjb25zdCBQSFhfRVJST1JfQ0xBU1MgPSBcInBoeC1lcnJvclwiO1xuZXhwb3J0IGNvbnN0IFBIWF9DTElFTlRfRVJST1JfQ0xBU1MgPSBcInBoeC1jbGllbnQtZXJyb3JcIjtcbmV4cG9ydCBjb25zdCBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTID0gXCJwaHgtc2VydmVyLWVycm9yXCI7XG5leHBvcnQgY29uc3QgUEhYX1BBUkVOVF9JRCA9IFwiZGF0YS1waHgtcGFyZW50LWlkXCI7XG5leHBvcnQgY29uc3QgUEhYX01BSU4gPSBcImRhdGEtcGh4LW1haW5cIjtcbmV4cG9ydCBjb25zdCBQSFhfUk9PVF9JRCA9IFwiZGF0YS1waHgtcm9vdC1pZFwiO1xuZXhwb3J0IGNvbnN0IFBIWF9WSUVXUE9SVF9UT1AgPSBcInZpZXdwb3J0LXRvcFwiO1xuZXhwb3J0IGNvbnN0IFBIWF9WSUVXUE9SVF9CT1RUT00gPSBcInZpZXdwb3J0LWJvdHRvbVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9UUklHR0VSX0FDVElPTiA9IFwidHJpZ2dlci1hY3Rpb25cIjtcbmV4cG9ydCBjb25zdCBQSFhfSEFTX0ZPQ1VTRUQgPSBcInBoeC1oYXMtZm9jdXNlZFwiO1xuZXhwb3J0IGNvbnN0IEZPQ1VTQUJMRV9JTlBVVFMgPSBbXG4gIFwidGV4dFwiLFxuICBcInRleHRhcmVhXCIsXG4gIFwibnVtYmVyXCIsXG4gIFwiZW1haWxcIixcbiAgXCJwYXNzd29yZFwiLFxuICBcInNlYXJjaFwiLFxuICBcInRlbFwiLFxuICBcInVybFwiLFxuICBcImRhdGVcIixcbiAgXCJ0aW1lXCIsXG4gIFwiZGF0ZXRpbWUtbG9jYWxcIixcbiAgXCJjb2xvclwiLFxuICBcInJhbmdlXCIsXG5dO1xuZXhwb3J0IGNvbnN0IENIRUNLQUJMRV9JTlBVVFMgPSBbXCJjaGVja2JveFwiLCBcInJhZGlvXCJdO1xuZXhwb3J0IGNvbnN0IFBIWF9IQVNfU1VCTUlUVEVEID0gXCJwaHgtaGFzLXN1Ym1pdHRlZFwiO1xuZXhwb3J0IGNvbnN0IFBIWF9TRVNTSU9OID0gXCJkYXRhLXBoeC1zZXNzaW9uXCI7XG5leHBvcnQgY29uc3QgUEhYX1ZJRVdfU0VMRUNUT1IgPSBgWyR7UEhYX1NFU1NJT059XWA7XG5leHBvcnQgY29uc3QgUEhYX1NUSUNLWSA9IFwiZGF0YS1waHgtc3RpY2t5XCI7XG5leHBvcnQgY29uc3QgUEhYX1NUQVRJQyA9IFwiZGF0YS1waHgtc3RhdGljXCI7XG5leHBvcnQgY29uc3QgUEhYX1JFQURPTkxZID0gXCJkYXRhLXBoeC1yZWFkb25seVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9ESVNBQkxFRCA9IFwiZGF0YS1waHgtZGlzYWJsZWRcIjtcbmV4cG9ydCBjb25zdCBQSFhfRElTQUJMRV9XSVRIID0gXCJkaXNhYmxlLXdpdGhcIjtcbmV4cG9ydCBjb25zdCBQSFhfRElTQUJMRV9XSVRIX1JFU1RPUkUgPSBcImRhdGEtcGh4LWRpc2FibGUtd2l0aC1yZXN0b3JlXCI7XG5leHBvcnQgY29uc3QgUEhYX0hPT0sgPSBcImhvb2tcIjtcbmV4cG9ydCBjb25zdCBQSFhfREVCT1VOQ0UgPSBcImRlYm91bmNlXCI7XG5leHBvcnQgY29uc3QgUEhYX1RIUk9UVExFID0gXCJ0aHJvdHRsZVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9VUERBVEUgPSBcInVwZGF0ZVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9TVFJFQU0gPSBcInN0cmVhbVwiO1xuZXhwb3J0IGNvbnN0IFBIWF9TVFJFQU1fUkVGID0gXCJkYXRhLXBoeC1zdHJlYW1cIjtcbmV4cG9ydCBjb25zdCBQSFhfUE9SVEFMID0gXCJkYXRhLXBoeC1wb3J0YWxcIjtcbmV4cG9ydCBjb25zdCBQSFhfVEVMRVBPUlRFRF9SRUYgPSBcImRhdGEtcGh4LXRlbGVwb3J0ZWRcIjtcbmV4cG9ydCBjb25zdCBQSFhfVEVMRVBPUlRFRF9TUkMgPSBcImRhdGEtcGh4LXRlbGVwb3J0ZWQtc3JjXCI7XG5leHBvcnQgY29uc3QgUEhYX1JVTlRJTUVfSE9PSyA9IFwiZGF0YS1waHgtcnVudGltZS1ob29rXCI7XG5leHBvcnQgY29uc3QgUEhYX0xWX1BJRCA9IFwiZGF0YS1waHgtcGlkXCI7XG5leHBvcnQgY29uc3QgUEhYX0tFWSA9IFwia2V5XCI7XG5leHBvcnQgY29uc3QgUEhYX1BSSVZBVEUgPSBcInBoeFByaXZhdGVcIjtcbmV4cG9ydCBjb25zdCBQSFhfQVVUT19SRUNPVkVSID0gXCJhdXRvLXJlY292ZXJcIjtcbmV4cG9ydCBjb25zdCBQSFhfTFZfREVCVUcgPSBcInBoeDpsaXZlLXNvY2tldDpkZWJ1Z1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9MVl9QUk9GSUxFID0gXCJwaHg6bGl2ZS1zb2NrZXQ6cHJvZmlsaW5nXCI7XG5leHBvcnQgY29uc3QgUEhYX0xWX0xBVEVOQ1lfU0lNID0gXCJwaHg6bGl2ZS1zb2NrZXQ6bGF0ZW5jeS1zaW1cIjtcbmV4cG9ydCBjb25zdCBQSFhfTFZfSElTVE9SWV9QT1NJVElPTiA9IFwicGh4Om5hdi1oaXN0b3J5LXBvc2l0aW9uXCI7XG5leHBvcnQgY29uc3QgUEhYX1BST0dSRVNTID0gXCJwcm9ncmVzc1wiO1xuZXhwb3J0IGNvbnN0IFBIWF9NT1VOVEVEID0gXCJtb3VudGVkXCI7XG5leHBvcnQgY29uc3QgUEhYX1JFTE9BRF9TVEFUVVMgPSBcIl9fcGhvZW5peF9yZWxvYWRfc3RhdHVzX19cIjtcbmV4cG9ydCBjb25zdCBMT0FERVJfVElNRU9VVCA9IDE7XG5leHBvcnQgY29uc3QgTUFYX0NISUxEX0pPSU5fQVRURU1QVFMgPSAzO1xuZXhwb3J0IGNvbnN0IEJFRk9SRV9VTkxPQURfTE9BREVSX1RJTUVPVVQgPSAyMDA7XG5leHBvcnQgY29uc3QgRElTQ09OTkVDVEVEX1RJTUVPVVQgPSA1MDA7XG5leHBvcnQgY29uc3QgQklORElOR19QUkVGSVggPSBcInBoeC1cIjtcbmV4cG9ydCBjb25zdCBQVVNIX1RJTUVPVVQgPSAzMDAwMDtcbmV4cG9ydCBjb25zdCBMSU5LX0hFQURFUiA9IFwieC1yZXF1ZXN0ZWQtd2l0aFwiO1xuZXhwb3J0IGNvbnN0IFJFU1BPTlNFX1VSTF9IRUFERVIgPSBcIngtcmVzcG9uc2UtdXJsXCI7XG5leHBvcnQgY29uc3QgREVCT1VOQ0VfVFJJR0dFUiA9IFwiZGVib3VuY2UtdHJpZ2dlclwiO1xuZXhwb3J0IGNvbnN0IFRIUk9UVExFRCA9IFwidGhyb3R0bGVkXCI7XG5leHBvcnQgY29uc3QgREVCT1VOQ0VfUFJFVl9LRVkgPSBcImRlYm91bmNlLXByZXYta2V5XCI7XG5leHBvcnQgY29uc3QgREVGQVVMVFMgPSB7XG4gIGRlYm91bmNlOiAzMDAsXG4gIHRocm90dGxlOiAzMDAsXG59O1xuZXhwb3J0IGNvbnN0IFBIWF9QRU5ESU5HX0FUVFJTID0gW1BIWF9SRUZfTE9BRElORywgUEhYX1JFRl9TUkMsIFBIWF9SRUZfTE9DS107XG4vLyBSZW5kZXJlZFxuZXhwb3J0IGNvbnN0IFNUQVRJQyA9IFwic1wiO1xuZXhwb3J0IGNvbnN0IFJPT1QgPSBcInJcIjtcbmV4cG9ydCBjb25zdCBDT01QT05FTlRTID0gXCJjXCI7XG5leHBvcnQgY29uc3QgS0VZRUQgPSBcImtcIjtcbmV4cG9ydCBjb25zdCBLRVlFRF9DT1VOVCA9IFwia2NcIjtcbmV4cG9ydCBjb25zdCBFVkVOVFMgPSBcImVcIjtcbmV4cG9ydCBjb25zdCBSRVBMWSA9IFwiclwiO1xuZXhwb3J0IGNvbnN0IFRJVExFID0gXCJ0XCI7XG5leHBvcnQgY29uc3QgVEVNUExBVEVTID0gXCJwXCI7XG5leHBvcnQgY29uc3QgU1RSRUFNID0gXCJzdHJlYW1cIjtcbiIsICJpbXBvcnQgeyBsb2dFcnJvciB9IGZyb20gXCIuL3V0aWxzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVudHJ5VXBsb2FkZXIge1xuICBjb25zdHJ1Y3RvcihlbnRyeSwgY29uZmlnLCBsaXZlU29ja2V0KSB7XG4gICAgY29uc3QgeyBjaHVua19zaXplLCBjaHVua190aW1lb3V0IH0gPSBjb25maWc7XG4gICAgdGhpcy5saXZlU29ja2V0ID0gbGl2ZVNvY2tldDtcbiAgICB0aGlzLmVudHJ5ID0gZW50cnk7XG4gICAgdGhpcy5vZmZzZXQgPSAwO1xuICAgIHRoaXMuY2h1bmtTaXplID0gY2h1bmtfc2l6ZTtcbiAgICB0aGlzLmNodW5rVGltZW91dCA9IGNodW5rX3RpbWVvdXQ7XG4gICAgdGhpcy5jaHVua1RpbWVyID0gbnVsbDtcbiAgICB0aGlzLmVycm9yZWQgPSBmYWxzZTtcbiAgICB0aGlzLnVwbG9hZENoYW5uZWwgPSBsaXZlU29ja2V0LmNoYW5uZWwoYGx2dToke2VudHJ5LnJlZn1gLCB7XG4gICAgICB0b2tlbjogZW50cnkubWV0YWRhdGEoKSxcbiAgICB9KTtcbiAgfVxuXG4gIGVycm9yKHJlYXNvbikge1xuICAgIGlmICh0aGlzLmVycm9yZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy51cGxvYWRDaGFubmVsLmxlYXZlKCk7XG4gICAgdGhpcy5lcnJvcmVkID0gdHJ1ZTtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5jaHVua1RpbWVyKTtcbiAgICB0aGlzLmVudHJ5LmVycm9yKHJlYXNvbik7XG4gIH1cblxuICB1cGxvYWQoKSB7XG4gICAgdGhpcy51cGxvYWRDaGFubmVsLm9uRXJyb3IoKHJlYXNvbikgPT4gdGhpcy5lcnJvcihyZWFzb24pKTtcbiAgICB0aGlzLnVwbG9hZENoYW5uZWxcbiAgICAgIC5qb2luKClcbiAgICAgIC5yZWNlaXZlKFwib2tcIiwgKF9kYXRhKSA9PiB0aGlzLnJlYWROZXh0Q2h1bmsoKSlcbiAgICAgIC5yZWNlaXZlKFwiZXJyb3JcIiwgKHJlYXNvbikgPT4gdGhpcy5lcnJvcihyZWFzb24pKTtcbiAgfVxuXG4gIGlzRG9uZSgpIHtcbiAgICByZXR1cm4gdGhpcy5vZmZzZXQgPj0gdGhpcy5lbnRyeS5maWxlLnNpemU7XG4gIH1cblxuICByZWFkTmV4dENodW5rKCkge1xuICAgIGNvbnN0IHJlYWRlciA9IG5ldyB3aW5kb3cuRmlsZVJlYWRlcigpO1xuICAgIGNvbnN0IGJsb2IgPSB0aGlzLmVudHJ5LmZpbGUuc2xpY2UoXG4gICAgICB0aGlzLm9mZnNldCxcbiAgICAgIHRoaXMuY2h1bmtTaXplICsgdGhpcy5vZmZzZXQsXG4gICAgKTtcbiAgICByZWFkZXIub25sb2FkID0gKGUpID0+IHtcbiAgICAgIGlmIChlLnRhcmdldC5lcnJvciA9PT0gbnVsbCkge1xuICAgICAgICB0aGlzLm9mZnNldCArPSAvKiogQHR5cGUge0FycmF5QnVmZmVyfSAqLyAoZS50YXJnZXQucmVzdWx0KS5ieXRlTGVuZ3RoO1xuICAgICAgICB0aGlzLnB1c2hDaHVuaygvKiogQHR5cGUge0FycmF5QnVmZmVyfSAqLyAoZS50YXJnZXQucmVzdWx0KSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gbG9nRXJyb3IoXCJSZWFkIGVycm9yOiBcIiArIGUudGFyZ2V0LmVycm9yKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHJlYWRlci5yZWFkQXNBcnJheUJ1ZmZlcihibG9iKTtcbiAgfVxuXG4gIHB1c2hDaHVuayhjaHVuaykge1xuICAgIGlmICghdGhpcy51cGxvYWRDaGFubmVsLmlzSm9pbmVkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy51cGxvYWRDaGFubmVsXG4gICAgICAucHVzaChcImNodW5rXCIsIGNodW5rLCB0aGlzLmNodW5rVGltZW91dClcbiAgICAgIC5yZWNlaXZlKFwib2tcIiwgKCkgPT4ge1xuICAgICAgICB0aGlzLmVudHJ5LnByb2dyZXNzKCh0aGlzLm9mZnNldCAvIHRoaXMuZW50cnkuZmlsZS5zaXplKSAqIDEwMCk7XG4gICAgICAgIGlmICghdGhpcy5pc0RvbmUoKSkge1xuICAgICAgICAgIHRoaXMuY2h1bmtUaW1lciA9IHNldFRpbWVvdXQoXG4gICAgICAgICAgICAoKSA9PiB0aGlzLnJlYWROZXh0Q2h1bmsoKSxcbiAgICAgICAgICAgIHRoaXMubGl2ZVNvY2tldC5nZXRMYXRlbmN5U2ltKCkgfHwgMCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgLnJlY2VpdmUoXCJlcnJvclwiLCAoeyByZWFzb24gfSkgPT4gdGhpcy5lcnJvcihyZWFzb24pKTtcbiAgfVxufVxuIiwgImltcG9ydCB7IFBIWF9WSUVXX1NFTEVDVE9SIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5cbmltcG9ydCBFbnRyeVVwbG9hZGVyIGZyb20gXCIuL2VudHJ5X3VwbG9hZGVyXCI7XG5cbmV4cG9ydCBjb25zdCBsb2dFcnJvciA9IChtc2csIG9iaikgPT4gY29uc29sZS5lcnJvciAmJiBjb25zb2xlLmVycm9yKG1zZywgb2JqKTtcblxuZXhwb3J0IGNvbnN0IGlzQ2lkID0gKGNpZCkgPT4ge1xuICBjb25zdCB0eXBlID0gdHlwZW9mIGNpZDtcbiAgcmV0dXJuIHR5cGUgPT09IFwibnVtYmVyXCIgfHwgKHR5cGUgPT09IFwic3RyaW5nXCIgJiYgL14oMHxbMS05XVxcZCopJC8udGVzdChjaWQpKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3REdXBsaWNhdGVJZHMoKSB7XG4gIGNvbnN0IGlkcyA9IG5ldyBTZXQoKTtcbiAgY29uc3QgZWxlbXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFwiKltpZF1cIik7XG4gIGZvciAobGV0IGkgPSAwLCBsZW4gPSBlbGVtcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgIGlmIChpZHMuaGFzKGVsZW1zW2ldLmlkKSkge1xuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgYE11bHRpcGxlIElEcyBkZXRlY3RlZDogJHtlbGVtc1tpXS5pZH0uIEVuc3VyZSB1bmlxdWUgZWxlbWVudCBpZHMuYCxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlkcy5hZGQoZWxlbXNbaV0uaWQpO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZGV0ZWN0SW52YWxpZFN0cmVhbUluc2VydHMoaW5zZXJ0cykge1xuICBjb25zdCBlcnJvcnMgPSBuZXcgU2V0KCk7XG4gIE9iamVjdC5rZXlzKGluc2VydHMpLmZvckVhY2goKGlkKSA9PiB7XG4gICAgY29uc3Qgc3RyZWFtRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgaWYgKFxuICAgICAgc3RyZWFtRWwgJiZcbiAgICAgIHN0cmVhbUVsLnBhcmVudEVsZW1lbnQgJiZcbiAgICAgIHN0cmVhbUVsLnBhcmVudEVsZW1lbnQuZ2V0QXR0cmlidXRlKFwicGh4LXVwZGF0ZVwiKSAhPT0gXCJzdHJlYW1cIlxuICAgICkge1xuICAgICAgZXJyb3JzLmFkZChcbiAgICAgICAgYFRoZSBzdHJlYW0gY29udGFpbmVyIHdpdGggaWQgXCIke3N0cmVhbUVsLnBhcmVudEVsZW1lbnQuaWR9XCIgaXMgbWlzc2luZyB0aGUgcGh4LXVwZGF0ZT1cInN0cmVhbVwiIGF0dHJpYnV0ZS4gRW5zdXJlIGl0IGlzIHNldCBmb3Igc3RyZWFtcyB0byB3b3JrIHByb3Blcmx5LmAsXG4gICAgICApO1xuICAgIH1cbiAgfSk7XG4gIGVycm9ycy5mb3JFYWNoKChlcnJvcikgPT4gY29uc29sZS5lcnJvcihlcnJvcikpO1xufVxuXG5leHBvcnQgY29uc3QgZGVidWcgPSAodmlldywga2luZCwgbXNnLCBvYmopID0+IHtcbiAgaWYgKHZpZXcubGl2ZVNvY2tldC5pc0RlYnVnRW5hYmxlZCgpKSB7XG4gICAgY29uc29sZS5sb2coYCR7dmlldy5pZH0gJHtraW5kfTogJHttc2d9IC0gYCwgb2JqKTtcbiAgfVxufTtcblxuLy8gd3JhcHMgdmFsdWUgaW4gY2xvc3VyZSBvciByZXR1cm5zIGNsb3N1cmVcbmV4cG9ydCBjb25zdCBjbG9zdXJlID0gKHZhbCkgPT5cbiAgdHlwZW9mIHZhbCA9PT0gXCJmdW5jdGlvblwiXG4gICAgPyB2YWxcbiAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgIH07XG5cbmV4cG9ydCBjb25zdCBjbG9uZSA9IChvYmopID0+IHtcbiAgcmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkob2JqKSk7XG59O1xuXG5leHBvcnQgY29uc3QgY2xvc2VzdFBoeEJpbmRpbmcgPSAoZWwsIGJpbmRpbmcsIGJvcmRlckVsKSA9PiB7XG4gIGRvIHtcbiAgICBpZiAoZWwubWF0Y2hlcyhgWyR7YmluZGluZ31dYCkgJiYgIWVsLmRpc2FibGVkKSB7XG4gICAgICByZXR1cm4gZWw7XG4gICAgfVxuICAgIGVsID0gZWwucGFyZW50RWxlbWVudCB8fCBlbC5wYXJlbnROb2RlO1xuICB9IHdoaWxlIChcbiAgICBlbCAhPT0gbnVsbCAmJlxuICAgIGVsLm5vZGVUeXBlID09PSAxICYmXG4gICAgISgoYm9yZGVyRWwgJiYgYm9yZGVyRWwuaXNTYW1lTm9kZShlbCkpIHx8IGVsLm1hdGNoZXMoUEhYX1ZJRVdfU0VMRUNUT1IpKVxuICApO1xuICByZXR1cm4gbnVsbDtcbn07XG5cbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChvYmopID0+IHtcbiAgcmV0dXJuIG9iaiAhPT0gbnVsbCAmJiB0eXBlb2Ygb2JqID09PSBcIm9iamVjdFwiICYmICEob2JqIGluc3RhbmNlb2YgQXJyYXkpO1xufTtcblxuZXhwb3J0IGNvbnN0IGlzRXF1YWxPYmogPSAob2JqMSwgb2JqMikgPT5cbiAgSlNPTi5zdHJpbmdpZnkob2JqMSkgPT09IEpTT04uc3RyaW5naWZ5KG9iajIpO1xuXG5leHBvcnQgY29uc3QgaXNFbXB0eSA9IChvYmopID0+IHtcbiAgZm9yIChjb25zdCB4IGluIG9iaikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbmV4cG9ydCBjb25zdCBtYXliZSA9IChlbCwgY2FsbGJhY2spID0+IGVsICYmIGNhbGxiYWNrKGVsKTtcblxuZXhwb3J0IGNvbnN0IGNoYW5uZWxVcGxvYWRlciA9IGZ1bmN0aW9uIChlbnRyaWVzLCBvbkVycm9yLCByZXNwLCBsaXZlU29ja2V0KSB7XG4gIGVudHJpZXMuZm9yRWFjaCgoZW50cnkpID0+IHtcbiAgICBjb25zdCBlbnRyeVVwbG9hZGVyID0gbmV3IEVudHJ5VXBsb2FkZXIoZW50cnksIHJlc3AuY29uZmlnLCBsaXZlU29ja2V0KTtcbiAgICBlbnRyeVVwbG9hZGVyLnVwbG9hZCgpO1xuICB9KTtcbn07XG4iLCAiY29uc3QgQnJvd3NlciA9IHtcbiAgY2FuUHVzaFN0YXRlKCkge1xuICAgIHJldHVybiB0eXBlb2YgaGlzdG9yeS5wdXNoU3RhdGUgIT09IFwidW5kZWZpbmVkXCI7XG4gIH0sXG5cbiAgZHJvcExvY2FsKGxvY2FsU3RvcmFnZSwgbmFtZXNwYWNlLCBzdWJrZXkpIHtcbiAgICByZXR1cm4gbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5sb2NhbEtleShuYW1lc3BhY2UsIHN1YmtleSkpO1xuICB9LFxuXG4gIHVwZGF0ZUxvY2FsKGxvY2FsU3RvcmFnZSwgbmFtZXNwYWNlLCBzdWJrZXksIGluaXRpYWwsIGZ1bmMpIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5nZXRMb2NhbChsb2NhbFN0b3JhZ2UsIG5hbWVzcGFjZSwgc3Via2V5KTtcbiAgICBjb25zdCBrZXkgPSB0aGlzLmxvY2FsS2V5KG5hbWVzcGFjZSwgc3Via2V5KTtcbiAgICBjb25zdCBuZXdWYWwgPSBjdXJyZW50ID09PSBudWxsID8gaW5pdGlhbCA6IGZ1bmMoY3VycmVudCk7XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oa2V5LCBKU09OLnN0cmluZ2lmeShuZXdWYWwpKTtcbiAgICByZXR1cm4gbmV3VmFsO1xuICB9LFxuXG4gIGdldExvY2FsKGxvY2FsU3RvcmFnZSwgbmFtZXNwYWNlLCBzdWJrZXkpIHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSh0aGlzLmxvY2FsS2V5KG5hbWVzcGFjZSwgc3Via2V5KSkpO1xuICB9LFxuXG4gIHVwZGF0ZUN1cnJlbnRTdGF0ZShjYWxsYmFjaykge1xuICAgIGlmICghdGhpcy5jYW5QdXNoU3RhdGUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBoaXN0b3J5LnJlcGxhY2VTdGF0ZShcbiAgICAgIGNhbGxiYWNrKGhpc3Rvcnkuc3RhdGUgfHwge30pLFxuICAgICAgXCJcIixcbiAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmLFxuICAgICk7XG4gIH0sXG5cbiAgcHVzaFN0YXRlKGtpbmQsIG1ldGEsIHRvKSB7XG4gICAgaWYgKHRoaXMuY2FuUHVzaFN0YXRlKCkpIHtcbiAgICAgIGlmICh0byAhPT0gd2luZG93LmxvY2F0aW9uLmhyZWYpIHtcbiAgICAgICAgaWYgKG1ldGEudHlwZSA9PSBcInJlZGlyZWN0XCIgJiYgbWV0YS5zY3JvbGwpIHtcbiAgICAgICAgICAvLyBJZiB3ZSdyZSByZWRpcmVjdGluZyBzdG9yZSB0aGUgY3VycmVudCBzY3JvbGxZIGZvciB0aGUgY3VycmVudCBoaXN0b3J5IHN0YXRlLlxuICAgICAgICAgIGNvbnN0IGN1cnJlbnRTdGF0ZSA9IGhpc3Rvcnkuc3RhdGUgfHwge307XG4gICAgICAgICAgY3VycmVudFN0YXRlLnNjcm9sbCA9IG1ldGEuc2Nyb2xsO1xuICAgICAgICAgIGhpc3RvcnkucmVwbGFjZVN0YXRlKGN1cnJlbnRTdGF0ZSwgXCJcIiwgd2luZG93LmxvY2F0aW9uLmhyZWYpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZXRlIG1ldGEuc2Nyb2xsOyAvLyBPbmx5IHN0b3JlIHRoZSBzY3JvbGwgaW4gdGhlIHJlZGlyZWN0IGNhc2UuXG4gICAgICAgIGhpc3Rvcnlba2luZCArIFwiU3RhdGVcIl0obWV0YSwgXCJcIiwgdG8gfHwgbnVsbCk7IC8vIElFIHdpbGwgY29lcmNlIHVuZGVmaW5lZCB0byBzdHJpbmdcblxuICAgICAgICAvLyB3aGVuIHVzaW5nIG5hdmlnYXRlLCB3ZSdkIGNhbGwgcHVzaFN0YXRlIGltbWVkaWF0ZWx5IGJlZm9yZSBwYXRjaGluZyB0aGUgRE9NLFxuICAgICAgICAvLyBqdW1waW5nIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGUgcGFnZSwgZWZmZWN0aXZlbHkgaWdub3JpbmcgdGhlIHNjcm9sbEludG9WaWV3O1xuICAgICAgICAvLyB0aGVyZWZvcmUgd2Ugd2FpdCBmb3IgdGhlIG5leHQgZnJhbWUgKGFmdGVyIHRoZSBET00gcGF0Y2gpIGFuZCBvbmx5IHRoZW4gdHJ5XG4gICAgICAgIC8vIHRvIHNjcm9sbCB0byB0aGUgaGFzaEVsXG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGhhc2hFbCA9IHRoaXMuZ2V0SGFzaFRhcmdldEVsKHdpbmRvdy5sb2NhdGlvbi5oYXNoKTtcblxuICAgICAgICAgIGlmIChoYXNoRWwpIHtcbiAgICAgICAgICAgIGhhc2hFbC5zY3JvbGxJbnRvVmlldygpO1xuICAgICAgICAgIH0gZWxzZSBpZiAobWV0YS50eXBlID09PSBcInJlZGlyZWN0XCIpIHtcbiAgICAgICAgICAgIHdpbmRvdy5zY3JvbGwoMCwgMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yZWRpcmVjdCh0byk7XG4gICAgfVxuICB9LFxuXG4gIHNldENvb2tpZShuYW1lLCB2YWx1ZSwgbWF4QWdlU2Vjb25kcykge1xuICAgIGNvbnN0IGV4cGlyZXMgPVxuICAgICAgdHlwZW9mIG1heEFnZVNlY29uZHMgPT09IFwibnVtYmVyXCIgPyBgIG1heC1hZ2U9JHttYXhBZ2VTZWNvbmRzfTtgIDogXCJcIjtcbiAgICBkb2N1bWVudC5jb29raWUgPSBgJHtuYW1lfT0ke3ZhbHVlfTske2V4cGlyZXN9IHBhdGg9L2A7XG4gIH0sXG5cbiAgZ2V0Q29va2llKG5hbWUpIHtcbiAgICByZXR1cm4gZG9jdW1lbnQuY29va2llLnJlcGxhY2UoXG4gICAgICBuZXcgUmVnRXhwKGAoPzooPzpefC4qO1xccyopJHtuYW1lfVxccypcXD1cXHMqKFteO10qKS4qJCl8Xi4qJGApLFxuICAgICAgXCIkMVwiLFxuICAgICk7XG4gIH0sXG5cbiAgZGVsZXRlQ29va2llKG5hbWUpIHtcbiAgICBkb2N1bWVudC5jb29raWUgPSBgJHtuYW1lfT07IG1heC1hZ2U9LTE7IHBhdGg9L2A7XG4gIH0sXG5cbiAgcmVkaXJlY3QoXG4gICAgdG9VUkwsXG4gICAgZmxhc2gsXG4gICAgbmF2aWdhdGUgPSAodXJsKSA9PiB7XG4gICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IHVybDtcbiAgICB9LFxuICApIHtcbiAgICBpZiAoZmxhc2gpIHtcbiAgICAgIHRoaXMuc2V0Q29va2llKFwiX19waG9lbml4X2ZsYXNoX19cIiwgZmxhc2gsIDYwKTtcbiAgICB9XG4gICAgbmF2aWdhdGUodG9VUkwpO1xuICB9LFxuXG4gIGxvY2FsS2V5KG5hbWVzcGFjZSwgc3Via2V5KSB7XG4gICAgcmV0dXJuIGAke25hbWVzcGFjZX0tJHtzdWJrZXl9YDtcbiAgfSxcblxuICBnZXRIYXNoVGFyZ2V0RWwobWF5YmVIYXNoKSB7XG4gICAgY29uc3QgaGFzaCA9IG1heWJlSGFzaC50b1N0cmluZygpLnN1YnN0cmluZygxKTtcbiAgICBpZiAoaGFzaCA9PT0gXCJcIikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICByZXR1cm4gKFxuICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaGFzaCkgfHxcbiAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYGFbbmFtZT1cIiR7aGFzaH1cIl1gKVxuICAgICk7XG4gIH0sXG59O1xuXG5leHBvcnQgZGVmYXVsdCBCcm93c2VyO1xuIiwgImltcG9ydCB7XG4gIENIRUNLQUJMRV9JTlBVVFMsXG4gIERFQk9VTkNFX1BSRVZfS0VZLFxuICBERUJPVU5DRV9UUklHR0VSLFxuICBGT0NVU0FCTEVfSU5QVVRTLFxuICBQSFhfQ09NUE9ORU5ULFxuICBQSFhfVklFV19SRUYsXG4gIFBIWF9URUxFUE9SVEVEX1JFRixcbiAgUEhYX0hBU19GT0NVU0VELFxuICBQSFhfSEFTX1NVQk1JVFRFRCxcbiAgUEhYX01BSU4sXG4gIFBIWF9QQVJFTlRfSUQsXG4gIFBIWF9QUklWQVRFLFxuICBQSFhfUkVGX1NSQyxcbiAgUEhYX1JFRl9MT0NLLFxuICBQSFhfUEVORElOR19BVFRSUyxcbiAgUEhYX1JPT1RfSUQsXG4gIFBIWF9TRVNTSU9OLFxuICBQSFhfU1RBVElDLFxuICBQSFhfVVBMT0FEX1JFRixcbiAgUEhYX1ZJRVdfU0VMRUNUT1IsXG4gIFBIWF9TVElDS1ksXG4gIFBIWF9FVkVOVF9DTEFTU0VTLFxuICBUSFJPVFRMRUQsXG4gIFBIWF9QT1JUQUwsXG4gIFBIWF9TVFJFQU0sXG59IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG5pbXBvcnQgeyBsb2dFcnJvciB9IGZyb20gXCIuL3V0aWxzXCI7XG5cbmNvbnN0IERPTSA9IHtcbiAgYnlJZChpZCkge1xuICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCkgfHwgbG9nRXJyb3IoYG5vIGlkIGZvdW5kIGZvciAke2lkfWApO1xuICB9LFxuXG4gIHJlbW92ZUNsYXNzKGVsLCBjbGFzc05hbWUpIHtcbiAgICBlbC5jbGFzc0xpc3QucmVtb3ZlKGNsYXNzTmFtZSk7XG4gICAgaWYgKGVsLmNsYXNzTGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgIGVsLnJlbW92ZUF0dHJpYnV0ZShcImNsYXNzXCIpO1xuICAgIH1cbiAgfSxcblxuICBhbGwobm9kZSwgcXVlcnksIGNhbGxiYWNrKSB7XG4gICAgaWYgKCFub2RlKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIGNvbnN0IGFycmF5ID0gQXJyYXkuZnJvbShub2RlLnF1ZXJ5U2VsZWN0b3JBbGwocXVlcnkpKTtcbiAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgIGFycmF5LmZvckVhY2goY2FsbGJhY2spO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXk7XG4gIH0sXG5cbiAgY2hpbGROb2RlTGVuZ3RoKGh0bWwpIHtcbiAgICBjb25zdCB0ZW1wbGF0ZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0ZW1wbGF0ZVwiKTtcbiAgICB0ZW1wbGF0ZS5pbm5lckhUTUwgPSBodG1sO1xuICAgIHJldHVybiB0ZW1wbGF0ZS5jb250ZW50LmNoaWxkRWxlbWVudENvdW50O1xuICB9LFxuXG4gIGlzVXBsb2FkSW5wdXQoZWwpIHtcbiAgICByZXR1cm4gZWwudHlwZSA9PT0gXCJmaWxlXCIgJiYgZWwuZ2V0QXR0cmlidXRlKFBIWF9VUExPQURfUkVGKSAhPT0gbnVsbDtcbiAgfSxcblxuICBpc0F1dG9VcGxvYWQoaW5wdXRFbCkge1xuICAgIHJldHVybiBpbnB1dEVsLmhhc0F0dHJpYnV0ZShcImRhdGEtcGh4LWF1dG8tdXBsb2FkXCIpO1xuICB9LFxuXG4gIGZpbmRVcGxvYWRJbnB1dHMobm9kZSkge1xuICAgIGNvbnN0IGZvcm1JZCA9IG5vZGUuaWQ7XG4gICAgY29uc3QgaW5wdXRzT3V0c2lkZUZvcm0gPSB0aGlzLmFsbChcbiAgICAgIGRvY3VtZW50LFxuICAgICAgYGlucHV0W3R5cGU9XCJmaWxlXCJdWyR7UEhYX1VQTE9BRF9SRUZ9XVtmb3JtPVwiJHtmb3JtSWR9XCJdYCxcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmFsbChub2RlLCBgaW5wdXRbdHlwZT1cImZpbGVcIl1bJHtQSFhfVVBMT0FEX1JFRn1dYCkuY29uY2F0KFxuICAgICAgaW5wdXRzT3V0c2lkZUZvcm0sXG4gICAgKTtcbiAgfSxcblxuICBmaW5kQ29tcG9uZW50Tm9kZUxpc3Qodmlld0lkLCBjaWQsIGRvYyA9IGRvY3VtZW50KSB7XG4gICAgcmV0dXJuIHRoaXMuYWxsKFxuICAgICAgZG9jLFxuICAgICAgYFske1BIWF9WSUVXX1JFRn09XCIke3ZpZXdJZH1cIl1bJHtQSFhfQ09NUE9ORU5UfT1cIiR7Y2lkfVwiXWAsXG4gICAgKTtcbiAgfSxcblxuICBpc1BoeERlc3Ryb3llZChub2RlKSB7XG4gICAgcmV0dXJuIG5vZGUuaWQgJiYgRE9NLnByaXZhdGUobm9kZSwgXCJkZXN0cm95ZWRcIikgPyB0cnVlIDogZmFsc2U7XG4gIH0sXG5cbiAgd2FudHNOZXdUYWIoZSkge1xuICAgIGNvbnN0IHdhbnRzTmV3VGFiID1cbiAgICAgIGUuY3RybEtleSB8fCBlLnNoaWZ0S2V5IHx8IGUubWV0YUtleSB8fCAoZS5idXR0b24gJiYgZS5idXR0b24gPT09IDEpO1xuICAgIGNvbnN0IGlzRG93bmxvYWQgPVxuICAgICAgZS50YXJnZXQgaW5zdGFuY2VvZiBIVE1MQW5jaG9yRWxlbWVudCAmJlxuICAgICAgZS50YXJnZXQuaGFzQXR0cmlidXRlKFwiZG93bmxvYWRcIik7XG4gICAgY29uc3QgaXNUYXJnZXRCbGFuayA9XG4gICAgICBlLnRhcmdldC5oYXNBdHRyaWJ1dGUoXCJ0YXJnZXRcIikgJiZcbiAgICAgIGUudGFyZ2V0LmdldEF0dHJpYnV0ZShcInRhcmdldFwiKS50b0xvd2VyQ2FzZSgpID09PSBcIl9ibGFua1wiO1xuICAgIGNvbnN0IGlzVGFyZ2V0TmFtZWRUYWIgPVxuICAgICAgZS50YXJnZXQuaGFzQXR0cmlidXRlKFwidGFyZ2V0XCIpICYmXG4gICAgICAhZS50YXJnZXQuZ2V0QXR0cmlidXRlKFwidGFyZ2V0XCIpLnN0YXJ0c1dpdGgoXCJfXCIpO1xuICAgIHJldHVybiB3YW50c05ld1RhYiB8fCBpc1RhcmdldEJsYW5rIHx8IGlzRG93bmxvYWQgfHwgaXNUYXJnZXROYW1lZFRhYjtcbiAgfSxcblxuICBpc1VubG9hZGFibGVGb3JtU3VibWl0KGUpIHtcbiAgICAvLyBJZ25vcmUgZm9ybSBzdWJtaXNzaW9ucyBpbnRlbmRlZCB0byBjbG9zZSBhIG5hdGl2ZSA8ZGlhbG9nPiBlbGVtZW50XG4gICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSFRNTC9FbGVtZW50L2RpYWxvZyN1c2FnZV9ub3Rlc1xuICAgIGNvbnN0IGlzRGlhbG9nU3VibWl0ID1cbiAgICAgIChlLnRhcmdldCAmJiBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoXCJtZXRob2RcIikgPT09IFwiZGlhbG9nXCIpIHx8XG4gICAgICAoZS5zdWJtaXR0ZXIgJiYgZS5zdWJtaXR0ZXIuZ2V0QXR0cmlidXRlKFwiZm9ybW1ldGhvZFwiKSA9PT0gXCJkaWFsb2dcIik7XG5cbiAgICBpZiAoaXNEaWFsb2dTdWJtaXQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICFlLmRlZmF1bHRQcmV2ZW50ZWQgJiYgIXRoaXMud2FudHNOZXdUYWIoZSk7XG4gICAgfVxuICB9LFxuXG4gIGlzTmV3UGFnZUNsaWNrKGUsIGN1cnJlbnRMb2NhdGlvbikge1xuICAgIGNvbnN0IGhyZWYgPVxuICAgICAgZS50YXJnZXQgaW5zdGFuY2VvZiBIVE1MQW5jaG9yRWxlbWVudFxuICAgICAgICA/IGUudGFyZ2V0LmdldEF0dHJpYnV0ZShcImhyZWZcIilcbiAgICAgICAgOiBudWxsO1xuICAgIGxldCB1cmw7XG5cbiAgICBpZiAoZS5kZWZhdWx0UHJldmVudGVkIHx8IGhyZWYgPT09IG51bGwgfHwgdGhpcy53YW50c05ld1RhYihlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoaHJlZi5zdGFydHNXaXRoKFwibWFpbHRvOlwiKSB8fCBocmVmLnN0YXJ0c1dpdGgoXCJ0ZWw6XCIpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChlLnRhcmdldC5pc0NvbnRlbnRFZGl0YWJsZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICB1cmwgPSBuZXcgVVJMKGhyZWYpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdXJsID0gbmV3IFVSTChocmVmLCBjdXJyZW50TG9jYXRpb24pO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIGJhZCBVUkwsIGZhbGxiYWNrIHRvIGxldCBicm93c2VyIHRyeSBpdCBhcyBleHRlcm5hbFxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICB1cmwuaG9zdCA9PT0gY3VycmVudExvY2F0aW9uLmhvc3QgJiZcbiAgICAgIHVybC5wcm90b2NvbCA9PT0gY3VycmVudExvY2F0aW9uLnByb3RvY29sXG4gICAgKSB7XG4gICAgICBpZiAoXG4gICAgICAgIHVybC5wYXRobmFtZSA9PT0gY3VycmVudExvY2F0aW9uLnBhdGhuYW1lICYmXG4gICAgICAgIHVybC5zZWFyY2ggPT09IGN1cnJlbnRMb2NhdGlvbi5zZWFyY2hcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdXJsLmhhc2ggPT09IFwiXCIgJiYgIXVybC5ocmVmLmVuZHNXaXRoKFwiI1wiKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVybC5wcm90b2NvbC5zdGFydHNXaXRoKFwiaHR0cFwiKTtcbiAgfSxcblxuICBtYXJrUGh4Q2hpbGREZXN0cm95ZWQoZWwpIHtcbiAgICBpZiAodGhpcy5pc1BoeENoaWxkKGVsKSkge1xuICAgICAgZWwuc2V0QXR0cmlidXRlKFBIWF9TRVNTSU9OLCBcIlwiKTtcbiAgICB9XG4gICAgdGhpcy5wdXRQcml2YXRlKGVsLCBcImRlc3Ryb3llZFwiLCB0cnVlKTtcbiAgfSxcblxuICBmaW5kUGh4Q2hpbGRyZW5JbkZyYWdtZW50KGh0bWwsIHBhcmVudElkKSB7XG4gICAgY29uc3QgdGVtcGxhdGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwidGVtcGxhdGVcIik7XG4gICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gaHRtbDtcbiAgICByZXR1cm4gdGhpcy5maW5kUGh4Q2hpbGRyZW4odGVtcGxhdGUuY29udGVudCwgcGFyZW50SWQpO1xuICB9LFxuXG4gIGlzSWdub3JlZChlbCwgcGh4VXBkYXRlKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIChlbC5nZXRBdHRyaWJ1dGUocGh4VXBkYXRlKSB8fCBlbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXBoeC11cGRhdGVcIikpID09PVxuICAgICAgXCJpZ25vcmVcIlxuICAgICk7XG4gIH0sXG5cbiAgaXNQaHhVcGRhdGUoZWwsIHBoeFVwZGF0ZSwgdXBkYXRlVHlwZXMpIHtcbiAgICByZXR1cm4gKFxuICAgICAgZWwuZ2V0QXR0cmlidXRlICYmIHVwZGF0ZVR5cGVzLmluZGV4T2YoZWwuZ2V0QXR0cmlidXRlKHBoeFVwZGF0ZSkpID49IDBcbiAgICApO1xuICB9LFxuXG4gIGZpbmRQaHhTdGlja3koZWwpIHtcbiAgICByZXR1cm4gdGhpcy5hbGwoZWwsIGBbJHtQSFhfU1RJQ0tZfV1gKTtcbiAgfSxcblxuICBmaW5kUGh4Q2hpbGRyZW4oZWwsIHBhcmVudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuYWxsKGVsLCBgJHtQSFhfVklFV19TRUxFQ1RPUn1bJHtQSFhfUEFSRU5UX0lEfT1cIiR7cGFyZW50SWR9XCJdYCk7XG4gIH0sXG5cbiAgZmluZEV4aXN0aW5nUGFyZW50Q0lEcyh2aWV3SWQsIGNpZHMpIHtcbiAgICAvLyB3ZSBvbmx5IHdhbnQgdG8gZmluZCBwYXJlbnRzIHRoYXQgZXhpc3Qgb24gdGhlIHBhZ2VcbiAgICAvLyBpZiBhIGNpZCBpcyBub3Qgb24gdGhlIHBhZ2UsIHRoZSBvbmx5IHdheSBpdCBjYW4gYmUgYWRkZWQgYmFjayB0byB0aGUgcGFnZVxuICAgIC8vIGlzIGlmIGEgcGFyZW50IGFkZHMgaXQgYmFjaywgdGhlcmVmb3JlIGlmIGEgY2lkIGRvZXMgbm90IGV4aXN0IG9uIHRoZSBwYWdlLFxuICAgIC8vIHdlIHNob3VsZCBub3QgdHJ5IHRvIHJlbmRlciBpdCBieSBpdHNlbGYgKGJlY2F1c2UgaXQgd291bGQgYmUgcmVuZGVyZWQgdHdpY2UsXG4gICAgLy8gb25lIGJ5IHRoZSBwYXJlbnQsIGFuZCBhIHNlY29uZCB0aW1lIGJ5IGl0c2VsZilcbiAgICBjb25zdCBwYXJlbnRDaWRzID0gbmV3IFNldCgpO1xuICAgIGNvbnN0IGNoaWxkcmVuQ2lkcyA9IG5ldyBTZXQoKTtcblxuICAgIGNpZHMuZm9yRWFjaCgoY2lkKSA9PiB7XG4gICAgICB0aGlzLmFsbChcbiAgICAgICAgZG9jdW1lbnQsXG4gICAgICAgIGBbJHtQSFhfVklFV19SRUZ9PVwiJHt2aWV3SWR9XCJdWyR7UEhYX0NPTVBPTkVOVH09XCIke2NpZH1cIl1gLFxuICAgICAgKS5mb3JFYWNoKChwYXJlbnQpID0+IHtcbiAgICAgICAgcGFyZW50Q2lkcy5hZGQoY2lkKTtcbiAgICAgICAgdGhpcy5hbGwocGFyZW50LCBgWyR7UEhYX1ZJRVdfUkVGfT1cIiR7dmlld0lkfVwiXVske1BIWF9DT01QT05FTlR9XWApXG4gICAgICAgICAgLm1hcCgoZWwpID0+IHBhcnNlSW50KGVsLmdldEF0dHJpYnV0ZShQSFhfQ09NUE9ORU5UKSkpXG4gICAgICAgICAgLmZvckVhY2goKGNoaWxkQ0lEKSA9PiBjaGlsZHJlbkNpZHMuYWRkKGNoaWxkQ0lEKSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNoaWxkcmVuQ2lkcy5mb3JFYWNoKChjaGlsZENpZCkgPT4gcGFyZW50Q2lkcy5kZWxldGUoY2hpbGRDaWQpKTtcblxuICAgIHJldHVybiBwYXJlbnRDaWRzO1xuICB9LFxuXG4gIHByaXZhdGUoZWwsIGtleSkge1xuICAgIHJldHVybiBlbFtQSFhfUFJJVkFURV0gJiYgZWxbUEhYX1BSSVZBVEVdW2tleV07XG4gIH0sXG5cbiAgZGVsZXRlUHJpdmF0ZShlbCwga2V5KSB7XG4gICAgZWxbUEhYX1BSSVZBVEVdICYmIGRlbGV0ZSBlbFtQSFhfUFJJVkFURV1ba2V5XTtcbiAgfSxcblxuICBwdXRQcml2YXRlKGVsLCBrZXksIHZhbHVlKSB7XG4gICAgaWYgKCFlbFtQSFhfUFJJVkFURV0pIHtcbiAgICAgIGVsW1BIWF9QUklWQVRFXSA9IHt9O1xuICAgIH1cbiAgICBlbFtQSFhfUFJJVkFURV1ba2V5XSA9IHZhbHVlO1xuICB9LFxuXG4gIHVwZGF0ZVByaXZhdGUoZWwsIGtleSwgZGVmYXVsdFZhbCwgdXBkYXRlRnVuYykge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5wcml2YXRlKGVsLCBrZXkpO1xuICAgIGlmIChleGlzdGluZyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLnB1dFByaXZhdGUoZWwsIGtleSwgdXBkYXRlRnVuYyhkZWZhdWx0VmFsKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucHV0UHJpdmF0ZShlbCwga2V5LCB1cGRhdGVGdW5jKGV4aXN0aW5nKSk7XG4gICAgfVxuICB9LFxuXG4gIHN5bmNQZW5kaW5nQXR0cnMoZnJvbUVsLCB0b0VsKSB7XG4gICAgaWYgKCFmcm9tRWwuaGFzQXR0cmlidXRlKFBIWF9SRUZfU1JDKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBQSFhfRVZFTlRfQ0xBU1NFUy5mb3JFYWNoKChjbGFzc05hbWUpID0+IHtcbiAgICAgIGZyb21FbC5jbGFzc0xpc3QuY29udGFpbnMoY2xhc3NOYW1lKSAmJiB0b0VsLmNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lKTtcbiAgICB9KTtcbiAgICBQSFhfUEVORElOR19BVFRSUy5maWx0ZXIoKGF0dHIpID0+IGZyb21FbC5oYXNBdHRyaWJ1dGUoYXR0cikpLmZvckVhY2goXG4gICAgICAoYXR0cikgPT4ge1xuICAgICAgICB0b0VsLnNldEF0dHJpYnV0ZShhdHRyLCBmcm9tRWwuZ2V0QXR0cmlidXRlKGF0dHIpKTtcbiAgICAgIH0sXG4gICAgKTtcbiAgfSxcblxuICBjb3B5UHJpdmF0ZXModGFyZ2V0LCBzb3VyY2UpIHtcbiAgICBpZiAoc291cmNlW1BIWF9QUklWQVRFXSkge1xuICAgICAgdGFyZ2V0W1BIWF9QUklWQVRFXSA9IHNvdXJjZVtQSFhfUFJJVkFURV07XG4gICAgfVxuICB9LFxuXG4gIHB1dFRpdGxlKHN0cikge1xuICAgIGNvbnN0IHRpdGxlRWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwidGl0bGVcIik7XG4gICAgaWYgKHRpdGxlRWwpIHtcbiAgICAgIGNvbnN0IHsgcHJlZml4LCBzdWZmaXgsIGRlZmF1bHQ6IGRlZmF1bHRUaXRsZSB9ID0gdGl0bGVFbC5kYXRhc2V0O1xuICAgICAgY29uc3QgaXNFbXB0eSA9IHR5cGVvZiBzdHIgIT09IFwic3RyaW5nXCIgfHwgc3RyLnRyaW0oKSA9PT0gXCJcIjtcbiAgICAgIGlmIChpc0VtcHR5ICYmIHR5cGVvZiBkZWZhdWx0VGl0bGUgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbm5lciA9IGlzRW1wdHkgPyBkZWZhdWx0VGl0bGUgOiBzdHI7XG4gICAgICBkb2N1bWVudC50aXRsZSA9IGAke3ByZWZpeCB8fCBcIlwifSR7aW5uZXIgfHwgXCJcIn0ke3N1ZmZpeCB8fCBcIlwifWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRvY3VtZW50LnRpdGxlID0gc3RyO1xuICAgIH1cbiAgfSxcblxuICBkZWJvdW5jZShcbiAgICBlbCxcbiAgICBldmVudCxcbiAgICBwaHhEZWJvdW5jZSxcbiAgICBkZWZhdWx0RGVib3VuY2UsXG4gICAgcGh4VGhyb3R0bGUsXG4gICAgZGVmYXVsdFRocm90dGxlLFxuICAgIGFzeW5jRmlsdGVyLFxuICAgIGNhbGxiYWNrLFxuICApIHtcbiAgICBsZXQgZGVib3VuY2UgPSBlbC5nZXRBdHRyaWJ1dGUocGh4RGVib3VuY2UpO1xuICAgIGxldCB0aHJvdHRsZSA9IGVsLmdldEF0dHJpYnV0ZShwaHhUaHJvdHRsZSk7XG5cbiAgICBpZiAoZGVib3VuY2UgPT09IFwiXCIpIHtcbiAgICAgIGRlYm91bmNlID0gZGVmYXVsdERlYm91bmNlO1xuICAgIH1cbiAgICBpZiAodGhyb3R0bGUgPT09IFwiXCIpIHtcbiAgICAgIHRocm90dGxlID0gZGVmYXVsdFRocm90dGxlO1xuICAgIH1cbiAgICBjb25zdCB2YWx1ZSA9IGRlYm91bmNlIHx8IHRocm90dGxlO1xuICAgIHN3aXRjaCAodmFsdWUpIHtcbiAgICAgIGNhc2UgbnVsbDpcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKCk7XG5cbiAgICAgIGNhc2UgXCJibHVyXCI6XG4gICAgICAgIHRoaXMuaW5jQ3ljbGUoZWwsIFwiZGVib3VuY2UtYmx1ci1jeWNsZVwiLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKGFzeW5jRmlsdGVyKCkpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHRoaXMub25jZShlbCwgXCJkZWJvdW5jZS1ibHVyXCIpKSB7XG4gICAgICAgICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihcImJsdXJcIiwgKCkgPT5cbiAgICAgICAgICAgIHRoaXMudHJpZ2dlckN5Y2xlKGVsLCBcImRlYm91bmNlLWJsdXItY3ljbGVcIiksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGNvbnN0IHRpbWVvdXQgPSBwYXJzZUludCh2YWx1ZSk7XG4gICAgICAgIGNvbnN0IHRyaWdnZXIgPSAoKSA9PlxuICAgICAgICAgIHRocm90dGxlID8gdGhpcy5kZWxldGVQcml2YXRlKGVsLCBUSFJPVFRMRUQpIDogY2FsbGJhY2soKTtcbiAgICAgICAgY29uc3QgY3VycmVudEN5Y2xlID0gdGhpcy5pbmNDeWNsZShlbCwgREVCT1VOQ0VfVFJJR0dFUiwgdHJpZ2dlcik7XG4gICAgICAgIGlmIChpc05hTih0aW1lb3V0KSkge1xuICAgICAgICAgIHJldHVybiBsb2dFcnJvcihgaW52YWxpZCB0aHJvdHRsZS9kZWJvdW5jZSB2YWx1ZTogJHt2YWx1ZX1gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhyb3R0bGUpIHtcbiAgICAgICAgICBsZXQgbmV3S2V5RG93biA9IGZhbHNlO1xuICAgICAgICAgIGlmIChldmVudC50eXBlID09PSBcImtleWRvd25cIikge1xuICAgICAgICAgICAgY29uc3QgcHJldktleSA9IHRoaXMucHJpdmF0ZShlbCwgREVCT1VOQ0VfUFJFVl9LRVkpO1xuICAgICAgICAgICAgdGhpcy5wdXRQcml2YXRlKGVsLCBERUJPVU5DRV9QUkVWX0tFWSwgZXZlbnQua2V5KTtcbiAgICAgICAgICAgIG5ld0tleURvd24gPSBwcmV2S2V5ICE9PSBldmVudC5rZXk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFuZXdLZXlEb3duICYmIHRoaXMucHJpdmF0ZShlbCwgVEhST1RUTEVEKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgICAgY29uc3QgdCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICBpZiAoYXN5bmNGaWx0ZXIoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMudHJpZ2dlckN5Y2xlKGVsLCBERUJPVU5DRV9UUklHR0VSKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGltZW91dCk7XG4gICAgICAgICAgICB0aGlzLnB1dFByaXZhdGUoZWwsIFRIUk9UVExFRCwgdCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGFzeW5jRmlsdGVyKCkpIHtcbiAgICAgICAgICAgICAgdGhpcy50cmlnZ2VyQ3ljbGUoZWwsIERFQk9VTkNFX1RSSUdHRVIsIGN1cnJlbnRDeWNsZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSwgdGltZW91dCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBmb3JtID0gZWwuZm9ybTtcbiAgICAgICAgaWYgKGZvcm0gJiYgdGhpcy5vbmNlKGZvcm0sIFwiYmluZC1kZWJvdW5jZVwiKSkge1xuICAgICAgICAgIGZvcm0uYWRkRXZlbnRMaXN0ZW5lcihcInN1Ym1pdFwiLCAoKSA9PiB7XG4gICAgICAgICAgICBBcnJheS5mcm9tKG5ldyBGb3JtRGF0YShmb3JtKS5lbnRyaWVzKCksIChbbmFtZV0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgaW5wdXQgPSBmb3JtLnF1ZXJ5U2VsZWN0b3IoYFtuYW1lPVwiJHtuYW1lfVwiXWApO1xuICAgICAgICAgICAgICB0aGlzLmluY0N5Y2xlKGlucHV0LCBERUJPVU5DRV9UUklHR0VSKTtcbiAgICAgICAgICAgICAgdGhpcy5kZWxldGVQcml2YXRlKGlucHV0LCBUSFJPVFRMRUQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMub25jZShlbCwgXCJiaW5kLWRlYm91bmNlXCIpKSB7XG4gICAgICAgICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihcImJsdXJcIiwgKCkgPT4ge1xuICAgICAgICAgICAgLy8gYmVjYXVzZSB3ZSB0cmlnZ2VyIHRoZSBjYWxsYmFjayBoZXJlLFxuICAgICAgICAgICAgLy8gd2UgYWxzbyBjbGVhciB0aGUgdGhyb3R0bGUgdGltZW91dCB0byBwcmV2ZW50IHRoZSBjYWxsYmFja1xuICAgICAgICAgICAgLy8gZnJvbSBiZWluZyBjYWxsZWQgYWdhaW4gYWZ0ZXIgdGhlIHRpbWVvdXQgZmlyZXNcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnByaXZhdGUoZWwsIFRIUk9UVExFRCkpO1xuICAgICAgICAgICAgdGhpcy50cmlnZ2VyQ3ljbGUoZWwsIERFQk9VTkNFX1RSSUdHRVIpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICB9LFxuXG4gIHRyaWdnZXJDeWNsZShlbCwga2V5LCBjdXJyZW50Q3ljbGUpIHtcbiAgICBjb25zdCBbY3ljbGUsIHRyaWdnZXJdID0gdGhpcy5wcml2YXRlKGVsLCBrZXkpO1xuICAgIGlmICghY3VycmVudEN5Y2xlKSB7XG4gICAgICBjdXJyZW50Q3ljbGUgPSBjeWNsZTtcbiAgICB9XG4gICAgaWYgKGN1cnJlbnRDeWNsZSA9PT0gY3ljbGUpIHtcbiAgICAgIHRoaXMuaW5jQ3ljbGUoZWwsIGtleSk7XG4gICAgICB0cmlnZ2VyKCk7XG4gICAgfVxuICB9LFxuXG4gIG9uY2UoZWwsIGtleSkge1xuICAgIGlmICh0aGlzLnByaXZhdGUoZWwsIGtleSkgPT09IHRydWUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdGhpcy5wdXRQcml2YXRlKGVsLCBrZXksIHRydWUpO1xuICAgIHJldHVybiB0cnVlO1xuICB9LFxuXG4gIGluY0N5Y2xlKGVsLCBrZXksIHRyaWdnZXIgPSBmdW5jdGlvbiAoKSB7fSkge1xuICAgIGxldCBbY3VycmVudEN5Y2xlXSA9IHRoaXMucHJpdmF0ZShlbCwga2V5KSB8fCBbMCwgdHJpZ2dlcl07XG4gICAgY3VycmVudEN5Y2xlKys7XG4gICAgdGhpcy5wdXRQcml2YXRlKGVsLCBrZXksIFtjdXJyZW50Q3ljbGUsIHRyaWdnZXJdKTtcbiAgICByZXR1cm4gY3VycmVudEN5Y2xlO1xuICB9LFxuXG4gIC8vIG1haW50YWlucyBvciBhZGRzIHByaXZhdGVseSB1c2VkIGhvb2sgaW5mb3JtYXRpb25cbiAgLy8gZnJvbUVsIGFuZCB0b0VsIGNhbiBiZSB0aGUgc2FtZSBlbGVtZW50IGluIHRoZSBjYXNlIG9mIGEgbmV3bHkgYWRkZWQgbm9kZVxuICAvLyBmcm9tRWwgYW5kIHRvRWwgY2FuIGJlIGFueSBIVE1MIG5vZGUgdHlwZSwgc28gd2UgbmVlZCB0byBjaGVjayBpZiBpdCdzIGFuIGVsZW1lbnQgbm9kZVxuICBtYWludGFpblByaXZhdGVIb29rcyhmcm9tRWwsIHRvRWwsIHBoeFZpZXdwb3J0VG9wLCBwaHhWaWV3cG9ydEJvdHRvbSkge1xuICAgIC8vIG1haW50YWluIHRoZSBob29rcyBjcmVhdGVkIHdpdGggY3JlYXRlSG9va1xuICAgIGlmIChcbiAgICAgIGZyb21FbC5oYXNBdHRyaWJ1dGUgJiZcbiAgICAgIGZyb21FbC5oYXNBdHRyaWJ1dGUoXCJkYXRhLXBoeC1ob29rXCIpICYmXG4gICAgICAhdG9FbC5oYXNBdHRyaWJ1dGUoXCJkYXRhLXBoeC1ob29rXCIpXG4gICAgKSB7XG4gICAgICB0b0VsLnNldEF0dHJpYnV0ZShcImRhdGEtcGh4LWhvb2tcIiwgZnJvbUVsLmdldEF0dHJpYnV0ZShcImRhdGEtcGh4LWhvb2tcIikpO1xuICAgIH1cbiAgICAvLyBhZGQgaG9va3MgdG8gZWxlbWVudHMgd2l0aCB2aWV3cG9ydCBhdHRyaWJ1dGVzXG4gICAgaWYgKFxuICAgICAgdG9FbC5oYXNBdHRyaWJ1dGUgJiZcbiAgICAgICh0b0VsLmhhc0F0dHJpYnV0ZShwaHhWaWV3cG9ydFRvcCkgfHxcbiAgICAgICAgdG9FbC5oYXNBdHRyaWJ1dGUocGh4Vmlld3BvcnRCb3R0b20pKVxuICAgICkge1xuICAgICAgdG9FbC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXBoeC1ob29rXCIsIFwiUGhvZW5peC5JbmZpbml0ZVNjcm9sbFwiKTtcbiAgICB9XG4gIH0sXG5cbiAgcHV0Q3VzdG9tRWxIb29rKGVsLCBob29rKSB7XG4gICAgaWYgKGVsLmlzQ29ubmVjdGVkKSB7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXBoeC1ob29rXCIsIFwiXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBcbiAgICAgICAgaG9vayBhdHRhY2hlZCB0byBub24tY29ubmVjdGVkIERPTSBlbGVtZW50XG4gICAgICAgIGVuc3VyZSB5b3UgYXJlIGNhbGxpbmcgY3JlYXRlSG9vayB3aXRoaW4geW91ciBjb25uZWN0ZWRDYWxsYmFjay4gJHtlbC5vdXRlckhUTUx9XG4gICAgICBgKTtcbiAgICB9XG4gICAgdGhpcy5wdXRQcml2YXRlKGVsLCBcImN1c3RvbS1lbC1ob29rXCIsIGhvb2spO1xuICB9LFxuXG4gIGdldEN1c3RvbUVsSG9vayhlbCkge1xuICAgIHJldHVybiB0aGlzLnByaXZhdGUoZWwsIFwiY3VzdG9tLWVsLWhvb2tcIik7XG4gIH0sXG5cbiAgaXNVc2VkSW5wdXQoZWwpIHtcbiAgICByZXR1cm4gKFxuICAgICAgZWwubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmXG4gICAgICAodGhpcy5wcml2YXRlKGVsLCBQSFhfSEFTX0ZPQ1VTRUQpIHx8IHRoaXMucHJpdmF0ZShlbCwgUEhYX0hBU19TVUJNSVRURUQpKVxuICAgICk7XG4gIH0sXG5cbiAgcmVzZXRGb3JtKGZvcm0pIHtcbiAgICBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpLmZvckVhY2goKGlucHV0KSA9PiB7XG4gICAgICB0aGlzLmRlbGV0ZVByaXZhdGUoaW5wdXQsIFBIWF9IQVNfRk9DVVNFRCk7XG4gICAgICB0aGlzLmRlbGV0ZVByaXZhdGUoaW5wdXQsIFBIWF9IQVNfU1VCTUlUVEVEKTtcbiAgICB9KTtcbiAgfSxcblxuICBpc1BoeENoaWxkKG5vZGUpIHtcbiAgICByZXR1cm4gbm9kZS5nZXRBdHRyaWJ1dGUgJiYgbm9kZS5nZXRBdHRyaWJ1dGUoUEhYX1BBUkVOVF9JRCk7XG4gIH0sXG5cbiAgaXNQaHhTdGlja3kobm9kZSkge1xuICAgIHJldHVybiBub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZShQSFhfU1RJQ0tZKSAhPT0gbnVsbDtcbiAgfSxcblxuICBpc0NoaWxkT2ZBbnkoZWwsIHBhcmVudHMpIHtcbiAgICByZXR1cm4gISFwYXJlbnRzLmZpbmQoKHBhcmVudCkgPT4gcGFyZW50LmNvbnRhaW5zKGVsKSk7XG4gIH0sXG5cbiAgZmlyc3RQaHhDaGlsZChlbCkge1xuICAgIHJldHVybiB0aGlzLmlzUGh4Q2hpbGQoZWwpID8gZWwgOiB0aGlzLmFsbChlbCwgYFske1BIWF9QQVJFTlRfSUR9XWApWzBdO1xuICB9LFxuXG4gIGlzUG9ydGFsVGVtcGxhdGUoZWwpIHtcbiAgICByZXR1cm4gZWwudGFnTmFtZSA9PT0gXCJURU1QTEFURVwiICYmIGVsLmhhc0F0dHJpYnV0ZShQSFhfUE9SVEFMKTtcbiAgfSxcblxuICBjbG9zZXN0Vmlld0VsKGVsKSB7XG4gICAgLy8gZmluZCB0aGUgY2xvc2VzdCBwb3J0YWwgb3IgdmlldyBlbGVtZW50LCB3aGljaGV2ZXIgY29tZXMgZmlyc3RcbiAgICBjb25zdCBwb3J0YWxPclZpZXdFbCA9IGVsLmNsb3Nlc3QoXG4gICAgICBgWyR7UEhYX1RFTEVQT1JURURfUkVGfV0sJHtQSFhfVklFV19TRUxFQ1RPUn1gLFxuICAgICk7XG4gICAgaWYgKCFwb3J0YWxPclZpZXdFbCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGlmIChwb3J0YWxPclZpZXdFbC5oYXNBdHRyaWJ1dGUoUEhYX1RFTEVQT1JURURfUkVGKSkge1xuICAgICAgLy8gUEhYX1RFTEVQT1JURURfUkVGIGlzIHNldCB0byB0aGUgaWQgb2YgdGhlIHZpZXcgdGhhdCBvd25zIHRoZSBwb3J0YWwgZWxlbWVudFxuICAgICAgcmV0dXJuIHRoaXMuYnlJZChwb3J0YWxPclZpZXdFbC5nZXRBdHRyaWJ1dGUoUEhYX1RFTEVQT1JURURfUkVGKSk7XG4gICAgfSBlbHNlIGlmIChwb3J0YWxPclZpZXdFbC5oYXNBdHRyaWJ1dGUoUEhYX1NFU1NJT04pKSB7XG4gICAgICByZXR1cm4gcG9ydGFsT3JWaWV3RWw7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9LFxuXG4gIGRpc3BhdGNoRXZlbnQodGFyZ2V0LCBuYW1lLCBvcHRzID0ge30pIHtcbiAgICBsZXQgZGVmYXVsdEJ1YmJsZSA9IHRydWU7XG4gICAgY29uc3QgaXNVcGxvYWRUYXJnZXQgPVxuICAgICAgdGFyZ2V0Lm5vZGVOYW1lID09PSBcIklOUFVUXCIgJiYgdGFyZ2V0LnR5cGUgPT09IFwiZmlsZVwiO1xuICAgIGlmIChpc1VwbG9hZFRhcmdldCAmJiBuYW1lID09PSBcImNsaWNrXCIpIHtcbiAgICAgIGRlZmF1bHRCdWJibGUgPSBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgYnViYmxlcyA9IG9wdHMuYnViYmxlcyA9PT0gdW5kZWZpbmVkID8gZGVmYXVsdEJ1YmJsZSA6ICEhb3B0cy5idWJibGVzO1xuICAgIGNvbnN0IGV2ZW50T3B0cyA9IHtcbiAgICAgIGJ1YmJsZXM6IGJ1YmJsZXMsXG4gICAgICBjYW5jZWxhYmxlOiB0cnVlLFxuICAgICAgZGV0YWlsOiBvcHRzLmRldGFpbCB8fCB7fSxcbiAgICB9O1xuICAgIGNvbnN0IGV2ZW50ID1cbiAgICAgIG5hbWUgPT09IFwiY2xpY2tcIlxuICAgICAgICA/IG5ldyBNb3VzZUV2ZW50KFwiY2xpY2tcIiwgZXZlbnRPcHRzKVxuICAgICAgICA6IG5ldyBDdXN0b21FdmVudChuYW1lLCBldmVudE9wdHMpO1xuICAgIHRhcmdldC5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgfSxcblxuICBjbG9uZU5vZGUobm9kZSwgaHRtbCkge1xuICAgIGlmICh0eXBlb2YgaHRtbCA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgcmV0dXJuIG5vZGUuY2xvbmVOb2RlKHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBjbG9uZWQgPSBub2RlLmNsb25lTm9kZShmYWxzZSk7XG4gICAgICBjbG9uZWQuaW5uZXJIVE1MID0gaHRtbDtcbiAgICAgIHJldHVybiBjbG9uZWQ7XG4gICAgfVxuICB9LFxuXG4gIC8vIG1lcmdlIGF0dHJpYnV0ZXMgZnJvbSBzb3VyY2UgdG8gdGFyZ2V0XG4gIC8vIGlmIGFuIGVsZW1lbnQgaXMgaWdub3JlZCwgd2Ugb25seSBtZXJnZSBkYXRhIGF0dHJpYnV0ZXNcbiAgLy8gaW5jbHVkaW5nIHJlbW92aW5nIGRhdGEgYXR0cmlidXRlcyB0aGF0IGFyZSBubyBsb25nZXIgaW4gdGhlIHNvdXJjZVxuICBtZXJnZUF0dHJzKHRhcmdldCwgc291cmNlLCBvcHRzID0ge30pIHtcbiAgICBjb25zdCBleGNsdWRlID0gbmV3IFNldChvcHRzLmV4Y2x1ZGUgfHwgW10pO1xuICAgIGNvbnN0IGlzSWdub3JlZCA9IG9wdHMuaXNJZ25vcmVkO1xuICAgIGNvbnN0IHNvdXJjZUF0dHJzID0gc291cmNlLmF0dHJpYnV0ZXM7XG4gICAgZm9yIChsZXQgaSA9IHNvdXJjZUF0dHJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBjb25zdCBuYW1lID0gc291cmNlQXR0cnNbaV0ubmFtZTtcbiAgICAgIGlmICghZXhjbHVkZS5oYXMobmFtZSkpIHtcbiAgICAgICAgY29uc3Qgc291cmNlVmFsdWUgPSBzb3VyY2UuZ2V0QXR0cmlidXRlKG5hbWUpO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgdGFyZ2V0LmdldEF0dHJpYnV0ZShuYW1lKSAhPT0gc291cmNlVmFsdWUgJiZcbiAgICAgICAgICAoIWlzSWdub3JlZCB8fCAoaXNJZ25vcmVkICYmIG5hbWUuc3RhcnRzV2l0aChcImRhdGEtXCIpKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGFyZ2V0LnNldEF0dHJpYnV0ZShuYW1lLCBzb3VyY2VWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFdlIGV4Y2x1ZGUgdGhlIHZhbHVlIGZyb20gYmVpbmcgbWVyZ2VkIG9uIGZvY3VzZWQgaW5wdXRzLCBiZWNhdXNlIHRoZVxuICAgICAgICAvLyB1c2VyJ3MgaW5wdXQgc2hvdWxkIGFsd2F5cyB3aW4uXG4gICAgICAgIC8vIFdlIGNhbiBzdGlsbCBhc3NpZ24gaXQgYXMgbG9uZyBhcyB0aGUgdmFsdWUgcHJvcGVydHkgaXMgdGhlIHNhbWUsIHRob3VnaC5cbiAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhIHNpdHVhdGlvbiB3aGVyZSB0aGUgdXBkYXRlZCBob29rIGlzIG5vdCBiZWluZyB0cmlnZ2VyZWRcbiAgICAgICAgLy8gd2hlbiBhbiBpbnB1dCBpcyBiYWNrIGluIGl0cyBcIm9yaWdpbmFsIHN0YXRlXCIsIGJlY2F1c2UgdGhlIGF0dHJpYnV0ZVxuICAgICAgICAvLyB3YXMgbmV2ZXIgY2hhbmdlZCwgc2VlOlxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMjE2M1xuICAgICAgICBpZiAobmFtZSA9PT0gXCJ2YWx1ZVwiKSB7XG4gICAgICAgICAgY29uc3Qgc291cmNlVmFsdWUgPSBzb3VyY2UudmFsdWUgPz8gc291cmNlLmdldEF0dHJpYnV0ZShuYW1lKTtcbiAgICAgICAgICBpZiAodGFyZ2V0LnZhbHVlID09PSBzb3VyY2VWYWx1ZSkge1xuICAgICAgICAgICAgLy8gYWN0dWFsbHkgc2V0IHRoZSB2YWx1ZSBhdHRyaWJ1dGUgdG8gc3luYyBpdCB3aXRoIHRoZSB2YWx1ZSBwcm9wZXJ0eVxuICAgICAgICAgICAgdGFyZ2V0LnNldEF0dHJpYnV0ZShcInZhbHVlXCIsIHNvdXJjZS5nZXRBdHRyaWJ1dGUobmFtZSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldEF0dHJzID0gdGFyZ2V0LmF0dHJpYnV0ZXM7XG4gICAgZm9yIChsZXQgaSA9IHRhcmdldEF0dHJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBjb25zdCBuYW1lID0gdGFyZ2V0QXR0cnNbaV0ubmFtZTtcbiAgICAgIGlmIChpc0lnbm9yZWQpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIG5hbWUuc3RhcnRzV2l0aChcImRhdGEtXCIpICYmXG4gICAgICAgICAgIXNvdXJjZS5oYXNBdHRyaWJ1dGUobmFtZSkgJiZcbiAgICAgICAgICAhUEhYX1BFTkRJTkdfQVRUUlMuaW5jbHVkZXMobmFtZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGFyZ2V0LnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCFzb3VyY2UuaGFzQXR0cmlidXRlKG5hbWUpKSB7XG4gICAgICAgICAgdGFyZ2V0LnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBtZXJnZUZvY3VzZWRJbnB1dCh0YXJnZXQsIHNvdXJjZSkge1xuICAgIC8vIHNraXAgc2VsZWN0cyBiZWNhdXNlIEZGIHdpbGwgcmVzZXQgaGlnaGxpZ2h0ZWQgaW5kZXggZm9yIGFueSBzZXRBdHRyaWJ1dGVcbiAgICBpZiAoISh0YXJnZXQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkpIHtcbiAgICAgIERPTS5tZXJnZUF0dHJzKHRhcmdldCwgc291cmNlLCB7IGV4Y2x1ZGU6IFtcInZhbHVlXCJdIH0pO1xuICAgIH1cblxuICAgIGlmIChzb3VyY2UucmVhZE9ubHkpIHtcbiAgICAgIHRhcmdldC5zZXRBdHRyaWJ1dGUoXCJyZWFkb25seVwiLCB0cnVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGFyZ2V0LnJlbW92ZUF0dHJpYnV0ZShcInJlYWRvbmx5XCIpO1xuICAgIH1cbiAgfSxcblxuICBoYXNTZWxlY3Rpb25SYW5nZShlbCkge1xuICAgIHJldHVybiAoXG4gICAgICBlbC5zZXRTZWxlY3Rpb25SYW5nZSAmJiAoZWwudHlwZSA9PT0gXCJ0ZXh0XCIgfHwgZWwudHlwZSA9PT0gXCJ0ZXh0YXJlYVwiKVxuICAgICk7XG4gIH0sXG5cbiAgcmVzdG9yZUZvY3VzKGZvY3VzZWQsIHNlbGVjdGlvblN0YXJ0LCBzZWxlY3Rpb25FbmQpIHtcbiAgICBpZiAoZm9jdXNlZCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSB7XG4gICAgICBmb2N1c2VkLmZvY3VzKCk7XG4gICAgfVxuICAgIGlmICghRE9NLmlzVGV4dHVhbElucHV0KGZvY3VzZWQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgd2FzRm9jdXNlZCA9IGZvY3VzZWQubWF0Y2hlcyhcIjpmb2N1c1wiKTtcbiAgICBpZiAoIXdhc0ZvY3VzZWQpIHtcbiAgICAgIGZvY3VzZWQuZm9jdXMoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuaGFzU2VsZWN0aW9uUmFuZ2UoZm9jdXNlZCkpIHtcbiAgICAgIGZvY3VzZWQuc2V0U2VsZWN0aW9uUmFuZ2Uoc2VsZWN0aW9uU3RhcnQsIHNlbGVjdGlvbkVuZCk7XG4gICAgfVxuICB9LFxuXG4gIGlzRm9ybUlucHV0KGVsKSB7XG4gICAgaWYgKGVsLmxvY2FsTmFtZSAmJiBjdXN0b21FbGVtZW50cy5nZXQoZWwubG9jYWxOYW1lKSkge1xuICAgICAgLy8gQ3VzdG9tIEVsZW1lbnRzIG1heSBiZSBmb3JtIGFzc29jaWF0ZWQuIFRoaXMgYWxsb3dzIHRoZW1cbiAgICAgIC8vIHRvIHBhcnRpY2lwYXRlIHdpdGhpbiBhIGZvcm0ncyBsaWZlY3ljbGUsIGluY2x1ZGluZyBmb3JtXG4gICAgICAvLyB2YWxpZGl0eSBhbmQgZm9ybSBzdWJtaXNzaW9ucy5cbiAgICAgIC8vIFRoZSBzcGVjIGZvciBGb3JtIEFzc29jaWF0ZWQgY3VzdG9tIGVsZW1lbnRzIHJlcXVpcmVzIHRoZVxuICAgICAgLy8gY3VzdG9tIGVsZW1lbnQncyBjbGFzcyB0byBjb250YWluIGEgc3RhdGljIGJvb2xlYW4gdmFsdWUgb2YgYGZvcm1Bc3NvY2lhdGVkYFxuICAgICAgLy8gd2hpY2ggaWRlbnRpZmllcyB0aGlzIGNsYXNzIGFzIGFsbG93ZWQgdG8gYXNzb2NpYXRlIHRvIGEgZm9ybS5cbiAgICAgIC8vIFNlZSBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL2Rldi9jdXN0b20tZWxlbWVudHMuaHRtbCNjdXN0b20tZWxlbWVudHMtZmFjZS1leGFtcGxlXG4gICAgICAvLyBmb3IgZGV0YWlscy5cbiAgICAgIHJldHVybiBjdXN0b21FbGVtZW50cy5nZXQoZWwubG9jYWxOYW1lKVtgZm9ybUFzc29jaWF0ZWRgXTtcbiAgICB9XG5cbiAgICByZXR1cm4gKFxuICAgICAgL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWEpJC9pLnRlc3QoZWwudGFnTmFtZSkgJiYgZWwudHlwZSAhPT0gXCJidXR0b25cIlxuICAgICk7XG4gIH0sXG5cbiAgc3luY0F0dHJzVG9Qcm9wcyhlbCkge1xuICAgIGlmIChcbiAgICAgIGVsIGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJlxuICAgICAgQ0hFQ0tBQkxFX0lOUFVUUy5pbmRleE9mKGVsLnR5cGUudG9Mb2NhbGVMb3dlckNhc2UoKSkgPj0gMFxuICAgICkge1xuICAgICAgZWwuY2hlY2tlZCA9IGVsLmdldEF0dHJpYnV0ZShcImNoZWNrZWRcIikgIT09IG51bGw7XG4gICAgfVxuICB9LFxuXG4gIGlzVGV4dHVhbElucHV0KGVsKSB7XG4gICAgcmV0dXJuIEZPQ1VTQUJMRV9JTlBVVFMuaW5kZXhPZihlbC50eXBlKSA+PSAwO1xuICB9LFxuXG4gIGlzTm93VHJpZ2dlckZvcm1FeHRlcm5hbChlbCwgcGh4VHJpZ2dlckV4dGVybmFsKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIGVsLmdldEF0dHJpYnV0ZSAmJlxuICAgICAgZWwuZ2V0QXR0cmlidXRlKHBoeFRyaWdnZXJFeHRlcm5hbCkgIT09IG51bGwgJiZcbiAgICAgIGRvY3VtZW50LmJvZHkuY29udGFpbnMoZWwpXG4gICAgKTtcbiAgfSxcblxuICBjbGVhbkNoaWxkTm9kZXMoY29udGFpbmVyLCBwaHhVcGRhdGUpIHtcbiAgICBpZiAoXG4gICAgICBET00uaXNQaHhVcGRhdGUoY29udGFpbmVyLCBwaHhVcGRhdGUsIFtcImFwcGVuZFwiLCBcInByZXBlbmRcIiwgUEhYX1NUUkVBTV0pXG4gICAgKSB7XG4gICAgICBjb25zdCB0b1JlbW92ZSA9IFtdO1xuICAgICAgY29udGFpbmVyLmNoaWxkTm9kZXMuZm9yRWFjaCgoY2hpbGROb2RlKSA9PiB7XG4gICAgICAgIGlmICghY2hpbGROb2RlLmlkKSB7XG4gICAgICAgICAgLy8gU2tpcCB3YXJuaW5nIGlmIGl0J3MgYW4gZW1wdHkgdGV4dCBub2RlIChlLmcuIGEgbmV3LWxpbmUpXG4gICAgICAgICAgY29uc3QgaXNFbXB0eVRleHROb2RlID1cbiAgICAgICAgICAgIGNoaWxkTm9kZS5ub2RlVHlwZSA9PT0gTm9kZS5URVhUX05PREUgJiZcbiAgICAgICAgICAgIGNoaWxkTm9kZS5ub2RlVmFsdWUudHJpbSgpID09PSBcIlwiO1xuICAgICAgICAgIGlmICghaXNFbXB0eVRleHROb2RlICYmIGNoaWxkTm9kZS5ub2RlVHlwZSAhPT0gTm9kZS5DT01NRU5UX05PREUpIHtcbiAgICAgICAgICAgIGxvZ0Vycm9yKFxuICAgICAgICAgICAgICBcIm9ubHkgSFRNTCBlbGVtZW50IHRhZ3Mgd2l0aCBhbiBpZCBhcmUgYWxsb3dlZCBpbnNpZGUgY29udGFpbmVycyB3aXRoIHBoeC11cGRhdGUuXFxuXFxuXCIgK1xuICAgICAgICAgICAgICAgIGByZW1vdmluZyBpbGxlZ2FsIG5vZGU6IFwiJHsoY2hpbGROb2RlLm91dGVySFRNTCB8fCBjaGlsZE5vZGUubm9kZVZhbHVlKS50cmltKCl9XCJcXG5cXG5gLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdG9SZW1vdmUucHVzaChjaGlsZE5vZGUpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRvUmVtb3ZlLmZvckVhY2goKGNoaWxkTm9kZSkgPT4gY2hpbGROb2RlLnJlbW92ZSgpKTtcbiAgICB9XG4gIH0sXG5cbiAgcmVwbGFjZVJvb3RDb250YWluZXIoY29udGFpbmVyLCB0YWdOYW1lLCBhdHRycykge1xuICAgIGNvbnN0IHJldGFpbmVkQXR0cnMgPSBuZXcgU2V0KFtcbiAgICAgIFwiaWRcIixcbiAgICAgIFBIWF9TRVNTSU9OLFxuICAgICAgUEhYX1NUQVRJQyxcbiAgICAgIFBIWF9NQUlOLFxuICAgICAgUEhYX1JPT1RfSUQsXG4gICAgXSk7XG4gICAgaWYgKGNvbnRhaW5lci50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09IHRhZ05hbWUudG9Mb3dlckNhc2UoKSkge1xuICAgICAgQXJyYXkuZnJvbShjb250YWluZXIuYXR0cmlidXRlcylcbiAgICAgICAgLmZpbHRlcigoYXR0cikgPT4gIXJldGFpbmVkQXR0cnMuaGFzKGF0dHIubmFtZS50b0xvd2VyQ2FzZSgpKSlcbiAgICAgICAgLmZvckVhY2goKGF0dHIpID0+IGNvbnRhaW5lci5yZW1vdmVBdHRyaWJ1dGUoYXR0ci5uYW1lKSk7XG5cbiAgICAgIE9iamVjdC5rZXlzKGF0dHJzKVxuICAgICAgICAuZmlsdGVyKChuYW1lKSA9PiAhcmV0YWluZWRBdHRycy5oYXMobmFtZS50b0xvd2VyQ2FzZSgpKSlcbiAgICAgICAgLmZvckVhY2goKGF0dHIpID0+IGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoYXR0ciwgYXR0cnNbYXR0cl0pKTtcblxuICAgICAgcmV0dXJuIGNvbnRhaW5lcjtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmV3Q29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0YWdOYW1lKTtcbiAgICAgIE9iamVjdC5rZXlzKGF0dHJzKS5mb3JFYWNoKChhdHRyKSA9PlxuICAgICAgICBuZXdDb250YWluZXIuc2V0QXR0cmlidXRlKGF0dHIsIGF0dHJzW2F0dHJdKSxcbiAgICAgICk7XG4gICAgICByZXRhaW5lZEF0dHJzLmZvckVhY2goKGF0dHIpID0+XG4gICAgICAgIG5ld0NvbnRhaW5lci5zZXRBdHRyaWJ1dGUoYXR0ciwgY29udGFpbmVyLmdldEF0dHJpYnV0ZShhdHRyKSksXG4gICAgICApO1xuICAgICAgbmV3Q29udGFpbmVyLmlubmVySFRNTCA9IGNvbnRhaW5lci5pbm5lckhUTUw7XG4gICAgICBjb250YWluZXIucmVwbGFjZVdpdGgobmV3Q29udGFpbmVyKTtcbiAgICAgIHJldHVybiBuZXdDb250YWluZXI7XG4gICAgfVxuICB9LFxuXG4gIGdldFN0aWNreShlbCwgbmFtZSwgZGVmYXVsdFZhbCkge1xuICAgIGNvbnN0IG9wID0gKERPTS5wcml2YXRlKGVsLCBcInN0aWNreVwiKSB8fCBbXSkuZmluZChcbiAgICAgIChbZXhpc3RpbmdOYW1lXSkgPT4gbmFtZSA9PT0gZXhpc3RpbmdOYW1lLFxuICAgICk7XG4gICAgaWYgKG9wKSB7XG4gICAgICBjb25zdCBbX25hbWUsIF9vcCwgc3Rhc2hlZFJlc3VsdF0gPSBvcDtcbiAgICAgIHJldHVybiBzdGFzaGVkUmVzdWx0O1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdHlwZW9mIGRlZmF1bHRWYWwgPT09IFwiZnVuY3Rpb25cIiA/IGRlZmF1bHRWYWwoKSA6IGRlZmF1bHRWYWw7XG4gICAgfVxuICB9LFxuXG4gIGRlbGV0ZVN0aWNreShlbCwgbmFtZSkge1xuICAgIHRoaXMudXBkYXRlUHJpdmF0ZShlbCwgXCJzdGlja3lcIiwgW10sIChvcHMpID0+IHtcbiAgICAgIHJldHVybiBvcHMuZmlsdGVyKChbZXhpc3RpbmdOYW1lLCBfXSkgPT4gZXhpc3RpbmdOYW1lICE9PSBuYW1lKTtcbiAgICB9KTtcbiAgfSxcblxuICBwdXRTdGlja3koZWwsIG5hbWUsIG9wKSB7XG4gICAgY29uc3Qgc3Rhc2hlZFJlc3VsdCA9IG9wKGVsKTtcbiAgICB0aGlzLnVwZGF0ZVByaXZhdGUoZWwsIFwic3RpY2t5XCIsIFtdLCAob3BzKSA9PiB7XG4gICAgICBjb25zdCBleGlzdGluZ0luZGV4ID0gb3BzLmZpbmRJbmRleChcbiAgICAgICAgKFtleGlzdGluZ05hbWVdKSA9PiBuYW1lID09PSBleGlzdGluZ05hbWUsXG4gICAgICApO1xuICAgICAgaWYgKGV4aXN0aW5nSW5kZXggPj0gMCkge1xuICAgICAgICBvcHNbZXhpc3RpbmdJbmRleF0gPSBbbmFtZSwgb3AsIHN0YXNoZWRSZXN1bHRdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb3BzLnB1c2goW25hbWUsIG9wLCBzdGFzaGVkUmVzdWx0XSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3BzO1xuICAgIH0pO1xuICB9LFxuXG4gIGFwcGx5U3RpY2t5T3BlcmF0aW9ucyhlbCkge1xuICAgIGNvbnN0IG9wcyA9IERPTS5wcml2YXRlKGVsLCBcInN0aWNreVwiKTtcbiAgICBpZiAoIW9wcykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG9wcy5mb3JFYWNoKChbbmFtZSwgb3AsIF9zdGFzaGVkXSkgPT4gdGhpcy5wdXRTdGlja3koZWwsIG5hbWUsIG9wKSk7XG4gIH0sXG5cbiAgaXNMb2NrZWQoZWwpIHtcbiAgICByZXR1cm4gZWwuaGFzQXR0cmlidXRlICYmIGVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX0xPQ0spO1xuICB9LFxufTtcblxuZXhwb3J0IGRlZmF1bHQgRE9NO1xuIiwgImltcG9ydCB7XG4gIFBIWF9BQ1RJVkVfRU5UUllfUkVGUyxcbiAgUEhYX0xJVkVfRklMRV9VUERBVEVELFxuICBQSFhfUFJFRkxJR0hURURfUkVGUyxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5cbmltcG9ydCB7IGNoYW5uZWxVcGxvYWRlciwgbG9nRXJyb3IgfSBmcm9tIFwiLi91dGlsc1wiO1xuXG5pbXBvcnQgTGl2ZVVwbG9hZGVyIGZyb20gXCIuL2xpdmVfdXBsb2FkZXJcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVXBsb2FkRW50cnkge1xuICBzdGF0aWMgaXNBY3RpdmUoZmlsZUVsLCBmaWxlKSB7XG4gICAgY29uc3QgaXNOZXcgPSBmaWxlLl9waHhSZWYgPT09IHVuZGVmaW5lZDtcbiAgICBjb25zdCBhY3RpdmVSZWZzID0gZmlsZUVsLmdldEF0dHJpYnV0ZShQSFhfQUNUSVZFX0VOVFJZX1JFRlMpLnNwbGl0KFwiLFwiKTtcbiAgICBjb25zdCBpc0FjdGl2ZSA9IGFjdGl2ZVJlZnMuaW5kZXhPZihMaXZlVXBsb2FkZXIuZ2VuRmlsZVJlZihmaWxlKSkgPj0gMDtcbiAgICByZXR1cm4gZmlsZS5zaXplID4gMCAmJiAoaXNOZXcgfHwgaXNBY3RpdmUpO1xuICB9XG5cbiAgc3RhdGljIGlzUHJlZmxpZ2h0ZWQoZmlsZUVsLCBmaWxlKSB7XG4gICAgY29uc3QgcHJlZmxpZ2h0ZWRSZWZzID0gZmlsZUVsXG4gICAgICAuZ2V0QXR0cmlidXRlKFBIWF9QUkVGTElHSFRFRF9SRUZTKVxuICAgICAgLnNwbGl0KFwiLFwiKTtcbiAgICBjb25zdCBpc1ByZWZsaWdodGVkID1cbiAgICAgIHByZWZsaWdodGVkUmVmcy5pbmRleE9mKExpdmVVcGxvYWRlci5nZW5GaWxlUmVmKGZpbGUpKSA+PSAwO1xuICAgIHJldHVybiBpc1ByZWZsaWdodGVkICYmIHRoaXMuaXNBY3RpdmUoZmlsZUVsLCBmaWxlKTtcbiAgfVxuXG4gIHN0YXRpYyBpc1ByZWZsaWdodEluUHJvZ3Jlc3MoZmlsZSkge1xuICAgIHJldHVybiBmaWxlLl9wcmVmbGlnaHRJblByb2dyZXNzID09PSB0cnVlO1xuICB9XG5cbiAgc3RhdGljIG1hcmtQcmVmbGlnaHRJblByb2dyZXNzKGZpbGUpIHtcbiAgICBmaWxlLl9wcmVmbGlnaHRJblByb2dyZXNzID0gdHJ1ZTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGZpbGVFbCwgZmlsZSwgdmlldywgYXV0b1VwbG9hZCkge1xuICAgIHRoaXMucmVmID0gTGl2ZVVwbG9hZGVyLmdlbkZpbGVSZWYoZmlsZSk7XG4gICAgdGhpcy5maWxlRWwgPSBmaWxlRWw7XG4gICAgdGhpcy5maWxlID0gZmlsZTtcbiAgICB0aGlzLnZpZXcgPSB2aWV3O1xuICAgIHRoaXMubWV0YSA9IG51bGw7XG4gICAgdGhpcy5faXNDYW5jZWxsZWQgPSBmYWxzZTtcbiAgICB0aGlzLl9pc0RvbmUgPSBmYWxzZTtcbiAgICB0aGlzLl9wcm9ncmVzcyA9IDA7XG4gICAgdGhpcy5fbGFzdFByb2dyZXNzU2VudCA9IC0xO1xuICAgIHRoaXMuX29uRG9uZSA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIHRoaXMuX29uRWxVcGRhdGVkID0gdGhpcy5vbkVsVXBkYXRlZC5iaW5kKHRoaXMpO1xuICAgIHRoaXMuZmlsZUVsLmFkZEV2ZW50TGlzdGVuZXIoUEhYX0xJVkVfRklMRV9VUERBVEVELCB0aGlzLl9vbkVsVXBkYXRlZCk7XG4gICAgdGhpcy5hdXRvVXBsb2FkID0gYXV0b1VwbG9hZDtcbiAgfVxuXG4gIG1ldGFkYXRhKCkge1xuICAgIHJldHVybiB0aGlzLm1ldGE7XG4gIH1cblxuICBwcm9ncmVzcyhwcm9ncmVzcykge1xuICAgIHRoaXMuX3Byb2dyZXNzID0gTWF0aC5mbG9vcihwcm9ncmVzcyk7XG4gICAgaWYgKHRoaXMuX3Byb2dyZXNzID4gdGhpcy5fbGFzdFByb2dyZXNzU2VudCkge1xuICAgICAgaWYgKHRoaXMuX3Byb2dyZXNzID49IDEwMCkge1xuICAgICAgICB0aGlzLl9wcm9ncmVzcyA9IDEwMDtcbiAgICAgICAgdGhpcy5fbGFzdFByb2dyZXNzU2VudCA9IDEwMDtcbiAgICAgICAgdGhpcy5faXNEb25lID0gdHJ1ZTtcbiAgICAgICAgdGhpcy52aWV3LnB1c2hGaWxlUHJvZ3Jlc3ModGhpcy5maWxlRWwsIHRoaXMucmVmLCAxMDAsICgpID0+IHtcbiAgICAgICAgICBMaXZlVXBsb2FkZXIudW50cmFja0ZpbGUodGhpcy5maWxlRWwsIHRoaXMuZmlsZSk7XG4gICAgICAgICAgdGhpcy5fb25Eb25lKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5fbGFzdFByb2dyZXNzU2VudCA9IHRoaXMuX3Byb2dyZXNzO1xuICAgICAgICB0aGlzLnZpZXcucHVzaEZpbGVQcm9ncmVzcyh0aGlzLmZpbGVFbCwgdGhpcy5yZWYsIHRoaXMuX3Byb2dyZXNzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpc0NhbmNlbGxlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5faXNDYW5jZWxsZWQ7XG4gIH1cblxuICBjYW5jZWwoKSB7XG4gICAgdGhpcy5maWxlLl9wcmVmbGlnaHRJblByb2dyZXNzID0gZmFsc2U7XG4gICAgdGhpcy5faXNDYW5jZWxsZWQgPSB0cnVlO1xuICAgIHRoaXMuX2lzRG9uZSA9IHRydWU7XG4gICAgdGhpcy5fb25Eb25lKCk7XG4gIH1cblxuICBpc0RvbmUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2lzRG9uZTtcbiAgfVxuXG4gIGVycm9yKHJlYXNvbiA9IFwiZmFpbGVkXCIpIHtcbiAgICB0aGlzLmZpbGVFbC5yZW1vdmVFdmVudExpc3RlbmVyKFBIWF9MSVZFX0ZJTEVfVVBEQVRFRCwgdGhpcy5fb25FbFVwZGF0ZWQpO1xuICAgIHRoaXMudmlldy5wdXNoRmlsZVByb2dyZXNzKHRoaXMuZmlsZUVsLCB0aGlzLnJlZiwgeyBlcnJvcjogcmVhc29uIH0pO1xuICAgIGlmICghdGhpcy5pc0F1dG9VcGxvYWQoKSkge1xuICAgICAgTGl2ZVVwbG9hZGVyLmNsZWFyRmlsZXModGhpcy5maWxlRWwpO1xuICAgIH1cbiAgfVxuXG4gIGlzQXV0b1VwbG9hZCgpIHtcbiAgICByZXR1cm4gdGhpcy5hdXRvVXBsb2FkO1xuICB9XG5cbiAgLy9wcml2YXRlXG5cbiAgb25Eb25lKGNhbGxiYWNrKSB7XG4gICAgdGhpcy5fb25Eb25lID0gKCkgPT4ge1xuICAgICAgdGhpcy5maWxlRWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihQSFhfTElWRV9GSUxFX1VQREFURUQsIHRoaXMuX29uRWxVcGRhdGVkKTtcbiAgICAgIGNhbGxiYWNrKCk7XG4gICAgfTtcbiAgfVxuXG4gIG9uRWxVcGRhdGVkKCkge1xuICAgIGNvbnN0IGFjdGl2ZVJlZnMgPSB0aGlzLmZpbGVFbFxuICAgICAgLmdldEF0dHJpYnV0ZShQSFhfQUNUSVZFX0VOVFJZX1JFRlMpXG4gICAgICAuc3BsaXQoXCIsXCIpO1xuICAgIGlmIChhY3RpdmVSZWZzLmluZGV4T2YodGhpcy5yZWYpID09PSAtMSkge1xuICAgICAgTGl2ZVVwbG9hZGVyLnVudHJhY2tGaWxlKHRoaXMuZmlsZUVsLCB0aGlzLmZpbGUpO1xuICAgICAgdGhpcy5jYW5jZWwoKTtcbiAgICB9XG4gIH1cblxuICB0b1ByZWZsaWdodFBheWxvYWQoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxhc3RfbW9kaWZpZWQ6IHRoaXMuZmlsZS5sYXN0TW9kaWZpZWQsXG4gICAgICBuYW1lOiB0aGlzLmZpbGUubmFtZSxcbiAgICAgIHJlbGF0aXZlX3BhdGg6IHRoaXMuZmlsZS53ZWJraXRSZWxhdGl2ZVBhdGgsXG4gICAgICBzaXplOiB0aGlzLmZpbGUuc2l6ZSxcbiAgICAgIHR5cGU6IHRoaXMuZmlsZS50eXBlLFxuICAgICAgcmVmOiB0aGlzLnJlZixcbiAgICAgIG1ldGE6IHR5cGVvZiB0aGlzLmZpbGUubWV0YSA9PT0gXCJmdW5jdGlvblwiID8gdGhpcy5maWxlLm1ldGEoKSA6IHVuZGVmaW5lZCxcbiAgICB9O1xuICB9XG5cbiAgdXBsb2FkZXIodXBsb2FkZXJzKSB7XG4gICAgaWYgKHRoaXMubWV0YS51cGxvYWRlcikge1xuICAgICAgY29uc3QgY2FsbGJhY2sgPVxuICAgICAgICB1cGxvYWRlcnNbdGhpcy5tZXRhLnVwbG9hZGVyXSB8fFxuICAgICAgICBsb2dFcnJvcihgbm8gdXBsb2FkZXIgY29uZmlndXJlZCBmb3IgJHt0aGlzLm1ldGEudXBsb2FkZXJ9YCk7XG4gICAgICByZXR1cm4geyBuYW1lOiB0aGlzLm1ldGEudXBsb2FkZXIsIGNhbGxiYWNrOiBjYWxsYmFjayB9O1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4geyBuYW1lOiBcImNoYW5uZWxcIiwgY2FsbGJhY2s6IGNoYW5uZWxVcGxvYWRlciB9O1xuICAgIH1cbiAgfVxuXG4gIHppcFBvc3RGbGlnaHQocmVzcCkge1xuICAgIHRoaXMubWV0YSA9IHJlc3AuZW50cmllc1t0aGlzLnJlZl07XG4gICAgaWYgKCF0aGlzLm1ldGEpIHtcbiAgICAgIGxvZ0Vycm9yKGBubyBwcmVmbGlnaHQgdXBsb2FkIHJlc3BvbnNlIHJldHVybmVkIHdpdGggcmVmICR7dGhpcy5yZWZ9YCwge1xuICAgICAgICBpbnB1dDogdGhpcy5maWxlRWwsXG4gICAgICAgIHJlc3BvbnNlOiByZXNwLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iLCAiaW1wb3J0IHtcbiAgUEhYX0RPTkVfUkVGUyxcbiAgUEhYX1BSRUZMSUdIVEVEX1JFRlMsXG4gIFBIWF9VUExPQURfUkVGLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuaW1wb3J0IHt9IGZyb20gXCIuL3V0aWxzXCI7XG5cbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCI7XG5pbXBvcnQgVXBsb2FkRW50cnkgZnJvbSBcIi4vdXBsb2FkX2VudHJ5XCI7XG5cbmxldCBsaXZlVXBsb2FkZXJGaWxlUmVmID0gMDtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTGl2ZVVwbG9hZGVyIHtcbiAgc3RhdGljIGdlbkZpbGVSZWYoZmlsZSkge1xuICAgIGNvbnN0IHJlZiA9IGZpbGUuX3BoeFJlZjtcbiAgICBpZiAocmVmICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiByZWY7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZpbGUuX3BoeFJlZiA9IChsaXZlVXBsb2FkZXJGaWxlUmVmKyspLnRvU3RyaW5nKCk7XG4gICAgICByZXR1cm4gZmlsZS5fcGh4UmVmO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBnZXRFbnRyeURhdGFVUkwoaW5wdXRFbCwgcmVmLCBjYWxsYmFjaykge1xuICAgIGNvbnN0IGZpbGUgPSB0aGlzLmFjdGl2ZUZpbGVzKGlucHV0RWwpLmZpbmQoXG4gICAgICAoZmlsZSkgPT4gdGhpcy5nZW5GaWxlUmVmKGZpbGUpID09PSByZWYsXG4gICAgKTtcbiAgICBjYWxsYmFjayhVUkwuY3JlYXRlT2JqZWN0VVJMKGZpbGUpKTtcbiAgfVxuXG4gIHN0YXRpYyBoYXNVcGxvYWRzSW5Qcm9ncmVzcyhmb3JtRWwpIHtcbiAgICBsZXQgYWN0aXZlID0gMDtcbiAgICBET00uZmluZFVwbG9hZElucHV0cyhmb3JtRWwpLmZvckVhY2goKGlucHV0KSA9PiB7XG4gICAgICBpZiAoXG4gICAgICAgIGlucHV0LmdldEF0dHJpYnV0ZShQSFhfUFJFRkxJR0hURURfUkVGUykgIT09XG4gICAgICAgIGlucHV0LmdldEF0dHJpYnV0ZShQSFhfRE9ORV9SRUZTKVxuICAgICAgKSB7XG4gICAgICAgIGFjdGl2ZSsrO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBhY3RpdmUgPiAwO1xuICB9XG5cbiAgc3RhdGljIHNlcmlhbGl6ZVVwbG9hZHMoaW5wdXRFbCkge1xuICAgIGNvbnN0IGZpbGVzID0gdGhpcy5hY3RpdmVGaWxlcyhpbnB1dEVsKTtcbiAgICBjb25zdCBmaWxlRGF0YSA9IHt9O1xuICAgIGZpbGVzLmZvckVhY2goKGZpbGUpID0+IHtcbiAgICAgIGNvbnN0IGVudHJ5ID0geyBwYXRoOiBpbnB1dEVsLm5hbWUgfTtcbiAgICAgIGNvbnN0IHVwbG9hZFJlZiA9IGlucHV0RWwuZ2V0QXR0cmlidXRlKFBIWF9VUExPQURfUkVGKTtcbiAgICAgIGZpbGVEYXRhW3VwbG9hZFJlZl0gPSBmaWxlRGF0YVt1cGxvYWRSZWZdIHx8IFtdO1xuICAgICAgZW50cnkucmVmID0gdGhpcy5nZW5GaWxlUmVmKGZpbGUpO1xuICAgICAgZW50cnkubGFzdF9tb2RpZmllZCA9IGZpbGUubGFzdE1vZGlmaWVkO1xuICAgICAgZW50cnkubmFtZSA9IGZpbGUubmFtZSB8fCBlbnRyeS5yZWY7XG4gICAgICBlbnRyeS5yZWxhdGl2ZV9wYXRoID0gZmlsZS53ZWJraXRSZWxhdGl2ZVBhdGg7XG4gICAgICBlbnRyeS50eXBlID0gZmlsZS50eXBlO1xuICAgICAgZW50cnkuc2l6ZSA9IGZpbGUuc2l6ZTtcbiAgICAgIGlmICh0eXBlb2YgZmlsZS5tZXRhID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgZW50cnkubWV0YSA9IGZpbGUubWV0YSgpO1xuICAgICAgfVxuICAgICAgZmlsZURhdGFbdXBsb2FkUmVmXS5wdXNoKGVudHJ5KTtcbiAgICB9KTtcbiAgICByZXR1cm4gZmlsZURhdGE7XG4gIH1cblxuICBzdGF0aWMgY2xlYXJGaWxlcyhpbnB1dEVsKSB7XG4gICAgaW5wdXRFbC52YWx1ZSA9IG51bGw7XG4gICAgaW5wdXRFbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpO1xuICAgIERPTS5wdXRQcml2YXRlKGlucHV0RWwsIFwiZmlsZXNcIiwgW10pO1xuICB9XG5cbiAgc3RhdGljIHVudHJhY2tGaWxlKGlucHV0RWwsIGZpbGUpIHtcbiAgICBET00ucHV0UHJpdmF0ZShcbiAgICAgIGlucHV0RWwsXG4gICAgICBcImZpbGVzXCIsXG4gICAgICBET00ucHJpdmF0ZShpbnB1dEVsLCBcImZpbGVzXCIpLmZpbHRlcigoZikgPT4gIU9iamVjdC5pcyhmLCBmaWxlKSksXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge0hUTUxJbnB1dEVsZW1lbnR9IGlucHV0RWxcbiAgICogQHBhcmFtIHtBcnJheTxGaWxlfEJsb2I+fSBmaWxlc1xuICAgKiBAcGFyYW0ge0RhdGFUcmFuc2Zlcn0gW2RhdGFUcmFuc2Zlcl1cbiAgICovXG4gIHN0YXRpYyB0cmFja0ZpbGVzKGlucHV0RWwsIGZpbGVzLCBkYXRhVHJhbnNmZXIpIHtcbiAgICBpZiAoaW5wdXRFbC5nZXRBdHRyaWJ1dGUoXCJtdWx0aXBsZVwiKSAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgbmV3RmlsZXMgPSBmaWxlcy5maWx0ZXIoXG4gICAgICAgIChmaWxlKSA9PiAhdGhpcy5hY3RpdmVGaWxlcyhpbnB1dEVsKS5maW5kKChmKSA9PiBPYmplY3QuaXMoZiwgZmlsZSkpLFxuICAgICAgKTtcbiAgICAgIERPTS51cGRhdGVQcml2YXRlKGlucHV0RWwsIFwiZmlsZXNcIiwgW10sIChleGlzdGluZykgPT5cbiAgICAgICAgZXhpc3RpbmcuY29uY2F0KG5ld0ZpbGVzKSxcbiAgICAgICk7XG4gICAgICBpbnB1dEVsLnZhbHVlID0gbnVsbDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVzZXQgaW5wdXRFbCBmaWxlcyB0byBhbGlnbiBvdXRwdXQgd2l0aCBwcm9ncmFtbWF0aWMgY2hhbmdlcyAoaS5lLiBkcmFnIGFuZCBkcm9wKVxuICAgICAgaWYgKGRhdGFUcmFuc2ZlciAmJiBkYXRhVHJhbnNmZXIuZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBpbnB1dEVsLmZpbGVzID0gZGF0YVRyYW5zZmVyLmZpbGVzO1xuICAgICAgfVxuICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXRFbCwgXCJmaWxlc1wiLCBmaWxlcyk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGFjdGl2ZUZpbGVJbnB1dHMoZm9ybUVsKSB7XG4gICAgY29uc3QgZmlsZUlucHV0cyA9IERPTS5maW5kVXBsb2FkSW5wdXRzKGZvcm1FbCk7XG4gICAgcmV0dXJuIEFycmF5LmZyb20oZmlsZUlucHV0cykuZmlsdGVyKFxuICAgICAgKGVsKSA9PiBlbC5maWxlcyAmJiB0aGlzLmFjdGl2ZUZpbGVzKGVsKS5sZW5ndGggPiAwLFxuICAgICk7XG4gIH1cblxuICBzdGF0aWMgYWN0aXZlRmlsZXMoaW5wdXQpIHtcbiAgICByZXR1cm4gKERPTS5wcml2YXRlKGlucHV0LCBcImZpbGVzXCIpIHx8IFtdKS5maWx0ZXIoKGYpID0+XG4gICAgICBVcGxvYWRFbnRyeS5pc0FjdGl2ZShpbnB1dCwgZiksXG4gICAgKTtcbiAgfVxuXG4gIHN0YXRpYyBpbnB1dHNBd2FpdGluZ1ByZWZsaWdodChmb3JtRWwpIHtcbiAgICBjb25zdCBmaWxlSW5wdXRzID0gRE9NLmZpbmRVcGxvYWRJbnB1dHMoZm9ybUVsKTtcbiAgICByZXR1cm4gQXJyYXkuZnJvbShmaWxlSW5wdXRzKS5maWx0ZXIoXG4gICAgICAoaW5wdXQpID0+IHRoaXMuZmlsZXNBd2FpdGluZ1ByZWZsaWdodChpbnB1dCkubGVuZ3RoID4gMCxcbiAgICApO1xuICB9XG5cbiAgc3RhdGljIGZpbGVzQXdhaXRpbmdQcmVmbGlnaHQoaW5wdXQpIHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmVGaWxlcyhpbnB1dCkuZmlsdGVyKFxuICAgICAgKGYpID0+XG4gICAgICAgICFVcGxvYWRFbnRyeS5pc1ByZWZsaWdodGVkKGlucHV0LCBmKSAmJlxuICAgICAgICAhVXBsb2FkRW50cnkuaXNQcmVmbGlnaHRJblByb2dyZXNzKGYpLFxuICAgICk7XG4gIH1cblxuICBzdGF0aWMgbWFya1ByZWZsaWdodEluUHJvZ3Jlc3MoZW50cmllcykge1xuICAgIGVudHJpZXMuZm9yRWFjaCgoZW50cnkpID0+IFVwbG9hZEVudHJ5Lm1hcmtQcmVmbGlnaHRJblByb2dyZXNzKGVudHJ5LmZpbGUpKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGlucHV0RWwsIHZpZXcsIG9uQ29tcGxldGUpIHtcbiAgICB0aGlzLmF1dG9VcGxvYWQgPSBET00uaXNBdXRvVXBsb2FkKGlucHV0RWwpO1xuICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgdGhpcy5vbkNvbXBsZXRlID0gb25Db21wbGV0ZTtcbiAgICB0aGlzLl9lbnRyaWVzID0gQXJyYXkuZnJvbShcbiAgICAgIExpdmVVcGxvYWRlci5maWxlc0F3YWl0aW5nUHJlZmxpZ2h0KGlucHV0RWwpIHx8IFtdLFxuICAgICkubWFwKChmaWxlKSA9PiBuZXcgVXBsb2FkRW50cnkoaW5wdXRFbCwgZmlsZSwgdmlldywgdGhpcy5hdXRvVXBsb2FkKSk7XG5cbiAgICAvLyBwcmV2ZW50IHNlbmRpbmcgZHVwbGljYXRlIHByZWZsaWdodCByZXF1ZXN0c1xuICAgIExpdmVVcGxvYWRlci5tYXJrUHJlZmxpZ2h0SW5Qcm9ncmVzcyh0aGlzLl9lbnRyaWVzKTtcblxuICAgIHRoaXMubnVtRW50cmllc0luUHJvZ3Jlc3MgPSB0aGlzLl9lbnRyaWVzLmxlbmd0aDtcbiAgfVxuXG4gIGlzQXV0b1VwbG9hZCgpIHtcbiAgICByZXR1cm4gdGhpcy5hdXRvVXBsb2FkO1xuICB9XG5cbiAgZW50cmllcygpIHtcbiAgICByZXR1cm4gdGhpcy5fZW50cmllcztcbiAgfVxuXG4gIGluaXRBZGFwdGVyVXBsb2FkKHJlc3AsIG9uRXJyb3IsIGxpdmVTb2NrZXQpIHtcbiAgICB0aGlzLl9lbnRyaWVzID0gdGhpcy5fZW50cmllcy5tYXAoKGVudHJ5KSA9PiB7XG4gICAgICBpZiAoZW50cnkuaXNDYW5jZWxsZWQoKSkge1xuICAgICAgICB0aGlzLm51bUVudHJpZXNJblByb2dyZXNzLS07XG4gICAgICAgIGlmICh0aGlzLm51bUVudHJpZXNJblByb2dyZXNzID09PSAwKSB7XG4gICAgICAgICAgdGhpcy5vbkNvbXBsZXRlKCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVudHJ5LnppcFBvc3RGbGlnaHQocmVzcCk7XG4gICAgICAgIGVudHJ5Lm9uRG9uZSgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5udW1FbnRyaWVzSW5Qcm9ncmVzcy0tO1xuICAgICAgICAgIGlmICh0aGlzLm51bUVudHJpZXNJblByb2dyZXNzID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLm9uQ29tcGxldGUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGVudHJ5O1xuICAgIH0pO1xuXG4gICAgY29uc3QgZ3JvdXBlZEVudHJpZXMgPSB0aGlzLl9lbnRyaWVzLnJlZHVjZSgoYWNjLCBlbnRyeSkgPT4ge1xuICAgICAgaWYgKCFlbnRyeS5tZXRhKSB7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9XG4gICAgICBjb25zdCB7IG5hbWUsIGNhbGxiYWNrIH0gPSBlbnRyeS51cGxvYWRlcihsaXZlU29ja2V0LnVwbG9hZGVycyk7XG4gICAgICBhY2NbbmFtZV0gPSBhY2NbbmFtZV0gfHwgeyBjYWxsYmFjazogY2FsbGJhY2ssIGVudHJpZXM6IFtdIH07XG4gICAgICBhY2NbbmFtZV0uZW50cmllcy5wdXNoKGVudHJ5KTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pO1xuXG4gICAgZm9yIChjb25zdCBuYW1lIGluIGdyb3VwZWRFbnRyaWVzKSB7XG4gICAgICBjb25zdCB7IGNhbGxiYWNrLCBlbnRyaWVzIH0gPSBncm91cGVkRW50cmllc1tuYW1lXTtcbiAgICAgIGNhbGxiYWNrKGVudHJpZXMsIG9uRXJyb3IsIHJlc3AsIGxpdmVTb2NrZXQpO1xuICAgIH1cbiAgfVxufVxuIiwgImNvbnN0IEFSSUEgPSB7XG4gIGFueU9mKGluc3RhbmNlLCBjbGFzc2VzKSB7XG4gICAgcmV0dXJuIGNsYXNzZXMuZmluZCgobmFtZSkgPT4gaW5zdGFuY2UgaW5zdGFuY2VvZiBuYW1lKTtcbiAgfSxcblxuICBpc0ZvY3VzYWJsZShlbCwgaW50ZXJhY3RpdmVPbmx5KSB7XG4gICAgcmV0dXJuIChcbiAgICAgIChlbCBpbnN0YW5jZW9mIEhUTUxBbmNob3JFbGVtZW50ICYmIGVsLnJlbCAhPT0gXCJpZ25vcmVcIikgfHxcbiAgICAgIChlbCBpbnN0YW5jZW9mIEhUTUxBcmVhRWxlbWVudCAmJiBlbC5ocmVmICE9PSB1bmRlZmluZWQpIHx8XG4gICAgICAoIWVsLmRpc2FibGVkICYmXG4gICAgICAgIHRoaXMuYW55T2YoZWwsIFtcbiAgICAgICAgICBIVE1MSW5wdXRFbGVtZW50LFxuICAgICAgICAgIEhUTUxTZWxlY3RFbGVtZW50LFxuICAgICAgICAgIEhUTUxUZXh0QXJlYUVsZW1lbnQsXG4gICAgICAgICAgSFRNTEJ1dHRvbkVsZW1lbnQsXG4gICAgICAgIF0pKSB8fFxuICAgICAgZWwgaW5zdGFuY2VvZiBIVE1MSUZyYW1lRWxlbWVudCB8fFxuICAgICAgKGVsLnRhYkluZGV4ID49IDAgJiYgZWwuZ2V0QXR0cmlidXRlKFwiYXJpYS1oaWRkZW5cIikgIT09IFwidHJ1ZVwiKSB8fFxuICAgICAgKCFpbnRlcmFjdGl2ZU9ubHkgJiZcbiAgICAgICAgZWwuZ2V0QXR0cmlidXRlKFwidGFiaW5kZXhcIikgIT09IG51bGwgJiZcbiAgICAgICAgZWwuZ2V0QXR0cmlidXRlKFwiYXJpYS1oaWRkZW5cIikgIT09IFwidHJ1ZVwiKVxuICAgICk7XG4gIH0sXG5cbiAgYXR0ZW1wdEZvY3VzKGVsLCBpbnRlcmFjdGl2ZU9ubHkpIHtcbiAgICBpZiAodGhpcy5pc0ZvY3VzYWJsZShlbCwgaW50ZXJhY3RpdmVPbmx5KSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgZWwuZm9jdXMoKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyB0aGF0J3MgZmluZVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gISFkb2N1bWVudC5hY3RpdmVFbGVtZW50ICYmIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQuaXNTYW1lTm9kZShlbCk7XG4gIH0sXG5cbiAgZm9jdXNGaXJzdEludGVyYWN0aXZlKGVsKSB7XG4gICAgbGV0IGNoaWxkID0gZWwuZmlyc3RFbGVtZW50Q2hpbGQ7XG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBpZiAodGhpcy5hdHRlbXB0Rm9jdXMoY2hpbGQsIHRydWUpIHx8IHRoaXMuZm9jdXNGaXJzdEludGVyYWN0aXZlKGNoaWxkKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGNoaWxkID0gY2hpbGQubmV4dEVsZW1lbnRTaWJsaW5nO1xuICAgIH1cbiAgfSxcblxuICBmb2N1c0ZpcnN0KGVsKSB7XG4gICAgbGV0IGNoaWxkID0gZWwuZmlyc3RFbGVtZW50Q2hpbGQ7XG4gICAgd2hpbGUgKGNoaWxkKSB7XG4gICAgICBpZiAodGhpcy5hdHRlbXB0Rm9jdXMoY2hpbGQpIHx8IHRoaXMuZm9jdXNGaXJzdChjaGlsZCkpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgICBjaGlsZCA9IGNoaWxkLm5leHRFbGVtZW50U2libGluZztcbiAgICB9XG4gIH0sXG5cbiAgZm9jdXNMYXN0KGVsKSB7XG4gICAgbGV0IGNoaWxkID0gZWwubGFzdEVsZW1lbnRDaGlsZDtcbiAgICB3aGlsZSAoY2hpbGQpIHtcbiAgICAgIGlmICh0aGlzLmF0dGVtcHRGb2N1cyhjaGlsZCkgfHwgdGhpcy5mb2N1c0xhc3QoY2hpbGQpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgY2hpbGQgPSBjaGlsZC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nO1xuICAgIH1cbiAgfSxcbn07XG5leHBvcnQgZGVmYXVsdCBBUklBO1xuIiwgImltcG9ydCB7XG4gIFBIWF9BQ1RJVkVfRU5UUllfUkVGUyxcbiAgUEhYX0xJVkVfRklMRV9VUERBVEVELFxuICBQSFhfUFJFRkxJR0hURURfUkVGUyxcbiAgUEhYX1VQTE9BRF9SRUYsXG59IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG5pbXBvcnQgTGl2ZVVwbG9hZGVyIGZyb20gXCIuL2xpdmVfdXBsb2FkZXJcIjtcbmltcG9ydCBBUklBIGZyb20gXCIuL2FyaWFcIjtcblxuY29uc3QgSG9va3MgPSB7XG4gIExpdmVGaWxlVXBsb2FkOiB7XG4gICAgYWN0aXZlUmVmcygpIHtcbiAgICAgIHJldHVybiB0aGlzLmVsLmdldEF0dHJpYnV0ZShQSFhfQUNUSVZFX0VOVFJZX1JFRlMpO1xuICAgIH0sXG5cbiAgICBwcmVmbGlnaHRlZFJlZnMoKSB7XG4gICAgICByZXR1cm4gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX1BSRUZMSUdIVEVEX1JFRlMpO1xuICAgIH0sXG5cbiAgICBtb3VudGVkKCkge1xuICAgICAgdGhpcy5wcmVmbGlnaHRlZFdhcyA9IHRoaXMucHJlZmxpZ2h0ZWRSZWZzKCk7XG4gICAgfSxcblxuICAgIHVwZGF0ZWQoKSB7XG4gICAgICBjb25zdCBuZXdQcmVmbGlnaHRzID0gdGhpcy5wcmVmbGlnaHRlZFJlZnMoKTtcbiAgICAgIGlmICh0aGlzLnByZWZsaWdodGVkV2FzICE9PSBuZXdQcmVmbGlnaHRzKSB7XG4gICAgICAgIHRoaXMucHJlZmxpZ2h0ZWRXYXMgPSBuZXdQcmVmbGlnaHRzO1xuICAgICAgICBpZiAobmV3UHJlZmxpZ2h0cyA9PT0gXCJcIikge1xuICAgICAgICAgIHRoaXMuX192aWV3KCkuY2FuY2VsU3VibWl0KHRoaXMuZWwuZm9ybSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuYWN0aXZlUmVmcygpID09PSBcIlwiKSB7XG4gICAgICAgIHRoaXMuZWwudmFsdWUgPSBudWxsO1xuICAgICAgfVxuICAgICAgdGhpcy5lbC5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudChQSFhfTElWRV9GSUxFX1VQREFURUQpKTtcbiAgICB9LFxuICB9LFxuXG4gIExpdmVJbWdQcmV2aWV3OiB7XG4gICAgbW91bnRlZCgpIHtcbiAgICAgIHRoaXMucmVmID0gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXBoeC1lbnRyeS1yZWZcIik7XG4gICAgICB0aGlzLmlucHV0RWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcbiAgICAgICAgdGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpLFxuICAgICAgKTtcbiAgICAgIExpdmVVcGxvYWRlci5nZXRFbnRyeURhdGFVUkwodGhpcy5pbnB1dEVsLCB0aGlzLnJlZiwgKHVybCkgPT4ge1xuICAgICAgICB0aGlzLnVybCA9IHVybDtcbiAgICAgICAgdGhpcy5lbC5zcmMgPSB1cmw7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIGRlc3Ryb3llZCgpIHtcbiAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwodGhpcy51cmwpO1xuICAgIH0sXG4gIH0sXG4gIEZvY3VzV3JhcDoge1xuICAgIG1vdW50ZWQoKSB7XG4gICAgICB0aGlzLmZvY3VzU3RhcnQgPSB0aGlzLmVsLmZpcnN0RWxlbWVudENoaWxkO1xuICAgICAgdGhpcy5mb2N1c0VuZCA9IHRoaXMuZWwubGFzdEVsZW1lbnRDaGlsZDtcbiAgICAgIHRoaXMuZm9jdXNTdGFydC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgKGUpID0+IHtcbiAgICAgICAgaWYgKCFlLnJlbGF0ZWRUYXJnZXQgfHwgIXRoaXMuZWwuY29udGFpbnMoZS5yZWxhdGVkVGFyZ2V0KSkge1xuICAgICAgICAgIC8vIEhhbmRsZSBmb2N1cyBlbnRlcmluZyBmcm9tIG91dHNpZGUgKGUuZy4gVGFiIHdoZW4gYm9keSBpcyBmb2N1c2VkKVxuICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNjM2XG4gICAgICAgICAgY29uc3QgbmV4dEZvY3VzID0gZS50YXJnZXQubmV4dEVsZW1lbnRTaWJsaW5nO1xuICAgICAgICAgIEFSSUEuYXR0ZW1wdEZvY3VzKG5leHRGb2N1cykgfHwgQVJJQS5mb2N1c0ZpcnN0KG5leHRGb2N1cyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgQVJJQS5mb2N1c0xhc3QodGhpcy5lbCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy5mb2N1c0VuZC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgKGUpID0+IHtcbiAgICAgICAgaWYgKCFlLnJlbGF0ZWRUYXJnZXQgfHwgIXRoaXMuZWwuY29udGFpbnMoZS5yZWxhdGVkVGFyZ2V0KSkge1xuICAgICAgICAgIC8vIEhhbmRsZSBmb2N1cyBlbnRlcmluZyBmcm9tIG91dHNpZGUgKGUuZy4gU2hpZnQrVGFiIHdoZW4gYm9keSBpcyBmb2N1c2VkKVxuICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNjM2XG4gICAgICAgICAgY29uc3QgbmV4dEZvY3VzID0gZS50YXJnZXQucHJldmlvdXNFbGVtZW50U2libGluZztcbiAgICAgICAgICBBUklBLmF0dGVtcHRGb2N1cyhuZXh0Rm9jdXMpIHx8IEFSSUEuZm9jdXNMYXN0KG5leHRGb2N1cyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgQVJJQS5mb2N1c0ZpcnN0KHRoaXMuZWwpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIC8vIG9ubHkgdHJ5IHRvIGNoYW5nZSB0aGUgZm9jdXMgaWYgaXQgaXMgbm90IGFscmVhZHkgaW5zaWRlXG4gICAgICBpZiAoIXRoaXMuZWwuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkpIHtcbiAgICAgICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKFwicGh4OnNob3ctZW5kXCIsICgpID0+IHRoaXMuZWwuZm9jdXMoKSk7XG4gICAgICAgIGlmICh3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSh0aGlzLmVsKS5kaXNwbGF5ICE9PSBcIm5vbmVcIikge1xuICAgICAgICAgIEFSSUEuZm9jdXNGaXJzdCh0aGlzLmVsKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gIH0sXG59O1xuXG5jb25zdCBmaW5kU2Nyb2xsQ29udGFpbmVyID0gKGVsKSA9PiB7XG4gIC8vIHRoZSBzY3JvbGwgZXZlbnQgd29uJ3QgYmUgZmlyZWQgb24gdGhlIGh0bWwvYm9keSBlbGVtZW50IGV2ZW4gaWYgb3ZlcmZsb3cgaXMgc2V0XG4gIC8vIHRoZXJlZm9yZSB3ZSByZXR1cm4gbnVsbCB0byBpbnN0ZWFkIGxpc3RlbiBmb3Igc2Nyb2xsIGV2ZW50cyBvbiBkb2N1bWVudFxuICBpZiAoW1wiSFRNTFwiLCBcIkJPRFlcIl0uaW5kZXhPZihlbC5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpKSA+PSAwKSByZXR1cm4gbnVsbDtcbiAgaWYgKFtcInNjcm9sbFwiLCBcImF1dG9cIl0uaW5kZXhPZihnZXRDb21wdXRlZFN0eWxlKGVsKS5vdmVyZmxvd1kpID49IDApXG4gICAgcmV0dXJuIGVsO1xuICByZXR1cm4gZmluZFNjcm9sbENvbnRhaW5lcihlbC5wYXJlbnRFbGVtZW50KTtcbn07XG5cbmNvbnN0IHNjcm9sbFRvcCA9IChzY3JvbGxDb250YWluZXIpID0+IHtcbiAgaWYgKHNjcm9sbENvbnRhaW5lcikge1xuICAgIHJldHVybiBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wIHx8IGRvY3VtZW50LmJvZHkuc2Nyb2xsVG9wO1xuICB9XG59O1xuXG5jb25zdCBib3R0b20gPSAoc2Nyb2xsQ29udGFpbmVyKSA9PiB7XG4gIGlmIChzY3JvbGxDb250YWluZXIpIHtcbiAgICByZXR1cm4gc2Nyb2xsQ29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmJvdHRvbTtcbiAgfSBlbHNlIHtcbiAgICAvLyB3aGVuIHdlIGhhdmUgbm8gY29udGFpbmVyLCB0aGUgd2hvbGUgcGFnZSBzY3JvbGxzLFxuICAgIC8vIHRoZXJlZm9yZSB0aGUgYm90dG9tIGNvb3JkaW5hdGUgaXMgdGhlIHZpZXdwb3J0IGhlaWdodFxuICAgIHJldHVybiB3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcbiAgfVxufTtcblxuY29uc3QgdG9wID0gKHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBpZiAoc2Nyb2xsQ29udGFpbmVyKSB7XG4gICAgcmV0dXJuIHNjcm9sbENvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3A7XG4gIH0gZWxzZSB7XG4gICAgLy8gd2hlbiB3ZSBoYXZlIG5vIGNvbnRhaW5lciB0aGUgd2hvbGUgcGFnZSBzY3JvbGxzLFxuICAgIC8vIHRoZXJlZm9yZSB0aGUgdG9wIGNvb3JkaW5hdGUgaXMgMFxuICAgIHJldHVybiAwO1xuICB9XG59O1xuXG5jb25zdCBpc0F0Vmlld3BvcnRUb3AgPSAoZWwsIHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBjb25zdCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gIHJldHVybiAoXG4gICAgTWF0aC5jZWlsKHJlY3QudG9wKSA+PSB0b3Aoc2Nyb2xsQ29udGFpbmVyKSAmJlxuICAgIE1hdGguY2VpbChyZWN0LmxlZnQpID49IDAgJiZcbiAgICBNYXRoLmZsb29yKHJlY3QudG9wKSA8PSBib3R0b20oc2Nyb2xsQ29udGFpbmVyKVxuICApO1xufTtcblxuY29uc3QgaXNBdFZpZXdwb3J0Qm90dG9tID0gKGVsLCBzY3JvbGxDb250YWluZXIpID0+IHtcbiAgY29uc3QgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICByZXR1cm4gKFxuICAgIE1hdGguY2VpbChyZWN0LmJvdHRvbSkgPj0gdG9wKHNjcm9sbENvbnRhaW5lcikgJiZcbiAgICBNYXRoLmNlaWwocmVjdC5sZWZ0KSA+PSAwICYmXG4gICAgTWF0aC5mbG9vcihyZWN0LmJvdHRvbSkgPD0gYm90dG9tKHNjcm9sbENvbnRhaW5lcilcbiAgKTtcbn07XG5cbmNvbnN0IGlzV2l0aGluVmlld3BvcnQgPSAoZWwsIHNjcm9sbENvbnRhaW5lcikgPT4ge1xuICBjb25zdCByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gIHJldHVybiAoXG4gICAgTWF0aC5jZWlsKHJlY3QudG9wKSA+PSB0b3Aoc2Nyb2xsQ29udGFpbmVyKSAmJlxuICAgIE1hdGguY2VpbChyZWN0LmxlZnQpID49IDAgJiZcbiAgICBNYXRoLmZsb29yKHJlY3QudG9wKSA8PSBib3R0b20oc2Nyb2xsQ29udGFpbmVyKVxuICApO1xufTtcblxuSG9va3MuSW5maW5pdGVTY3JvbGwgPSB7XG4gIG1vdW50ZWQoKSB7XG4gICAgdGhpcy5zY3JvbGxDb250YWluZXIgPSBmaW5kU2Nyb2xsQ29udGFpbmVyKHRoaXMuZWwpO1xuICAgIGxldCBzY3JvbGxCZWZvcmUgPSBzY3JvbGxUb3AodGhpcy5zY3JvbGxDb250YWluZXIpO1xuICAgIGxldCB0b3BPdmVycmFuID0gZmFsc2U7XG4gICAgY29uc3QgdGhyb3R0bGVJbnRlcnZhbCA9IDUwMDtcbiAgICBsZXQgcGVuZGluZ09wID0gbnVsbDtcblxuICAgIGNvbnN0IG9uVG9wT3ZlcnJ1biA9IHRoaXMudGhyb3R0bGUoXG4gICAgICB0aHJvdHRsZUludGVydmFsLFxuICAgICAgKHRvcEV2ZW50LCBmaXJzdENoaWxkKSA9PiB7XG4gICAgICAgIHBlbmRpbmdPcCA9ICgpID0+IHRydWU7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5qcygpLnB1c2godGhpcy5lbCwgdG9wRXZlbnQsIHtcbiAgICAgICAgICB2YWx1ZTogeyBpZDogZmlyc3RDaGlsZC5pZCwgX292ZXJyYW46IHRydWUgfSxcbiAgICAgICAgICBjYWxsYmFjazogKCkgPT4ge1xuICAgICAgICAgICAgcGVuZGluZ09wID0gbnVsbDtcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIGNvbnN0IG9uRmlyc3RDaGlsZEF0VG9wID0gdGhpcy50aHJvdHRsZShcbiAgICAgIHRocm90dGxlSW50ZXJ2YWwsXG4gICAgICAodG9wRXZlbnQsIGZpcnN0Q2hpbGQpID0+IHtcbiAgICAgICAgcGVuZGluZ09wID0gKCkgPT4gZmlyc3RDaGlsZC5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiBcInN0YXJ0XCIgfSk7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5qcygpLnB1c2godGhpcy5lbCwgdG9wRXZlbnQsIHtcbiAgICAgICAgICB2YWx1ZTogeyBpZDogZmlyc3RDaGlsZC5pZCB9LFxuICAgICAgICAgIGNhbGxiYWNrOiAoKSA9PiB7XG4gICAgICAgICAgICBwZW5kaW5nT3AgPSBudWxsO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHRoYXQgdGhlIERPTSBpcyBwYXRjaGVkIGJ5IHdhaXRpbmcgZm9yIHRoZSBuZXh0IHRpY2tcbiAgICAgICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgICAgICBpZiAoIWlzV2l0aGluVmlld3BvcnQoZmlyc3RDaGlsZCwgdGhpcy5zY3JvbGxDb250YWluZXIpKSB7XG4gICAgICAgICAgICAgICAgZmlyc3RDaGlsZC5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiBcInN0YXJ0XCIgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICApO1xuXG4gICAgY29uc3Qgb25MYXN0Q2hpbGRBdEJvdHRvbSA9IHRoaXMudGhyb3R0bGUoXG4gICAgICB0aHJvdHRsZUludGVydmFsLFxuICAgICAgKGJvdHRvbUV2ZW50LCBsYXN0Q2hpbGQpID0+IHtcbiAgICAgICAgcGVuZGluZ09wID0gKCkgPT4gbGFzdENoaWxkLnNjcm9sbEludG9WaWV3KHsgYmxvY2s6IFwiZW5kXCIgfSk7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5qcygpLnB1c2godGhpcy5lbCwgYm90dG9tRXZlbnQsIHtcbiAgICAgICAgICB2YWx1ZTogeyBpZDogbGFzdENoaWxkLmlkIH0sXG4gICAgICAgICAgY2FsbGJhY2s6ICgpID0+IHtcbiAgICAgICAgICAgIHBlbmRpbmdPcCA9IG51bGw7XG4gICAgICAgICAgICAvLyBtYWtlIHN1cmUgdGhhdCB0aGUgRE9NIGlzIHBhdGNoZWQgYnkgd2FpdGluZyBmb3IgdGhlIG5leHQgdGlja1xuICAgICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgICAgIGlmICghaXNXaXRoaW5WaWV3cG9ydChsYXN0Q2hpbGQsIHRoaXMuc2Nyb2xsQ29udGFpbmVyKSkge1xuICAgICAgICAgICAgICAgIGxhc3RDaGlsZC5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiBcImVuZFwiIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIHRoaXMub25TY3JvbGwgPSAoX2UpID0+IHtcbiAgICAgIGNvbnN0IHNjcm9sbE5vdyA9IHNjcm9sbFRvcCh0aGlzLnNjcm9sbENvbnRhaW5lcik7XG5cbiAgICAgIGlmIChwZW5kaW5nT3ApIHtcbiAgICAgICAgc2Nyb2xsQmVmb3JlID0gc2Nyb2xsTm93O1xuICAgICAgICByZXR1cm4gcGVuZGluZ09wKCk7XG4gICAgICB9XG4gICAgICBjb25zdCByZWN0ID0gdGhpcy5lbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGNvbnN0IHRvcEV2ZW50ID0gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoXG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5iaW5kaW5nKFwidmlld3BvcnQtdG9wXCIpLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGJvdHRvbUV2ZW50ID0gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoXG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5iaW5kaW5nKFwidmlld3BvcnQtYm90dG9tXCIpLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGxhc3RDaGlsZCA9IHRoaXMuZWwubGFzdEVsZW1lbnRDaGlsZDtcbiAgICAgIGNvbnN0IGZpcnN0Q2hpbGQgPSB0aGlzLmVsLmZpcnN0RWxlbWVudENoaWxkO1xuICAgICAgY29uc3QgaXNTY3JvbGxpbmdVcCA9IHNjcm9sbE5vdyA8IHNjcm9sbEJlZm9yZTtcbiAgICAgIGNvbnN0IGlzU2Nyb2xsaW5nRG93biA9IHNjcm9sbE5vdyA+IHNjcm9sbEJlZm9yZTtcblxuICAgICAgLy8gZWwgb3ZlcnJhbiB3aGlsZSBzY3JvbGxpbmcgdXBcbiAgICAgIGlmIChpc1Njcm9sbGluZ1VwICYmIHRvcEV2ZW50ICYmICF0b3BPdmVycmFuICYmIHJlY3QudG9wID49IDApIHtcbiAgICAgICAgdG9wT3ZlcnJhbiA9IHRydWU7XG4gICAgICAgIG9uVG9wT3ZlcnJ1bih0b3BFdmVudCwgZmlyc3RDaGlsZCk7XG4gICAgICB9IGVsc2UgaWYgKGlzU2Nyb2xsaW5nRG93biAmJiB0b3BPdmVycmFuICYmIHJlY3QudG9wIDw9IDApIHtcbiAgICAgICAgdG9wT3ZlcnJhbiA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIHRvcEV2ZW50ICYmXG4gICAgICAgIGlzU2Nyb2xsaW5nVXAgJiZcbiAgICAgICAgaXNBdFZpZXdwb3J0VG9wKGZpcnN0Q2hpbGQsIHRoaXMuc2Nyb2xsQ29udGFpbmVyKVxuICAgICAgKSB7XG4gICAgICAgIG9uRmlyc3RDaGlsZEF0VG9wKHRvcEV2ZW50LCBmaXJzdENoaWxkKTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIGJvdHRvbUV2ZW50ICYmXG4gICAgICAgIGlzU2Nyb2xsaW5nRG93biAmJlxuICAgICAgICBpc0F0Vmlld3BvcnRCb3R0b20obGFzdENoaWxkLCB0aGlzLnNjcm9sbENvbnRhaW5lcilcbiAgICAgICkge1xuICAgICAgICBvbkxhc3RDaGlsZEF0Qm90dG9tKGJvdHRvbUV2ZW50LCBsYXN0Q2hpbGQpO1xuICAgICAgfVxuICAgICAgc2Nyb2xsQmVmb3JlID0gc2Nyb2xsTm93O1xuICAgIH07XG5cbiAgICBpZiAodGhpcy5zY3JvbGxDb250YWluZXIpIHtcbiAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgdGhpcy5vblNjcm9sbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHRoaXMub25TY3JvbGwpO1xuICAgIH1cbiAgfSxcblxuICBkZXN0cm95ZWQoKSB7XG4gICAgaWYgKHRoaXMuc2Nyb2xsQ29udGFpbmVyKSB7XG4gICAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5yZW1vdmVFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHRoaXMub25TY3JvbGwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCB0aGlzLm9uU2Nyb2xsKTtcbiAgICB9XG4gIH0sXG5cbiAgdGhyb3R0bGUoaW50ZXJ2YWwsIGNhbGxiYWNrKSB7XG4gICAgbGV0IGxhc3RDYWxsQXQgPSAwO1xuICAgIGxldCB0aW1lcjtcblxuICAgIHJldHVybiAoLi4uYXJncykgPT4ge1xuICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHJlbWFpbmluZ1RpbWUgPSBpbnRlcnZhbCAtIChub3cgLSBsYXN0Q2FsbEF0KTtcblxuICAgICAgaWYgKHJlbWFpbmluZ1RpbWUgPD0gMCB8fCByZW1haW5pbmdUaW1lID4gaW50ZXJ2YWwpIHtcbiAgICAgICAgaWYgKHRpbWVyKSB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgICB0aW1lciA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgbGFzdENhbGxBdCA9IG5vdztcbiAgICAgICAgY2FsbGJhY2soLi4uYXJncyk7XG4gICAgICB9IGVsc2UgaWYgKCF0aW1lcikge1xuICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGxhc3RDYWxsQXQgPSBEYXRlLm5vdygpO1xuICAgICAgICAgIHRpbWVyID0gbnVsbDtcbiAgICAgICAgICBjYWxsYmFjayguLi5hcmdzKTtcbiAgICAgICAgfSwgcmVtYWluaW5nVGltZSk7XG4gICAgICB9XG4gICAgfTtcbiAgfSxcbn07XG5leHBvcnQgZGVmYXVsdCBIb29rcztcbiIsICJpbXBvcnQge1xuICBQSFhfUkVGX0xPQURJTkcsXG4gIFBIWF9SRUZfTE9DSyxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9QRU5ESU5HX1JFRlMsXG4gIFBIWF9FVkVOVF9DTEFTU0VTLFxuICBQSFhfRElTQUJMRUQsXG4gIFBIWF9SRUFET05MWSxcbiAgUEhYX0RJU0FCTEVfV0lUSF9SRVNUT1JFLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRWxlbWVudFJlZiB7XG4gIHN0YXRpYyBvblVubG9jayhlbCwgY2FsbGJhY2spIHtcbiAgICBpZiAoIURPTS5pc0xvY2tlZChlbCkgJiYgIWVsLmNsb3Nlc3QoYFske1BIWF9SRUZfTE9DS31dYCkpIHtcbiAgICAgIHJldHVybiBjYWxsYmFjaygpO1xuICAgIH1cbiAgICBjb25zdCBjbG9zZXN0TG9jayA9IGVsLmNsb3Nlc3QoYFske1BIWF9SRUZfTE9DS31dYCk7XG4gICAgY29uc3QgcmVmID0gY2xvc2VzdExvY2tcbiAgICAgIC5jbG9zZXN0KGBbJHtQSFhfUkVGX0xPQ0t9XWApXG4gICAgICAuZ2V0QXR0cmlidXRlKFBIWF9SRUZfTE9DSyk7XG4gICAgY2xvc2VzdExvY2suYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIGBwaHg6dW5kby1sb2NrOiR7cmVmfWAsXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICB9LFxuICAgICAgeyBvbmNlOiB0cnVlIH0sXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGVsKSB7XG4gICAgdGhpcy5lbCA9IGVsO1xuICAgIHRoaXMubG9hZGluZ1JlZiA9IGVsLmhhc0F0dHJpYnV0ZShQSFhfUkVGX0xPQURJTkcpXG4gICAgICA/IHBhcnNlSW50KGVsLmdldEF0dHJpYnV0ZShQSFhfUkVGX0xPQURJTkcpLCAxMClcbiAgICAgIDogbnVsbDtcbiAgICB0aGlzLmxvY2tSZWYgPSBlbC5oYXNBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKVxuICAgICAgPyBwYXJzZUludChlbC5nZXRBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKSwgMTApXG4gICAgICA6IG51bGw7XG4gIH1cblxuICAvLyBwdWJsaWNcblxuICBtYXliZVVuZG8ocmVmLCBwaHhFdmVudCwgZWFjaENsb25lQ2FsbGJhY2spIHtcbiAgICBpZiAoIXRoaXMuaXNXaXRoaW4ocmVmKSkge1xuICAgICAgLy8gd2UgY2Fubm90IHVuZG8gdGhlIGxvY2sgLyBsb2FkaW5nIG5vdywgYXMgdGhlcmUgaXMgYSBuZXdlciBvbmUgYWxyZWFkeSBzZXQ7XG4gICAgICAvLyB3ZSBuZWVkIHRvIHN0b3JlIHRoZSBvcmlnaW5hbCByZWYgd2UgdHJpZWQgdG8gc2VuZCB0aGUgdW5kbyBldmVudCBsYXRlclxuICAgICAgRE9NLnVwZGF0ZVByaXZhdGUodGhpcy5lbCwgUEhYX1BFTkRJTkdfUkVGUywgW10sIChwZW5kaW5nUmVmcykgPT4ge1xuICAgICAgICBwZW5kaW5nUmVmcy5wdXNoKHJlZik7XG4gICAgICAgIHJldHVybiBwZW5kaW5nUmVmcztcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHVuZG8gbG9ja3MgYW5kIGFwcGx5IGNsb25lc1xuICAgIHRoaXMudW5kb0xvY2tzKHJlZiwgcGh4RXZlbnQsIGVhY2hDbG9uZUNhbGxiYWNrKTtcblxuICAgIC8vIHVuZG8gbG9hZGluZyBzdGF0ZXNcbiAgICB0aGlzLnVuZG9Mb2FkaW5nKHJlZiwgcGh4RXZlbnQpO1xuXG4gICAgLy8gZW5zdXJlIHVuZG8gZXZlbnRzIGFyZSBmaXJlZCBmb3IgcGVuZGluZyByZWZzIHRoYXRcbiAgICAvLyBhcmUgcmVzb2x2ZWQgYnkgdGhlIGN1cnJlbnQgcmVmLCBvdGhlcndpc2Ugd2UnZCBsZWFrIGV2ZW50IGxpc3RlbmVyc1xuICAgIERPTS51cGRhdGVQcml2YXRlKHRoaXMuZWwsIFBIWF9QRU5ESU5HX1JFRlMsIFtdLCAocGVuZGluZ1JlZnMpID0+IHtcbiAgICAgIHJldHVybiBwZW5kaW5nUmVmcy5maWx0ZXIoKHBlbmRpbmdSZWYpID0+IHtcbiAgICAgICAgbGV0IG9wdHMgPSB7XG4gICAgICAgICAgZGV0YWlsOiB7IHJlZjogcGVuZGluZ1JlZiwgZXZlbnQ6IHBoeEV2ZW50IH0sXG4gICAgICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgICAgICBjYW5jZWxhYmxlOiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHRoaXMubG9hZGluZ1JlZiAmJiB0aGlzLmxvYWRpbmdSZWYgPiBwZW5kaW5nUmVmKSB7XG4gICAgICAgICAgdGhpcy5lbC5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IEN1c3RvbUV2ZW50KGBwaHg6dW5kby1sb2FkaW5nOiR7cGVuZGluZ1JlZn1gLCBvcHRzKSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmxvY2tSZWYgJiYgdGhpcy5sb2NrUmVmID4gcGVuZGluZ1JlZikge1xuICAgICAgICAgIHRoaXMuZWwuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgIG5ldyBDdXN0b21FdmVudChgcGh4OnVuZG8tbG9jazoke3BlbmRpbmdSZWZ9YCwgb3B0cyksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcGVuZGluZ1JlZiA+IHJlZjtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLy8gY2xlYW4gdXAgaWYgZnVsbHkgcmVzb2x2ZWRcbiAgICBpZiAodGhpcy5pc0Z1bGx5UmVzb2x2ZWRCeShyZWYpKSB7XG4gICAgICB0aGlzLmVsLnJlbW92ZUF0dHJpYnV0ZShQSFhfUkVGX1NSQyk7XG4gICAgfVxuICB9XG5cbiAgLy8gcHJpdmF0ZVxuXG4gIGlzV2l0aGluKHJlZikge1xuICAgIHJldHVybiAhKFxuICAgICAgdGhpcy5sb2FkaW5nUmVmICE9PSBudWxsICYmXG4gICAgICB0aGlzLmxvYWRpbmdSZWYgPiByZWYgJiZcbiAgICAgIHRoaXMubG9ja1JlZiAhPT0gbnVsbCAmJlxuICAgICAgdGhpcy5sb2NrUmVmID4gcmVmXG4gICAgKTtcbiAgfVxuXG4gIC8vIENoZWNrIGZvciBjbG9uZWQgUEhYX1JFRl9MT0NLIGVsZW1lbnQgdGhhdCBoYXMgYmVlbiBtb3JwaGVkIGJlaGluZFxuICAvLyB0aGUgc2NlbmVzIHdoaWxlIHRoaXMgZWxlbWVudCB3YXMgbG9ja2VkIGluIHRoZSBET00uXG4gIC8vIFdoZW4gd2UgYXBwbHkgdGhlIGNsb25lZCB0cmVlIHRvIHRoZSBhY3RpdmUgRE9NIGVsZW1lbnQsIHdlIG11c3RcbiAgLy9cbiAgLy8gICAxLiBleGVjdXRlIHBlbmRpbmcgbW91bnRlZCBob29rcyBmb3Igbm9kZXMgbm93IGluIHRoZSBET01cbiAgLy8gICAyLiB1bmRvIGFueSByZWYgaW5zaWRlIHRoZSBjbG9uZWQgdHJlZSB0aGF0IGhhcyBzaW5jZSBiZWVuIGFjaydkXG4gIHVuZG9Mb2NrcyhyZWYsIHBoeEV2ZW50LCBlYWNoQ2xvbmVDYWxsYmFjaykge1xuICAgIGlmICghdGhpcy5pc0xvY2tVbmRvbmVCeShyZWYpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY2xvbmVkVHJlZSA9IERPTS5wcml2YXRlKHRoaXMuZWwsIFBIWF9SRUZfTE9DSyk7XG4gICAgaWYgKGNsb25lZFRyZWUpIHtcbiAgICAgIGVhY2hDbG9uZUNhbGxiYWNrKGNsb25lZFRyZWUpO1xuICAgICAgRE9NLmRlbGV0ZVByaXZhdGUodGhpcy5lbCwgUEhYX1JFRl9MT0NLKTtcbiAgICB9XG4gICAgdGhpcy5lbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKTtcblxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICBkZXRhaWw6IHsgcmVmOiByZWYsIGV2ZW50OiBwaHhFdmVudCB9LFxuICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgIGNhbmNlbGFibGU6IGZhbHNlLFxuICAgIH07XG4gICAgdGhpcy5lbC5kaXNwYXRjaEV2ZW50KFxuICAgICAgbmV3IEN1c3RvbUV2ZW50KGBwaHg6dW5kby1sb2NrOiR7dGhpcy5sb2NrUmVmfWAsIG9wdHMpLFxuICAgICk7XG4gIH1cblxuICB1bmRvTG9hZGluZyhyZWYsIHBoeEV2ZW50KSB7XG4gICAgaWYgKCF0aGlzLmlzTG9hZGluZ1VuZG9uZUJ5KHJlZikpIHtcbiAgICAgIGlmIChcbiAgICAgICAgdGhpcy5jYW5VbmRvTG9hZGluZyhyZWYpICYmXG4gICAgICAgIHRoaXMuZWwuY2xhc3NMaXN0LmNvbnRhaW5zKFwicGh4LXN1Ym1pdC1sb2FkaW5nXCIpXG4gICAgICApIHtcbiAgICAgICAgdGhpcy5lbC5jbGFzc0xpc3QucmVtb3ZlKFwicGh4LWNoYW5nZS1sb2FkaW5nXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmNhblVuZG9Mb2FkaW5nKHJlZikpIHtcbiAgICAgIHRoaXMuZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUZfTE9BRElORyk7XG4gICAgICBjb25zdCBkaXNhYmxlZFZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRCk7XG4gICAgICBjb25zdCByZWFkT25seVZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9SRUFET05MWSk7XG4gICAgICAvLyByZXN0b3JlIGlucHV0c1xuICAgICAgaWYgKHJlYWRPbmx5VmFsICE9PSBudWxsKSB7XG4gICAgICAgIHRoaXMuZWwucmVhZE9ubHkgPSByZWFkT25seVZhbCA9PT0gXCJ0cnVlXCIgPyB0cnVlIDogZmFsc2U7XG4gICAgICAgIHRoaXMuZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUFET05MWSk7XG4gICAgICB9XG4gICAgICBpZiAoZGlzYWJsZWRWYWwgIT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5lbC5kaXNhYmxlZCA9IGRpc2FibGVkVmFsID09PSBcInRydWVcIiA/IHRydWUgOiBmYWxzZTtcbiAgICAgICAgdGhpcy5lbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX0RJU0FCTEVEKTtcbiAgICAgIH1cbiAgICAgIC8vIHJlc3RvcmUgZGlzYWJsZXNcbiAgICAgIGNvbnN0IGRpc2FibGVSZXN0b3JlID0gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX0RJU0FCTEVfV0lUSF9SRVNUT1JFKTtcbiAgICAgIGlmIChkaXNhYmxlUmVzdG9yZSAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmVsLmlubmVyVGV4dCA9IGRpc2FibGVSZXN0b3JlO1xuICAgICAgICB0aGlzLmVsLnJlbW92ZUF0dHJpYnV0ZShQSFhfRElTQUJMRV9XSVRIX1JFU1RPUkUpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBvcHRzID0ge1xuICAgICAgICBkZXRhaWw6IHsgcmVmOiByZWYsIGV2ZW50OiBwaHhFdmVudCB9LFxuICAgICAgICBidWJibGVzOiB0cnVlLFxuICAgICAgICBjYW5jZWxhYmxlOiBmYWxzZSxcbiAgICAgIH07XG4gICAgICB0aGlzLmVsLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgIG5ldyBDdXN0b21FdmVudChgcGh4OnVuZG8tbG9hZGluZzoke3RoaXMubG9hZGluZ1JlZn1gLCBvcHRzKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gcmVtb3ZlIGNsYXNzZXNcbiAgICBQSFhfRVZFTlRfQ0xBU1NFUy5mb3JFYWNoKChuYW1lKSA9PiB7XG4gICAgICBpZiAobmFtZSAhPT0gXCJwaHgtc3VibWl0LWxvYWRpbmdcIiB8fCB0aGlzLmNhblVuZG9Mb2FkaW5nKHJlZikpIHtcbiAgICAgICAgRE9NLnJlbW92ZUNsYXNzKHRoaXMuZWwsIG5hbWUpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgaXNMb2FkaW5nVW5kb25lQnkocmVmKSB7XG4gICAgcmV0dXJuIHRoaXMubG9hZGluZ1JlZiA9PT0gbnVsbCA/IGZhbHNlIDogdGhpcy5sb2FkaW5nUmVmIDw9IHJlZjtcbiAgfVxuICBpc0xvY2tVbmRvbmVCeShyZWYpIHtcbiAgICByZXR1cm4gdGhpcy5sb2NrUmVmID09PSBudWxsID8gZmFsc2UgOiB0aGlzLmxvY2tSZWYgPD0gcmVmO1xuICB9XG5cbiAgaXNGdWxseVJlc29sdmVkQnkocmVmKSB7XG4gICAgcmV0dXJuIChcbiAgICAgICh0aGlzLmxvYWRpbmdSZWYgPT09IG51bGwgfHwgdGhpcy5sb2FkaW5nUmVmIDw9IHJlZikgJiZcbiAgICAgICh0aGlzLmxvY2tSZWYgPT09IG51bGwgfHwgdGhpcy5sb2NrUmVmIDw9IHJlZilcbiAgICApO1xuICB9XG5cbiAgLy8gb25seSByZW1vdmUgdGhlIHBoeC1zdWJtaXQtbG9hZGluZyBjbGFzcyBpZiB3ZSBhcmUgbm90IGxvY2tlZFxuICBjYW5VbmRvTG9hZGluZyhyZWYpIHtcbiAgICByZXR1cm4gdGhpcy5sb2NrUmVmID09PSBudWxsIHx8IHRoaXMubG9ja1JlZiA8PSByZWY7XG4gIH1cbn1cbiIsICJpbXBvcnQgeyBtYXliZSB9IGZyb20gXCIuL3V0aWxzXCI7XG5cbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIERPTVBvc3RNb3JwaFJlc3RvcmVyIHtcbiAgY29uc3RydWN0b3IoY29udGFpbmVyQmVmb3JlLCBjb250YWluZXJBZnRlciwgdXBkYXRlVHlwZSkge1xuICAgIGNvbnN0IGlkc0JlZm9yZSA9IG5ldyBTZXQoKTtcbiAgICBjb25zdCBpZHNBZnRlciA9IG5ldyBTZXQoXG4gICAgICBbLi4uY29udGFpbmVyQWZ0ZXIuY2hpbGRyZW5dLm1hcCgoY2hpbGQpID0+IGNoaWxkLmlkKSxcbiAgICApO1xuXG4gICAgY29uc3QgZWxlbWVudHNUb01vZGlmeSA9IFtdO1xuXG4gICAgQXJyYXkuZnJvbShjb250YWluZXJCZWZvcmUuY2hpbGRyZW4pLmZvckVhY2goKGNoaWxkKSA9PiB7XG4gICAgICBpZiAoY2hpbGQuaWQpIHtcbiAgICAgICAgLy8gYWxsIG9mIG91ciBjaGlsZHJlbiBzaG91bGQgYmUgZWxlbWVudHMgd2l0aCBpZHNcbiAgICAgICAgaWRzQmVmb3JlLmFkZChjaGlsZC5pZCk7XG4gICAgICAgIGlmIChpZHNBZnRlci5oYXMoY2hpbGQuaWQpKSB7XG4gICAgICAgICAgY29uc3QgcHJldmlvdXNFbGVtZW50SWQgPVxuICAgICAgICAgICAgY2hpbGQucHJldmlvdXNFbGVtZW50U2libGluZyAmJiBjaGlsZC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nLmlkO1xuICAgICAgICAgIGVsZW1lbnRzVG9Nb2RpZnkucHVzaCh7XG4gICAgICAgICAgICBlbGVtZW50SWQ6IGNoaWxkLmlkLFxuICAgICAgICAgICAgcHJldmlvdXNFbGVtZW50SWQ6IHByZXZpb3VzRWxlbWVudElkLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLmNvbnRhaW5lcklkID0gY29udGFpbmVyQWZ0ZXIuaWQ7XG4gICAgdGhpcy51cGRhdGVUeXBlID0gdXBkYXRlVHlwZTtcbiAgICB0aGlzLmVsZW1lbnRzVG9Nb2RpZnkgPSBlbGVtZW50c1RvTW9kaWZ5O1xuICAgIHRoaXMuZWxlbWVudElkc1RvQWRkID0gWy4uLmlkc0FmdGVyXS5maWx0ZXIoKGlkKSA9PiAhaWRzQmVmb3JlLmhhcyhpZCkpO1xuICB9XG5cbiAgLy8gV2UgZG8gdGhlIGZvbGxvd2luZyB0byBvcHRpbWl6ZSBhcHBlbmQvcHJlcGVuZCBvcGVyYXRpb25zOlxuICAvLyAgIDEpIFRyYWNrIGlkcyBvZiBtb2RpZmllZCBlbGVtZW50cyAmIG9mIG5ldyBlbGVtZW50c1xuICAvLyAgIDIpIEFsbCB0aGUgbW9kaWZpZWQgZWxlbWVudHMgYXJlIHB1dCBiYWNrIGluIHRoZSBjb3JyZWN0IHBvc2l0aW9uIGluIHRoZSBET00gdHJlZVxuICAvLyAgICAgIGJ5IHN0b3JpbmcgdGhlIGlkIG9mIHRoZWlyIHByZXZpb3VzIHNpYmxpbmdcbiAgLy8gICAzKSBOZXcgZWxlbWVudHMgYXJlIGdvaW5nIHRvIGJlIHB1dCBpbiB0aGUgcmlnaHQgcGxhY2UgYnkgbW9ycGhkb20gZHVyaW5nIGFwcGVuZC5cbiAgLy8gICAgICBGb3IgcHJlcGVuZCwgd2UgbW92ZSB0aGVtIHRvIHRoZSBmaXJzdCBwb3NpdGlvbiBpbiB0aGUgY29udGFpbmVyXG4gIHBlcmZvcm0oKSB7XG4gICAgY29uc3QgY29udGFpbmVyID0gRE9NLmJ5SWQodGhpcy5jb250YWluZXJJZCk7XG4gICAgaWYgKCFjb250YWluZXIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5lbGVtZW50c1RvTW9kaWZ5LmZvckVhY2goKGVsZW1lbnRUb01vZGlmeSkgPT4ge1xuICAgICAgaWYgKGVsZW1lbnRUb01vZGlmeS5wcmV2aW91c0VsZW1lbnRJZCkge1xuICAgICAgICBtYXliZShcbiAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChlbGVtZW50VG9Nb2RpZnkucHJldmlvdXNFbGVtZW50SWQpLFxuICAgICAgICAgIChwcmV2aW91c0VsZW0pID0+IHtcbiAgICAgICAgICAgIG1heWJlKFxuICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChlbGVtZW50VG9Nb2RpZnkuZWxlbWVudElkKSxcbiAgICAgICAgICAgICAgKGVsZW0pID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBpc0luUmlnaHRQbGFjZSA9XG4gICAgICAgICAgICAgICAgICBlbGVtLnByZXZpb3VzRWxlbWVudFNpYmxpbmcgJiZcbiAgICAgICAgICAgICAgICAgIGVsZW0ucHJldmlvdXNFbGVtZW50U2libGluZy5pZCA9PSBwcmV2aW91c0VsZW0uaWQ7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0luUmlnaHRQbGFjZSkge1xuICAgICAgICAgICAgICAgICAgcHJldmlvdXNFbGVtLmluc2VydEFkamFjZW50RWxlbWVudChcImFmdGVyZW5kXCIsIGVsZW0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFRoaXMgaXMgdGhlIGZpcnN0IGVsZW1lbnQgaW4gdGhlIGNvbnRhaW5lclxuICAgICAgICBtYXliZShkb2N1bWVudC5nZXRFbGVtZW50QnlJZChlbGVtZW50VG9Nb2RpZnkuZWxlbWVudElkKSwgKGVsZW0pID0+IHtcbiAgICAgICAgICBjb25zdCBpc0luUmlnaHRQbGFjZSA9IGVsZW0ucHJldmlvdXNFbGVtZW50U2libGluZyA9PSBudWxsO1xuICAgICAgICAgIGlmICghaXNJblJpZ2h0UGxhY2UpIHtcbiAgICAgICAgICAgIGNvbnRhaW5lci5pbnNlcnRBZGphY2VudEVsZW1lbnQoXCJhZnRlcmJlZ2luXCIsIGVsZW0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy51cGRhdGVUeXBlID09IFwicHJlcGVuZFwiKSB7XG4gICAgICB0aGlzLmVsZW1lbnRJZHNUb0FkZC5yZXZlcnNlKCkuZm9yRWFjaCgoZWxlbUlkKSA9PiB7XG4gICAgICAgIG1heWJlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGVsZW1JZCksIChlbGVtKSA9PlxuICAgICAgICAgIGNvbnRhaW5lci5pbnNlcnRBZGphY2VudEVsZW1lbnQoXCJhZnRlcmJlZ2luXCIsIGVsZW0pLFxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iLCAidmFyIERPQ1VNRU5UX0ZSQUdNRU5UX05PREUgPSAxMTtcblxuZnVuY3Rpb24gbW9ycGhBdHRycyhmcm9tTm9kZSwgdG9Ob2RlKSB7XG4gICAgdmFyIHRvTm9kZUF0dHJzID0gdG9Ob2RlLmF0dHJpYnV0ZXM7XG4gICAgdmFyIGF0dHI7XG4gICAgdmFyIGF0dHJOYW1lO1xuICAgIHZhciBhdHRyTmFtZXNwYWNlVVJJO1xuICAgIHZhciBhdHRyVmFsdWU7XG4gICAgdmFyIGZyb21WYWx1ZTtcblxuICAgIC8vIGRvY3VtZW50LWZyYWdtZW50cyBkb250IGhhdmUgYXR0cmlidXRlcyBzbyBsZXRzIG5vdCBkbyBhbnl0aGluZ1xuICAgIGlmICh0b05vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUgfHwgZnJvbU5vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyB1cGRhdGUgYXR0cmlidXRlcyBvbiBvcmlnaW5hbCBET00gZWxlbWVudFxuICAgIGZvciAodmFyIGkgPSB0b05vZGVBdHRycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICBhdHRyID0gdG9Ob2RlQXR0cnNbaV07XG4gICAgICAgIGF0dHJOYW1lID0gYXR0ci5uYW1lO1xuICAgICAgICBhdHRyTmFtZXNwYWNlVVJJID0gYXR0ci5uYW1lc3BhY2VVUkk7XG4gICAgICAgIGF0dHJWYWx1ZSA9IGF0dHIudmFsdWU7XG5cbiAgICAgICAgaWYgKGF0dHJOYW1lc3BhY2VVUkkpIHtcbiAgICAgICAgICAgIGF0dHJOYW1lID0gYXR0ci5sb2NhbE5hbWUgfHwgYXR0ck5hbWU7XG4gICAgICAgICAgICBmcm9tVmFsdWUgPSBmcm9tTm9kZS5nZXRBdHRyaWJ1dGVOUyhhdHRyTmFtZXNwYWNlVVJJLCBhdHRyTmFtZSk7XG5cbiAgICAgICAgICAgIGlmIChmcm9tVmFsdWUgIT09IGF0dHJWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmIChhdHRyLnByZWZpeCA9PT0gJ3htbG5zJyl7XG4gICAgICAgICAgICAgICAgICAgIGF0dHJOYW1lID0gYXR0ci5uYW1lOyAvLyBJdCdzIG5vdCBhbGxvd2VkIHRvIHNldCBhbiBhdHRyaWJ1dGUgd2l0aCB0aGUgWE1MTlMgbmFtZXNwYWNlIHdpdGhvdXQgc3BlY2lmeWluZyB0aGUgYHhtbG5zYCBwcmVmaXhcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZnJvbU5vZGUuc2V0QXR0cmlidXRlTlMoYXR0ck5hbWVzcGFjZVVSSSwgYXR0ck5hbWUsIGF0dHJWYWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmcm9tVmFsdWUgPSBmcm9tTm9kZS5nZXRBdHRyaWJ1dGUoYXR0ck5hbWUpO1xuXG4gICAgICAgICAgICBpZiAoZnJvbVZhbHVlICE9PSBhdHRyVmFsdWUpIHtcbiAgICAgICAgICAgICAgICBmcm9tTm9kZS5zZXRBdHRyaWJ1dGUoYXR0ck5hbWUsIGF0dHJWYWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgYW55IGV4dHJhIGF0dHJpYnV0ZXMgZm91bmQgb24gdGhlIG9yaWdpbmFsIERPTSBlbGVtZW50IHRoYXRcbiAgICAvLyB3ZXJlbid0IGZvdW5kIG9uIHRoZSB0YXJnZXQgZWxlbWVudC5cbiAgICB2YXIgZnJvbU5vZGVBdHRycyA9IGZyb21Ob2RlLmF0dHJpYnV0ZXM7XG5cbiAgICBmb3IgKHZhciBkID0gZnJvbU5vZGVBdHRycy5sZW5ndGggLSAxOyBkID49IDA7IGQtLSkge1xuICAgICAgICBhdHRyID0gZnJvbU5vZGVBdHRyc1tkXTtcbiAgICAgICAgYXR0ck5hbWUgPSBhdHRyLm5hbWU7XG4gICAgICAgIGF0dHJOYW1lc3BhY2VVUkkgPSBhdHRyLm5hbWVzcGFjZVVSSTtcblxuICAgICAgICBpZiAoYXR0ck5hbWVzcGFjZVVSSSkge1xuICAgICAgICAgICAgYXR0ck5hbWUgPSBhdHRyLmxvY2FsTmFtZSB8fCBhdHRyTmFtZTtcblxuICAgICAgICAgICAgaWYgKCF0b05vZGUuaGFzQXR0cmlidXRlTlMoYXR0ck5hbWVzcGFjZVVSSSwgYXR0ck5hbWUpKSB7XG4gICAgICAgICAgICAgICAgZnJvbU5vZGUucmVtb3ZlQXR0cmlidXRlTlMoYXR0ck5hbWVzcGFjZVVSSSwgYXR0ck5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCF0b05vZGUuaGFzQXR0cmlidXRlKGF0dHJOYW1lKSkge1xuICAgICAgICAgICAgICAgIGZyb21Ob2RlLnJlbW92ZUF0dHJpYnV0ZShhdHRyTmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5cbnZhciByYW5nZTsgLy8gQ3JlYXRlIGEgcmFuZ2Ugb2JqZWN0IGZvciBlZmZpY2VudGx5IHJlbmRlcmluZyBzdHJpbmdzIHRvIGVsZW1lbnRzLlxudmFyIE5TX1hIVE1MID0gJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnO1xuXG52YXIgZG9jID0gdHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJyA/IHVuZGVmaW5lZCA6IGRvY3VtZW50O1xudmFyIEhBU19URU1QTEFURV9TVVBQT1JUID0gISFkb2MgJiYgJ2NvbnRlbnQnIGluIGRvYy5jcmVhdGVFbGVtZW50KCd0ZW1wbGF0ZScpO1xudmFyIEhBU19SQU5HRV9TVVBQT1JUID0gISFkb2MgJiYgZG9jLmNyZWF0ZVJhbmdlICYmICdjcmVhdGVDb250ZXh0dWFsRnJhZ21lbnQnIGluIGRvYy5jcmVhdGVSYW5nZSgpO1xuXG5mdW5jdGlvbiBjcmVhdGVGcmFnbWVudEZyb21UZW1wbGF0ZShzdHIpIHtcbiAgICB2YXIgdGVtcGxhdGUgPSBkb2MuY3JlYXRlRWxlbWVudCgndGVtcGxhdGUnKTtcbiAgICB0ZW1wbGF0ZS5pbm5lckhUTUwgPSBzdHI7XG4gICAgcmV0dXJuIHRlbXBsYXRlLmNvbnRlbnQuY2hpbGROb2Rlc1swXTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlRnJhZ21lbnRGcm9tUmFuZ2Uoc3RyKSB7XG4gICAgaWYgKCFyYW5nZSkge1xuICAgICAgICByYW5nZSA9IGRvYy5jcmVhdGVSYW5nZSgpO1xuICAgICAgICByYW5nZS5zZWxlY3ROb2RlKGRvYy5ib2R5KTtcbiAgICB9XG5cbiAgICB2YXIgZnJhZ21lbnQgPSByYW5nZS5jcmVhdGVDb250ZXh0dWFsRnJhZ21lbnQoc3RyKTtcbiAgICByZXR1cm4gZnJhZ21lbnQuY2hpbGROb2Rlc1swXTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlRnJhZ21lbnRGcm9tV3JhcChzdHIpIHtcbiAgICB2YXIgZnJhZ21lbnQgPSBkb2MuY3JlYXRlRWxlbWVudCgnYm9keScpO1xuICAgIGZyYWdtZW50LmlubmVySFRNTCA9IHN0cjtcbiAgICByZXR1cm4gZnJhZ21lbnQuY2hpbGROb2Rlc1swXTtcbn1cblxuLyoqXG4gKiBUaGlzIGlzIGFib3V0IHRoZSBzYW1lXG4gKiB2YXIgaHRtbCA9IG5ldyBET01QYXJzZXIoKS5wYXJzZUZyb21TdHJpbmcoc3RyLCAndGV4dC9odG1sJyk7XG4gKiByZXR1cm4gaHRtbC5ib2R5LmZpcnN0Q2hpbGQ7XG4gKlxuICogQG1ldGhvZCB0b0VsZW1lbnRcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJcbiAqL1xuZnVuY3Rpb24gdG9FbGVtZW50KHN0cikge1xuICAgIHN0ciA9IHN0ci50cmltKCk7XG4gICAgaWYgKEhBU19URU1QTEFURV9TVVBQT1JUKSB7XG4gICAgICAvLyBhdm9pZCByZXN0cmljdGlvbnMgb24gY29udGVudCBmb3IgdGhpbmdzIGxpa2UgYDx0cj48dGg+SGk8L3RoPjwvdHI+YCB3aGljaFxuICAgICAgLy8gY3JlYXRlQ29udGV4dHVhbEZyYWdtZW50IGRvZXNuJ3Qgc3VwcG9ydFxuICAgICAgLy8gPHRlbXBsYXRlPiBzdXBwb3J0IG5vdCBhdmFpbGFibGUgaW4gSUVcbiAgICAgIHJldHVybiBjcmVhdGVGcmFnbWVudEZyb21UZW1wbGF0ZShzdHIpO1xuICAgIH0gZWxzZSBpZiAoSEFTX1JBTkdFX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiBjcmVhdGVGcmFnbWVudEZyb21SYW5nZShzdHIpO1xuICAgIH1cblxuICAgIHJldHVybiBjcmVhdGVGcmFnbWVudEZyb21XcmFwKHN0cik7XG59XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHR3byBub2RlJ3MgbmFtZXMgYXJlIHRoZSBzYW1lLlxuICpcbiAqIE5PVEU6IFdlIGRvbid0IGJvdGhlciBjaGVja2luZyBgbmFtZXNwYWNlVVJJYCBiZWNhdXNlIHlvdSB3aWxsIG5ldmVyIGZpbmQgdHdvIEhUTUwgZWxlbWVudHMgd2l0aCB0aGUgc2FtZVxuICogICAgICAgbm9kZU5hbWUgYW5kIGRpZmZlcmVudCBuYW1lc3BhY2UgVVJJcy5cbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGFcbiAqIEBwYXJhbSB7RWxlbWVudH0gYiBUaGUgdGFyZ2V0IGVsZW1lbnRcbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGNvbXBhcmVOb2RlTmFtZXMoZnJvbUVsLCB0b0VsKSB7XG4gICAgdmFyIGZyb21Ob2RlTmFtZSA9IGZyb21FbC5ub2RlTmFtZTtcbiAgICB2YXIgdG9Ob2RlTmFtZSA9IHRvRWwubm9kZU5hbWU7XG4gICAgdmFyIGZyb21Db2RlU3RhcnQsIHRvQ29kZVN0YXJ0O1xuXG4gICAgaWYgKGZyb21Ob2RlTmFtZSA9PT0gdG9Ob2RlTmFtZSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBmcm9tQ29kZVN0YXJ0ID0gZnJvbU5vZGVOYW1lLmNoYXJDb2RlQXQoMCk7XG4gICAgdG9Db2RlU3RhcnQgPSB0b05vZGVOYW1lLmNoYXJDb2RlQXQoMCk7XG5cbiAgICAvLyBJZiB0aGUgdGFyZ2V0IGVsZW1lbnQgaXMgYSB2aXJ0dWFsIERPTSBub2RlIG9yIFNWRyBub2RlIHRoZW4gd2UgbWF5XG4gICAgLy8gbmVlZCB0byBub3JtYWxpemUgdGhlIHRhZyBuYW1lIGJlZm9yZSBjb21wYXJpbmcuIE5vcm1hbCBIVE1MIGVsZW1lbnRzIHRoYXQgYXJlXG4gICAgLy8gaW4gdGhlIFwiaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbFwiXG4gICAgLy8gYXJlIGNvbnZlcnRlZCB0byB1cHBlciBjYXNlXG4gICAgaWYgKGZyb21Db2RlU3RhcnQgPD0gOTAgJiYgdG9Db2RlU3RhcnQgPj0gOTcpIHsgLy8gZnJvbSBpcyB1cHBlciBhbmQgdG8gaXMgbG93ZXJcbiAgICAgICAgcmV0dXJuIGZyb21Ob2RlTmFtZSA9PT0gdG9Ob2RlTmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgIH0gZWxzZSBpZiAodG9Db2RlU3RhcnQgPD0gOTAgJiYgZnJvbUNvZGVTdGFydCA+PSA5NykgeyAvLyB0byBpcyB1cHBlciBhbmQgZnJvbSBpcyBsb3dlclxuICAgICAgICByZXR1cm4gdG9Ob2RlTmFtZSA9PT0gZnJvbU5vZGVOYW1lLnRvVXBwZXJDYXNlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDcmVhdGUgYW4gZWxlbWVudCwgb3B0aW9uYWxseSB3aXRoIGEga25vd24gbmFtZXNwYWNlIFVSSS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSB0aGUgZWxlbWVudCBuYW1lLCBlLmcuICdkaXYnIG9yICdzdmcnXG4gKiBAcGFyYW0ge3N0cmluZ30gW25hbWVzcGFjZVVSSV0gdGhlIGVsZW1lbnQncyBuYW1lc3BhY2UgVVJJLCBpLmUuIHRoZSB2YWx1ZSBvZlxuICogaXRzIGB4bWxuc2AgYXR0cmlidXRlIG9yIGl0cyBpbmZlcnJlZCBuYW1lc3BhY2UuXG4gKlxuICogQHJldHVybiB7RWxlbWVudH1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlRWxlbWVudE5TKG5hbWUsIG5hbWVzcGFjZVVSSSkge1xuICAgIHJldHVybiAhbmFtZXNwYWNlVVJJIHx8IG5hbWVzcGFjZVVSSSA9PT0gTlNfWEhUTUwgP1xuICAgICAgICBkb2MuY3JlYXRlRWxlbWVudChuYW1lKSA6XG4gICAgICAgIGRvYy5jcmVhdGVFbGVtZW50TlMobmFtZXNwYWNlVVJJLCBuYW1lKTtcbn1cblxuLyoqXG4gKiBDb3BpZXMgdGhlIGNoaWxkcmVuIG9mIG9uZSBET00gZWxlbWVudCB0byBhbm90aGVyIERPTSBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIG1vdmVDaGlsZHJlbihmcm9tRWwsIHRvRWwpIHtcbiAgICB2YXIgY3VyQ2hpbGQgPSBmcm9tRWwuZmlyc3RDaGlsZDtcbiAgICB3aGlsZSAoY3VyQ2hpbGQpIHtcbiAgICAgICAgdmFyIG5leHRDaGlsZCA9IGN1ckNoaWxkLm5leHRTaWJsaW5nO1xuICAgICAgICB0b0VsLmFwcGVuZENoaWxkKGN1ckNoaWxkKTtcbiAgICAgICAgY3VyQ2hpbGQgPSBuZXh0Q2hpbGQ7XG4gICAgfVxuICAgIHJldHVybiB0b0VsO1xufVxuXG5mdW5jdGlvbiBzeW5jQm9vbGVhbkF0dHJQcm9wKGZyb21FbCwgdG9FbCwgbmFtZSkge1xuICAgIGlmIChmcm9tRWxbbmFtZV0gIT09IHRvRWxbbmFtZV0pIHtcbiAgICAgICAgZnJvbUVsW25hbWVdID0gdG9FbFtuYW1lXTtcbiAgICAgICAgaWYgKGZyb21FbFtuYW1lXSkge1xuICAgICAgICAgICAgZnJvbUVsLnNldEF0dHJpYnV0ZShuYW1lLCAnJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmcm9tRWwucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG52YXIgc3BlY2lhbEVsSGFuZGxlcnMgPSB7XG4gICAgT1BUSU9OOiBmdW5jdGlvbihmcm9tRWwsIHRvRWwpIHtcbiAgICAgICAgdmFyIHBhcmVudE5vZGUgPSBmcm9tRWwucGFyZW50Tm9kZTtcbiAgICAgICAgaWYgKHBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgIHZhciBwYXJlbnROYW1lID0gcGFyZW50Tm9kZS5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgICAgICAgICAgaWYgKHBhcmVudE5hbWUgPT09ICdPUFRHUk9VUCcpIHtcbiAgICAgICAgICAgICAgICBwYXJlbnROb2RlID0gcGFyZW50Tm9kZS5wYXJlbnROb2RlO1xuICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnROb2RlICYmIHBhcmVudE5vZGUubm9kZU5hbWUudG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwYXJlbnROYW1lID09PSAnU0VMRUNUJyAmJiAhcGFyZW50Tm9kZS5oYXNBdHRyaWJ1dGUoJ211bHRpcGxlJykpIHtcbiAgICAgICAgICAgICAgICBpZiAoZnJvbUVsLmhhc0F0dHJpYnV0ZSgnc2VsZWN0ZWQnKSAmJiAhdG9FbC5zZWxlY3RlZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBXb3JrYXJvdW5kIGZvciBNUyBFZGdlIGJ1ZyB3aGVyZSB0aGUgJ3NlbGVjdGVkJyBhdHRyaWJ1dGUgY2FuIG9ubHkgYmVcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlZCBpZiBzZXQgdG8gYSBub24tZW1wdHkgdmFsdWU6XG4gICAgICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1pY3Jvc29mdC5jb20vZW4tdXMvbWljcm9zb2Z0LWVkZ2UvcGxhdGZvcm0vaXNzdWVzLzEyMDg3Njc5L1xuICAgICAgICAgICAgICAgICAgICBmcm9tRWwuc2V0QXR0cmlidXRlKCdzZWxlY3RlZCcsICdzZWxlY3RlZCcpO1xuICAgICAgICAgICAgICAgICAgICBmcm9tRWwucmVtb3ZlQXR0cmlidXRlKCdzZWxlY3RlZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBXZSBoYXZlIHRvIHJlc2V0IHNlbGVjdCBlbGVtZW50J3Mgc2VsZWN0ZWRJbmRleCB0byAtMSwgb3RoZXJ3aXNlIHNldHRpbmdcbiAgICAgICAgICAgICAgICAvLyBmcm9tRWwuc2VsZWN0ZWQgdXNpbmcgdGhlIHN5bmNCb29sZWFuQXR0clByb3AgYmVsb3cgaGFzIG5vIGVmZmVjdC5cbiAgICAgICAgICAgICAgICAvLyBUaGUgY29ycmVjdCBzZWxlY3RlZEluZGV4IHdpbGwgYmUgc2V0IGluIHRoZSBTRUxFQ1Qgc3BlY2lhbCBoYW5kbGVyIGJlbG93LlxuICAgICAgICAgICAgICAgIHBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCA9IC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHN5bmNCb29sZWFuQXR0clByb3AoZnJvbUVsLCB0b0VsLCAnc2VsZWN0ZWQnKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFRoZSBcInZhbHVlXCIgYXR0cmlidXRlIGlzIHNwZWNpYWwgZm9yIHRoZSA8aW5wdXQ+IGVsZW1lbnQgc2luY2UgaXQgc2V0c1xuICAgICAqIHRoZSBpbml0aWFsIHZhbHVlLiBDaGFuZ2luZyB0aGUgXCJ2YWx1ZVwiIGF0dHJpYnV0ZSB3aXRob3V0IGNoYW5naW5nIHRoZVxuICAgICAqIFwidmFsdWVcIiBwcm9wZXJ0eSB3aWxsIGhhdmUgbm8gZWZmZWN0IHNpbmNlIGl0IGlzIG9ubHkgdXNlZCB0byB0aGUgc2V0IHRoZVxuICAgICAqIGluaXRpYWwgdmFsdWUuICBTaW1pbGFyIGZvciB0aGUgXCJjaGVja2VkXCIgYXR0cmlidXRlLCBhbmQgXCJkaXNhYmxlZFwiLlxuICAgICAqL1xuICAgIElOUFVUOiBmdW5jdGlvbihmcm9tRWwsIHRvRWwpIHtcbiAgICAgICAgc3luY0Jvb2xlYW5BdHRyUHJvcChmcm9tRWwsIHRvRWwsICdjaGVja2VkJyk7XG4gICAgICAgIHN5bmNCb29sZWFuQXR0clByb3AoZnJvbUVsLCB0b0VsLCAnZGlzYWJsZWQnKTtcblxuICAgICAgICBpZiAoZnJvbUVsLnZhbHVlICE9PSB0b0VsLnZhbHVlKSB7XG4gICAgICAgICAgICBmcm9tRWwudmFsdWUgPSB0b0VsLnZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0b0VsLmhhc0F0dHJpYnV0ZSgndmFsdWUnKSkge1xuICAgICAgICAgICAgZnJvbUVsLnJlbW92ZUF0dHJpYnV0ZSgndmFsdWUnKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBURVhUQVJFQTogZnVuY3Rpb24oZnJvbUVsLCB0b0VsKSB7XG4gICAgICAgIHZhciBuZXdWYWx1ZSA9IHRvRWwudmFsdWU7XG4gICAgICAgIGlmIChmcm9tRWwudmFsdWUgIT09IG5ld1ZhbHVlKSB7XG4gICAgICAgICAgICBmcm9tRWwudmFsdWUgPSBuZXdWYWx1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBmaXJzdENoaWxkID0gZnJvbUVsLmZpcnN0Q2hpbGQ7XG4gICAgICAgIGlmIChmaXJzdENoaWxkKSB7XG4gICAgICAgICAgICAvLyBOZWVkZWQgZm9yIElFLiBBcHBhcmVudGx5IElFIHNldHMgdGhlIHBsYWNlaG9sZGVyIGFzIHRoZVxuICAgICAgICAgICAgLy8gbm9kZSB2YWx1ZSBhbmQgdmlzZSB2ZXJzYS4gVGhpcyBpZ25vcmVzIGFuIGVtcHR5IHVwZGF0ZS5cbiAgICAgICAgICAgIHZhciBvbGRWYWx1ZSA9IGZpcnN0Q2hpbGQubm9kZVZhbHVlO1xuXG4gICAgICAgICAgICBpZiAob2xkVmFsdWUgPT0gbmV3VmFsdWUgfHwgKCFuZXdWYWx1ZSAmJiBvbGRWYWx1ZSA9PSBmcm9tRWwucGxhY2Vob2xkZXIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmaXJzdENoaWxkLm5vZGVWYWx1ZSA9IG5ld1ZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBTRUxFQ1Q6IGZ1bmN0aW9uKGZyb21FbCwgdG9FbCkge1xuICAgICAgICBpZiAoIXRvRWwuaGFzQXR0cmlidXRlKCdtdWx0aXBsZScpKSB7XG4gICAgICAgICAgICB2YXIgc2VsZWN0ZWRJbmRleCA9IC0xO1xuICAgICAgICAgICAgdmFyIGkgPSAwO1xuICAgICAgICAgICAgLy8gV2UgaGF2ZSB0byBsb29wIHRocm91Z2ggY2hpbGRyZW4gb2YgZnJvbUVsLCBub3QgdG9FbCBzaW5jZSBub2RlcyBjYW4gYmUgbW92ZWRcbiAgICAgICAgICAgIC8vIGZyb20gdG9FbCB0byBmcm9tRWwgZGlyZWN0bHkgd2hlbiBtb3JwaGluZy5cbiAgICAgICAgICAgIC8vIEF0IHRoZSB0aW1lIHRoaXMgc3BlY2lhbCBoYW5kbGVyIGlzIGludm9rZWQsIGFsbCBjaGlsZHJlbiBoYXZlIGFscmVhZHkgYmVlbiBtb3JwaGVkXG4gICAgICAgICAgICAvLyBhbmQgYXBwZW5kZWQgdG8gLyByZW1vdmVkIGZyb20gZnJvbUVsLCBzbyB1c2luZyBmcm9tRWwgaGVyZSBpcyBzYWZlIGFuZCBjb3JyZWN0LlxuICAgICAgICAgICAgdmFyIGN1ckNoaWxkID0gZnJvbUVsLmZpcnN0Q2hpbGQ7XG4gICAgICAgICAgICB2YXIgb3B0Z3JvdXA7XG4gICAgICAgICAgICB2YXIgbm9kZU5hbWU7XG4gICAgICAgICAgICB3aGlsZShjdXJDaGlsZCkge1xuICAgICAgICAgICAgICAgIG5vZGVOYW1lID0gY3VyQ2hpbGQubm9kZU5hbWUgJiYgY3VyQ2hpbGQubm9kZU5hbWUudG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgICAgICBpZiAobm9kZU5hbWUgPT09ICdPUFRHUk9VUCcpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0Z3JvdXAgPSBjdXJDaGlsZDtcbiAgICAgICAgICAgICAgICAgICAgY3VyQ2hpbGQgPSBvcHRncm91cC5maXJzdENoaWxkO1xuICAgICAgICAgICAgICAgICAgICAvLyBoYW5kbGUgZW1wdHkgb3B0Z3JvdXBzXG4gICAgICAgICAgICAgICAgICAgIGlmICghY3VyQ2hpbGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1ckNoaWxkID0gb3B0Z3JvdXAubmV4dFNpYmxpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAobm9kZU5hbWUgPT09ICdPUFRJT04nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VyQ2hpbGQuaGFzQXR0cmlidXRlKCdzZWxlY3RlZCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRJbmRleCA9IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpKys7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY3VyQ2hpbGQgPSBjdXJDaGlsZC5uZXh0U2libGluZztcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFjdXJDaGlsZCAmJiBvcHRncm91cCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY3VyQ2hpbGQgPSBvcHRncm91cC5uZXh0U2libGluZztcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZnJvbUVsLnNlbGVjdGVkSW5kZXggPSBzZWxlY3RlZEluZGV4O1xuICAgICAgICB9XG4gICAgfVxufTtcblxudmFyIEVMRU1FTlRfTk9ERSA9IDE7XG52YXIgRE9DVU1FTlRfRlJBR01FTlRfTk9ERSQxID0gMTE7XG52YXIgVEVYVF9OT0RFID0gMztcbnZhciBDT01NRU5UX05PREUgPSA4O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxuZnVuY3Rpb24gZGVmYXVsdEdldE5vZGVLZXkobm9kZSkge1xuICBpZiAobm9kZSkge1xuICAgIHJldHVybiAobm9kZS5nZXRBdHRyaWJ1dGUgJiYgbm9kZS5nZXRBdHRyaWJ1dGUoJ2lkJykpIHx8IG5vZGUuaWQ7XG4gIH1cbn1cblxuZnVuY3Rpb24gbW9ycGhkb21GYWN0b3J5KG1vcnBoQXR0cnMpIHtcblxuICByZXR1cm4gZnVuY3Rpb24gbW9ycGhkb20oZnJvbU5vZGUsIHRvTm9kZSwgb3B0aW9ucykge1xuICAgIGlmICghb3B0aW9ucykge1xuICAgICAgb3B0aW9ucyA9IHt9O1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdG9Ob2RlID09PSAnc3RyaW5nJykge1xuICAgICAgaWYgKGZyb21Ob2RlLm5vZGVOYW1lID09PSAnI2RvY3VtZW50JyB8fCBmcm9tTm9kZS5ub2RlTmFtZSA9PT0gJ0hUTUwnIHx8IGZyb21Ob2RlLm5vZGVOYW1lID09PSAnQk9EWScpIHtcbiAgICAgICAgdmFyIHRvTm9kZUh0bWwgPSB0b05vZGU7XG4gICAgICAgIHRvTm9kZSA9IGRvYy5jcmVhdGVFbGVtZW50KCdodG1sJyk7XG4gICAgICAgIHRvTm9kZS5pbm5lckhUTUwgPSB0b05vZGVIdG1sO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdG9Ob2RlID0gdG9FbGVtZW50KHRvTm9kZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0b05vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUkMSkge1xuICAgICAgdG9Ob2RlID0gdG9Ob2RlLmZpcnN0RWxlbWVudENoaWxkO1xuICAgIH1cblxuICAgIHZhciBnZXROb2RlS2V5ID0gb3B0aW9ucy5nZXROb2RlS2V5IHx8IGRlZmF1bHRHZXROb2RlS2V5O1xuICAgIHZhciBvbkJlZm9yZU5vZGVBZGRlZCA9IG9wdGlvbnMub25CZWZvcmVOb2RlQWRkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25Ob2RlQWRkZWQgPSBvcHRpb25zLm9uTm9kZUFkZGVkIHx8IG5vb3A7XG4gICAgdmFyIG9uQmVmb3JlRWxVcGRhdGVkID0gb3B0aW9ucy5vbkJlZm9yZUVsVXBkYXRlZCB8fCBub29wO1xuICAgIHZhciBvbkVsVXBkYXRlZCA9IG9wdGlvbnMub25FbFVwZGF0ZWQgfHwgbm9vcDtcbiAgICB2YXIgb25CZWZvcmVOb2RlRGlzY2FyZGVkID0gb3B0aW9ucy5vbkJlZm9yZU5vZGVEaXNjYXJkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25Ob2RlRGlzY2FyZGVkID0gb3B0aW9ucy5vbk5vZGVEaXNjYXJkZWQgfHwgbm9vcDtcbiAgICB2YXIgb25CZWZvcmVFbENoaWxkcmVuVXBkYXRlZCA9IG9wdGlvbnMub25CZWZvcmVFbENoaWxkcmVuVXBkYXRlZCB8fCBub29wO1xuICAgIHZhciBza2lwRnJvbUNoaWxkcmVuID0gb3B0aW9ucy5za2lwRnJvbUNoaWxkcmVuIHx8IG5vb3A7XG4gICAgdmFyIGFkZENoaWxkID0gb3B0aW9ucy5hZGRDaGlsZCB8fCBmdW5jdGlvbihwYXJlbnQsIGNoaWxkKXsgcmV0dXJuIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7IH07XG4gICAgdmFyIGNoaWxkcmVuT25seSA9IG9wdGlvbnMuY2hpbGRyZW5Pbmx5ID09PSB0cnVlO1xuXG4gICAgLy8gVGhpcyBvYmplY3QgaXMgdXNlZCBhcyBhIGxvb2t1cCB0byBxdWlja2x5IGZpbmQgYWxsIGtleWVkIGVsZW1lbnRzIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZS5cbiAgICB2YXIgZnJvbU5vZGVzTG9va3VwID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB2YXIga2V5ZWRSZW1vdmFsTGlzdCA9IFtdO1xuXG4gICAgZnVuY3Rpb24gYWRkS2V5ZWRSZW1vdmFsKGtleSkge1xuICAgICAga2V5ZWRSZW1vdmFsTGlzdC5wdXNoKGtleSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMobm9kZSwgc2tpcEtleWVkTm9kZXMpIHtcbiAgICAgIGlmIChub2RlLm5vZGVUeXBlID09PSBFTEVNRU5UX05PREUpIHtcbiAgICAgICAgdmFyIGN1ckNoaWxkID0gbm9kZS5maXJzdENoaWxkO1xuICAgICAgICB3aGlsZSAoY3VyQ2hpbGQpIHtcblxuICAgICAgICAgIHZhciBrZXkgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBpZiAoc2tpcEtleWVkTm9kZXMgJiYgKGtleSA9IGdldE5vZGVLZXkoY3VyQ2hpbGQpKSkge1xuICAgICAgICAgICAgLy8gSWYgd2UgYXJlIHNraXBwaW5nIGtleWVkIG5vZGVzIHRoZW4gd2UgYWRkIHRoZSBrZXlcbiAgICAgICAgICAgIC8vIHRvIGEgbGlzdCBzbyB0aGF0IGl0IGNhbiBiZSBoYW5kbGVkIGF0IHRoZSB2ZXJ5IGVuZC5cbiAgICAgICAgICAgIGFkZEtleWVkUmVtb3ZhbChrZXkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBPbmx5IHJlcG9ydCB0aGUgbm9kZSBhcyBkaXNjYXJkZWQgaWYgaXQgaXMgbm90IGtleWVkLiBXZSBkbyB0aGlzIGJlY2F1c2VcbiAgICAgICAgICAgIC8vIGF0IHRoZSBlbmQgd2UgbG9vcCB0aHJvdWdoIGFsbCBrZXllZCBlbGVtZW50cyB0aGF0IHdlcmUgdW5tYXRjaGVkXG4gICAgICAgICAgICAvLyBhbmQgdGhlbiBkaXNjYXJkIHRoZW0gaW4gb25lIGZpbmFsIHBhc3MuXG4gICAgICAgICAgICBvbk5vZGVEaXNjYXJkZWQoY3VyQ2hpbGQpO1xuICAgICAgICAgICAgaWYgKGN1ckNoaWxkLmZpcnN0Q2hpbGQpIHtcbiAgICAgICAgICAgICAgd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMoY3VyQ2hpbGQsIHNraXBLZXllZE5vZGVzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJDaGlsZCA9IGN1ckNoaWxkLm5leHRTaWJsaW5nO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgKiBSZW1vdmVzIGEgRE9NIG5vZGUgb3V0IG9mIHRoZSBvcmlnaW5hbCBET01cbiAgICAqXG4gICAgKiBAcGFyYW0gIHtOb2RlfSBub2RlIFRoZSBub2RlIHRvIHJlbW92ZVxuICAgICogQHBhcmFtICB7Tm9kZX0gcGFyZW50Tm9kZSBUaGUgbm9kZXMgcGFyZW50XG4gICAgKiBAcGFyYW0gIHtCb29sZWFufSBza2lwS2V5ZWROb2RlcyBJZiB0cnVlIHRoZW4gZWxlbWVudHMgd2l0aCBrZXlzIHdpbGwgYmUgc2tpcHBlZCBhbmQgbm90IGRpc2NhcmRlZC5cbiAgICAqIEByZXR1cm4ge3VuZGVmaW5lZH1cbiAgICAqL1xuICAgIGZ1bmN0aW9uIHJlbW92ZU5vZGUobm9kZSwgcGFyZW50Tm9kZSwgc2tpcEtleWVkTm9kZXMpIHtcbiAgICAgIGlmIChvbkJlZm9yZU5vZGVEaXNjYXJkZWQobm9kZSkgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHBhcmVudE5vZGUpIHtcbiAgICAgICAgcGFyZW50Tm9kZS5yZW1vdmVDaGlsZChub2RlKTtcbiAgICAgIH1cblxuICAgICAgb25Ob2RlRGlzY2FyZGVkKG5vZGUpO1xuICAgICAgd2Fsa0Rpc2NhcmRlZENoaWxkTm9kZXMobm9kZSwgc2tpcEtleWVkTm9kZXMpO1xuICAgIH1cblxuICAgIC8vIC8vIFRyZWVXYWxrZXIgaW1wbGVtZW50YXRpb24gaXMgbm8gZmFzdGVyLCBidXQga2VlcGluZyB0aGlzIGFyb3VuZCBpbiBjYXNlIHRoaXMgY2hhbmdlcyBpbiB0aGUgZnV0dXJlXG4gICAgLy8gZnVuY3Rpb24gaW5kZXhUcmVlKHJvb3QpIHtcbiAgICAvLyAgICAgdmFyIHRyZWVXYWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKFxuICAgIC8vICAgICAgICAgcm9vdCxcbiAgICAvLyAgICAgICAgIE5vZGVGaWx0ZXIuU0hPV19FTEVNRU5UKTtcbiAgICAvL1xuICAgIC8vICAgICB2YXIgZWw7XG4gICAgLy8gICAgIHdoaWxlKChlbCA9IHRyZWVXYWxrZXIubmV4dE5vZGUoKSkpIHtcbiAgICAvLyAgICAgICAgIHZhciBrZXkgPSBnZXROb2RlS2V5KGVsKTtcbiAgICAvLyAgICAgICAgIGlmIChrZXkpIHtcbiAgICAvLyAgICAgICAgICAgICBmcm9tTm9kZXNMb29rdXBba2V5XSA9IGVsO1xuICAgIC8vICAgICAgICAgfVxuICAgIC8vICAgICB9XG4gICAgLy8gfVxuXG4gICAgLy8gLy8gTm9kZUl0ZXJhdG9yIGltcGxlbWVudGF0aW9uIGlzIG5vIGZhc3RlciwgYnV0IGtlZXBpbmcgdGhpcyBhcm91bmQgaW4gY2FzZSB0aGlzIGNoYW5nZXMgaW4gdGhlIGZ1dHVyZVxuICAgIC8vXG4gICAgLy8gZnVuY3Rpb24gaW5kZXhUcmVlKG5vZGUpIHtcbiAgICAvLyAgICAgdmFyIG5vZGVJdGVyYXRvciA9IGRvY3VtZW50LmNyZWF0ZU5vZGVJdGVyYXRvcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCk7XG4gICAgLy8gICAgIHZhciBlbDtcbiAgICAvLyAgICAgd2hpbGUoKGVsID0gbm9kZUl0ZXJhdG9yLm5leHROb2RlKCkpKSB7XG4gICAgLy8gICAgICAgICB2YXIga2V5ID0gZ2V0Tm9kZUtleShlbCk7XG4gICAgLy8gICAgICAgICBpZiAoa2V5KSB7XG4gICAgLy8gICAgICAgICAgICAgZnJvbU5vZGVzTG9va3VwW2tleV0gPSBlbDtcbiAgICAvLyAgICAgICAgIH1cbiAgICAvLyAgICAgfVxuICAgIC8vIH1cblxuICAgIGZ1bmN0aW9uIGluZGV4VHJlZShub2RlKSB7XG4gICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFIHx8IG5vZGUubm9kZVR5cGUgPT09IERPQ1VNRU5UX0ZSQUdNRU5UX05PREUkMSkge1xuICAgICAgICB2YXIgY3VyQ2hpbGQgPSBub2RlLmZpcnN0Q2hpbGQ7XG4gICAgICAgIHdoaWxlIChjdXJDaGlsZCkge1xuICAgICAgICAgIHZhciBrZXkgPSBnZXROb2RlS2V5KGN1ckNoaWxkKTtcbiAgICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICBmcm9tTm9kZXNMb29rdXBba2V5XSA9IGN1ckNoaWxkO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFdhbGsgcmVjdXJzaXZlbHlcbiAgICAgICAgICBpbmRleFRyZWUoY3VyQ2hpbGQpO1xuXG4gICAgICAgICAgY3VyQ2hpbGQgPSBjdXJDaGlsZC5uZXh0U2libGluZztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGluZGV4VHJlZShmcm9tTm9kZSk7XG5cbiAgICBmdW5jdGlvbiBoYW5kbGVOb2RlQWRkZWQoZWwpIHtcbiAgICAgIG9uTm9kZUFkZGVkKGVsKTtcblxuICAgICAgdmFyIGN1ckNoaWxkID0gZWwuZmlyc3RDaGlsZDtcbiAgICAgIHdoaWxlIChjdXJDaGlsZCkge1xuICAgICAgICB2YXIgbmV4dFNpYmxpbmcgPSBjdXJDaGlsZC5uZXh0U2libGluZztcblxuICAgICAgICB2YXIga2V5ID0gZ2V0Tm9kZUtleShjdXJDaGlsZCk7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICB2YXIgdW5tYXRjaGVkRnJvbUVsID0gZnJvbU5vZGVzTG9va3VwW2tleV07XG4gICAgICAgICAgLy8gaWYgd2UgZmluZCBhIGR1cGxpY2F0ZSAjaWQgbm9kZSBpbiBjYWNoZSwgcmVwbGFjZSBgZWxgIHdpdGggY2FjaGUgdmFsdWVcbiAgICAgICAgICAvLyBhbmQgbW9ycGggaXQgdG8gdGhlIGNoaWxkIG5vZGUuXG4gICAgICAgICAgaWYgKHVubWF0Y2hlZEZyb21FbCAmJiBjb21wYXJlTm9kZU5hbWVzKGN1ckNoaWxkLCB1bm1hdGNoZWRGcm9tRWwpKSB7XG4gICAgICAgICAgICBjdXJDaGlsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZCh1bm1hdGNoZWRGcm9tRWwsIGN1ckNoaWxkKTtcbiAgICAgICAgICAgIG1vcnBoRWwodW5tYXRjaGVkRnJvbUVsLCBjdXJDaGlsZCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJDaGlsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIHJlY3Vyc2l2ZWx5IGNhbGwgZm9yIGN1ckNoaWxkIGFuZCBpdCdzIGNoaWxkcmVuIHRvIHNlZSBpZiB3ZSBmaW5kIHNvbWV0aGluZyBpblxuICAgICAgICAgIC8vIGZyb21Ob2Rlc0xvb2t1cFxuICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJDaGlsZCk7XG4gICAgICAgIH1cblxuICAgICAgICBjdXJDaGlsZCA9IG5leHRTaWJsaW5nO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNsZWFudXBGcm9tRWwoZnJvbUVsLCBjdXJGcm9tTm9kZUNoaWxkLCBjdXJGcm9tTm9kZUtleSkge1xuICAgICAgLy8gV2UgaGF2ZSBwcm9jZXNzZWQgYWxsIG9mIHRoZSBcInRvIG5vZGVzXCIuIElmIGN1ckZyb21Ob2RlQ2hpbGQgaXNcbiAgICAgIC8vIG5vbi1udWxsIHRoZW4gd2Ugc3RpbGwgaGF2ZSBzb21lIGZyb20gbm9kZXMgbGVmdCBvdmVyIHRoYXQgbmVlZFxuICAgICAgLy8gdG8gYmUgcmVtb3ZlZFxuICAgICAgd2hpbGUgKGN1ckZyb21Ob2RlQ2hpbGQpIHtcbiAgICAgICAgdmFyIGZyb21OZXh0U2libGluZyA9IGN1ckZyb21Ob2RlQ2hpbGQubmV4dFNpYmxpbmc7XG4gICAgICAgIGlmICgoY3VyRnJvbU5vZGVLZXkgPSBnZXROb2RlS2V5KGN1ckZyb21Ob2RlQ2hpbGQpKSkge1xuICAgICAgICAgIC8vIFNpbmNlIHRoZSBub2RlIGlzIGtleWVkIGl0IG1pZ2h0IGJlIG1hdGNoZWQgdXAgbGF0ZXIgc28gd2UgZGVmZXJcbiAgICAgICAgICAvLyB0aGUgYWN0dWFsIHJlbW92YWwgdG8gbGF0ZXJcbiAgICAgICAgICBhZGRLZXllZFJlbW92YWwoY3VyRnJvbU5vZGVLZXkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5PVEU6IHdlIHNraXAgbmVzdGVkIGtleWVkIG5vZGVzIGZyb20gYmVpbmcgcmVtb3ZlZCBzaW5jZSB0aGVyZSBpc1xuICAgICAgICAgIC8vICAgICAgIHN0aWxsIGEgY2hhbmNlIHRoZXkgd2lsbCBiZSBtYXRjaGVkIHVwIGxhdGVyXG4gICAgICAgICAgcmVtb3ZlTm9kZShjdXJGcm9tTm9kZUNoaWxkLCBmcm9tRWwsIHRydWUgLyogc2tpcCBrZXllZCBub2RlcyAqLyk7XG4gICAgICAgIH1cbiAgICAgICAgY3VyRnJvbU5vZGVDaGlsZCA9IGZyb21OZXh0U2libGluZztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtb3JwaEVsKGZyb21FbCwgdG9FbCwgY2hpbGRyZW5Pbmx5KSB7XG4gICAgICB2YXIgdG9FbEtleSA9IGdldE5vZGVLZXkodG9FbCk7XG5cbiAgICAgIGlmICh0b0VsS2V5KSB7XG4gICAgICAgIC8vIElmIGFuIGVsZW1lbnQgd2l0aCBhbiBJRCBpcyBiZWluZyBtb3JwaGVkIHRoZW4gaXQgd2lsbCBiZSBpbiB0aGUgZmluYWxcbiAgICAgICAgLy8gRE9NIHNvIGNsZWFyIGl0IG91dCBvZiB0aGUgc2F2ZWQgZWxlbWVudHMgY29sbGVjdGlvblxuICAgICAgICBkZWxldGUgZnJvbU5vZGVzTG9va3VwW3RvRWxLZXldO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWNoaWxkcmVuT25seSkge1xuICAgICAgICAvLyBvcHRpb25hbFxuICAgICAgICB2YXIgYmVmb3JlVXBkYXRlUmVzdWx0ID0gb25CZWZvcmVFbFVwZGF0ZWQoZnJvbUVsLCB0b0VsKTtcbiAgICAgICAgaWYgKGJlZm9yZVVwZGF0ZVJlc3VsdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAoYmVmb3JlVXBkYXRlUmVzdWx0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgICBmcm9tRWwgPSBiZWZvcmVVcGRhdGVSZXN1bHQ7XG4gICAgICAgICAgLy8gcmVpbmRleCB0aGUgbmV3IGZyb21FbCBpbiBjYXNlIGl0J3Mgbm90IGluIHRoZSBzYW1lXG4gICAgICAgICAgLy8gdHJlZSBhcyB0aGUgb3JpZ2luYWwgZnJvbUVsXG4gICAgICAgICAgLy8gKFBob2VuaXggTGl2ZVZpZXcgc29tZXRpbWVzIHJldHVybnMgYSBjbG9uZWQgdHJlZSxcbiAgICAgICAgICAvLyAgYnV0IGtleWVkIGxvb2t1cHMgd291bGQgc3RpbGwgcG9pbnQgdG8gdGhlIG9yaWdpbmFsIHRyZWUpXG4gICAgICAgICAgaW5kZXhUcmVlKGZyb21FbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB1cGRhdGUgYXR0cmlidXRlcyBvbiBvcmlnaW5hbCBET00gZWxlbWVudCBmaXJzdFxuICAgICAgICBtb3JwaEF0dHJzKGZyb21FbCwgdG9FbCk7XG4gICAgICAgIC8vIG9wdGlvbmFsXG4gICAgICAgIG9uRWxVcGRhdGVkKGZyb21FbCk7XG5cbiAgICAgICAgaWYgKG9uQmVmb3JlRWxDaGlsZHJlblVwZGF0ZWQoZnJvbUVsLCB0b0VsKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGZyb21FbC5ub2RlTmFtZSAhPT0gJ1RFWFRBUkVBJykge1xuICAgICAgICBtb3JwaENoaWxkcmVuKGZyb21FbCwgdG9FbCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzcGVjaWFsRWxIYW5kbGVycy5URVhUQVJFQShmcm9tRWwsIHRvRWwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1vcnBoQ2hpbGRyZW4oZnJvbUVsLCB0b0VsKSB7XG4gICAgICB2YXIgc2tpcEZyb20gPSBza2lwRnJvbUNoaWxkcmVuKGZyb21FbCwgdG9FbCk7XG4gICAgICB2YXIgY3VyVG9Ob2RlQ2hpbGQgPSB0b0VsLmZpcnN0Q2hpbGQ7XG4gICAgICB2YXIgY3VyRnJvbU5vZGVDaGlsZCA9IGZyb21FbC5maXJzdENoaWxkO1xuICAgICAgdmFyIGN1clRvTm9kZUtleTtcbiAgICAgIHZhciBjdXJGcm9tTm9kZUtleTtcblxuICAgICAgdmFyIGZyb21OZXh0U2libGluZztcbiAgICAgIHZhciB0b05leHRTaWJsaW5nO1xuICAgICAgdmFyIG1hdGNoaW5nRnJvbUVsO1xuXG4gICAgICAvLyB3YWxrIHRoZSBjaGlsZHJlblxuICAgICAgb3V0ZXI6IHdoaWxlIChjdXJUb05vZGVDaGlsZCkge1xuICAgICAgICB0b05leHRTaWJsaW5nID0gY3VyVG9Ob2RlQ2hpbGQubmV4dFNpYmxpbmc7XG4gICAgICAgIGN1clRvTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyVG9Ob2RlQ2hpbGQpO1xuXG4gICAgICAgIC8vIHdhbGsgdGhlIGZyb21Ob2RlIGNoaWxkcmVuIGFsbCB0aGUgd2F5IHRocm91Z2hcbiAgICAgICAgd2hpbGUgKCFza2lwRnJvbSAmJiBjdXJGcm9tTm9kZUNoaWxkKSB7XG4gICAgICAgICAgZnJvbU5leHRTaWJsaW5nID0gY3VyRnJvbU5vZGVDaGlsZC5uZXh0U2libGluZztcblxuICAgICAgICAgIGlmIChjdXJUb05vZGVDaGlsZC5pc1NhbWVOb2RlICYmIGN1clRvTm9kZUNoaWxkLmlzU2FtZU5vZGUoY3VyRnJvbU5vZGVDaGlsZCkpIHtcbiAgICAgICAgICAgIGN1clRvTm9kZUNoaWxkID0gdG9OZXh0U2libGluZztcbiAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQgPSBmcm9tTmV4dFNpYmxpbmc7XG4gICAgICAgICAgICBjb250aW51ZSBvdXRlcjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJGcm9tTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyRnJvbU5vZGVDaGlsZCk7XG5cbiAgICAgICAgICB2YXIgY3VyRnJvbU5vZGVUeXBlID0gY3VyRnJvbU5vZGVDaGlsZC5ub2RlVHlwZTtcblxuICAgICAgICAgIC8vIHRoaXMgbWVhbnMgaWYgdGhlIGN1ckZyb21Ob2RlQ2hpbGQgZG9lc250IGhhdmUgYSBtYXRjaCB3aXRoIHRoZSBjdXJUb05vZGVDaGlsZFxuICAgICAgICAgIHZhciBpc0NvbXBhdGlibGUgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICBpZiAoY3VyRnJvbU5vZGVUeXBlID09PSBjdXJUb05vZGVDaGlsZC5ub2RlVHlwZSkge1xuICAgICAgICAgICAgaWYgKGN1ckZyb21Ob2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgICAgICAgIC8vIEJvdGggbm9kZXMgYmVpbmcgY29tcGFyZWQgYXJlIEVsZW1lbnQgbm9kZXNcblxuICAgICAgICAgICAgICBpZiAoY3VyVG9Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIHRhcmdldCBub2RlIGhhcyBhIGtleSBzbyB3ZSB3YW50IHRvIG1hdGNoIGl0IHVwIHdpdGggdGhlIGNvcnJlY3QgZWxlbWVudFxuICAgICAgICAgICAgICAgIC8vIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZVxuICAgICAgICAgICAgICAgIGlmIChjdXJUb05vZGVLZXkgIT09IGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgICAvLyBUaGUgY3VycmVudCBlbGVtZW50IGluIHRoZSBvcmlnaW5hbCBET00gdHJlZSBkb2VzIG5vdCBoYXZlIGEgbWF0Y2hpbmcga2V5IHNvXG4gICAgICAgICAgICAgICAgICAvLyBsZXQncyBjaGVjayBvdXIgbG9va3VwIHRvIHNlZSBpZiB0aGVyZSBpcyBhIG1hdGNoaW5nIGVsZW1lbnQgaW4gdGhlIG9yaWdpbmFsXG4gICAgICAgICAgICAgICAgICAvLyBET00gdHJlZVxuICAgICAgICAgICAgICAgICAgaWYgKChtYXRjaGluZ0Zyb21FbCA9IGZyb21Ob2Rlc0xvb2t1cFtjdXJUb05vZGVLZXldKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZnJvbU5leHRTaWJsaW5nID09PSBtYXRjaGluZ0Zyb21FbCkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIFNwZWNpYWwgY2FzZSBmb3Igc2luZ2xlIGVsZW1lbnQgcmVtb3ZhbHMuIFRvIGF2b2lkIHJlbW92aW5nIHRoZSBvcmlnaW5hbFxuICAgICAgICAgICAgICAgICAgICAgIC8vIERPTSBub2RlIG91dCBvZiB0aGUgdHJlZSAoc2luY2UgdGhhdCBjYW4gYnJlYWsgQ1NTIHRyYW5zaXRpb25zLCBldGMuKSxcbiAgICAgICAgICAgICAgICAgICAgICAvLyB3ZSB3aWxsIGluc3RlYWQgZGlzY2FyZCB0aGUgY3VycmVudCBub2RlIGFuZCB3YWl0IHVudGlsIHRoZSBuZXh0XG4gICAgICAgICAgICAgICAgICAgICAgLy8gaXRlcmF0aW9uIHRvIHByb3Blcmx5IG1hdGNoIHVwIHRoZSBrZXllZCB0YXJnZXQgZWxlbWVudCB3aXRoIGl0cyBtYXRjaGluZ1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGVsZW1lbnQgaW4gdGhlIG9yaWdpbmFsIHRyZWVcbiAgICAgICAgICAgICAgICAgICAgICBpc0NvbXBhdGlibGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBXZSBmb3VuZCBhIG1hdGNoaW5nIGtleWVkIGVsZW1lbnQgc29tZXdoZXJlIGluIHRoZSBvcmlnaW5hbCBET00gdHJlZS5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBMZXQncyBtb3ZlIHRoZSBvcmlnaW5hbCBET00gbm9kZSBpbnRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIGFuZCBtb3JwaFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGl0LlxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gTk9URTogV2UgdXNlIGluc2VydEJlZm9yZSBpbnN0ZWFkIG9mIHJlcGxhY2VDaGlsZCBiZWNhdXNlIHdlIHdhbnQgdG8gZ28gdGhyb3VnaFxuICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBgcmVtb3ZlTm9kZSgpYCBmdW5jdGlvbiBmb3IgdGhlIG5vZGUgdGhhdCBpcyBiZWluZyBkaXNjYXJkZWQgc28gdGhhdFxuICAgICAgICAgICAgICAgICAgICAgIC8vIGFsbCBsaWZlY3ljbGUgaG9va3MgYXJlIGNvcnJlY3RseSBpbnZva2VkXG4gICAgICAgICAgICAgICAgICAgICAgZnJvbUVsLmluc2VydEJlZm9yZShtYXRjaGluZ0Zyb21FbCwgY3VyRnJvbU5vZGVDaGlsZCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tTmV4dFNpYmxpbmcgPSBjdXJGcm9tTm9kZUNoaWxkLm5leHRTaWJsaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTaW5jZSB0aGUgbm9kZSBpcyBrZXllZCBpdCBtaWdodCBiZSBtYXRjaGVkIHVwIGxhdGVyIHNvIHdlIGRlZmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgYWN0dWFsIHJlbW92YWwgdG8gbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZEtleWVkUmVtb3ZhbChjdXJGcm9tTm9kZUtleSk7XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5PVEU6IHdlIHNraXAgbmVzdGVkIGtleWVkIG5vZGVzIGZyb20gYmVpbmcgcmVtb3ZlZCBzaW5jZSB0aGVyZSBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgc3RpbGwgYSBjaGFuY2UgdGhleSB3aWxsIGJlIG1hdGNoZWQgdXAgbGF0ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZU5vZGUoY3VyRnJvbU5vZGVDaGlsZCwgZnJvbUVsLCB0cnVlIC8qIHNraXAga2V5ZWQgbm9kZXMgKi8pO1xuICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQgPSBtYXRjaGluZ0Zyb21FbDtcbiAgICAgICAgICAgICAgICAgICAgICBjdXJGcm9tTm9kZUtleSA9IGdldE5vZGVLZXkoY3VyRnJvbU5vZGVDaGlsZCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSBub2RlcyBhcmUgbm90IGNvbXBhdGlibGUgc2luY2UgdGhlIFwidG9cIiBub2RlIGhhcyBhIGtleSBhbmQgdGhlcmVcbiAgICAgICAgICAgICAgICAgICAgLy8gaXMgbm8gbWF0Y2hpbmcga2V5ZWQgbm9kZSBpbiB0aGUgc291cmNlIHRyZWVcbiAgICAgICAgICAgICAgICAgICAgaXNDb21wYXRpYmxlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKGN1ckZyb21Ob2RlS2V5KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIG9yaWdpbmFsIGhhcyBhIGtleVxuICAgICAgICAgICAgICAgIGlzQ29tcGF0aWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgaXNDb21wYXRpYmxlID0gaXNDb21wYXRpYmxlICE9PSBmYWxzZSAmJiBjb21wYXJlTm9kZU5hbWVzKGN1ckZyb21Ob2RlQ2hpbGQsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgICAgaWYgKGlzQ29tcGF0aWJsZSkge1xuICAgICAgICAgICAgICAgIC8vIFdlIGZvdW5kIGNvbXBhdGlibGUgRE9NIGVsZW1lbnRzIHNvIHRyYW5zZm9ybVxuICAgICAgICAgICAgICAgIC8vIHRoZSBjdXJyZW50IFwiZnJvbVwiIG5vZGUgdG8gbWF0Y2ggdGhlIGN1cnJlbnRcbiAgICAgICAgICAgICAgICAvLyB0YXJnZXQgRE9NIG5vZGUuXG4gICAgICAgICAgICAgICAgLy8gTU9SUEhcbiAgICAgICAgICAgICAgICBtb3JwaEVsKGN1ckZyb21Ob2RlQ2hpbGQsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGN1ckZyb21Ob2RlVHlwZSA9PT0gVEVYVF9OT0RFIHx8IGN1ckZyb21Ob2RlVHlwZSA9PSBDT01NRU5UX05PREUpIHtcbiAgICAgICAgICAgICAgLy8gQm90aCBub2RlcyBiZWluZyBjb21wYXJlZCBhcmUgVGV4dCBvciBDb21tZW50IG5vZGVzXG4gICAgICAgICAgICAgIGlzQ29tcGF0aWJsZSA9IHRydWU7XG4gICAgICAgICAgICAgIC8vIFNpbXBseSB1cGRhdGUgbm9kZVZhbHVlIG9uIHRoZSBvcmlnaW5hbCBub2RlIHRvXG4gICAgICAgICAgICAgIC8vIGNoYW5nZSB0aGUgdGV4dCB2YWx1ZVxuICAgICAgICAgICAgICBpZiAoY3VyRnJvbU5vZGVDaGlsZC5ub2RlVmFsdWUgIT09IGN1clRvTm9kZUNoaWxkLm5vZGVWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGN1ckZyb21Ob2RlQ2hpbGQubm9kZVZhbHVlID0gY3VyVG9Ob2RlQ2hpbGQubm9kZVZhbHVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoaXNDb21wYXRpYmxlKSB7XG4gICAgICAgICAgICAvLyBBZHZhbmNlIGJvdGggdGhlIFwidG9cIiBjaGlsZCBhbmQgdGhlIFwiZnJvbVwiIGNoaWxkIHNpbmNlIHdlIGZvdW5kIGEgbWF0Y2hcbiAgICAgICAgICAgIC8vIE5vdGhpbmcgZWxzZSB0byBkbyBhcyB3ZSBhbHJlYWR5IHJlY3Vyc2l2ZWx5IGNhbGxlZCBtb3JwaENoaWxkcmVuIGFib3ZlXG4gICAgICAgICAgICBjdXJUb05vZGVDaGlsZCA9IHRvTmV4dFNpYmxpbmc7XG4gICAgICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgICAgICAgY29udGludWUgb3V0ZXI7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTm8gY29tcGF0aWJsZSBtYXRjaCBzbyByZW1vdmUgdGhlIG9sZCBub2RlIGZyb20gdGhlIERPTSBhbmQgY29udGludWUgdHJ5aW5nIHRvIGZpbmQgYVxuICAgICAgICAgIC8vIG1hdGNoIGluIHRoZSBvcmlnaW5hbCBET00uIEhvd2V2ZXIsIHdlIG9ubHkgZG8gdGhpcyBpZiB0aGUgZnJvbSBub2RlIGlzIG5vdCBrZXllZFxuICAgICAgICAgIC8vIHNpbmNlIGl0IGlzIHBvc3NpYmxlIHRoYXQgYSBrZXllZCBub2RlIG1pZ2h0IG1hdGNoIHVwIHdpdGggYSBub2RlIHNvbWV3aGVyZSBlbHNlIGluIHRoZVxuICAgICAgICAgIC8vIHRhcmdldCB0cmVlIGFuZCB3ZSBkb24ndCB3YW50IHRvIGRpc2NhcmQgaXQganVzdCB5ZXQgc2luY2UgaXQgc3RpbGwgbWlnaHQgZmluZCBhXG4gICAgICAgICAgLy8gaG9tZSBpbiB0aGUgZmluYWwgRE9NIHRyZWUuIEFmdGVyIGV2ZXJ5dGhpbmcgaXMgZG9uZSB3ZSB3aWxsIHJlbW92ZSBhbnkga2V5ZWQgbm9kZXNcbiAgICAgICAgICAvLyB0aGF0IGRpZG4ndCBmaW5kIGEgaG9tZVxuICAgICAgICAgIGlmIChjdXJGcm9tTm9kZUtleSkge1xuICAgICAgICAgICAgLy8gU2luY2UgdGhlIG5vZGUgaXMga2V5ZWQgaXQgbWlnaHQgYmUgbWF0Y2hlZCB1cCBsYXRlciBzbyB3ZSBkZWZlclxuICAgICAgICAgICAgLy8gdGhlIGFjdHVhbCByZW1vdmFsIHRvIGxhdGVyXG4gICAgICAgICAgICBhZGRLZXllZFJlbW92YWwoY3VyRnJvbU5vZGVLZXkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBOT1RFOiB3ZSBza2lwIG5lc3RlZCBrZXllZCBub2RlcyBmcm9tIGJlaW5nIHJlbW92ZWQgc2luY2UgdGhlcmUgaXNcbiAgICAgICAgICAgIC8vICAgICAgIHN0aWxsIGEgY2hhbmNlIHRoZXkgd2lsbCBiZSBtYXRjaGVkIHVwIGxhdGVyXG4gICAgICAgICAgICByZW1vdmVOb2RlKGN1ckZyb21Ob2RlQ2hpbGQsIGZyb21FbCwgdHJ1ZSAvKiBza2lwIGtleWVkIG5vZGVzICovKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgICB9IC8vIEVORDogd2hpbGUoY3VyRnJvbU5vZGVDaGlsZCkge31cblxuICAgICAgICAvLyBJZiB3ZSBnb3QgdGhpcyBmYXIgdGhlbiB3ZSBkaWQgbm90IGZpbmQgYSBjYW5kaWRhdGUgbWF0Y2ggZm9yXG4gICAgICAgIC8vIG91ciBcInRvIG5vZGVcIiBhbmQgd2UgZXhoYXVzdGVkIGFsbCBvZiB0aGUgY2hpbGRyZW4gXCJmcm9tXCJcbiAgICAgICAgLy8gbm9kZXMuIFRoZXJlZm9yZSwgd2Ugd2lsbCBqdXN0IGFwcGVuZCB0aGUgY3VycmVudCBcInRvXCIgbm9kZVxuICAgICAgICAvLyB0byB0aGUgZW5kXG4gICAgICAgIGlmIChjdXJUb05vZGVLZXkgJiYgKG1hdGNoaW5nRnJvbUVsID0gZnJvbU5vZGVzTG9va3VwW2N1clRvTm9kZUtleV0pICYmIGNvbXBhcmVOb2RlTmFtZXMobWF0Y2hpbmdGcm9tRWwsIGN1clRvTm9kZUNoaWxkKSkge1xuICAgICAgICAgIC8vIE1PUlBIXG4gICAgICAgICAgaWYoIXNraXBGcm9tKXsgYWRkQ2hpbGQoZnJvbUVsLCBtYXRjaGluZ0Zyb21FbCk7IH1cbiAgICAgICAgICBtb3JwaEVsKG1hdGNoaW5nRnJvbUVsLCBjdXJUb05vZGVDaGlsZCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIG9uQmVmb3JlTm9kZUFkZGVkUmVzdWx0ID0gb25CZWZvcmVOb2RlQWRkZWQoY3VyVG9Ob2RlQ2hpbGQpO1xuICAgICAgICAgIGlmIChvbkJlZm9yZU5vZGVBZGRlZFJlc3VsdCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGlmIChvbkJlZm9yZU5vZGVBZGRlZFJlc3VsdCkge1xuICAgICAgICAgICAgICBjdXJUb05vZGVDaGlsZCA9IG9uQmVmb3JlTm9kZUFkZGVkUmVzdWx0O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY3VyVG9Ob2RlQ2hpbGQuYWN0dWFsaXplKSB7XG4gICAgICAgICAgICAgIGN1clRvTm9kZUNoaWxkID0gY3VyVG9Ob2RlQ2hpbGQuYWN0dWFsaXplKGZyb21FbC5vd25lckRvY3VtZW50IHx8IGRvYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhZGRDaGlsZChmcm9tRWwsIGN1clRvTm9kZUNoaWxkKTtcbiAgICAgICAgICAgIGhhbmRsZU5vZGVBZGRlZChjdXJUb05vZGVDaGlsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY3VyVG9Ob2RlQ2hpbGQgPSB0b05leHRTaWJsaW5nO1xuICAgICAgICBjdXJGcm9tTm9kZUNoaWxkID0gZnJvbU5leHRTaWJsaW5nO1xuICAgICAgfVxuXG4gICAgICBjbGVhbnVwRnJvbUVsKGZyb21FbCwgY3VyRnJvbU5vZGVDaGlsZCwgY3VyRnJvbU5vZGVLZXkpO1xuXG4gICAgICB2YXIgc3BlY2lhbEVsSGFuZGxlciA9IHNwZWNpYWxFbEhhbmRsZXJzW2Zyb21FbC5ub2RlTmFtZV07XG4gICAgICBpZiAoc3BlY2lhbEVsSGFuZGxlcikge1xuICAgICAgICBzcGVjaWFsRWxIYW5kbGVyKGZyb21FbCwgdG9FbCk7XG4gICAgICB9XG4gICAgfSAvLyBFTkQ6IG1vcnBoQ2hpbGRyZW4oLi4uKVxuXG4gICAgdmFyIG1vcnBoZWROb2RlID0gZnJvbU5vZGU7XG4gICAgdmFyIG1vcnBoZWROb2RlVHlwZSA9IG1vcnBoZWROb2RlLm5vZGVUeXBlO1xuICAgIHZhciB0b05vZGVUeXBlID0gdG9Ob2RlLm5vZGVUeXBlO1xuXG4gICAgaWYgKCFjaGlsZHJlbk9ubHkpIHtcbiAgICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB3ZSBhcmUgZ2l2ZW4gdHdvIERPTSBub2RlcyB0aGF0IGFyZSBub3RcbiAgICAgIC8vIGNvbXBhdGlibGUgKGUuZy4gPGRpdj4gLS0+IDxzcGFuPiBvciA8ZGl2PiAtLT4gVEVYVClcbiAgICAgIGlmIChtb3JwaGVkTm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERSkge1xuICAgICAgICBpZiAodG9Ob2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgICAgaWYgKCFjb21wYXJlTm9kZU5hbWVzKGZyb21Ob2RlLCB0b05vZGUpKSB7XG4gICAgICAgICAgICBvbk5vZGVEaXNjYXJkZWQoZnJvbU5vZGUpO1xuICAgICAgICAgICAgbW9ycGhlZE5vZGUgPSBtb3ZlQ2hpbGRyZW4oZnJvbU5vZGUsIGNyZWF0ZUVsZW1lbnROUyh0b05vZGUubm9kZU5hbWUsIHRvTm9kZS5uYW1lc3BhY2VVUkkpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gR29pbmcgZnJvbSBhbiBlbGVtZW50IG5vZGUgdG8gYSB0ZXh0IG5vZGVcbiAgICAgICAgICBtb3JwaGVkTm9kZSA9IHRvTm9kZTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChtb3JwaGVkTm9kZVR5cGUgPT09IFRFWFRfTk9ERSB8fCBtb3JwaGVkTm9kZVR5cGUgPT09IENPTU1FTlRfTk9ERSkgeyAvLyBUZXh0IG9yIGNvbW1lbnQgbm9kZVxuICAgICAgICBpZiAodG9Ob2RlVHlwZSA9PT0gbW9ycGhlZE5vZGVUeXBlKSB7XG4gICAgICAgICAgaWYgKG1vcnBoZWROb2RlLm5vZGVWYWx1ZSAhPT0gdG9Ob2RlLm5vZGVWYWx1ZSkge1xuICAgICAgICAgICAgbW9ycGhlZE5vZGUubm9kZVZhbHVlID0gdG9Ob2RlLm5vZGVWYWx1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gbW9ycGhlZE5vZGU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gVGV4dCBub2RlIHRvIHNvbWV0aGluZyBlbHNlXG4gICAgICAgICAgbW9ycGhlZE5vZGUgPSB0b05vZGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobW9ycGhlZE5vZGUgPT09IHRvTm9kZSkge1xuICAgICAgLy8gVGhlIFwidG8gbm9kZVwiIHdhcyBub3QgY29tcGF0aWJsZSB3aXRoIHRoZSBcImZyb20gbm9kZVwiIHNvIHdlIGhhZCB0b1xuICAgICAgLy8gdG9zcyBvdXQgdGhlIFwiZnJvbSBub2RlXCIgYW5kIHVzZSB0aGUgXCJ0byBub2RlXCJcbiAgICAgIG9uTm9kZURpc2NhcmRlZChmcm9tTm9kZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0b05vZGUuaXNTYW1lTm9kZSAmJiB0b05vZGUuaXNTYW1lTm9kZShtb3JwaGVkTm9kZSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBtb3JwaEVsKG1vcnBoZWROb2RlLCB0b05vZGUsIGNoaWxkcmVuT25seSk7XG5cbiAgICAgIC8vIFdlIG5vdyBuZWVkIHRvIGxvb3Agb3ZlciBhbnkga2V5ZWQgbm9kZXMgdGhhdCBtaWdodCBuZWVkIHRvIGJlXG4gICAgICAvLyByZW1vdmVkLiBXZSBvbmx5IGRvIHRoZSByZW1vdmFsIGlmIHdlIGtub3cgdGhhdCB0aGUga2V5ZWQgbm9kZVxuICAgICAgLy8gbmV2ZXIgZm91bmQgYSBtYXRjaC4gV2hlbiBhIGtleWVkIG5vZGUgaXMgbWF0Y2hlZCB1cCB3ZSByZW1vdmVcbiAgICAgIC8vIGl0IG91dCBvZiBmcm9tTm9kZXNMb29rdXAgYW5kIHdlIHVzZSBmcm9tTm9kZXNMb29rdXAgdG8gZGV0ZXJtaW5lXG4gICAgICAvLyBpZiBhIGtleWVkIG5vZGUgaGFzIGJlZW4gbWF0Y2hlZCB1cCBvciBub3RcbiAgICAgIGlmIChrZXllZFJlbW92YWxMaXN0KSB7XG4gICAgICAgIGZvciAodmFyIGk9MCwgbGVuPWtleWVkUmVtb3ZhbExpc3QubGVuZ3RoOyBpPGxlbjsgaSsrKSB7XG4gICAgICAgICAgdmFyIGVsVG9SZW1vdmUgPSBmcm9tTm9kZXNMb29rdXBba2V5ZWRSZW1vdmFsTGlzdFtpXV07XG4gICAgICAgICAgaWYgKGVsVG9SZW1vdmUpIHtcbiAgICAgICAgICAgIHJlbW92ZU5vZGUoZWxUb1JlbW92ZSwgZWxUb1JlbW92ZS5wYXJlbnROb2RlLCBmYWxzZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFjaGlsZHJlbk9ubHkgJiYgbW9ycGhlZE5vZGUgIT09IGZyb21Ob2RlICYmIGZyb21Ob2RlLnBhcmVudE5vZGUpIHtcbiAgICAgIGlmIChtb3JwaGVkTm9kZS5hY3R1YWxpemUpIHtcbiAgICAgICAgbW9ycGhlZE5vZGUgPSBtb3JwaGVkTm9kZS5hY3R1YWxpemUoZnJvbU5vZGUub3duZXJEb2N1bWVudCB8fCBkb2MpO1xuICAgICAgfVxuICAgICAgLy8gSWYgd2UgaGFkIHRvIHN3YXAgb3V0IHRoZSBmcm9tIG5vZGUgd2l0aCBhIG5ldyBub2RlIGJlY2F1c2UgdGhlIG9sZFxuICAgICAgLy8gbm9kZSB3YXMgbm90IGNvbXBhdGlibGUgd2l0aCB0aGUgdGFyZ2V0IG5vZGUgdGhlbiB3ZSBuZWVkIHRvXG4gICAgICAvLyByZXBsYWNlIHRoZSBvbGQgRE9NIG5vZGUgaW4gdGhlIG9yaWdpbmFsIERPTSB0cmVlLiBUaGlzIGlzIG9ubHlcbiAgICAgIC8vIHBvc3NpYmxlIGlmIHRoZSBvcmlnaW5hbCBET00gbm9kZSB3YXMgcGFydCBvZiBhIERPTSB0cmVlIHdoaWNoXG4gICAgICAvLyB3ZSBrbm93IGlzIHRoZSBjYXNlIGlmIGl0IGhhcyBhIHBhcmVudCBub2RlLlxuICAgICAgZnJvbU5vZGUucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobW9ycGhlZE5vZGUsIGZyb21Ob2RlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbW9ycGhlZE5vZGU7XG4gIH07XG59XG5cbnZhciBtb3JwaGRvbSA9IG1vcnBoZG9tRmFjdG9yeShtb3JwaEF0dHJzKTtcblxuZXhwb3J0IGRlZmF1bHQgbW9ycGhkb207XG4iLCAiaW1wb3J0IHtcbiAgUEhYX0NPTVBPTkVOVCxcbiAgUEhYX1BSVU5FLFxuICBQSFhfUk9PVF9JRCxcbiAgUEhYX1NFU1NJT04sXG4gIFBIWF9TS0lQLFxuICBQSFhfTUFHSUNfSUQsXG4gIFBIWF9TVEFUSUMsXG4gIFBIWF9UUklHR0VSX0FDVElPTixcbiAgUEhYX1VQREFURSxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9SRUZfTE9DSyxcbiAgUEhYX1NUUkVBTSxcbiAgUEhYX1NUUkVBTV9SRUYsXG4gIFBIWF9WSUVXUE9SVF9UT1AsXG4gIFBIWF9WSUVXUE9SVF9CT1RUT00sXG4gIFBIWF9QT1JUQUwsXG4gIFBIWF9URUxFUE9SVEVEX1JFRixcbiAgUEhYX1RFTEVQT1JURURfU1JDLFxuICBQSFhfUlVOVElNRV9IT09LLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuaW1wb3J0IHsgZGV0ZWN0RHVwbGljYXRlSWRzLCBkZXRlY3RJbnZhbGlkU3RyZWFtSW5zZXJ0cywgaXNDaWQgfSBmcm9tIFwiLi91dGlsc1wiO1xuaW1wb3J0IEVsZW1lbnRSZWYgZnJvbSBcIi4vZWxlbWVudF9yZWZcIjtcbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCI7XG5pbXBvcnQgRE9NUG9zdE1vcnBoUmVzdG9yZXIgZnJvbSBcIi4vZG9tX3Bvc3RfbW9ycGhfcmVzdG9yZXJcIjtcbmltcG9ydCBtb3JwaGRvbSBmcm9tIFwibW9ycGhkb21cIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRE9NUGF0Y2gge1xuICBjb25zdHJ1Y3Rvcih2aWV3LCBjb250YWluZXIsIGlkLCBodG1sLCBzdHJlYW1zLCB0YXJnZXRDSUQsIG9wdHMgPSB7fSkge1xuICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgdGhpcy5saXZlU29ja2V0ID0gdmlldy5saXZlU29ja2V0O1xuICAgIHRoaXMuY29udGFpbmVyID0gY29udGFpbmVyO1xuICAgIHRoaXMuaWQgPSBpZDtcbiAgICB0aGlzLnJvb3RJRCA9IHZpZXcucm9vdC5pZDtcbiAgICB0aGlzLmh0bWwgPSBodG1sO1xuICAgIHRoaXMuc3RyZWFtcyA9IHN0cmVhbXM7XG4gICAgdGhpcy5zdHJlYW1JbnNlcnRzID0ge307XG4gICAgdGhpcy5zdHJlYW1Db21wb25lbnRSZXN0b3JlID0ge307XG4gICAgdGhpcy50YXJnZXRDSUQgPSB0YXJnZXRDSUQ7XG4gICAgdGhpcy5jaWRQYXRjaCA9IGlzQ2lkKHRoaXMudGFyZ2V0Q0lEKTtcbiAgICB0aGlzLnBlbmRpbmdSZW1vdmVzID0gW107XG4gICAgdGhpcy5waHhSZW1vdmUgPSB0aGlzLmxpdmVTb2NrZXQuYmluZGluZyhcInJlbW92ZVwiKTtcbiAgICB0aGlzLnRhcmdldENvbnRhaW5lciA9IHRoaXMuaXNDSURQYXRjaCgpXG4gICAgICA/IHRoaXMudGFyZ2V0Q0lEQ29udGFpbmVyKGh0bWwpXG4gICAgICA6IGNvbnRhaW5lcjtcbiAgICB0aGlzLmNhbGxiYWNrcyA9IHtcbiAgICAgIGJlZm9yZWFkZGVkOiBbXSxcbiAgICAgIGJlZm9yZXVwZGF0ZWQ6IFtdLFxuICAgICAgYmVmb3JlcGh4Q2hpbGRBZGRlZDogW10sXG4gICAgICBhZnRlcmFkZGVkOiBbXSxcbiAgICAgIGFmdGVydXBkYXRlZDogW10sXG4gICAgICBhZnRlcmRpc2NhcmRlZDogW10sXG4gICAgICBhZnRlcnBoeENoaWxkQWRkZWQ6IFtdLFxuICAgICAgYWZ0ZXJ0cmFuc2l0aW9uc0Rpc2NhcmRlZDogW10sXG4gICAgfTtcbiAgICB0aGlzLndpdGhDaGlsZHJlbiA9IG9wdHMud2l0aENoaWxkcmVuIHx8IG9wdHMudW5kb1JlZiB8fCBmYWxzZTtcbiAgICB0aGlzLnVuZG9SZWYgPSBvcHRzLnVuZG9SZWY7XG4gIH1cblxuICBiZWZvcmUoa2luZCwgY2FsbGJhY2spIHtcbiAgICB0aGlzLmNhbGxiYWNrc1tgYmVmb3JlJHtraW5kfWBdLnB1c2goY2FsbGJhY2spO1xuICB9XG4gIGFmdGVyKGtpbmQsIGNhbGxiYWNrKSB7XG4gICAgdGhpcy5jYWxsYmFja3NbYGFmdGVyJHtraW5kfWBdLnB1c2goY2FsbGJhY2spO1xuICB9XG5cbiAgdHJhY2tCZWZvcmUoa2luZCwgLi4uYXJncykge1xuICAgIHRoaXMuY2FsbGJhY2tzW2BiZWZvcmUke2tpbmR9YF0uZm9yRWFjaCgoY2FsbGJhY2spID0+IGNhbGxiYWNrKC4uLmFyZ3MpKTtcbiAgfVxuXG4gIHRyYWNrQWZ0ZXIoa2luZCwgLi4uYXJncykge1xuICAgIHRoaXMuY2FsbGJhY2tzW2BhZnRlciR7a2luZH1gXS5mb3JFYWNoKChjYWxsYmFjaykgPT4gY2FsbGJhY2soLi4uYXJncykpO1xuICB9XG5cbiAgbWFya1BydW5hYmxlQ29udGVudEZvclJlbW92YWwoKSB7XG4gICAgY29uc3QgcGh4VXBkYXRlID0gdGhpcy5saXZlU29ja2V0LmJpbmRpbmcoUEhYX1VQREFURSk7XG4gICAgRE9NLmFsbChcbiAgICAgIHRoaXMuY29udGFpbmVyLFxuICAgICAgYFske3BoeFVwZGF0ZX09YXBwZW5kXSA+ICosIFske3BoeFVwZGF0ZX09cHJlcGVuZF0gPiAqYCxcbiAgICAgIChlbCkgPT4ge1xuICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoUEhYX1BSVU5FLCBcIlwiKTtcbiAgICAgIH0sXG4gICAgKTtcbiAgfVxuXG4gIHBlcmZvcm0oaXNKb2luUGF0Y2gpIHtcbiAgICBjb25zdCB7IHZpZXcsIGxpdmVTb2NrZXQsIGh0bWwsIGNvbnRhaW5lciB9ID0gdGhpcztcbiAgICBsZXQgdGFyZ2V0Q29udGFpbmVyID0gdGhpcy50YXJnZXRDb250YWluZXI7XG5cbiAgICBpZiAodGhpcy5pc0NJRFBhdGNoKCkgJiYgIXRoaXMudGFyZ2V0Q29udGFpbmVyKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuaXNDSURQYXRjaCgpKSB7XG4gICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9wdWxsLzM5NDJcbiAgICAgIC8vIHdlIG5lZWQgdG8gZW5zdXJlIHRoYXQgbm8gcGFyZW50IGlzIGxvY2tlZFxuICAgICAgY29uc3QgY2xvc2VzdExvY2sgPSB0YXJnZXRDb250YWluZXIuY2xvc2VzdChgWyR7UEhYX1JFRl9MT0NLfV1gKTtcbiAgICAgIGlmIChjbG9zZXN0TG9jaykge1xuICAgICAgICBjb25zdCBjbG9uZWRUcmVlID0gRE9NLnByaXZhdGUoY2xvc2VzdExvY2ssIFBIWF9SRUZfTE9DSyk7XG4gICAgICAgIGlmIChjbG9uZWRUcmVlKSB7XG4gICAgICAgICAgLy8gaWYgYSBwYXJlbnQgaXMgbG9ja2VkIHdpdGggYSBjbG9uZWQgdHJlZSwgd2UgbmVlZCB0byBwYXRjaCB0aGUgY2xvbmVkIHRyZWUgaW5zdGVhZFxuICAgICAgICAgIHRhcmdldENvbnRhaW5lciA9IGNsb25lZFRyZWUucXVlcnlTZWxlY3RvcihcbiAgICAgICAgICAgIGBbZGF0YS1waHgtY29tcG9uZW50PVwiJHt0aGlzLnRhcmdldENJRH1cIl1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBmb2N1c2VkID0gbGl2ZVNvY2tldC5nZXRBY3RpdmVFbGVtZW50KCk7XG4gICAgY29uc3QgeyBzZWxlY3Rpb25TdGFydCwgc2VsZWN0aW9uRW5kIH0gPVxuICAgICAgZm9jdXNlZCAmJiBET00uaGFzU2VsZWN0aW9uUmFuZ2UoZm9jdXNlZCkgPyBmb2N1c2VkIDoge307XG4gICAgY29uc3QgcGh4VXBkYXRlID0gbGl2ZVNvY2tldC5iaW5kaW5nKFBIWF9VUERBVEUpO1xuICAgIGNvbnN0IHBoeFZpZXdwb3J0VG9wID0gbGl2ZVNvY2tldC5iaW5kaW5nKFBIWF9WSUVXUE9SVF9UT1ApO1xuICAgIGNvbnN0IHBoeFZpZXdwb3J0Qm90dG9tID0gbGl2ZVNvY2tldC5iaW5kaW5nKFBIWF9WSUVXUE9SVF9CT1RUT00pO1xuICAgIGNvbnN0IHBoeFRyaWdnZXJFeHRlcm5hbCA9IGxpdmVTb2NrZXQuYmluZGluZyhQSFhfVFJJR0dFUl9BQ1RJT04pO1xuICAgIGNvbnN0IGFkZGVkID0gW107XG4gICAgY29uc3QgdXBkYXRlcyA9IFtdO1xuICAgIGNvbnN0IGFwcGVuZFByZXBlbmRVcGRhdGVzID0gW107XG5cbiAgICAvLyBhcyB0aGUgcG9ydGFsIHRhcmdldCBpdHNlbGYgY291bGQgYmUgYXQgdGhlIGVuZCBvZiB0aGUgRE9NLFxuICAgIC8vIGl0IG1heSBub3QgYmUgcHJlc2VudCB3aGlsZSBtb3JwaGluZyBwcmV2aW91cyBwYXJ0cztcbiAgICAvLyB0aGVyZWZvcmUgd2UgYXBwbHkgYWxsIHRlbGVwb3J0cyBhZnRlciB0aGUgbW9ycGhpbmcgaXMgZG9uZStcbiAgICBjb25zdCBwb3J0YWxDYWxsYmFja3MgPSBbXTtcblxuICAgIGxldCBleHRlcm5hbEZvcm1UcmlnZ2VyZWQgPSBudWxsO1xuXG4gICAgY29uc3QgbW9ycGggPSAoXG4gICAgICB0YXJnZXRDb250YWluZXIsXG4gICAgICBzb3VyY2UsXG4gICAgICB3aXRoQ2hpbGRyZW4gPSB0aGlzLndpdGhDaGlsZHJlbixcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IG1vcnBoQ2FsbGJhY2tzID0ge1xuICAgICAgICAvLyBub3JtYWxseSwgd2UgYXJlIHJ1bm5pbmcgd2l0aCBjaGlsZHJlbk9ubHksIGFzIHRoZSBwYXRjaCBIVE1MIGZvciBhIExWXG4gICAgICAgIC8vIGRvZXMgbm90IGluY2x1ZGUgdGhlIExWIGF0dHJzIChkYXRhLXBoeC1zZXNzaW9uLCBldGMuKVxuICAgICAgICAvLyB3aGVuIHdlIGFyZSBwYXRjaGluZyBhIGxpdmUgY29tcG9uZW50LCB3ZSBkbyB3YW50IHRvIHBhdGNoIHRoZSByb290IGVsZW1lbnQgYXMgd2VsbDtcbiAgICAgICAgLy8gYW5vdGhlciBjYXNlIGlzIHRoZSByZWN1cnNpdmUgcGF0Y2ggb2YgYSBzdHJlYW0gaXRlbSB0aGF0IHdhcyBrZXB0IG9uIHJlc2V0ICgtPiBvbkJlZm9yZU5vZGVBZGRlZClcbiAgICAgICAgY2hpbGRyZW5Pbmx5OlxuICAgICAgICAgIHRhcmdldENvbnRhaW5lci5nZXRBdHRyaWJ1dGUoUEhYX0NPTVBPTkVOVCkgPT09IG51bGwgJiYgIXdpdGhDaGlsZHJlbixcbiAgICAgICAgZ2V0Tm9kZUtleTogKG5vZGUpID0+IHtcbiAgICAgICAgICBpZiAoRE9NLmlzUGh4RGVzdHJveWVkKG5vZGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIGpvaW4gcGF0Y2gsIHRoZW4gYnkgZGVmaW5pdGlvbiB0aGVyZSB3YXMgbm8gUEhYX01BR0lDX0lELlxuICAgICAgICAgIC8vIFRoaXMgaXMgaW1wb3J0YW50IHRvIHJlZHVjZSB0aGUgYW1vdW50IG9mIGVsZW1lbnRzIG1vcnBoZG9tIGRpc2NhcmRzLlxuICAgICAgICAgIGlmIChpc0pvaW5QYXRjaCkge1xuICAgICAgICAgICAgcmV0dXJuIG5vZGUuaWQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBub2RlLmlkIHx8IChub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZShQSFhfTUFHSUNfSUQpKVxuICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICAgIC8vIHNraXAgaW5kZXhpbmcgZnJvbSBjaGlsZHJlbiB3aGVuIGNvbnRhaW5lciBpcyBzdHJlYW1cbiAgICAgICAgc2tpcEZyb21DaGlsZHJlbjogKGZyb20pID0+IHtcbiAgICAgICAgICByZXR1cm4gZnJvbS5nZXRBdHRyaWJ1dGUocGh4VXBkYXRlKSA9PT0gUEhYX1NUUkVBTTtcbiAgICAgICAgfSxcbiAgICAgICAgLy8gdGVsbCBtb3JwaGRvbSBob3cgdG8gYWRkIGEgY2hpbGRcbiAgICAgICAgYWRkQ2hpbGQ6IChwYXJlbnQsIGNoaWxkKSA9PiB7XG4gICAgICAgICAgY29uc3QgeyByZWYsIHN0cmVhbUF0IH0gPSB0aGlzLmdldFN0cmVhbUluc2VydChjaGlsZCk7XG4gICAgICAgICAgaWYgKHJlZiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyZW50LmFwcGVuZENoaWxkKGNoaWxkKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNldFN0cmVhbVJlZihjaGlsZCwgcmVmKTtcblxuICAgICAgICAgIC8vIHN0cmVhbWluZ1xuICAgICAgICAgIGlmIChzdHJlYW1BdCA9PT0gMCkge1xuICAgICAgICAgICAgcGFyZW50Lmluc2VydEFkamFjZW50RWxlbWVudChcImFmdGVyYmVnaW5cIiwgY2hpbGQpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoc3RyZWFtQXQgPT09IC0xKSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0Q2hpbGQgPSBwYXJlbnQubGFzdEVsZW1lbnRDaGlsZDtcbiAgICAgICAgICAgIGlmIChsYXN0Q2hpbGQgJiYgIWxhc3RDaGlsZC5oYXNBdHRyaWJ1dGUoUEhYX1NUUkVBTV9SRUYpKSB7XG4gICAgICAgICAgICAgIGNvbnN0IG5vblN0cmVhbUNoaWxkID0gQXJyYXkuZnJvbShwYXJlbnQuY2hpbGRyZW4pLmZpbmQoXG4gICAgICAgICAgICAgICAgKGMpID0+ICFjLmhhc0F0dHJpYnV0ZShQSFhfU1RSRUFNX1JFRiksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIHBhcmVudC5pbnNlcnRCZWZvcmUoY2hpbGQsIG5vblN0cmVhbUNoaWxkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChzdHJlYW1BdCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IHNpYmxpbmcgPSBBcnJheS5mcm9tKHBhcmVudC5jaGlsZHJlbilbc3RyZWFtQXRdO1xuICAgICAgICAgICAgcGFyZW50Lmluc2VydEJlZm9yZShjaGlsZCwgc2libGluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBvbkJlZm9yZU5vZGVBZGRlZDogKGVsKSA9PiB7XG4gICAgICAgICAgLy8gZG9uJ3QgYWRkIHVwZGF0ZV9vbmx5IG5vZGVzIGlmIHRoZXkgZGlkIG5vdCBhbHJlYWR5IGV4aXN0XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5nZXRTdHJlYW1JbnNlcnQoZWwpPy51cGRhdGVPbmx5ICYmXG4gICAgICAgICAgICAhdGhpcy5zdHJlYW1Db21wb25lbnRSZXN0b3JlW2VsLmlkXVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIERPTS5tYWludGFpblByaXZhdGVIb29rcyhlbCwgZWwsIHBoeFZpZXdwb3J0VG9wLCBwaHhWaWV3cG9ydEJvdHRvbSk7XG4gICAgICAgICAgdGhpcy50cmFja0JlZm9yZShcImFkZGVkXCIsIGVsKTtcblxuICAgICAgICAgIGxldCBtb3JwaGVkRWwgPSBlbDtcbiAgICAgICAgICAvLyB0aGlzIGlzIGEgc3RyZWFtIGl0ZW0gdGhhdCB3YXMga2VwdCBvbiByZXNldCwgcmVjdXJzaXZlbHkgbW9ycGggaXRcbiAgICAgICAgICBpZiAodGhpcy5zdHJlYW1Db21wb25lbnRSZXN0b3JlW2VsLmlkXSkge1xuICAgICAgICAgICAgbW9ycGhlZEVsID0gdGhpcy5zdHJlYW1Db21wb25lbnRSZXN0b3JlW2VsLmlkXTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnN0cmVhbUNvbXBvbmVudFJlc3RvcmVbZWwuaWRdO1xuICAgICAgICAgICAgbW9ycGgobW9ycGhlZEVsLCBlbCwgdHJ1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIG1vcnBoZWRFbDtcbiAgICAgICAgfSxcbiAgICAgICAgb25Ob2RlQWRkZWQ6IChlbCkgPT4ge1xuICAgICAgICAgIGlmIChlbC5nZXRBdHRyaWJ1dGUpIHtcbiAgICAgICAgICAgIHRoaXMubWF5YmVSZU9yZGVyU3RyZWFtKGVsLCB0cnVlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gcGh4LXBvcnRhbCBoYW5kbGluZ1xuICAgICAgICAgIGlmIChET00uaXNQb3J0YWxUZW1wbGF0ZShlbCkpIHtcbiAgICAgICAgICAgIHBvcnRhbENhbGxiYWNrcy5wdXNoKCgpID0+IHRoaXMudGVsZXBvcnQoZWwsIG1vcnBoKSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gaGFjayB0byBmaXggU2FmYXJpIGhhbmRsaW5nIG9mIGltZyBzcmNzZXQgYW5kIHZpZGVvIHRhZ3NcbiAgICAgICAgICBpZiAoZWwgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICYmIGVsLnNyY3NldCkge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXNlbGYtYXNzaWduXG4gICAgICAgICAgICBlbC5zcmNzZXQgPSBlbC5zcmNzZXQ7XG4gICAgICAgICAgfSBlbHNlIGlmIChlbCBpbnN0YW5jZW9mIEhUTUxWaWRlb0VsZW1lbnQgJiYgZWwuYXV0b3BsYXkpIHtcbiAgICAgICAgICAgIGVsLnBsYXkoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKERPTS5pc05vd1RyaWdnZXJGb3JtRXh0ZXJuYWwoZWwsIHBoeFRyaWdnZXJFeHRlcm5hbCkpIHtcbiAgICAgICAgICAgIGV4dGVybmFsRm9ybVRyaWdnZXJlZCA9IGVsO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIG5lc3RlZCB2aWV3IGhhbmRsaW5nXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgKERPTS5pc1BoeENoaWxkKGVsKSAmJiB2aWV3Lm93bnNFbGVtZW50KGVsKSkgfHxcbiAgICAgICAgICAgIChET00uaXNQaHhTdGlja3koZWwpICYmIHZpZXcub3duc0VsZW1lbnQoZWwucGFyZW50Tm9kZSkpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLnRyYWNrQWZ0ZXIoXCJwaHhDaGlsZEFkZGVkXCIsIGVsKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBkYXRhLXBoeC1ydW50aW1lLWhvb2tcbiAgICAgICAgICBpZiAoZWwubm9kZU5hbWUgPT09IFwiU0NSSVBUXCIgJiYgZWwuaGFzQXR0cmlidXRlKFBIWF9SVU5USU1FX0hPT0spKSB7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVJ1bnRpbWVIb29rKGVsLCBzb3VyY2UpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGFkZGVkLnB1c2goZWwpO1xuICAgICAgICB9LFxuICAgICAgICBvbk5vZGVEaXNjYXJkZWQ6IChlbCkgPT4gdGhpcy5vbk5vZGVEaXNjYXJkZWQoZWwpLFxuICAgICAgICBvbkJlZm9yZU5vZGVEaXNjYXJkZWQ6IChlbCkgPT4ge1xuICAgICAgICAgIGlmIChlbC5nZXRBdHRyaWJ1dGUgJiYgZWwuZ2V0QXR0cmlidXRlKFBIWF9QUlVORSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBlbC5wYXJlbnRFbGVtZW50ICE9PSBudWxsICYmXG4gICAgICAgICAgICBlbC5pZCAmJlxuICAgICAgICAgICAgRE9NLmlzUGh4VXBkYXRlKGVsLnBhcmVudEVsZW1lbnQsIHBoeFVwZGF0ZSwgW1xuICAgICAgICAgICAgICBQSFhfU1RSRUFNLFxuICAgICAgICAgICAgICBcImFwcGVuZFwiLFxuICAgICAgICAgICAgICBcInByZXBlbmRcIixcbiAgICAgICAgICAgIF0pXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIGRvbid0IHJlbW92ZSB0ZWxlcG9ydGVkIGVsZW1lbnRzXG4gICAgICAgICAgaWYgKGVsLmdldEF0dHJpYnV0ZSAmJiBlbC5nZXRBdHRyaWJ1dGUoUEhYX1RFTEVQT1JURURfUkVGKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodGhpcy5tYXliZVBlbmRpbmdSZW1vdmUoZWwpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh0aGlzLnNraXBDSURTaWJsaW5nKGVsKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChET00uaXNQb3J0YWxUZW1wbGF0ZShlbCkpIHtcbiAgICAgICAgICAgIC8vIGlmIHRoZSBwb3J0YWwgdGVtcGxhdGUgaXRzZWxmIGlzIHJlbW92ZWQsIHJlbW92ZSB0aGUgdGVsZXBvcnRlZCBlbGVtZW50IGFzIHdlbGw7XG4gICAgICAgICAgICAvLyB3ZSBhbHNvIHBlcmZvcm0gYSBjaGVjayBhZnRlciBtb3JwaGRvbSBpcyBmaW5pc2hlZCB0byBjYXRjaCBwYXJlbnQgcmVtb3ZhbHNcbiAgICAgICAgICAgIGNvbnN0IHRlbGVwb3J0ZWRFbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFxuICAgICAgICAgICAgICBlbC5jb250ZW50LmZpcnN0RWxlbWVudENoaWxkLmlkLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmICh0ZWxlcG9ydGVkRWwpIHtcbiAgICAgICAgICAgICAgdGVsZXBvcnRlZEVsLnJlbW92ZSgpO1xuICAgICAgICAgICAgICBtb3JwaENhbGxiYWNrcy5vbk5vZGVEaXNjYXJkZWQodGVsZXBvcnRlZEVsKTtcbiAgICAgICAgICAgICAgdGhpcy52aWV3LmRyb3BQb3J0YWxFbGVtZW50SWQodGVsZXBvcnRlZEVsLmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgb25FbFVwZGF0ZWQ6IChlbCkgPT4ge1xuICAgICAgICAgIGlmIChET00uaXNOb3dUcmlnZ2VyRm9ybUV4dGVybmFsKGVsLCBwaHhUcmlnZ2VyRXh0ZXJuYWwpKSB7XG4gICAgICAgICAgICBleHRlcm5hbEZvcm1UcmlnZ2VyZWQgPSBlbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgdXBkYXRlcy5wdXNoKGVsKTtcbiAgICAgICAgICB0aGlzLm1heWJlUmVPcmRlclN0cmVhbShlbCwgZmFsc2UpO1xuICAgICAgICB9LFxuICAgICAgICBvbkJlZm9yZUVsVXBkYXRlZDogKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgICAgIC8vIGlmIHdlIGFyZSBwYXRjaGluZyB0aGUgcm9vdCB0YXJnZXQgY29udGFpbmVyIGFuZCB0aGUgaWQgaGFzIGNoYW5nZWQsIHRyZWF0IGl0IGFzIGEgbmV3IG5vZGVcbiAgICAgICAgICAvLyBieSByZXBsYWNpbmcgdGhlIGZyb21FbCB3aXRoIHRoZSB0b0VsLCB3aGljaCBlbnN1cmVzIGhvb2tzIGFyZSB0b3JuIGRvd24gYW5kIHJlLWNyZWF0ZWRcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBmcm9tRWwuaWQgJiZcbiAgICAgICAgICAgIGZyb21FbC5pc1NhbWVOb2RlKHRhcmdldENvbnRhaW5lcikgJiZcbiAgICAgICAgICAgIGZyb21FbC5pZCAhPT0gdG9FbC5pZFxuICAgICAgICAgICkge1xuICAgICAgICAgICAgbW9ycGhDYWxsYmFja3Mub25Ob2RlRGlzY2FyZGVkKGZyb21FbCk7XG4gICAgICAgICAgICBmcm9tRWwucmVwbGFjZVdpdGgodG9FbCk7XG4gICAgICAgICAgICByZXR1cm4gbW9ycGhDYWxsYmFja3Mub25Ob2RlQWRkZWQodG9FbCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIERPTS5zeW5jUGVuZGluZ0F0dHJzKGZyb21FbCwgdG9FbCk7XG4gICAgICAgICAgRE9NLm1haW50YWluUHJpdmF0ZUhvb2tzKFxuICAgICAgICAgICAgZnJvbUVsLFxuICAgICAgICAgICAgdG9FbCxcbiAgICAgICAgICAgIHBoeFZpZXdwb3J0VG9wLFxuICAgICAgICAgICAgcGh4Vmlld3BvcnRCb3R0b20sXG4gICAgICAgICAgKTtcbiAgICAgICAgICBET00uY2xlYW5DaGlsZE5vZGVzKHRvRWwsIHBoeFVwZGF0ZSk7XG4gICAgICAgICAgaWYgKHRoaXMuc2tpcENJRFNpYmxpbmcodG9FbCkpIHtcbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaXMgYSBsaXZlIGNvbXBvbmVudCB1c2VkIGluIGEgc3RyZWFtLCB3ZSBtYXkgbmVlZCB0byByZW9yZGVyIGl0XG4gICAgICAgICAgICB0aGlzLm1heWJlUmVPcmRlclN0cmVhbShmcm9tRWwpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoRE9NLmlzUGh4U3RpY2t5KGZyb21FbCkpIHtcbiAgICAgICAgICAgIFtQSFhfU0VTU0lPTiwgUEhYX1NUQVRJQywgUEhYX1JPT1RfSURdXG4gICAgICAgICAgICAgIC5tYXAoKGF0dHIpID0+IFtcbiAgICAgICAgICAgICAgICBhdHRyLFxuICAgICAgICAgICAgICAgIGZyb21FbC5nZXRBdHRyaWJ1dGUoYXR0ciksXG4gICAgICAgICAgICAgICAgdG9FbC5nZXRBdHRyaWJ1dGUoYXR0ciksXG4gICAgICAgICAgICAgIF0pXG4gICAgICAgICAgICAgIC5mb3JFYWNoKChbYXR0ciwgZnJvbVZhbCwgdG9WYWxdKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRvVmFsICYmIGZyb21WYWwgIT09IHRvVmFsKSB7XG4gICAgICAgICAgICAgICAgICBmcm9tRWwuc2V0QXR0cmlidXRlKGF0dHIsIHRvVmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIERPTS5pc0lnbm9yZWQoZnJvbUVsLCBwaHhVcGRhdGUpIHx8XG4gICAgICAgICAgICAoZnJvbUVsLmZvcm0gJiYgZnJvbUVsLmZvcm0uaXNTYW1lTm9kZShleHRlcm5hbEZvcm1UcmlnZ2VyZWQpKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy50cmFja0JlZm9yZShcInVwZGF0ZWRcIiwgZnJvbUVsLCB0b0VsKTtcbiAgICAgICAgICAgIERPTS5tZXJnZUF0dHJzKGZyb21FbCwgdG9FbCwge1xuICAgICAgICAgICAgICBpc0lnbm9yZWQ6IERPTS5pc0lnbm9yZWQoZnJvbUVsLCBwaHhVcGRhdGUpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB1cGRhdGVzLnB1c2goZnJvbUVsKTtcbiAgICAgICAgICAgIERPTS5hcHBseVN0aWNreU9wZXJhdGlvbnMoZnJvbUVsKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgZnJvbUVsLnR5cGUgPT09IFwibnVtYmVyXCIgJiZcbiAgICAgICAgICAgIGZyb21FbC52YWxpZGl0eSAmJlxuICAgICAgICAgICAgZnJvbUVsLnZhbGlkaXR5LmJhZElucHV0XG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIElmIHRoZSBlbGVtZW50IGhhcyBQSFhfUkVGX1NSQywgaXQgaXMgbG9hZGluZyBvciBsb2NrZWQgYW5kIGF3YWl0aW5nIGFuIGFjay5cbiAgICAgICAgICAvLyBJZiBpdCdzIGxvY2tlZCwgd2UgY2xvbmUgdGhlIGZyb21FbCB0cmVlIGFuZCBpbnN0cnVjdCBtb3JwaGRvbSB0byB1c2VcbiAgICAgICAgICAvLyB0aGUgY2xvbmVkIHRyZWUgYXMgdGhlIHNvdXJjZSBvZiB0aGUgbW9ycGggZm9yIHRoaXMgYnJhbmNoIGZyb20gaGVyZSBvbiBvdXQuXG4gICAgICAgICAgLy8gV2Uga2VlcCBhIHJlZmVyZW5jZSB0byB0aGUgY2xvbmVkIHRyZWUgaW4gdGhlIGVsZW1lbnQncyBwcml2YXRlIGRhdGEsIGFuZFxuICAgICAgICAgIC8vIG9uIGFjayAodmlldy51bmRvUmVmcyksIHdlIG1vcnBoIHRoZSBjbG9uZWQgdHJlZSB3aXRoIHRoZSB0cnVlIGZyb21FbCBpbiB0aGUgRE9NIHRvXG4gICAgICAgICAgLy8gYXBwbHkgYW55IGNoYW5nZXMgdGhhdCBoYXBwZW5lZCB3aGlsZSB0aGUgZWxlbWVudCB3YXMgbG9ja2VkLlxuICAgICAgICAgIGNvbnN0IGlzRm9jdXNlZEZvcm1FbCA9XG4gICAgICAgICAgICBmb2N1c2VkICYmIGZyb21FbC5pc1NhbWVOb2RlKGZvY3VzZWQpICYmIERPTS5pc0Zvcm1JbnB1dChmcm9tRWwpO1xuICAgICAgICAgIGNvbnN0IGZvY3VzZWRTZWxlY3RDaGFuZ2VkID1cbiAgICAgICAgICAgIGlzRm9jdXNlZEZvcm1FbCAmJiB0aGlzLmlzQ2hhbmdlZFNlbGVjdChmcm9tRWwsIHRvRWwpO1xuICAgICAgICAgIGlmIChmcm9tRWwuaGFzQXR0cmlidXRlKFBIWF9SRUZfU1JDKSkge1xuICAgICAgICAgICAgY29uc3QgcmVmID0gbmV3IEVsZW1lbnRSZWYoZnJvbUVsKTtcbiAgICAgICAgICAgIC8vIG9ubHkgcGVyZm9ybSB0aGUgY2xvbmUgc3RlcCBpZiB0aGlzIGlzIG5vdCBhIHBhdGNoIHRoYXQgdW5sb2Nrc1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICByZWYubG9ja1JlZiAmJlxuICAgICAgICAgICAgICAoIXRoaXMudW5kb1JlZiB8fCAhcmVmLmlzTG9ja1VuZG9uZUJ5KHRoaXMudW5kb1JlZikpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgaWYgKERPTS5pc1VwbG9hZElucHV0KGZyb21FbCkpIHtcbiAgICAgICAgICAgICAgICBET00ubWVyZ2VBdHRycyhmcm9tRWwsIHRvRWwsIHsgaXNJZ25vcmVkOiB0cnVlIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMudHJhY2tCZWZvcmUoXCJ1cGRhdGVkXCIsIGZyb21FbCwgdG9FbCk7XG4gICAgICAgICAgICAgICAgdXBkYXRlcy5wdXNoKGZyb21FbCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgRE9NLmFwcGx5U3RpY2t5T3BlcmF0aW9ucyhmcm9tRWwpO1xuICAgICAgICAgICAgICBjb25zdCBpc0xvY2tlZCA9IGZyb21FbC5oYXNBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLKTtcbiAgICAgICAgICAgICAgY29uc3QgY2xvbmUgPSBpc0xvY2tlZFxuICAgICAgICAgICAgICAgID8gRE9NLnByaXZhdGUoZnJvbUVsLCBQSFhfUkVGX0xPQ0spIHx8IGZyb21FbC5jbG9uZU5vZGUodHJ1ZSlcbiAgICAgICAgICAgICAgICA6IG51bGw7XG4gICAgICAgICAgICAgIGlmIChjbG9uZSkge1xuICAgICAgICAgICAgICAgIERPTS5wdXRQcml2YXRlKGZyb21FbCwgUEhYX1JFRl9MT0NLLCBjbG9uZSk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0ZvY3VzZWRGb3JtRWwpIHtcbiAgICAgICAgICAgICAgICAgIGZyb21FbCA9IGNsb25lO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIG5lc3RlZCB2aWV3IGhhbmRsaW5nXG4gICAgICAgICAgaWYgKERPTS5pc1BoeENoaWxkKHRvRWwpKSB7XG4gICAgICAgICAgICBjb25zdCBwcmV2U2Vzc2lvbiA9IGZyb21FbC5nZXRBdHRyaWJ1dGUoUEhYX1NFU1NJT04pO1xuICAgICAgICAgICAgRE9NLm1lcmdlQXR0cnMoZnJvbUVsLCB0b0VsLCB7IGV4Y2x1ZGU6IFtQSFhfU1RBVElDXSB9KTtcbiAgICAgICAgICAgIGlmIChwcmV2U2Vzc2lvbiAhPT0gXCJcIikge1xuICAgICAgICAgICAgICBmcm9tRWwuc2V0QXR0cmlidXRlKFBIWF9TRVNTSU9OLCBwcmV2U2Vzc2lvbik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmcm9tRWwuc2V0QXR0cmlidXRlKFBIWF9ST09UX0lELCB0aGlzLnJvb3RJRCk7XG4gICAgICAgICAgICBET00uYXBwbHlTdGlja3lPcGVyYXRpb25zKGZyb21FbCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gaWYgd2UgYXJlIHVuZG9pbmcgYSBsb2NrLCBjb3B5IHBvdGVudGlhbGx5IG5lc3RlZCBjbG9uZXMgb3ZlclxuICAgICAgICAgIGlmICh0aGlzLnVuZG9SZWYgJiYgRE9NLnByaXZhdGUodG9FbCwgUEhYX1JFRl9MT0NLKSkge1xuICAgICAgICAgICAgRE9NLnB1dFByaXZhdGUoXG4gICAgICAgICAgICAgIGZyb21FbCxcbiAgICAgICAgICAgICAgUEhYX1JFRl9MT0NLLFxuICAgICAgICAgICAgICBET00ucHJpdmF0ZSh0b0VsLCBQSFhfUkVGX0xPQ0spLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gbm93IGNvcHkgcmVndWxhciBET00ucHJpdmF0ZSBkYXRhXG4gICAgICAgICAgRE9NLmNvcHlQcml2YXRlcyh0b0VsLCBmcm9tRWwpO1xuXG4gICAgICAgICAgLy8gcGh4LXBvcnRhbCBoYW5kbGluZ1xuICAgICAgICAgIGlmIChET00uaXNQb3J0YWxUZW1wbGF0ZSh0b0VsKSkge1xuICAgICAgICAgICAgcG9ydGFsQ2FsbGJhY2tzLnB1c2goKCkgPT4gdGhpcy50ZWxlcG9ydCh0b0VsLCBtb3JwaCkpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIHNraXAgcGF0Y2hpbmcgZm9jdXNlZCBpbnB1dHMgdW5sZXNzIGZvY3VzIGlzIGEgc2VsZWN0IHRoYXQgaGFzIGNoYW5nZWQgb3B0aW9uc1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGlzRm9jdXNlZEZvcm1FbCAmJlxuICAgICAgICAgICAgZnJvbUVsLnR5cGUgIT09IFwiaGlkZGVuXCIgJiZcbiAgICAgICAgICAgICFmb2N1c2VkU2VsZWN0Q2hhbmdlZFxuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy50cmFja0JlZm9yZShcInVwZGF0ZWRcIiwgZnJvbUVsLCB0b0VsKTtcbiAgICAgICAgICAgIERPTS5tZXJnZUZvY3VzZWRJbnB1dChmcm9tRWwsIHRvRWwpO1xuICAgICAgICAgICAgRE9NLnN5bmNBdHRyc1RvUHJvcHMoZnJvbUVsKTtcbiAgICAgICAgICAgIHVwZGF0ZXMucHVzaChmcm9tRWwpO1xuICAgICAgICAgICAgRE9NLmFwcGx5U3RpY2t5T3BlcmF0aW9ucyhmcm9tRWwpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBibHVyIGZvY3VzZWQgc2VsZWN0IGlmIGl0IGNoYW5nZWQgc28gbmF0aXZlIFVJIGlzIHVwZGF0ZWQgKGllIHNhZmFyaSB3b24ndCB1cGRhdGUgdmlzaWJsZSBvcHRpb25zKVxuICAgICAgICAgICAgaWYgKGZvY3VzZWRTZWxlY3RDaGFuZ2VkKSB7XG4gICAgICAgICAgICAgIGZyb21FbC5ibHVyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoRE9NLmlzUGh4VXBkYXRlKHRvRWwsIHBoeFVwZGF0ZSwgW1wiYXBwZW5kXCIsIFwicHJlcGVuZFwiXSkpIHtcbiAgICAgICAgICAgICAgYXBwZW5kUHJlcGVuZFVwZGF0ZXMucHVzaChcbiAgICAgICAgICAgICAgICBuZXcgRE9NUG9zdE1vcnBoUmVzdG9yZXIoXG4gICAgICAgICAgICAgICAgICBmcm9tRWwsXG4gICAgICAgICAgICAgICAgICB0b0VsLFxuICAgICAgICAgICAgICAgICAgdG9FbC5nZXRBdHRyaWJ1dGUocGh4VXBkYXRlKSxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBET00uc3luY0F0dHJzVG9Qcm9wcyh0b0VsKTtcbiAgICAgICAgICAgIERPTS5hcHBseVN0aWNreU9wZXJhdGlvbnModG9FbCk7XG4gICAgICAgICAgICB0aGlzLnRyYWNrQmVmb3JlKFwidXBkYXRlZFwiLCBmcm9tRWwsIHRvRWwpO1xuICAgICAgICAgICAgcmV0dXJuIGZyb21FbDtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICBtb3JwaGRvbSh0YXJnZXRDb250YWluZXIsIHNvdXJjZSwgbW9ycGhDYWxsYmFja3MpO1xuICAgIH07XG5cbiAgICB0aGlzLnRyYWNrQmVmb3JlKFwiYWRkZWRcIiwgY29udGFpbmVyKTtcbiAgICB0aGlzLnRyYWNrQmVmb3JlKFwidXBkYXRlZFwiLCBjb250YWluZXIsIGNvbnRhaW5lcik7XG5cbiAgICBsaXZlU29ja2V0LnRpbWUoXCJtb3JwaGRvbVwiLCAoKSA9PiB7XG4gICAgICB0aGlzLnN0cmVhbXMuZm9yRWFjaCgoW3JlZiwgaW5zZXJ0cywgZGVsZXRlSWRzLCByZXNldF0pID0+IHtcbiAgICAgICAgaW5zZXJ0cy5mb3JFYWNoKChba2V5LCBzdHJlYW1BdCwgbGltaXQsIHVwZGF0ZU9ubHldKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdHJlYW1JbnNlcnRzW2tleV0gPSB7IHJlZiwgc3RyZWFtQXQsIGxpbWl0LCByZXNldCwgdXBkYXRlT25seSB9O1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHJlc2V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBET00uYWxsKGNvbnRhaW5lciwgYFske1BIWF9TVFJFQU1fUkVGfT1cIiR7cmVmfVwiXWAsIChjaGlsZCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGRlbGV0ZUlkcy5mb3JFYWNoKChpZCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGNoaWxkID0gY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoYFtpZD1cIiR7aWR9XCJdYCk7XG4gICAgICAgICAgaWYgKGNoaWxkKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVN0cmVhbUNoaWxkRWxlbWVudChjaGlsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBjbGVhciBzdHJlYW0gaXRlbXMgZnJvbSB0aGUgZGVhZCByZW5kZXIgaWYgdGhleSBhcmUgbm90IGluc2VydGVkIGFnYWluXG4gICAgICBpZiAoaXNKb2luUGF0Y2gpIHtcbiAgICAgICAgRE9NLmFsbCh0aGlzLmNvbnRhaW5lciwgYFske3BoeFVwZGF0ZX09JHtQSFhfU1RSRUFNfV1gKVxuICAgICAgICAgIC8vIGl0IGlzIGltcG9ydGFudCB0byBmaWx0ZXIgdGhlIGVsZW1lbnQgYmVmb3JlIHJlbW92aW5nIHRoZW0sIGFzXG4gICAgICAgICAgLy8gaXQgbWF5IGhhcHBlbiB0aGF0IHN0cmVhbXMgYXJlIG5lc3RlZCBhbmQgdGhlIG93bmVyIGNoZWNrIGZhaWxzIGlmXG4gICAgICAgICAgLy8gYSBwYXJlbnQgaXMgcmVtb3ZlZCBiZWZvcmUgYSBjaGlsZFxuICAgICAgICAgIC5maWx0ZXIoKGVsKSA9PiB0aGlzLnZpZXcub3duc0VsZW1lbnQoZWwpKVxuICAgICAgICAgIC5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICAgICAgQXJyYXkuZnJvbShlbC5jaGlsZHJlbikuZm9yRWFjaCgoY2hpbGQpID0+IHtcbiAgICAgICAgICAgICAgLy8gd2UgYWxyZWFkeSBwZXJmb3JtZWQgdGhlIG93bmVyIGNoZWNrLCBlYWNoIGNoaWxkIGlzIGd1YXJhbnRlZWQgdG8gYmUgb3duZWRcbiAgICAgICAgICAgICAgLy8gYnkgdGhlIHZpZXcuIFRvIHByZXZlbnQgdGhlIG5lc3RlZCBvd25lciBjaGVjayBmcm9tIGZhaWxpbmcgaW4gY2FzZSBvZiBuZXN0ZWRcbiAgICAgICAgICAgICAgLy8gc3RyZWFtcyB3aGVyZSB0aGUgcGFyZW50IGlzIHJlbW92ZWQgYmVmb3JlIHRoZSBjaGlsZCwgd2UgZm9yY2UgdGhlIHJlbW92YWxcbiAgICAgICAgICAgICAgdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQsIHRydWUpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIG1vcnBoKHRhcmdldENvbnRhaW5lciwgaHRtbCk7XG4gICAgICAvLyBub3JtYWwgcGF0Y2ggY29tcGxldGUsIHRlbGVwb3J0IGVsZW1lbnRzIG5vd1xuICAgICAgcG9ydGFsQ2FsbGJhY2tzLmZvckVhY2goKGNhbGxiYWNrKSA9PiBjYWxsYmFjaygpKTtcbiAgICAgIC8vIGNoZWNrIGZvciBhbnkgdGVsZXBvcnRlZCBlbGVtZW50cyB0aGF0IGFyZSBub3QgaW4gdGhlIHZpZXcgYW55IG1vcmVcbiAgICAgIC8vIGFuZCByZW1vdmUgdGhlbVxuICAgICAgdGhpcy52aWV3LnBvcnRhbEVsZW1lbnRJZHMuZm9yRWFjaCgoaWQpID0+IHtcbiAgICAgICAgY29uc3QgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgIGlmIChlbCkge1xuICAgICAgICAgIGNvbnN0IHNvdXJjZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFxuICAgICAgICAgICAgZWwuZ2V0QXR0cmlidXRlKFBIWF9URUxFUE9SVEVEX1NSQyksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoIXNvdXJjZSkge1xuICAgICAgICAgICAgZWwucmVtb3ZlKCk7XG4gICAgICAgICAgICB0aGlzLm9uTm9kZURpc2NhcmRlZChlbCk7XG4gICAgICAgICAgICB0aGlzLnZpZXcuZHJvcFBvcnRhbEVsZW1lbnRJZChpZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGlmIChsaXZlU29ja2V0LmlzRGVidWdFbmFibGVkKCkpIHtcbiAgICAgIGRldGVjdER1cGxpY2F0ZUlkcygpO1xuICAgICAgZGV0ZWN0SW52YWxpZFN0cmVhbUluc2VydHModGhpcy5zdHJlYW1JbnNlcnRzKTtcbiAgICAgIC8vIHdhcm4gaWYgdGhlcmUgYXJlIGFueSBpbnB1dHMgbmFtZWQgXCJpZFwiXG4gICAgICBBcnJheS5mcm9tKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCJpbnB1dFtuYW1lPWlkXVwiKSkuZm9yRWFjaChcbiAgICAgICAgKG5vZGUpID0+IHtcbiAgICAgICAgICBpZiAobm9kZSBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgbm9kZS5mb3JtKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAnRGV0ZWN0ZWQgYW4gaW5wdXQgd2l0aCBuYW1lPVwiaWRcIiBpbnNpZGUgYSBmb3JtISBUaGlzIHdpbGwgY2F1c2UgcHJvYmxlbXMgd2hlbiBwYXRjaGluZyB0aGUgRE9NLlxcbicsXG4gICAgICAgICAgICAgIG5vZGUsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGFwcGVuZFByZXBlbmRVcGRhdGVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpdmVTb2NrZXQudGltZShcInBvc3QtbW9ycGggYXBwZW5kL3ByZXBlbmQgcmVzdG9yYXRpb25cIiwgKCkgPT4ge1xuICAgICAgICBhcHBlbmRQcmVwZW5kVXBkYXRlcy5mb3JFYWNoKCh1cGRhdGUpID0+IHVwZGF0ZS5wZXJmb3JtKCkpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgbGl2ZVNvY2tldC5zaWxlbmNlRXZlbnRzKCgpID0+XG4gICAgICBET00ucmVzdG9yZUZvY3VzKGZvY3VzZWQsIHNlbGVjdGlvblN0YXJ0LCBzZWxlY3Rpb25FbmQpLFxuICAgICk7XG4gICAgRE9NLmRpc3BhdGNoRXZlbnQoZG9jdW1lbnQsIFwicGh4OnVwZGF0ZVwiKTtcbiAgICBhZGRlZC5mb3JFYWNoKChlbCkgPT4gdGhpcy50cmFja0FmdGVyKFwiYWRkZWRcIiwgZWwpKTtcbiAgICB1cGRhdGVzLmZvckVhY2goKGVsKSA9PiB0aGlzLnRyYWNrQWZ0ZXIoXCJ1cGRhdGVkXCIsIGVsKSk7XG5cbiAgICB0aGlzLnRyYW5zaXRpb25QZW5kaW5nUmVtb3ZlcygpO1xuXG4gICAgaWYgKGV4dGVybmFsRm9ybVRyaWdnZXJlZCkge1xuICAgICAgbGl2ZVNvY2tldC51bmxvYWQoKTtcbiAgICAgIC8vIGNoZWNrIGZvciBzdWJtaXR0ZXIgYW5kIGluamVjdCBpdCBhcyBoaWRkZW4gaW5wdXQgZm9yIGV4dGVybmFsIHN1Ym1pdDtcbiAgICAgIC8vIEluIHRoZW9yeSwgaXQgY291bGQgaGFwcGVuIHRoYXQgdGhlIHN0b3JlZCBzdWJtaXR0ZXIgaXMgb3V0ZGF0ZWQgYW5kIGRvZXNuJ3RcbiAgICAgIC8vIGV4aXN0IGluIHRoZSBET00gYW55IG1vcmUsIGJ1dCB0aGlzIGlzIHVubGlrZWx5LCBzbyB3ZSBqdXN0IGFjY2VwdCBpdCBmb3Igbm93LlxuICAgICAgY29uc3Qgc3VibWl0dGVyID0gRE9NLnByaXZhdGUoZXh0ZXJuYWxGb3JtVHJpZ2dlcmVkLCBcInN1Ym1pdHRlclwiKTtcbiAgICAgIGlmIChzdWJtaXR0ZXIgJiYgc3VibWl0dGVyLm5hbWUgJiYgdGFyZ2V0Q29udGFpbmVyLmNvbnRhaW5zKHN1Ym1pdHRlcikpIHtcbiAgICAgICAgY29uc3QgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIik7XG4gICAgICAgIGlucHV0LnR5cGUgPSBcImhpZGRlblwiO1xuICAgICAgICBjb25zdCBmb3JtSWQgPSBzdWJtaXR0ZXIuZ2V0QXR0cmlidXRlKFwiZm9ybVwiKTtcbiAgICAgICAgaWYgKGZvcm1JZCkge1xuICAgICAgICAgIGlucHV0LnNldEF0dHJpYnV0ZShcImZvcm1cIiwgZm9ybUlkKTtcbiAgICAgICAgfVxuICAgICAgICBpbnB1dC5uYW1lID0gc3VibWl0dGVyLm5hbWU7XG4gICAgICAgIGlucHV0LnZhbHVlID0gc3VibWl0dGVyLnZhbHVlO1xuICAgICAgICBzdWJtaXR0ZXIucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUoaW5wdXQsIHN1Ym1pdHRlcik7XG4gICAgICB9XG4gICAgICAvLyB1c2UgcHJvdG90eXBlJ3Mgc3VibWl0IGluIGNhc2UgdGhlcmUncyBhIGZvcm0gY29udHJvbCB3aXRoIG5hbWUgb3IgaWQgb2YgXCJzdWJtaXRcIlxuICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0hUTUxGb3JtRWxlbWVudC9zdWJtaXRcbiAgICAgIE9iamVjdC5nZXRQcm90b3R5cGVPZihleHRlcm5hbEZvcm1UcmlnZ2VyZWQpLnN1Ym1pdC5jYWxsKFxuICAgICAgICBleHRlcm5hbEZvcm1UcmlnZ2VyZWQsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIG9uTm9kZURpc2NhcmRlZChlbCkge1xuICAgIC8vIG5lc3RlZCB2aWV3IGhhbmRsaW5nXG4gICAgaWYgKERPTS5pc1BoeENoaWxkKGVsKSB8fCBET00uaXNQaHhTdGlja3koZWwpKSB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQuZGVzdHJveVZpZXdCeUVsKGVsKTtcbiAgICB9XG4gICAgdGhpcy50cmFja0FmdGVyKFwiZGlzY2FyZGVkXCIsIGVsKTtcbiAgfVxuXG4gIG1heWJlUGVuZGluZ1JlbW92ZShub2RlKSB7XG4gICAgaWYgKG5vZGUuZ2V0QXR0cmlidXRlICYmIG5vZGUuZ2V0QXR0cmlidXRlKHRoaXMucGh4UmVtb3ZlKSAhPT0gbnVsbCkge1xuICAgICAgdGhpcy5wZW5kaW5nUmVtb3Zlcy5wdXNoKG5vZGUpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICByZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQsIGZvcmNlID0gZmFsc2UpIHtcbiAgICAvLyBtYWtlIHN1cmUgdG8gb25seSByZW1vdmUgZWxlbWVudHMgb3duZWQgYnkgdGhlIGN1cnJlbnQgdmlld1xuICAgIC8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMzA0N1xuICAgIC8vIGFuZCBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMzY4MVxuICAgIGlmICghZm9yY2UgJiYgIXRoaXMudmlldy5vd25zRWxlbWVudChjaGlsZCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyB3ZSBuZWVkIHRvIHN0b3JlIHRoZSBub2RlIGlmIGl0IGlzIGFjdHVhbGx5IHJlLWFkZGVkIGluIHRoZSBzYW1lIHBhdGNoXG4gICAgLy8gd2UgZG8gTk9UIHdhbnQgdG8gZXhlY3V0ZSBwaHgtcmVtb3ZlLCB3ZSBkbyBOT1Qgd2FudCB0byBjYWxsIG9uTm9kZURpc2NhcmRlZFxuICAgIGlmICh0aGlzLnN0cmVhbUluc2VydHNbY2hpbGQuaWRdKSB7XG4gICAgICB0aGlzLnN0cmVhbUNvbXBvbmVudFJlc3RvcmVbY2hpbGQuaWRdID0gY2hpbGQ7XG4gICAgICBjaGlsZC5yZW1vdmUoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gb25seSByZW1vdmUgdGhlIGVsZW1lbnQgbm93IGlmIGl0IGhhcyBubyBwaHgtcmVtb3ZlIGJpbmRpbmdcbiAgICAgIGlmICghdGhpcy5tYXliZVBlbmRpbmdSZW1vdmUoY2hpbGQpKSB7XG4gICAgICAgIGNoaWxkLnJlbW92ZSgpO1xuICAgICAgICB0aGlzLm9uTm9kZURpc2NhcmRlZChjaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0U3RyZWFtSW5zZXJ0KGVsKSB7XG4gICAgY29uc3QgaW5zZXJ0ID0gZWwuaWQgPyB0aGlzLnN0cmVhbUluc2VydHNbZWwuaWRdIDoge307XG4gICAgcmV0dXJuIGluc2VydCB8fCB7fTtcbiAgfVxuXG4gIHNldFN0cmVhbVJlZihlbCwgcmVmKSB7XG4gICAgRE9NLnB1dFN0aWNreShlbCwgUEhYX1NUUkVBTV9SRUYsIChlbCkgPT5cbiAgICAgIGVsLnNldEF0dHJpYnV0ZShQSFhfU1RSRUFNX1JFRiwgcmVmKSxcbiAgICApO1xuICB9XG5cbiAgbWF5YmVSZU9yZGVyU3RyZWFtKGVsLCBpc05ldykge1xuICAgIGNvbnN0IHsgcmVmLCBzdHJlYW1BdCwgcmVzZXQgfSA9IHRoaXMuZ2V0U3RyZWFtSW5zZXJ0KGVsKTtcbiAgICBpZiAoc3RyZWFtQXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHdlIG5lZWQgdG8gc2V0IHRoZSBQSFhfU1RSRUFNX1JFRiBoZXJlIGFzIHdlbGwgYXMgYWRkQ2hpbGQgaXMgaW52b2tlZCBvbmx5IGZvciBwYXJlbnRzXG4gICAgdGhpcy5zZXRTdHJlYW1SZWYoZWwsIHJlZik7XG5cbiAgICBpZiAoIXJlc2V0ICYmICFpc05ldykge1xuICAgICAgLy8gd2Ugb25seSByZW9yZGVyIGlmIHRoZSBlbGVtZW50IGlzIG5ldyBvciBpdCdzIGEgc3RyZWFtIHJlc2V0XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gY2hlY2sgaWYgdGhlIGVsZW1lbnQgaGFzIGEgcGFyZW50IGVsZW1lbnQ7XG4gICAgLy8gaXQgZG9lc24ndCBpZiB3ZSBhcmUgY3VycmVudGx5IHJlY3Vyc2l2ZWx5IG1vcnBoaW5nIChyZXN0b3JpbmcgYSBzYXZlZCBzdHJlYW0gY2hpbGQpXG4gICAgLy8gYmVjYXVzZSB0aGUgZWxlbWVudCBpcyBub3QgeWV0IGFkZGVkIHRvIHRoZSByZWFsIGRvbTtcbiAgICAvLyByZW9yZGVyaW5nIGRvZXMgbm90IG1ha2Ugc2Vuc2UgaW4gdGhhdCBjYXNlIGFueXdheVxuICAgIGlmICghZWwucGFyZW50RWxlbWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzdHJlYW1BdCA9PT0gMCkge1xuICAgICAgZWwucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUoZWwsIGVsLnBhcmVudEVsZW1lbnQuZmlyc3RFbGVtZW50Q2hpbGQpO1xuICAgIH0gZWxzZSBpZiAoc3RyZWFtQXQgPiAwKSB7XG4gICAgICBjb25zdCBjaGlsZHJlbiA9IEFycmF5LmZyb20oZWwucGFyZW50RWxlbWVudC5jaGlsZHJlbik7XG4gICAgICBjb25zdCBvbGRJbmRleCA9IGNoaWxkcmVuLmluZGV4T2YoZWwpO1xuICAgICAgaWYgKHN0cmVhbUF0ID49IGNoaWxkcmVuLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgZWwucGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZChlbCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBzaWJsaW5nID0gY2hpbGRyZW5bc3RyZWFtQXRdO1xuICAgICAgICBpZiAob2xkSW5kZXggPiBzdHJlYW1BdCkge1xuICAgICAgICAgIGVsLnBhcmVudEVsZW1lbnQuaW5zZXJ0QmVmb3JlKGVsLCBzaWJsaW5nKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlbC5wYXJlbnRFbGVtZW50Lmluc2VydEJlZm9yZShlbCwgc2libGluZy5uZXh0RWxlbWVudFNpYmxpbmcpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5tYXliZUxpbWl0U3RyZWFtKGVsKTtcbiAgfVxuXG4gIG1heWJlTGltaXRTdHJlYW0oZWwpIHtcbiAgICBjb25zdCB7IGxpbWl0IH0gPSB0aGlzLmdldFN0cmVhbUluc2VydChlbCk7XG4gICAgY29uc3QgY2hpbGRyZW4gPSBsaW1pdCAhPT0gbnVsbCAmJiBBcnJheS5mcm9tKGVsLnBhcmVudEVsZW1lbnQuY2hpbGRyZW4pO1xuICAgIGlmIChsaW1pdCAmJiBsaW1pdCA8IDAgJiYgY2hpbGRyZW4ubGVuZ3RoID4gbGltaXQgKiAtMSkge1xuICAgICAgY2hpbGRyZW5cbiAgICAgICAgLnNsaWNlKDAsIGNoaWxkcmVuLmxlbmd0aCArIGxpbWl0KVxuICAgICAgICAuZm9yRWFjaCgoY2hpbGQpID0+IHRoaXMucmVtb3ZlU3RyZWFtQ2hpbGRFbGVtZW50KGNoaWxkKSk7XG4gICAgfSBlbHNlIGlmIChsaW1pdCAmJiBsaW1pdCA+PSAwICYmIGNoaWxkcmVuLmxlbmd0aCA+IGxpbWl0KSB7XG4gICAgICBjaGlsZHJlblxuICAgICAgICAuc2xpY2UobGltaXQpXG4gICAgICAgIC5mb3JFYWNoKChjaGlsZCkgPT4gdGhpcy5yZW1vdmVTdHJlYW1DaGlsZEVsZW1lbnQoY2hpbGQpKTtcbiAgICB9XG4gIH1cblxuICB0cmFuc2l0aW9uUGVuZGluZ1JlbW92ZXMoKSB7XG4gICAgY29uc3QgeyBwZW5kaW5nUmVtb3ZlcywgbGl2ZVNvY2tldCB9ID0gdGhpcztcbiAgICBpZiAocGVuZGluZ1JlbW92ZXMubGVuZ3RoID4gMCkge1xuICAgICAgbGl2ZVNvY2tldC50cmFuc2l0aW9uUmVtb3ZlcyhwZW5kaW5nUmVtb3ZlcywgKCkgPT4ge1xuICAgICAgICBwZW5kaW5nUmVtb3Zlcy5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGNoaWxkID0gRE9NLmZpcnN0UGh4Q2hpbGQoZWwpO1xuICAgICAgICAgIGlmIChjaGlsZCkge1xuICAgICAgICAgICAgbGl2ZVNvY2tldC5kZXN0cm95Vmlld0J5RWwoY2hpbGQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlbC5yZW1vdmUoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudHJhY2tBZnRlcihcInRyYW5zaXRpb25zRGlzY2FyZGVkXCIsIHBlbmRpbmdSZW1vdmVzKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlzQ2hhbmdlZFNlbGVjdChmcm9tRWwsIHRvRWwpIHtcbiAgICBpZiAoIShmcm9tRWwgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkgfHwgZnJvbUVsLm11bHRpcGxlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChmcm9tRWwub3B0aW9ucy5sZW5ndGggIT09IHRvRWwub3B0aW9ucy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIGtlZXAgdGhlIGN1cnJlbnQgdmFsdWVcbiAgICB0b0VsLnZhbHVlID0gZnJvbUVsLnZhbHVlO1xuXG4gICAgLy8gaW4gZ2VuZXJhbCB3ZSBoYXZlIHRvIGJlIHZlcnkgY2FyZWZ1bCB3aXRoIHVzaW5nIGlzRXF1YWxOb2RlIGFzIGl0IGRvZXMgbm90IGEgcmVsaWFibGVcbiAgICAvLyBET00gdHJlZSBlcXVhbGl0eSBjaGVjaywgYnV0IGZvciBzZWxlY3Rpb24gYXR0cmlidXRlcyBhbmQgb3B0aW9ucyBpdCB3b3JrcyBmaW5lXG4gICAgcmV0dXJuICFmcm9tRWwuaXNFcXVhbE5vZGUodG9FbCk7XG4gIH1cblxuICBpc0NJRFBhdGNoKCkge1xuICAgIHJldHVybiB0aGlzLmNpZFBhdGNoO1xuICB9XG5cbiAgc2tpcENJRFNpYmxpbmcoZWwpIHtcbiAgICByZXR1cm4gZWwubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmIGVsLmhhc0F0dHJpYnV0ZShQSFhfU0tJUCk7XG4gIH1cblxuICB0YXJnZXRDSURDb250YWluZXIoaHRtbCkge1xuICAgIGlmICghdGhpcy5pc0NJRFBhdGNoKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW2ZpcnN0LCAuLi5yZXN0XSA9IERPTS5maW5kQ29tcG9uZW50Tm9kZUxpc3QoXG4gICAgICB0aGlzLnZpZXcuaWQsXG4gICAgICB0aGlzLnRhcmdldENJRCxcbiAgICApO1xuICAgIGlmIChyZXN0Lmxlbmd0aCA9PT0gMCAmJiBET00uY2hpbGROb2RlTGVuZ3RoKGh0bWwpID09PSAxKSB7XG4gICAgICByZXR1cm4gZmlyc3Q7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmaXJzdCAmJiBmaXJzdC5wYXJlbnROb2RlO1xuICAgIH1cbiAgfVxuXG4gIGluZGV4T2YocGFyZW50LCBjaGlsZCkge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHBhcmVudC5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XG4gIH1cblxuICB0ZWxlcG9ydChlbCwgbW9ycGgpIHtcbiAgICBjb25zdCB0YXJnZXRTZWxlY3RvciA9IGVsLmdldEF0dHJpYnV0ZShQSFhfUE9SVEFMKTtcbiAgICBjb25zdCBwb3J0YWxDb250YWluZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRhcmdldFNlbGVjdG9yKTtcbiAgICBpZiAoIXBvcnRhbENvbnRhaW5lcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcInBvcnRhbCB0YXJnZXQgd2l0aCBzZWxlY3RvciBcIiArIHRhcmdldFNlbGVjdG9yICsgXCIgbm90IGZvdW5kXCIsXG4gICAgICApO1xuICAgIH1cbiAgICAvLyBwaHgtcG9ydGFsIHRlbXBsYXRlcyBtdXN0IGhhdmUgYSBzaW5nbGUgcm9vdCBlbGVtZW50LCBzbyB3ZSBhc3N1bWUgdGhpcyB0byBiZVxuICAgIC8vIHRoZSBjYXNlIGhlcmVcbiAgICBjb25zdCB0b1RlbGVwb3J0ID0gZWwuY29udGVudC5maXJzdEVsZW1lbnRDaGlsZDtcbiAgICAvLyB0aGUgUEhYX1NLSVAgb3B0aW1pemF0aW9uIGNhbiBhbHNvIGFwcGx5IGluc2lkZSBvZiB0aGUgPHRlbXBsYXRlPiBlbGVtZW50c1xuICAgIGlmICh0aGlzLnNraXBDSURTaWJsaW5nKHRvVGVsZXBvcnQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdG9UZWxlcG9ydD8uaWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJwaHgtcG9ydGFsIHRlbXBsYXRlIG11c3QgaGF2ZSBhIHNpbmdsZSByb290IGVsZW1lbnQgd2l0aCBJRCFcIixcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodG9UZWxlcG9ydC5pZCk7XG4gICAgbGV0IHBvcnRhbFRhcmdldDtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIC8vIGNoZWNrIGlmIHRoZSBlbGVtZW50IG5lZWRzIHRvIGJlIG1vdmVkIHRvIGFub3RoZXIgdGFyZ2V0XG4gICAgICBpZiAoIXBvcnRhbENvbnRhaW5lci5jb250YWlucyhleGlzdGluZykpIHtcbiAgICAgICAgcG9ydGFsQ29udGFpbmVyLmFwcGVuZENoaWxkKGV4aXN0aW5nKTtcbiAgICAgIH1cbiAgICAgIC8vIHdlIGFscmVhZHkgdGVsZXBvcnRlZCBpbiBhIHByZXZpb3VzIHBhdGNoXG4gICAgICBwb3J0YWxUYXJnZXQgPSBleGlzdGluZztcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY3JlYXRlIGVtcHR5IHRhcmdldCBhbmQgbW9ycGggaXQgcmVjdXJzaXZlbHlcbiAgICAgIHBvcnRhbFRhcmdldCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodG9UZWxlcG9ydC50YWdOYW1lKTtcbiAgICAgIHBvcnRhbENvbnRhaW5lci5hcHBlbmRDaGlsZChwb3J0YWxUYXJnZXQpO1xuICAgIH1cbiAgICAvLyBtYXJrIHRoZSB0YXJnZXQgYXMgdGVsZXBvcnRlZDtcbiAgICAvLyB0byBwcmV2ZW50IHVubmVjZXNzYXJ5IGF0dHJpYnV0ZSBtb2RpZmljYXRpb25zLCB3ZSBzZXQgdGhlIGF0dHJpYnV0ZVxuICAgIC8vIG9uIHRoZSBzb3VyY2UgYW5kIHJlbW92ZSBpdCBhZnRlciBtb3JwaGluZyAod2UgY291bGQgYWxzbyBqdXN0IGtlZXAgaXQpXG4gICAgLy8gb3RoZXJ3aXNlIG1vcnBoZG9tIHdvdWxkIHJlbW92ZSBpdCwgYXMgdGhlIHJlZiBpcyBub3QgcHJlc2VudCBpbiB0aGUgc291cmNlXG4gICAgLy8gYW5kIHdlJ2QgbmVlZCB0byBzZXQgaXQgYmFjayBhZnRlciBlYWNoIG1vcnBoXG4gICAgdG9UZWxlcG9ydC5zZXRBdHRyaWJ1dGUoUEhYX1RFTEVQT1JURURfUkVGLCB0aGlzLnZpZXcuaWQpO1xuICAgIHRvVGVsZXBvcnQuc2V0QXR0cmlidXRlKFBIWF9URUxFUE9SVEVEX1NSQywgZWwuaWQpO1xuICAgIG1vcnBoKHBvcnRhbFRhcmdldCwgdG9UZWxlcG9ydCwgdHJ1ZSk7XG4gICAgdG9UZWxlcG9ydC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1RFTEVQT1JURURfUkVGKTtcbiAgICB0b1RlbGVwb3J0LnJlbW92ZUF0dHJpYnV0ZShQSFhfVEVMRVBPUlRFRF9TUkMpO1xuICAgIC8vIHN0b3JlIGEgcmVmZXJlbmNlIHRvIHRoZSB0ZWxlcG9ydGVkIGVsZW1lbnQgaW4gdGhlIHZpZXdcbiAgICAvLyB0byBjbGVhbnVwIHdoZW4gdGhlIHZpZXcgaXMgZGVzdHJveWVkLCBpbiBjYXNlIHRoZSBwb3J0YWwgdGFyZ2V0XG4gICAgLy8gaXMgb3V0c2lkZSB0aGUgdmlldyBpdHNlbGZcbiAgICB0aGlzLnZpZXcucHVzaFBvcnRhbEVsZW1lbnRJZCh0b1RlbGVwb3J0LmlkKTtcbiAgfVxuXG4gIGhhbmRsZVJ1bnRpbWVIb29rKGVsLCBzb3VyY2UpIHtcbiAgICAvLyB1c3VhbGx5LCBzY3JpcHRzIGFyZSBub3QgZXhlY3V0ZWQgd2hlbiBtb3JwaGRvbSBhZGRzIHRoZW0gdG8gdGhlIERPTVxuICAgIC8vIHdlIHNwZWNpYWwgY2FzZSBydW50aW1lIGNvbG9jYXRlZCBob29rc1xuICAgIGNvbnN0IG5hbWUgPSBlbC5nZXRBdHRyaWJ1dGUoUEhYX1JVTlRJTUVfSE9PSyk7XG4gICAgbGV0IG5vbmNlID0gZWwuaGFzQXR0cmlidXRlKFwibm9uY2VcIikgPyBlbC5nZXRBdHRyaWJ1dGUoXCJub25jZVwiKSA6IG51bGw7XG4gICAgaWYgKGVsLmhhc0F0dHJpYnV0ZShcIm5vbmNlXCIpKSB7XG4gICAgICBjb25zdCB0ZW1wbGF0ZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0ZW1wbGF0ZVwiKTtcbiAgICAgIHRlbXBsYXRlLmlubmVySFRNTCA9IHNvdXJjZTtcbiAgICAgIG5vbmNlID0gdGVtcGxhdGUuY29udGVudFxuICAgICAgICAucXVlcnlTZWxlY3Rvcihgc2NyaXB0WyR7UEhYX1JVTlRJTUVfSE9PS309XCIke0NTUy5lc2NhcGUobmFtZSl9XCJdYClcbiAgICAgICAgLmdldEF0dHJpYnV0ZShcIm5vbmNlXCIpO1xuICAgIH1cbiAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic2NyaXB0XCIpO1xuICAgIHNjcmlwdC50ZXh0Q29udGVudCA9IGVsLnRleHRDb250ZW50O1xuICAgIERPTS5tZXJnZUF0dHJzKHNjcmlwdCwgZWwsIHsgaXNJZ25vcmVkOiBmYWxzZSB9KTtcbiAgICBpZiAobm9uY2UpIHtcbiAgICAgIHNjcmlwdC5ub25jZSA9IG5vbmNlO1xuICAgIH1cbiAgICBlbC5yZXBsYWNlV2l0aChzY3JpcHQpO1xuICAgIGVsID0gc2NyaXB0O1xuICB9XG59XG4iLCAiaW1wb3J0IHtcbiAgQ09NUE9ORU5UUyxcbiAgVEVNUExBVEVTLFxuICBFVkVOVFMsXG4gIFBIWF9DT01QT05FTlQsXG4gIFBIWF9WSUVXX1JFRixcbiAgUEhYX1NLSVAsXG4gIFBIWF9NQUdJQ19JRCxcbiAgUkVQTFksXG4gIFNUQVRJQyxcbiAgVElUTEUsXG4gIFNUUkVBTSxcbiAgUk9PVCxcbiAgS0VZRUQsXG4gIEtFWUVEX0NPVU5ULFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuaW1wb3J0IHsgaXNPYmplY3QsIGxvZ0Vycm9yLCBpc0NpZCB9IGZyb20gXCIuL3V0aWxzXCI7XG5cbmNvbnN0IFZPSURfVEFHUyA9IG5ldyBTZXQoW1xuICBcImFyZWFcIixcbiAgXCJiYXNlXCIsXG4gIFwiYnJcIixcbiAgXCJjb2xcIixcbiAgXCJjb21tYW5kXCIsXG4gIFwiZW1iZWRcIixcbiAgXCJoclwiLFxuICBcImltZ1wiLFxuICBcImlucHV0XCIsXG4gIFwia2V5Z2VuXCIsXG4gIFwibGlua1wiLFxuICBcIm1ldGFcIixcbiAgXCJwYXJhbVwiLFxuICBcInNvdXJjZVwiLFxuICBcInRyYWNrXCIsXG4gIFwid2JyXCIsXG5dKTtcbmNvbnN0IHF1b3RlQ2hhcnMgPSBuZXcgU2V0KFtcIidcIiwgJ1wiJ10pO1xuXG5leHBvcnQgY29uc3QgbW9kaWZ5Um9vdCA9IChodG1sLCBhdHRycywgY2xlYXJJbm5lckhUTUwpID0+IHtcbiAgbGV0IGkgPSAwO1xuICBsZXQgaW5zaWRlQ29tbWVudCA9IGZhbHNlO1xuICBsZXQgYmVmb3JlVGFnLCBhZnRlclRhZywgdGFnLCB0YWdOYW1lRW5kc0F0LCBpZCwgbmV3SFRNTDtcblxuICBjb25zdCBsb29rYWhlYWQgPSBodG1sLm1hdGNoKC9eKFxccyooPzo8IS0tLio/LS0+XFxzKikqKTwoW15cXHNcXC8+XSspLyk7XG4gIGlmIChsb29rYWhlYWQgPT09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYG1hbGZvcm1lZCBodG1sICR7aHRtbH1gKTtcbiAgfVxuXG4gIGkgPSBsb29rYWhlYWRbMF0ubGVuZ3RoO1xuICBiZWZvcmVUYWcgPSBsb29rYWhlYWRbMV07XG4gIHRhZyA9IGxvb2thaGVhZFsyXTtcbiAgdGFnTmFtZUVuZHNBdCA9IGk7XG5cbiAgLy8gU2NhbiB0aGUgb3BlbmluZyB0YWcgZm9yIGlkLCBpZiB0aGVyZSBpcyBhbnlcbiAgZm9yIChpOyBpIDwgaHRtbC5sZW5ndGg7IGkrKykge1xuICAgIGlmIChodG1sLmNoYXJBdChpKSA9PT0gXCI+XCIpIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBpZiAoaHRtbC5jaGFyQXQoaSkgPT09IFwiPVwiKSB7XG4gICAgICBjb25zdCBpc0lkID0gaHRtbC5zbGljZShpIC0gMywgaSkgPT09IFwiIGlkXCI7XG4gICAgICBpKys7XG4gICAgICBjb25zdCBjaGFyID0gaHRtbC5jaGFyQXQoaSk7XG4gICAgICBpZiAocXVvdGVDaGFycy5oYXMoY2hhcikpIHtcbiAgICAgICAgY29uc3QgYXR0clN0YXJ0c0F0ID0gaTtcbiAgICAgICAgaSsrO1xuICAgICAgICBmb3IgKGk7IGkgPCBodG1sLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaWYgKGh0bWwuY2hhckF0KGkpID09PSBjaGFyKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzSWQpIHtcbiAgICAgICAgICBpZCA9IGh0bWwuc2xpY2UoYXR0clN0YXJ0c0F0ICsgMSwgaSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBsZXQgY2xvc2VBdCA9IGh0bWwubGVuZ3RoIC0gMTtcbiAgaW5zaWRlQ29tbWVudCA9IGZhbHNlO1xuICB3aGlsZSAoY2xvc2VBdCA+PSBiZWZvcmVUYWcubGVuZ3RoICsgdGFnLmxlbmd0aCkge1xuICAgIGNvbnN0IGNoYXIgPSBodG1sLmNoYXJBdChjbG9zZUF0KTtcbiAgICBpZiAoaW5zaWRlQ29tbWVudCkge1xuICAgICAgaWYgKGNoYXIgPT09IFwiLVwiICYmIGh0bWwuc2xpY2UoY2xvc2VBdCAtIDMsIGNsb3NlQXQpID09PSBcIjwhLVwiKSB7XG4gICAgICAgIGluc2lkZUNvbW1lbnQgPSBmYWxzZTtcbiAgICAgICAgY2xvc2VBdCAtPSA0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2xvc2VBdCAtPSAxO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoY2hhciA9PT0gXCI+XCIgJiYgaHRtbC5zbGljZShjbG9zZUF0IC0gMiwgY2xvc2VBdCkgPT09IFwiLS1cIikge1xuICAgICAgaW5zaWRlQ29tbWVudCA9IHRydWU7XG4gICAgICBjbG9zZUF0IC09IDM7XG4gICAgfSBlbHNlIGlmIChjaGFyID09PSBcIj5cIikge1xuICAgICAgYnJlYWs7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNsb3NlQXQgLT0gMTtcbiAgICB9XG4gIH1cbiAgYWZ0ZXJUYWcgPSBodG1sLnNsaWNlKGNsb3NlQXQgKyAxLCBodG1sLmxlbmd0aCk7XG5cbiAgY29uc3QgYXR0cnNTdHIgPSBPYmplY3Qua2V5cyhhdHRycylcbiAgICAubWFwKChhdHRyKSA9PiAoYXR0cnNbYXR0cl0gPT09IHRydWUgPyBhdHRyIDogYCR7YXR0cn09XCIke2F0dHJzW2F0dHJdfVwiYCkpXG4gICAgLmpvaW4oXCIgXCIpO1xuXG4gIGlmIChjbGVhcklubmVySFRNTCkge1xuICAgIC8vIEtlZXAgdGhlIGlkIGlmIGFueVxuICAgIGNvbnN0IGlkQXR0clN0ciA9IGlkID8gYCBpZD1cIiR7aWR9XCJgIDogXCJcIjtcbiAgICBpZiAoVk9JRF9UQUdTLmhhcyh0YWcpKSB7XG4gICAgICBuZXdIVE1MID0gYDwke3RhZ30ke2lkQXR0clN0cn0ke2F0dHJzU3RyID09PSBcIlwiID8gXCJcIiA6IFwiIFwifSR7YXR0cnNTdHJ9Lz5gO1xuICAgIH0gZWxzZSB7XG4gICAgICBuZXdIVE1MID0gYDwke3RhZ30ke2lkQXR0clN0cn0ke2F0dHJzU3RyID09PSBcIlwiID8gXCJcIiA6IFwiIFwifSR7YXR0cnNTdHJ9PjwvJHt0YWd9PmA7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGNvbnN0IHJlc3QgPSBodG1sLnNsaWNlKHRhZ05hbWVFbmRzQXQsIGNsb3NlQXQgKyAxKTtcbiAgICBuZXdIVE1MID0gYDwke3RhZ30ke2F0dHJzU3RyID09PSBcIlwiID8gXCJcIiA6IFwiIFwifSR7YXR0cnNTdHJ9JHtyZXN0fWA7XG4gIH1cblxuICByZXR1cm4gW25ld0hUTUwsIGJlZm9yZVRhZywgYWZ0ZXJUYWddO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUmVuZGVyZWQge1xuICBzdGF0aWMgZXh0cmFjdChkaWZmKSB7XG4gICAgY29uc3QgeyBbUkVQTFldOiByZXBseSwgW0VWRU5UU106IGV2ZW50cywgW1RJVExFXTogdGl0bGUgfSA9IGRpZmY7XG4gICAgZGVsZXRlIGRpZmZbUkVQTFldO1xuICAgIGRlbGV0ZSBkaWZmW0VWRU5UU107XG4gICAgZGVsZXRlIGRpZmZbVElUTEVdO1xuICAgIHJldHVybiB7IGRpZmYsIHRpdGxlLCByZXBseTogcmVwbHkgfHwgbnVsbCwgZXZlbnRzOiBldmVudHMgfHwgW10gfTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHZpZXdJZCwgcmVuZGVyZWQpIHtcbiAgICB0aGlzLnZpZXdJZCA9IHZpZXdJZDtcbiAgICB0aGlzLnJlbmRlcmVkID0ge307XG4gICAgdGhpcy5tYWdpY0lkID0gMDtcbiAgICB0aGlzLm1lcmdlRGlmZihyZW5kZXJlZCk7XG4gIH1cblxuICBwYXJlbnRWaWV3SWQoKSB7XG4gICAgcmV0dXJuIHRoaXMudmlld0lkO1xuICB9XG5cbiAgdG9TdHJpbmcob25seUNpZHMpIHtcbiAgICBjb25zdCB7IGJ1ZmZlcjogc3RyLCBzdHJlYW1zOiBzdHJlYW1zIH0gPSB0aGlzLnJlY3Vyc2l2ZVRvU3RyaW5nKFxuICAgICAgdGhpcy5yZW5kZXJlZCxcbiAgICAgIHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU10sXG4gICAgICBvbmx5Q2lkcyxcbiAgICAgIHRydWUsXG4gICAgICB7fSxcbiAgICApO1xuICAgIHJldHVybiB7IGJ1ZmZlcjogc3RyLCBzdHJlYW1zOiBzdHJlYW1zIH07XG4gIH1cblxuICByZWN1cnNpdmVUb1N0cmluZyhcbiAgICByZW5kZXJlZCxcbiAgICBjb21wb25lbnRzID0gcmVuZGVyZWRbQ09NUE9ORU5UU10sXG4gICAgb25seUNpZHMsXG4gICAgY2hhbmdlVHJhY2tpbmcsXG4gICAgcm9vdEF0dHJzLFxuICApIHtcbiAgICBvbmx5Q2lkcyA9IG9ubHlDaWRzID8gbmV3IFNldChvbmx5Q2lkcykgOiBudWxsO1xuICAgIGNvbnN0IG91dHB1dCA9IHtcbiAgICAgIGJ1ZmZlcjogXCJcIixcbiAgICAgIGNvbXBvbmVudHM6IGNvbXBvbmVudHMsXG4gICAgICBvbmx5Q2lkczogb25seUNpZHMsXG4gICAgICBzdHJlYW1zOiBuZXcgU2V0KCksXG4gICAgfTtcbiAgICB0aGlzLnRvT3V0cHV0QnVmZmVyKHJlbmRlcmVkLCBudWxsLCBvdXRwdXQsIGNoYW5nZVRyYWNraW5nLCByb290QXR0cnMpO1xuICAgIHJldHVybiB7IGJ1ZmZlcjogb3V0cHV0LmJ1ZmZlciwgc3RyZWFtczogb3V0cHV0LnN0cmVhbXMgfTtcbiAgfVxuXG4gIGNvbXBvbmVudENJRHMoZGlmZikge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyhkaWZmW0NPTVBPTkVOVFNdIHx8IHt9KS5tYXAoKGkpID0+IHBhcnNlSW50KGkpKTtcbiAgfVxuXG4gIGlzQ29tcG9uZW50T25seURpZmYoZGlmZikge1xuICAgIGlmICghZGlmZltDT01QT05FTlRTXSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gT2JqZWN0LmtleXMoZGlmZikubGVuZ3RoID09PSAxO1xuICB9XG5cbiAgZ2V0Q29tcG9uZW50KGRpZmYsIGNpZCkge1xuICAgIHJldHVybiBkaWZmW0NPTVBPTkVOVFNdW2NpZF07XG4gIH1cblxuICByZXNldFJlbmRlcihjaWQpIHtcbiAgICAvLyB3ZSBhcmUgcmFjaW5nIGEgY29tcG9uZW50IGRlc3Ryb3ksIGl0IGNvdWxkIG5vdCBleGlzdCwgc29cbiAgICAvLyBtYWtlIHN1cmUgdGhhdCB3ZSBkb24ndCB0cnkgdG8gc2V0IHJlc2V0IG9uIHVuZGVmaW5lZFxuICAgIGlmICh0aGlzLnJlbmRlcmVkW0NPTVBPTkVOVFNdW2NpZF0pIHtcbiAgICAgIHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU11bY2lkXS5yZXNldCA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgbWVyZ2VEaWZmKGRpZmYpIHtcbiAgICBjb25zdCBuZXdjID0gZGlmZltDT01QT05FTlRTXTtcbiAgICBjb25zdCBjYWNoZSA9IHt9O1xuICAgIGRlbGV0ZSBkaWZmW0NPTVBPTkVOVFNdO1xuICAgIHRoaXMucmVuZGVyZWQgPSB0aGlzLm11dGFibGVNZXJnZSh0aGlzLnJlbmRlcmVkLCBkaWZmKTtcbiAgICB0aGlzLnJlbmRlcmVkW0NPTVBPTkVOVFNdID0gdGhpcy5yZW5kZXJlZFtDT01QT05FTlRTXSB8fCB7fTtcblxuICAgIGlmIChuZXdjKSB7XG4gICAgICBjb25zdCBvbGRjID0gdGhpcy5yZW5kZXJlZFtDT01QT05FTlRTXTtcblxuICAgICAgZm9yIChjb25zdCBjaWQgaW4gbmV3Yykge1xuICAgICAgICBuZXdjW2NpZF0gPSB0aGlzLmNhY2hlZEZpbmRDb21wb25lbnQoY2lkLCBuZXdjW2NpZF0sIG9sZGMsIG5ld2MsIGNhY2hlKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaWQgaW4gbmV3Yykge1xuICAgICAgICBvbGRjW2NpZF0gPSBuZXdjW2NpZF07XG4gICAgICB9XG4gICAgICBkaWZmW0NPTVBPTkVOVFNdID0gbmV3YztcbiAgICB9XG4gIH1cblxuICBjYWNoZWRGaW5kQ29tcG9uZW50KGNpZCwgY2RpZmYsIG9sZGMsIG5ld2MsIGNhY2hlKSB7XG4gICAgaWYgKGNhY2hlW2NpZF0pIHtcbiAgICAgIHJldHVybiBjYWNoZVtjaWRdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgbmRpZmYsXG4gICAgICAgIHN0YXQsXG4gICAgICAgIHNjaWQgPSBjZGlmZltTVEFUSUNdO1xuXG4gICAgICBpZiAoaXNDaWQoc2NpZCkpIHtcbiAgICAgICAgbGV0IHRkaWZmO1xuXG4gICAgICAgIGlmIChzY2lkID4gMCkge1xuICAgICAgICAgIHRkaWZmID0gdGhpcy5jYWNoZWRGaW5kQ29tcG9uZW50KHNjaWQsIG5ld2Nbc2NpZF0sIG9sZGMsIG5ld2MsIGNhY2hlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0ZGlmZiA9IG9sZGNbLXNjaWRdO1xuICAgICAgICB9XG5cbiAgICAgICAgc3RhdCA9IHRkaWZmW1NUQVRJQ107XG4gICAgICAgIG5kaWZmID0gdGhpcy5jbG9uZU1lcmdlKHRkaWZmLCBjZGlmZiwgdHJ1ZSk7XG4gICAgICAgIG5kaWZmW1NUQVRJQ10gPSBzdGF0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbmRpZmYgPVxuICAgICAgICAgIGNkaWZmW1NUQVRJQ10gIT09IHVuZGVmaW5lZCB8fCBvbGRjW2NpZF0gPT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgPyBjZGlmZlxuICAgICAgICAgICAgOiB0aGlzLmNsb25lTWVyZ2Uob2xkY1tjaWRdLCBjZGlmZiwgZmFsc2UpO1xuICAgICAgfVxuXG4gICAgICBjYWNoZVtjaWRdID0gbmRpZmY7XG4gICAgICByZXR1cm4gbmRpZmY7XG4gICAgfVxuICB9XG5cbiAgbXV0YWJsZU1lcmdlKHRhcmdldCwgc291cmNlKSB7XG4gICAgaWYgKHNvdXJjZVtTVEFUSUNdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBzb3VyY2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZG9NdXRhYmxlTWVyZ2UodGFyZ2V0LCBzb3VyY2UpO1xuICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9XG4gIH1cblxuICBkb011dGFibGVNZXJnZSh0YXJnZXQsIHNvdXJjZSkge1xuICAgIGlmIChzb3VyY2VbS0VZRURdKSB7XG4gICAgICB0aGlzLm1lcmdlS2V5ZWQodGFyZ2V0LCBzb3VyY2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKGNvbnN0IGtleSBpbiBzb3VyY2UpIHtcbiAgICAgICAgY29uc3QgdmFsID0gc291cmNlW2tleV07XG4gICAgICAgIGNvbnN0IHRhcmdldFZhbCA9IHRhcmdldFtrZXldO1xuICAgICAgICBjb25zdCBpc09ialZhbCA9IGlzT2JqZWN0KHZhbCk7XG4gICAgICAgIGlmIChpc09ialZhbCAmJiB2YWxbU1RBVElDXSA9PT0gdW5kZWZpbmVkICYmIGlzT2JqZWN0KHRhcmdldFZhbCkpIHtcbiAgICAgICAgICB0aGlzLmRvTXV0YWJsZU1lcmdlKHRhcmdldFZhbCwgdmFsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0YXJnZXRba2V5XSA9IHZhbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGFyZ2V0W1JPT1RdKSB7XG4gICAgICB0YXJnZXQubmV3UmVuZGVyID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICBjbG9uZShkaWZmKSB7XG4gICAgaWYgKFwic3RydWN0dXJlZENsb25lXCIgaW4gd2luZG93KSB7XG4gICAgICByZXR1cm4gc3RydWN0dXJlZENsb25lKGRpZmYpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBmYWxsYmFjayBmb3IgamVzdFxuICAgICAgcmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZGlmZikpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGtleWVkIGNvbXByZWhlbnNpb25zXG4gIG1lcmdlS2V5ZWQodGFyZ2V0LCBzb3VyY2UpIHtcbiAgICAvLyB3ZSBuZWVkIHRvIGNsb25lIHRoZSB0YXJnZXQgc2luY2UgZWxlbWVudHMgY2FuIG1vdmUgYW5kIG90aGVyd2lzZVxuICAgIC8vIGl0IGNvdWxkIGhhcHBlbiB0aGF0IHdlIG1vZGlmeSBhbiBlbGVtZW50IHRoYXQgd2UnbGwgbmVlZCB0byByZWZlciB0b1xuICAgIC8vIGxhdGVyXG4gICAgY29uc3QgY2xvbmVkVGFyZ2V0ID0gdGhpcy5jbG9uZSh0YXJnZXQpO1xuICAgIE9iamVjdC5lbnRyaWVzKHNvdXJjZVtLRVlFRF0pLmZvckVhY2goKFtpLCBlbnRyeV0pID0+IHtcbiAgICAgIGlmIChpID09PSBLRVlFRF9DT1VOVCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShlbnRyeSkpIHtcbiAgICAgICAgLy8gW29sZF9pZHgsIGRpZmZdXG4gICAgICAgIC8vIG1vdmVkIHdpdGggZGlmZlxuICAgICAgICBjb25zdCBbb2xkX2lkeCwgZGlmZl0gPSBlbnRyeTtcbiAgICAgICAgdGFyZ2V0W0tFWUVEXVtpXSA9IGNsb25lZFRhcmdldFtLRVlFRF1bb2xkX2lkeF07XG4gICAgICAgIHRoaXMuZG9NdXRhYmxlTWVyZ2UodGFyZ2V0W0tFWUVEXVtpXSwgZGlmZik7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBlbnRyeSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAvLyBtb3ZlZCB3aXRob3V0IGRpZmZcbiAgICAgICAgY29uc3Qgb2xkX2lkeCA9IGVudHJ5O1xuICAgICAgICB0YXJnZXRbS0VZRURdW2ldID0gY2xvbmVkVGFyZ2V0W0tFWUVEXVtvbGRfaWR4XTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGVudHJ5ID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIC8vIGRpZmYsIHNhbWUgcG9zaXRpb25cbiAgICAgICAgaWYgKCF0YXJnZXRbS0VZRURdW2ldKSB7XG4gICAgICAgICAgdGFyZ2V0W0tFWUVEXVtpXSA9IHt9O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZG9NdXRhYmxlTWVyZ2UodGFyZ2V0W0tFWUVEXVtpXSwgZW50cnkpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIC8vIGRyb3AgZXh0cmEgZW50cmllc1xuICAgIGlmIChzb3VyY2VbS0VZRURdW0tFWUVEX0NPVU5UXSA8IHRhcmdldFtLRVlFRF1bS0VZRURfQ09VTlRdKSB7XG4gICAgICBmb3IgKFxuICAgICAgICBsZXQgaSA9IHNvdXJjZVtLRVlFRF1bS0VZRURfQ09VTlRdO1xuICAgICAgICBpIDwgdGFyZ2V0W0tFWUVEXVtLRVlFRF9DT1VOVF07XG4gICAgICAgIGkrK1xuICAgICAgKSB7XG4gICAgICAgIGRlbGV0ZSB0YXJnZXRbS0VZRURdW2ldO1xuICAgICAgfVxuICAgIH1cbiAgICB0YXJnZXRbS0VZRURdW0tFWUVEX0NPVU5UXSA9IHNvdXJjZVtLRVlFRF1bS0VZRURfQ09VTlRdO1xuICAgIGlmIChzb3VyY2VbU1RSRUFNXSkge1xuICAgICAgdGFyZ2V0W1NUUkVBTV0gPSBzb3VyY2VbU1RSRUFNXTtcbiAgICB9XG4gICAgaWYgKHNvdXJjZVtURU1QTEFURVNdKSB7XG4gICAgICB0YXJnZXRbVEVNUExBVEVTXSA9IHNvdXJjZVtURU1QTEFURVNdO1xuICAgIH1cbiAgfVxuXG4gIC8vIE1lcmdlcyBjaWQgdHJlZXMgdG9nZXRoZXIsIGNvcHlpbmcgc3RhdGljcyBmcm9tIHNvdXJjZSB0cmVlLlxuICAvL1xuICAvLyBUaGUgYHBydW5lTWFnaWNJZGAgaXMgcGFzc2VkIHRvIGNvbnRyb2wgcHJ1bmluZyB0aGUgbWFnaWNJZCBvZiB0aGVcbiAgLy8gdGFyZ2V0LiBXZSBtdXN0IGFsd2F5cyBwcnVuZSB0aGUgbWFnaWNJZCB3aGVuIHdlIGFyZSBzaGFyaW5nIHN0YXRpY3NcbiAgLy8gZnJvbSBhbm90aGVyIGNvbXBvbmVudC4gSWYgbm90IHBydW5pbmcsIHdlIHJlcGxpY2F0ZSB0aGUgbG9naWMgZnJvbVxuICAvLyBtdXRhYmxlTWVyZ2UsIHdoZXJlIHdlIHNldCBuZXdSZW5kZXIgdG8gdHJ1ZSBpZiB0aGVyZSBpcyBhIHJvb3RcbiAgLy8gKGVmZmVjdGl2ZWx5IGZvcmNpbmcgdGhlIG5ldyB2ZXJzaW9uIHRvIGJlIHJlbmRlcmVkIGluc3RlYWQgb2Ygc2tpcHBlZClcbiAgLy9cbiAgY2xvbmVNZXJnZSh0YXJnZXQsIHNvdXJjZSwgcHJ1bmVNYWdpY0lkKSB7XG4gICAgY29uc3QgbWVyZ2VkID0geyAuLi50YXJnZXQsIC4uLnNvdXJjZSB9O1xuICAgIGZvciAoY29uc3Qga2V5IGluIG1lcmdlZCkge1xuICAgICAgY29uc3QgdmFsID0gc291cmNlW2tleV07XG4gICAgICBjb25zdCB0YXJnZXRWYWwgPSB0YXJnZXRba2V5XTtcbiAgICAgIGlmIChpc09iamVjdCh2YWwpICYmIHZhbFtTVEFUSUNdID09PSB1bmRlZmluZWQgJiYgaXNPYmplY3QodGFyZ2V0VmFsKSkge1xuICAgICAgICBtZXJnZWRba2V5XSA9IHRoaXMuY2xvbmVNZXJnZSh0YXJnZXRWYWwsIHZhbCwgcHJ1bmVNYWdpY0lkKTtcbiAgICAgIH0gZWxzZSBpZiAodmFsID09PSB1bmRlZmluZWQgJiYgaXNPYmplY3QodGFyZ2V0VmFsKSkge1xuICAgICAgICBtZXJnZWRba2V5XSA9IHRoaXMuY2xvbmVNZXJnZSh0YXJnZXRWYWwsIHt9LCBwcnVuZU1hZ2ljSWQpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAocHJ1bmVNYWdpY0lkKSB7XG4gICAgICBkZWxldGUgbWVyZ2VkLm1hZ2ljSWQ7XG4gICAgICBkZWxldGUgbWVyZ2VkLm5ld1JlbmRlcjtcbiAgICB9IGVsc2UgaWYgKHRhcmdldFtST09UXSkge1xuICAgICAgbWVyZ2VkLm5ld1JlbmRlciA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBtZXJnZWQ7XG4gIH1cblxuICBjb21wb25lbnRUb1N0cmluZyhjaWQpIHtcbiAgICBjb25zdCB7IGJ1ZmZlcjogc3RyLCBzdHJlYW1zIH0gPSB0aGlzLnJlY3Vyc2l2ZUNJRFRvU3RyaW5nKFxuICAgICAgdGhpcy5yZW5kZXJlZFtDT01QT05FTlRTXSxcbiAgICAgIGNpZCxcbiAgICAgIG51bGwsXG4gICAgKTtcbiAgICBjb25zdCBbc3RyaXBwZWRIVE1MLCBfYmVmb3JlLCBfYWZ0ZXJdID0gbW9kaWZ5Um9vdChzdHIsIHt9KTtcbiAgICByZXR1cm4geyBidWZmZXI6IHN0cmlwcGVkSFRNTCwgc3RyZWFtczogc3RyZWFtcyB9O1xuICB9XG5cbiAgcHJ1bmVDSURzKGNpZHMpIHtcbiAgICBjaWRzLmZvckVhY2goKGNpZCkgPT4gZGVsZXRlIHRoaXMucmVuZGVyZWRbQ09NUE9ORU5UU11bY2lkXSk7XG4gIH1cblxuICAvLyBwcml2YXRlXG5cbiAgZ2V0KCkge1xuICAgIHJldHVybiB0aGlzLnJlbmRlcmVkO1xuICB9XG5cbiAgaXNOZXdGaW5nZXJwcmludChkaWZmID0ge30pIHtcbiAgICByZXR1cm4gISFkaWZmW1NUQVRJQ107XG4gIH1cblxuICB0ZW1wbGF0ZVN0YXRpYyhwYXJ0LCB0ZW1wbGF0ZXMpIHtcbiAgICBpZiAodHlwZW9mIHBhcnQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgIHJldHVybiB0ZW1wbGF0ZXNbcGFydF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBwYXJ0O1xuICAgIH1cbiAgfVxuXG4gIG5leHRNYWdpY0lEKCkge1xuICAgIHRoaXMubWFnaWNJZCsrO1xuICAgIHJldHVybiBgbSR7dGhpcy5tYWdpY0lkfS0ke3RoaXMucGFyZW50Vmlld0lkKCl9YDtcbiAgfVxuXG4gIC8vIENvbnZlcnRzIHJlbmRlcmVkIHRyZWUgdG8gb3V0cHV0IGJ1ZmZlci5cbiAgLy9cbiAgLy8gY2hhbmdlVHJhY2tpbmcgY29udHJvbHMgaWYgd2UgY2FuIGFwcGx5IHRoZSBQSFhfU0tJUCBvcHRpbWl6YXRpb24uXG4gIHRvT3V0cHV0QnVmZmVyKHJlbmRlcmVkLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcsIHJvb3RBdHRycyA9IHt9KSB7XG4gICAgaWYgKHJlbmRlcmVkW0tFWUVEXSkge1xuICAgICAgcmV0dXJuIHRoaXMuY29tcHJlaGVuc2lvblRvQnVmZmVyKFxuICAgICAgICByZW5kZXJlZCxcbiAgICAgICAgdGVtcGxhdGVzLFxuICAgICAgICBvdXRwdXQsXG4gICAgICAgIGNoYW5nZVRyYWNraW5nLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBUZW1wbGF0ZXMgYXJlIGEgd2F5IG9mIHNoYXJpbmcgc3RhdGljcyBiZXR3ZWVuIG11bHRpcGxlIHJlbmRlcmVkIHN0cnVjdHMuXG4gICAgLy8gU2luY2UgTGl2ZVZpZXcgMS4xLCB0aG9zZSBjYW4gYWxzbyBhcHBlYXIgYXQgdGhlIHJvb3QgLSBmb3IgZXhhbXBsZSBpZiBvbmUgcmVuZGVyc1xuICAgIC8vIHR3byBjb21wcmVoZW5zaW9ucyB0aGF0IGNhbiBzaGFyZSBzdGF0aWNzLlxuICAgIC8vIFdoZW5ldmVyIHdlIGZpbmQgdGVtcGxhdGVzLCB3ZSBuZWVkIHRvIHVzZSB0aGVtIHJlY3Vyc2l2ZWx5LiBBbHNvLCB0ZW1wbGF0ZXMgY2FuXG4gICAgLy8gYmUgc2VudCBmb3IgZWFjaCBkaWZmLCBub3Qgb25seSBmb3IgdGhlIGluaXRpYWwgb25lLiBXZSBkb24ndCB3YW50IHRvIG1lcmdlIHRoZW1cbiAgICAvLyB0aG91Z2gsIHNvIHdlIGFsd2F5cyByZXNvbHZlIHRoZW0gYW5kIHJlbW92ZSB0aGVtIGZyb20gdGhlIHJlbmRlcmVkIG9iamVjdC5cbiAgICBpZiAocmVuZGVyZWRbVEVNUExBVEVTXSkge1xuICAgICAgdGVtcGxhdGVzID0gcmVuZGVyZWRbVEVNUExBVEVTXTtcbiAgICAgIGRlbGV0ZSByZW5kZXJlZFtURU1QTEFURVNdO1xuICAgIH1cblxuICAgIGxldCB7IFtTVEFUSUNdOiBzdGF0aWNzIH0gPSByZW5kZXJlZDtcbiAgICBzdGF0aWNzID0gdGhpcy50ZW1wbGF0ZVN0YXRpYyhzdGF0aWNzLCB0ZW1wbGF0ZXMpO1xuICAgIHJlbmRlcmVkW1NUQVRJQ10gPSBzdGF0aWNzO1xuICAgIGNvbnN0IGlzUm9vdCA9IHJlbmRlcmVkW1JPT1RdO1xuICAgIGNvbnN0IHByZXZCdWZmZXIgPSBvdXRwdXQuYnVmZmVyO1xuICAgIGlmIChpc1Jvb3QpIHtcbiAgICAgIG91dHB1dC5idWZmZXIgPSBcIlwiO1xuICAgIH1cblxuICAgIC8vIHRoaXMgY29uZGl0aW9uIGlzIGNhbGxlZCB3aGVuIGZpcnN0IHJlbmRlcmluZyBhbiBvcHRpbWl6YWJsZSBmdW5jdGlvbiBjb21wb25lbnQuXG4gICAgLy8gTEMgaGF2ZSB0aGVpciBtYWdpY0lkIHByZXZpb3VzbHkgc2V0XG4gICAgaWYgKGNoYW5nZVRyYWNraW5nICYmIGlzUm9vdCAmJiAhcmVuZGVyZWQubWFnaWNJZCkge1xuICAgICAgcmVuZGVyZWQubmV3UmVuZGVyID0gdHJ1ZTtcbiAgICAgIHJlbmRlcmVkLm1hZ2ljSWQgPSB0aGlzLm5leHRNYWdpY0lEKCk7XG4gICAgfVxuXG4gICAgb3V0cHV0LmJ1ZmZlciArPSBzdGF0aWNzWzBdO1xuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgc3RhdGljcy5sZW5ndGg7IGkrKykge1xuICAgICAgdGhpcy5keW5hbWljVG9CdWZmZXIocmVuZGVyZWRbaSAtIDFdLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcpO1xuICAgICAgb3V0cHV0LmJ1ZmZlciArPSBzdGF0aWNzW2ldO1xuICAgIH1cblxuICAgIC8vIEFwcGxpZXMgdGhlIHJvb3QgdGFnIFwic2tpcFwiIG9wdGltaXphdGlvbiBpZiBzdXBwb3J0ZWQsIHdoaWNoIGNsZWFyc1xuICAgIC8vIHRoZSByb290IHRhZyBhdHRyaWJ1dGVzIGFuZCBpbm5lckhUTUwsIGFuZCBvbmx5IG1haW50YWlucyB0aGUgbWFnaWNJZC5cbiAgICAvLyBXZSBjYW4gb25seSBza2lwIHdoZW4gY2hhbmdlVHJhY2tpbmcgaXMgc3VwcG9ydGVkLFxuICAgIC8vIGFuZCB3aGVuIHRoZSByb290IGVsZW1lbnQgaGFzbid0IGV4cGVyaWVuY2VkIGFuIHVucmVuZGVyZWQgbWVyZ2UgKG5ld1JlbmRlciB0cnVlKS5cbiAgICBpZiAoaXNSb290KSB7XG4gICAgICBsZXQgc2tpcCA9IGZhbHNlO1xuICAgICAgbGV0IGF0dHJzO1xuICAgICAgLy8gV2hlbiBhIExDIGlzIHJlLWFkZGVkIHRvIHRoZSBwYWdlLCB3ZSBuZWVkIHRvIHJlLXJlbmRlciB0aGUgZW50aXJlIExDIHRyZWUsXG4gICAgICAvLyB0aGVyZWZvcmUgY2hhbmdlVHJhY2tpbmcgaXMgZmFsc2U7IGhvd2V2ZXIsIHdlIG5lZWQgdG8ga2VlcCBhbGwgdGhlIG1hZ2ljSWRzXG4gICAgICAvLyBmcm9tIGFueSBmdW5jdGlvbiBjb21wb25lbnQgc28gdGhlIG5leHQgdGltZSB0aGUgTEMgaXMgdXBkYXRlZCwgd2UgY2FuIGFwcGx5XG4gICAgICAvLyB0aGUgc2tpcCBvcHRpbWl6YXRpb25cbiAgICAgIGlmIChjaGFuZ2VUcmFja2luZyB8fCByZW5kZXJlZC5tYWdpY0lkKSB7XG4gICAgICAgIHNraXAgPSBjaGFuZ2VUcmFja2luZyAmJiAhcmVuZGVyZWQubmV3UmVuZGVyO1xuICAgICAgICBhdHRycyA9IHsgW1BIWF9NQUdJQ19JRF06IHJlbmRlcmVkLm1hZ2ljSWQsIC4uLnJvb3RBdHRycyB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXR0cnMgPSByb290QXR0cnM7XG4gICAgICB9XG4gICAgICBpZiAoc2tpcCkge1xuICAgICAgICBhdHRyc1tQSFhfU0tJUF0gPSB0cnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgW25ld1Jvb3QsIGNvbW1lbnRCZWZvcmUsIGNvbW1lbnRBZnRlcl0gPSBtb2RpZnlSb290KFxuICAgICAgICBvdXRwdXQuYnVmZmVyLFxuICAgICAgICBhdHRycyxcbiAgICAgICAgc2tpcCxcbiAgICAgICk7XG4gICAgICByZW5kZXJlZC5uZXdSZW5kZXIgPSBmYWxzZTtcbiAgICAgIG91dHB1dC5idWZmZXIgPSBwcmV2QnVmZmVyICsgY29tbWVudEJlZm9yZSArIG5ld1Jvb3QgKyBjb21tZW50QWZ0ZXI7XG4gICAgfVxuICB9XG5cbiAgY29tcHJlaGVuc2lvblRvQnVmZmVyKHJlbmRlcmVkLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcpIHtcbiAgICBjb25zdCBrZXllZFRlbXBsYXRlcyA9IHRlbXBsYXRlcyB8fCByZW5kZXJlZFtURU1QTEFURVNdO1xuICAgIGNvbnN0IHN0YXRpY3MgPSB0aGlzLnRlbXBsYXRlU3RhdGljKHJlbmRlcmVkW1NUQVRJQ10sIHRlbXBsYXRlcyk7XG4gICAgcmVuZGVyZWRbU1RBVElDXSA9IHN0YXRpY3M7XG4gICAgZGVsZXRlIHJlbmRlcmVkW1RFTVBMQVRFU107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZW5kZXJlZFtLRVlFRF1bS0VZRURfQ09VTlRdOyBpKyspIHtcbiAgICAgIG91dHB1dC5idWZmZXIgKz0gc3RhdGljc1swXTtcbiAgICAgIGZvciAobGV0IGogPSAxOyBqIDwgc3RhdGljcy5sZW5ndGg7IGorKykge1xuICAgICAgICB0aGlzLmR5bmFtaWNUb0J1ZmZlcihcbiAgICAgICAgICByZW5kZXJlZFtLRVlFRF1baV1baiAtIDFdLFxuICAgICAgICAgIGtleWVkVGVtcGxhdGVzLFxuICAgICAgICAgIG91dHB1dCxcbiAgICAgICAgICBjaGFuZ2VUcmFja2luZyxcbiAgICAgICAgKTtcbiAgICAgICAgb3V0cHV0LmJ1ZmZlciArPSBzdGF0aWNzW2pdO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyB3ZSBkb24ndCBuZWVkIHRvIHN0b3JlIHRoZSByZW5kZXJlZCB0cmVlIGZvciBzdHJlYW1zXG4gICAgaWYgKHJlbmRlcmVkW1NUUkVBTV0pIHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IHJlbmRlcmVkW1NUUkVBTV07XG4gICAgICBjb25zdCBbX3JlZiwgX2luc2VydHMsIGRlbGV0ZUlkcywgcmVzZXRdID0gc3RyZWFtIHx8IFtudWxsLCB7fSwgW10sIG51bGxdO1xuICAgICAgaWYgKFxuICAgICAgICBzdHJlYW0gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAocmVuZGVyZWRbS0VZRURdW0tFWUVEX0NPVU5UXSA+IDAgfHwgZGVsZXRlSWRzLmxlbmd0aCA+IDAgfHwgcmVzZXQpXG4gICAgICApIHtcbiAgICAgICAgZGVsZXRlIHJlbmRlcmVkW1NUUkVBTV07XG4gICAgICAgIHJlbmRlcmVkW0tFWUVEXSA9IHtcbiAgICAgICAgICBbS0VZRURfQ09VTlRdOiAwLFxuICAgICAgICB9O1xuICAgICAgICBvdXRwdXQuc3RyZWFtcy5hZGQoc3RyZWFtKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBkeW5hbWljVG9CdWZmZXIocmVuZGVyZWQsIHRlbXBsYXRlcywgb3V0cHV0LCBjaGFuZ2VUcmFja2luZykge1xuICAgIGlmICh0eXBlb2YgcmVuZGVyZWQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgIGNvbnN0IHsgYnVmZmVyOiBzdHIsIHN0cmVhbXMgfSA9IHRoaXMucmVjdXJzaXZlQ0lEVG9TdHJpbmcoXG4gICAgICAgIG91dHB1dC5jb21wb25lbnRzLFxuICAgICAgICByZW5kZXJlZCxcbiAgICAgICAgb3V0cHV0Lm9ubHlDaWRzLFxuICAgICAgKTtcbiAgICAgIG91dHB1dC5idWZmZXIgKz0gc3RyO1xuICAgICAgb3V0cHV0LnN0cmVhbXMgPSBuZXcgU2V0KFsuLi5vdXRwdXQuc3RyZWFtcywgLi4uc3RyZWFtc10pO1xuICAgIH0gZWxzZSBpZiAoaXNPYmplY3QocmVuZGVyZWQpKSB7XG4gICAgICB0aGlzLnRvT3V0cHV0QnVmZmVyKHJlbmRlcmVkLCB0ZW1wbGF0ZXMsIG91dHB1dCwgY2hhbmdlVHJhY2tpbmcsIHt9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3V0cHV0LmJ1ZmZlciArPSByZW5kZXJlZDtcbiAgICB9XG4gIH1cblxuICByZWN1cnNpdmVDSURUb1N0cmluZyhjb21wb25lbnRzLCBjaWQsIG9ubHlDaWRzKSB7XG4gICAgY29uc3QgY29tcG9uZW50ID1cbiAgICAgIGNvbXBvbmVudHNbY2lkXSB8fCBsb2dFcnJvcihgbm8gY29tcG9uZW50IGZvciBDSUQgJHtjaWR9YCwgY29tcG9uZW50cyk7XG4gICAgY29uc3QgYXR0cnMgPSB7IFtQSFhfQ09NUE9ORU5UXTogY2lkLCBbUEhYX1ZJRVdfUkVGXTogdGhpcy52aWV3SWQgfTtcbiAgICBjb25zdCBza2lwID0gb25seUNpZHMgJiYgIW9ubHlDaWRzLmhhcyhjaWQpO1xuICAgIC8vIFR3byBvcHRpbWl6YXRpb24gcGF0aHMgYXBwbHkgaGVyZTpcbiAgICAvL1xuICAgIC8vICAgMS4gVGhlIG9ubHlDaWRzIG9wdGltaXphdGlvbiB3b3JrcyBieSB0aGUgc2VydmVyIGRpZmYgdGVsbGluZyB1cyBvbmx5IHNwZWNpZmljXG4gICAgLy8gICAgIGNpZCdzIGhhdmUgY2hhbmdlZC4gVGhpcyBhbGxvd3MgdXMgdG8gc2tpcCByZW5kZXJpbmcgYW55IGNvbXBvbmVudCB0aGF0IGhhc24ndCBjaGFuZ2VkLFxuICAgIC8vICAgICB3aGljaCB1bHRpbWF0ZWx5IHNldHMgUEhYX1NLSVAgcm9vdCBhdHRyaWJ1dGUgYW5kIGF2b2lkcyByZW5kZXJpbmcgdGhlIGlubmVySFRNTC5cbiAgICAvL1xuICAgIC8vICAgMi4gVGhlIHJvb3QgUEhYX1NLSVAgb3B0aW1pemF0aW9uIGdlbmVyYWxpemVzIHRvIGFsbCBIRUV4IGZ1bmN0aW9uIGNvbXBvbmVudHMsIGFuZFxuICAgIC8vICAgICB3b3JrcyBpbiB0aGUgc2FtZSBQSFhfU0tJUCBhdHRyaWJ1dGUgZmFzaGlvbiBhcyAxLCBidXQgdGhlIG5ld1JlbmRlciB0cmFja2luZyBpcyBkb25lXG4gICAgLy8gICAgIGF0IHRoZSBnZW5lcmFsIGRpZmYgbWVyZ2UgbGV2ZWwuIElmIHdlIG1lcmdlIGEgZGlmZiB3aXRoIG5ldyBkeW5hbWljcywgd2UgbmVjZXNzYXJpbHkgaGF2ZVxuICAgIC8vICAgICBleHBlcmllbmNlZCBhIGNoYW5nZSB3aGljaCBtdXN0IGJlIGEgbmV3UmVuZGVyLCBhbmQgdGh1cyB3ZSBjYW4ndCBza2lwIHRoZSByZW5kZXIuXG4gICAgLy9cbiAgICAvLyBCb3RoIG9wdGltaXphdGlvbiBmbG93cyBhcHBseSBoZXJlLiBuZXdSZW5kZXIgaXMgc2V0IGJhc2VkIG9uIHRoZSBvbmx5Q2lkcyBvcHRpbWl6YXRpb24sIGFuZFxuICAgIC8vIHdlIHRyYWNrIGEgZGV0ZXJtaW5pc3RpYyBtYWdpY0lkIGJhc2VkIG9uIHRoZSBjaWQuXG4gICAgLy9cbiAgICAvLyBjaGFuZ2VUcmFja2luZyBpcyBhYm91dCB0aGUgZW50aXJlIHRyZWVcbiAgICAvLyBuZXdSZW5kZXIgaXMgYWJvdXQgdGhlIGN1cnJlbnQgcm9vdCBpbiB0aGUgdHJlZVxuICAgIC8vXG4gICAgLy8gQnkgZGVmYXVsdCBjaGFuZ2VUcmFja2luZyBpcyBlbmFibGVkLCBidXQgd2Ugc3BlY2lhbCBjYXNlIHRoZSBmbG93IHdoZXJlIHRoZSBjbGllbnQgaXMgcHJ1bmluZ1xuICAgIC8vIGNpZHMgYW5kIHRoZSBzZXJ2ZXIgYWRkcyB0aGUgY29tcG9uZW50IGJhY2suIEluIHN1Y2ggY2FzZXMsIHdlIGV4cGxpY2l0bHkgZGlzYWJsZSBjaGFuZ2VUcmFja2luZ1xuICAgIC8vIHdpdGggcmVzZXRSZW5kZXIgZm9yIHRoaXMgY2lkLCB0aGVuIHJlLWVuYWJsZSBpdCBhZnRlciB0aGUgcmVjdXJzaXZlIGNhbGwgdG8gc2tpcCB0aGUgb3B0aW1pemF0aW9uXG4gICAgLy8gZm9yIHRoZSBlbnRpcmUgY29tcG9uZW50IHRyZWUuXG4gICAgY29tcG9uZW50Lm5ld1JlbmRlciA9ICFza2lwO1xuICAgIGNvbXBvbmVudC5tYWdpY0lkID0gYGMke2NpZH0tJHt0aGlzLnBhcmVudFZpZXdJZCgpfWA7XG4gICAgLy8gZW5hYmxlIGNoYW5nZSB0cmFja2luZyBhcyBsb25nIGFzIHRoZSBjb21wb25lbnQgaGFzbid0IGJlZW4gcmVzZXRcbiAgICBjb25zdCBjaGFuZ2VUcmFja2luZyA9ICFjb21wb25lbnQucmVzZXQ7XG4gICAgY29uc3QgeyBidWZmZXI6IGh0bWwsIHN0cmVhbXMgfSA9IHRoaXMucmVjdXJzaXZlVG9TdHJpbmcoXG4gICAgICBjb21wb25lbnQsXG4gICAgICBjb21wb25lbnRzLFxuICAgICAgb25seUNpZHMsXG4gICAgICBjaGFuZ2VUcmFja2luZyxcbiAgICAgIGF0dHJzLFxuICAgICk7XG4gICAgLy8gZGlzYWJsZSByZXNldCBhZnRlciB3ZSd2ZSByZW5kZXJlZFxuICAgIGRlbGV0ZSBjb21wb25lbnQucmVzZXQ7XG5cbiAgICByZXR1cm4geyBidWZmZXI6IGh0bWwsIHN0cmVhbXM6IHN0cmVhbXMgfTtcbiAgfVxufVxuIiwgImltcG9ydCBET00gZnJvbSBcIi4vZG9tXCI7XG5pbXBvcnQgQVJJQSBmcm9tIFwiLi9hcmlhXCI7XG5cbmNvbnN0IGZvY3VzU3RhY2sgPSBbXTtcbmNvbnN0IGRlZmF1bHRfdHJhbnNpdGlvbl90aW1lID0gMjAwO1xuXG5jb25zdCBKUyA9IHtcbiAgLy8gcHJpdmF0ZVxuICBleGVjKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBkZWZhdWx0cykge1xuICAgIGNvbnN0IFtkZWZhdWx0S2luZCwgZGVmYXVsdEFyZ3NdID0gZGVmYXVsdHMgfHwgW1xuICAgICAgbnVsbCxcbiAgICAgIHsgY2FsbGJhY2s6IGRlZmF1bHRzICYmIGRlZmF1bHRzLmNhbGxiYWNrIH0sXG4gICAgXTtcbiAgICBjb25zdCBjb21tYW5kcyA9XG4gICAgICBwaHhFdmVudC5jaGFyQXQoMCkgPT09IFwiW1wiXG4gICAgICAgID8gSlNPTi5wYXJzZShwaHhFdmVudClcbiAgICAgICAgOiBbW2RlZmF1bHRLaW5kLCBkZWZhdWx0QXJnc11dO1xuXG4gICAgY29tbWFuZHMuZm9yRWFjaCgoW2tpbmQsIGFyZ3NdKSA9PiB7XG4gICAgICBpZiAoa2luZCA9PT0gZGVmYXVsdEtpbmQpIHtcbiAgICAgICAgLy8gYWx3YXlzIHByZWZlciB0aGUgYXJncywgYnV0IGtlZXAgZXhpc3Rpbmcga2V5cyBmcm9tIHRoZSBkZWZhdWx0QXJnc1xuICAgICAgICBhcmdzID0geyAuLi5kZWZhdWx0QXJncywgLi4uYXJncyB9O1xuICAgICAgICBhcmdzLmNhbGxiYWNrID0gYXJncy5jYWxsYmFjayB8fCBkZWZhdWx0QXJncy5jYWxsYmFjaztcbiAgICAgIH1cbiAgICAgIHRoaXMuZmlsdGVyVG9FbHModmlldy5saXZlU29ja2V0LCBzb3VyY2VFbCwgYXJncykuZm9yRWFjaCgoZWwpID0+IHtcbiAgICAgICAgdGhpc1tgZXhlY18ke2tpbmR9YF0oZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCBhcmdzKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9LFxuXG4gIGlzVmlzaWJsZShlbCkge1xuICAgIHJldHVybiAhIShcbiAgICAgIGVsLm9mZnNldFdpZHRoIHx8XG4gICAgICBlbC5vZmZzZXRIZWlnaHQgfHxcbiAgICAgIGVsLmdldENsaWVudFJlY3RzKCkubGVuZ3RoID4gMFxuICAgICk7XG4gIH0sXG5cbiAgLy8gcmV0dXJucyB0cnVlIGlmIGFueSBwYXJ0IG9mIHRoZSBlbGVtZW50IGlzIGluc2lkZSB0aGUgdmlld3BvcnRcbiAgaXNJblZpZXdwb3J0KGVsKSB7XG4gICAgY29uc3QgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IHdpbmRvd0hlaWdodCA9XG4gICAgICB3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcbiAgICBjb25zdCB3aW5kb3dXaWR0aCA9XG4gICAgICB3aW5kb3cuaW5uZXJXaWR0aCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGg7XG5cbiAgICByZXR1cm4gKFxuICAgICAgcmVjdC5yaWdodCA+IDAgJiZcbiAgICAgIHJlY3QuYm90dG9tID4gMCAmJlxuICAgICAgcmVjdC5sZWZ0IDwgd2luZG93V2lkdGggJiZcbiAgICAgIHJlY3QudG9wIDwgd2luZG93SGVpZ2h0XG4gICAgKTtcbiAgfSxcblxuICAvLyBwcml2YXRlXG5cbiAgLy8gY29tbWFuZHNcblxuICBleGVjX2V4ZWMoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7IGF0dHIsIHRvIH0pIHtcbiAgICBjb25zdCBlbmNvZGVkSlMgPSBlbC5nZXRBdHRyaWJ1dGUoYXR0cik7XG4gICAgaWYgKCFlbmNvZGVkSlMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZXhwZWN0ZWQgJHthdHRyfSB0byBjb250YWluIEpTIGNvbW1hbmQgb24gXCIke3RvfVwiYCk7XG4gICAgfVxuICAgIHZpZXcubGl2ZVNvY2tldC5leGVjSlMoZWwsIGVuY29kZWRKUywgZXZlbnRUeXBlKTtcbiAgfSxcblxuICBleGVjX2Rpc3BhdGNoKFxuICAgIGUsXG4gICAgZXZlbnRUeXBlLFxuICAgIHBoeEV2ZW50LFxuICAgIHZpZXcsXG4gICAgc291cmNlRWwsXG4gICAgZWwsXG4gICAgeyBldmVudCwgZGV0YWlsLCBidWJibGVzLCBibG9ja2luZyB9LFxuICApIHtcbiAgICBkZXRhaWwgPSBkZXRhaWwgfHwge307XG4gICAgZGV0YWlsLmRpc3BhdGNoZXIgPSBzb3VyY2VFbDtcbiAgICBpZiAoYmxvY2tpbmcpIHtcbiAgICAgIGNvbnN0IHByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgX3JlamVjdCkgPT4ge1xuICAgICAgICBkZXRhaWwuZG9uZSA9IHJlc29sdmU7XG4gICAgICB9KTtcbiAgICAgIHZpZXcubGl2ZVNvY2tldC5hc3luY1RyYW5zaXRpb24ocHJvbWlzZSk7XG4gICAgfVxuICAgIERPTS5kaXNwYXRjaEV2ZW50KGVsLCBldmVudCwgeyBkZXRhaWwsIGJ1YmJsZXMgfSk7XG4gIH0sXG5cbiAgZXhlY19wdXNoKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwgYXJncykge1xuICAgIGNvbnN0IHtcbiAgICAgIGV2ZW50LFxuICAgICAgZGF0YSxcbiAgICAgIHRhcmdldCxcbiAgICAgIHBhZ2VfbG9hZGluZyxcbiAgICAgIGxvYWRpbmcsXG4gICAgICB2YWx1ZSxcbiAgICAgIGRpc3BhdGNoZXIsXG4gICAgICBjYWxsYmFjayxcbiAgICB9ID0gYXJncztcbiAgICBjb25zdCBwdXNoT3B0cyA9IHtcbiAgICAgIGxvYWRpbmcsXG4gICAgICB2YWx1ZSxcbiAgICAgIHRhcmdldCxcbiAgICAgIHBhZ2VfbG9hZGluZzogISFwYWdlX2xvYWRpbmcsXG4gICAgICBvcmlnaW5hbEV2ZW50OiBlLFxuICAgIH07XG4gICAgY29uc3QgdGFyZ2V0U3JjID1cbiAgICAgIGV2ZW50VHlwZSA9PT0gXCJjaGFuZ2VcIiAmJiBkaXNwYXRjaGVyID8gZGlzcGF0Y2hlciA6IHNvdXJjZUVsO1xuICAgIGNvbnN0IHBoeFRhcmdldCA9XG4gICAgICB0YXJnZXQgfHwgdGFyZ2V0U3JjLmdldEF0dHJpYnV0ZSh2aWV3LmJpbmRpbmcoXCJ0YXJnZXRcIikpIHx8IHRhcmdldFNyYztcbiAgICBjb25zdCBoYW5kbGVyID0gKHRhcmdldFZpZXcsIHRhcmdldEN0eCkgPT4ge1xuICAgICAgaWYgKCF0YXJnZXRWaWV3LmlzQ29ubmVjdGVkKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKGV2ZW50VHlwZSA9PT0gXCJjaGFuZ2VcIikge1xuICAgICAgICBsZXQgeyBuZXdDaWQsIF90YXJnZXQgfSA9IGFyZ3M7XG4gICAgICAgIF90YXJnZXQgPVxuICAgICAgICAgIF90YXJnZXQgfHwgKERPTS5pc0Zvcm1JbnB1dChzb3VyY2VFbCkgPyBzb3VyY2VFbC5uYW1lIDogdW5kZWZpbmVkKTtcbiAgICAgICAgaWYgKF90YXJnZXQpIHtcbiAgICAgICAgICBwdXNoT3B0cy5fdGFyZ2V0ID0gX3RhcmdldDtcbiAgICAgICAgfVxuICAgICAgICB0YXJnZXRWaWV3LnB1c2hJbnB1dChcbiAgICAgICAgICBzb3VyY2VFbCxcbiAgICAgICAgICB0YXJnZXRDdHgsXG4gICAgICAgICAgbmV3Q2lkLFxuICAgICAgICAgIGV2ZW50IHx8IHBoeEV2ZW50LFxuICAgICAgICAgIHB1c2hPcHRzLFxuICAgICAgICAgIGNhbGxiYWNrLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChldmVudFR5cGUgPT09IFwic3VibWl0XCIpIHtcbiAgICAgICAgY29uc3QgeyBzdWJtaXR0ZXIgfSA9IGFyZ3M7XG4gICAgICAgIHRhcmdldFZpZXcuc3VibWl0Rm9ybShcbiAgICAgICAgICBzb3VyY2VFbCxcbiAgICAgICAgICB0YXJnZXRDdHgsXG4gICAgICAgICAgZXZlbnQgfHwgcGh4RXZlbnQsXG4gICAgICAgICAgc3VibWl0dGVyLFxuICAgICAgICAgIHB1c2hPcHRzLFxuICAgICAgICAgIGNhbGxiYWNrLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGFyZ2V0Vmlldy5wdXNoRXZlbnQoXG4gICAgICAgICAgZXZlbnRUeXBlLFxuICAgICAgICAgIHNvdXJjZUVsLFxuICAgICAgICAgIHRhcmdldEN0eCxcbiAgICAgICAgICBldmVudCB8fCBwaHhFdmVudCxcbiAgICAgICAgICBkYXRhLFxuICAgICAgICAgIHB1c2hPcHRzLFxuICAgICAgICAgIGNhbGxiYWNrLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH07XG4gICAgLy8gaW4gY2FzZSBvZiBmb3JtUmVjb3ZlcnksIHRhcmdldFZpZXcgYW5kIHRhcmdldEN0eCBhcmUgcGFzc2VkIGFzIGFyZ3VtZW50XG4gICAgLy8gYXMgdGhleSBhcmUgbG9va2VkIHVwIGluIGEgdGVtcGxhdGUgZWxlbWVudCwgbm90IHRoZSByZWFsIERPTVxuICAgIGlmIChhcmdzLnRhcmdldFZpZXcgJiYgYXJncy50YXJnZXRDdHgpIHtcbiAgICAgIGhhbmRsZXIoYXJncy50YXJnZXRWaWV3LCBhcmdzLnRhcmdldEN0eCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZpZXcud2l0aGluVGFyZ2V0cyhwaHhUYXJnZXQsIGhhbmRsZXIpO1xuICAgIH1cbiAgfSxcblxuICBleGVjX25hdmlnYXRlKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwgeyBocmVmLCByZXBsYWNlIH0pIHtcbiAgICB2aWV3LmxpdmVTb2NrZXQuaGlzdG9yeVJlZGlyZWN0KFxuICAgICAgZSxcbiAgICAgIGhyZWYsXG4gICAgICByZXBsYWNlID8gXCJyZXBsYWNlXCIgOiBcInB1c2hcIixcbiAgICAgIG51bGwsXG4gICAgICBzb3VyY2VFbCxcbiAgICApO1xuICB9LFxuXG4gIGV4ZWNfcGF0Y2goZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7IGhyZWYsIHJlcGxhY2UgfSkge1xuICAgIHZpZXcubGl2ZVNvY2tldC5wdXNoSGlzdG9yeVBhdGNoKFxuICAgICAgZSxcbiAgICAgIGhyZWYsXG4gICAgICByZXBsYWNlID8gXCJyZXBsYWNlXCIgOiBcInB1c2hcIixcbiAgICAgIHNvdXJjZUVsLFxuICAgICk7XG4gIH0sXG5cbiAgZXhlY19mb2N1cyhlLCBldmVudFR5cGUsIHBoeEV2ZW50LCB2aWV3LCBzb3VyY2VFbCwgZWwpIHtcbiAgICBBUklBLmF0dGVtcHRGb2N1cyhlbCk7XG4gICAgLy8gaW4gY2FzZSB0aGUgSlMuZm9jdXMgY29tbWFuZCBpcyBpbiBhIEpTLnNob3cvaGlkZS90b2dnbGUgY2hhaW4sIGZvciBzaG93IHdlIG5lZWRcbiAgICAvLyB0byB3YWl0IGZvciBKUy5zaG93IHRvIGhhdmUgdXBkYXRlZCB0aGUgZWxlbWVudCdzIGRpc3BsYXkgcHJvcGVydHkgKHNlZSBleGVjX3RvZ2dsZSlcbiAgICAvLyBidXQgdGhhdCBydW4gaW4gbmVzdGVkIGFuaW1hdGlvbiBmcmFtZXMsIHRoZXJlZm9yZSB3ZSBuZWVkIHRvIHVzZSB0aGVtIGhlcmUgYXMgd2VsbFxuICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiBBUklBLmF0dGVtcHRGb2N1cyhlbCkpO1xuICAgIH0pO1xuICB9LFxuXG4gIGV4ZWNfZm9jdXNfZmlyc3QoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsKSB7XG4gICAgQVJJQS5mb2N1c0ZpcnN0SW50ZXJhY3RpdmUoZWwpIHx8IEFSSUEuZm9jdXNGaXJzdChlbCk7XG4gICAgLy8gaWYgeW91IHdvbmRlciBhYm91dCB0aGUgbmVzdGVkIGFuaW1hdGlvbiBmcmFtZXMsIHNlZSBleGVjX2ZvY3VzXG4gICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKFxuICAgICAgICAoKSA9PiBBUklBLmZvY3VzRmlyc3RJbnRlcmFjdGl2ZShlbCkgfHwgQVJJQS5mb2N1c0ZpcnN0KGVsKSxcbiAgICAgICk7XG4gICAgfSk7XG4gIH0sXG5cbiAgZXhlY19wdXNoX2ZvY3VzKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCkge1xuICAgIGZvY3VzU3RhY2sucHVzaChlbCB8fCBzb3VyY2VFbCk7XG4gIH0sXG5cbiAgZXhlY19wb3BfZm9jdXMoX2UsIF9ldmVudFR5cGUsIF9waHhFdmVudCwgX3ZpZXcsIF9zb3VyY2VFbCwgX2VsKSB7XG4gICAgY29uc3QgZWwgPSBmb2N1c1N0YWNrLnBvcCgpO1xuICAgIGlmIChlbCkge1xuICAgICAgZWwuZm9jdXMoKTtcbiAgICAgIC8vIGlmIHlvdSB3b25kZXIgYWJvdXQgdGhlIG5lc3RlZCBhbmltYXRpb24gZnJhbWVzLCBzZWUgZXhlY19mb2N1c1xuICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gZWwuZm9jdXMoKSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG5cbiAgZXhlY19hZGRfY2xhc3MoXG4gICAgZSxcbiAgICBldmVudFR5cGUsXG4gICAgcGh4RXZlbnQsXG4gICAgdmlldyxcbiAgICBzb3VyY2VFbCxcbiAgICBlbCxcbiAgICB7IG5hbWVzLCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyB9LFxuICApIHtcbiAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgbmFtZXMsIFtdLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZyk7XG4gIH0sXG5cbiAgZXhlY19yZW1vdmVfY2xhc3MoXG4gICAgZSxcbiAgICBldmVudFR5cGUsXG4gICAgcGh4RXZlbnQsXG4gICAgdmlldyxcbiAgICBzb3VyY2VFbCxcbiAgICBlbCxcbiAgICB7IG5hbWVzLCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyB9LFxuICApIHtcbiAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgW10sIG5hbWVzLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZyk7XG4gIH0sXG5cbiAgZXhlY190b2dnbGVfY2xhc3MoXG4gICAgZSxcbiAgICBldmVudFR5cGUsXG4gICAgcGh4RXZlbnQsXG4gICAgdmlldyxcbiAgICBzb3VyY2VFbCxcbiAgICBlbCxcbiAgICB7IG5hbWVzLCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyB9LFxuICApIHtcbiAgICB0aGlzLnRvZ2dsZUNsYXNzZXMoZWwsIG5hbWVzLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZyk7XG4gIH0sXG5cbiAgZXhlY190b2dnbGVfYXR0cihcbiAgICBlLFxuICAgIGV2ZW50VHlwZSxcbiAgICBwaHhFdmVudCxcbiAgICB2aWV3LFxuICAgIHNvdXJjZUVsLFxuICAgIGVsLFxuICAgIHsgYXR0cjogW2F0dHIsIHZhbDEsIHZhbDJdIH0sXG4gICkge1xuICAgIHRoaXMudG9nZ2xlQXR0cihlbCwgYXR0ciwgdmFsMSwgdmFsMik7XG4gIH0sXG5cbiAgZXhlY19pZ25vcmVfYXR0cnMoZSwgZXZlbnRUeXBlLCBwaHhFdmVudCwgdmlldywgc291cmNlRWwsIGVsLCB7IGF0dHJzIH0pIHtcbiAgICB0aGlzLmlnbm9yZUF0dHJzKGVsLCBhdHRycyk7XG4gIH0sXG5cbiAgZXhlY190cmFuc2l0aW9uKFxuICAgIGUsXG4gICAgZXZlbnRUeXBlLFxuICAgIHBoeEV2ZW50LFxuICAgIHZpZXcsXG4gICAgc291cmNlRWwsXG4gICAgZWwsXG4gICAgeyB0aW1lLCB0cmFuc2l0aW9uLCBibG9ja2luZyB9LFxuICApIHtcbiAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgW10sIFtdLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZyk7XG4gIH0sXG5cbiAgZXhlY190b2dnbGUoXG4gICAgZSxcbiAgICBldmVudFR5cGUsXG4gICAgcGh4RXZlbnQsXG4gICAgdmlldyxcbiAgICBzb3VyY2VFbCxcbiAgICBlbCxcbiAgICB7IGRpc3BsYXksIGlucywgb3V0cywgdGltZSwgYmxvY2tpbmcgfSxcbiAgKSB7XG4gICAgdGhpcy50b2dnbGUoZXZlbnRUeXBlLCB2aWV3LCBlbCwgZGlzcGxheSwgaW5zLCBvdXRzLCB0aW1lLCBibG9ja2luZyk7XG4gIH0sXG5cbiAgZXhlY19zaG93KFxuICAgIGUsXG4gICAgZXZlbnRUeXBlLFxuICAgIHBoeEV2ZW50LFxuICAgIHZpZXcsXG4gICAgc291cmNlRWwsXG4gICAgZWwsXG4gICAgeyBkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZyB9LFxuICApIHtcbiAgICB0aGlzLnNob3coZXZlbnRUeXBlLCB2aWV3LCBlbCwgZGlzcGxheSwgdHJhbnNpdGlvbiwgdGltZSwgYmxvY2tpbmcpO1xuICB9LFxuXG4gIGV4ZWNfaGlkZShcbiAgICBlLFxuICAgIGV2ZW50VHlwZSxcbiAgICBwaHhFdmVudCxcbiAgICB2aWV3LFxuICAgIHNvdXJjZUVsLFxuICAgIGVsLFxuICAgIHsgZGlzcGxheSwgdHJhbnNpdGlvbiwgdGltZSwgYmxvY2tpbmcgfSxcbiAgKSB7XG4gICAgdGhpcy5oaWRlKGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nKTtcbiAgfSxcblxuICBleGVjX3NldF9hdHRyKFxuICAgIGUsXG4gICAgZXZlbnRUeXBlLFxuICAgIHBoeEV2ZW50LFxuICAgIHZpZXcsXG4gICAgc291cmNlRWwsXG4gICAgZWwsXG4gICAgeyBhdHRyOiBbYXR0ciwgdmFsXSB9LFxuICApIHtcbiAgICB0aGlzLnNldE9yUmVtb3ZlQXR0cnMoZWwsIFtbYXR0ciwgdmFsXV0sIFtdKTtcbiAgfSxcblxuICBleGVjX3JlbW92ZV9hdHRyKGUsIGV2ZW50VHlwZSwgcGh4RXZlbnQsIHZpZXcsIHNvdXJjZUVsLCBlbCwgeyBhdHRyIH0pIHtcbiAgICB0aGlzLnNldE9yUmVtb3ZlQXR0cnMoZWwsIFtdLCBbYXR0cl0pO1xuICB9LFxuXG4gIGlnbm9yZUF0dHJzKGVsLCBhdHRycykge1xuICAgIERPTS5wdXRQcml2YXRlKGVsLCBcIkpTOmlnbm9yZV9hdHRyc1wiLCB7XG4gICAgICBhcHBseTogKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgICBBcnJheS5mcm9tKGZyb21FbC5hdHRyaWJ1dGVzKS5mb3JFYWNoKChhdHRyKSA9PiB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgYXR0cnMuc29tZShcbiAgICAgICAgICAgICAgKHRvSWdub3JlKSA9PlxuICAgICAgICAgICAgICAgIGF0dHIubmFtZSA9PSB0b0lnbm9yZSB8fFxuICAgICAgICAgICAgICAgICh0b0lnbm9yZS5pbmNsdWRlcyhcIipcIikgJiYgYXR0ci5uYW1lLm1hdGNoKHRvSWdub3JlKSAhPSBudWxsKSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHRvRWwuc2V0QXR0cmlidXRlKGF0dHIubmFtZSwgYXR0ci52YWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH0sXG5cbiAgb25CZWZvcmVFbFVwZGF0ZWQoZnJvbUVsLCB0b0VsKSB7XG4gICAgY29uc3QgaWdub3JlQXR0cnMgPSBET00ucHJpdmF0ZShmcm9tRWwsIFwiSlM6aWdub3JlX2F0dHJzXCIpO1xuICAgIGlmIChpZ25vcmVBdHRycykge1xuICAgICAgaWdub3JlQXR0cnMuYXBwbHkoZnJvbUVsLCB0b0VsKTtcbiAgICB9XG4gIH0sXG5cbiAgLy8gdXRpbHMgZm9yIGNvbW1hbmRzXG5cbiAgc2hvdyhldmVudFR5cGUsIHZpZXcsIGVsLCBkaXNwbGF5LCB0cmFuc2l0aW9uLCB0aW1lLCBibG9ja2luZykge1xuICAgIGlmICghdGhpcy5pc1Zpc2libGUoZWwpKSB7XG4gICAgICB0aGlzLnRvZ2dsZShcbiAgICAgICAgZXZlbnRUeXBlLFxuICAgICAgICB2aWV3LFxuICAgICAgICBlbCxcbiAgICAgICAgZGlzcGxheSxcbiAgICAgICAgdHJhbnNpdGlvbixcbiAgICAgICAgbnVsbCxcbiAgICAgICAgdGltZSxcbiAgICAgICAgYmxvY2tpbmcsXG4gICAgICApO1xuICAgIH1cbiAgfSxcblxuICBoaWRlKGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIHRyYW5zaXRpb24sIHRpbWUsIGJsb2NraW5nKSB7XG4gICAgaWYgKHRoaXMuaXNWaXNpYmxlKGVsKSkge1xuICAgICAgdGhpcy50b2dnbGUoXG4gICAgICAgIGV2ZW50VHlwZSxcbiAgICAgICAgdmlldyxcbiAgICAgICAgZWwsXG4gICAgICAgIGRpc3BsYXksXG4gICAgICAgIG51bGwsXG4gICAgICAgIHRyYW5zaXRpb24sXG4gICAgICAgIHRpbWUsXG4gICAgICAgIGJsb2NraW5nLFxuICAgICAgKTtcbiAgICB9XG4gIH0sXG5cbiAgdG9nZ2xlKGV2ZW50VHlwZSwgdmlldywgZWwsIGRpc3BsYXksIGlucywgb3V0cywgdGltZSwgYmxvY2tpbmcpIHtcbiAgICB0aW1lID0gdGltZSB8fCBkZWZhdWx0X3RyYW5zaXRpb25fdGltZTtcbiAgICBjb25zdCBbaW5DbGFzc2VzLCBpblN0YXJ0Q2xhc3NlcywgaW5FbmRDbGFzc2VzXSA9IGlucyB8fCBbW10sIFtdLCBbXV07XG4gICAgY29uc3QgW291dENsYXNzZXMsIG91dFN0YXJ0Q2xhc3Nlcywgb3V0RW5kQ2xhc3Nlc10gPSBvdXRzIHx8IFtbXSwgW10sIFtdXTtcbiAgICBpZiAoaW5DbGFzc2VzLmxlbmd0aCA+IDAgfHwgb3V0Q2xhc3Nlcy5sZW5ndGggPiAwKSB7XG4gICAgICBpZiAodGhpcy5pc1Zpc2libGUoZWwpKSB7XG4gICAgICAgIGNvbnN0IG9uU3RhcnQgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoXG4gICAgICAgICAgICBlbCxcbiAgICAgICAgICAgIG91dFN0YXJ0Q2xhc3NlcyxcbiAgICAgICAgICAgIGluQ2xhc3Nlcy5jb25jYXQoaW5TdGFydENsYXNzZXMpLmNvbmNhdChpbkVuZENsYXNzZXMpLFxuICAgICAgICAgICk7XG4gICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgb3V0Q2xhc3NlcywgW10pO1xuICAgICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PlxuICAgICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgb3V0RW5kQ2xhc3Nlcywgb3V0U3RhcnRDbGFzc2VzKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG9uRW5kID0gKCkgPT4ge1xuICAgICAgICAgIHRoaXMuYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBbXSwgb3V0Q2xhc3Nlcy5jb25jYXQob3V0RW5kQ2xhc3NlcykpO1xuICAgICAgICAgIERPTS5wdXRTdGlja3koXG4gICAgICAgICAgICBlbCxcbiAgICAgICAgICAgIFwidG9nZ2xlXCIsXG4gICAgICAgICAgICAoY3VycmVudEVsKSA9PiAoY3VycmVudEVsLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIiksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBlbC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudChcInBoeDpoaWRlLWVuZFwiKSk7XG4gICAgICAgIH07XG4gICAgICAgIGVsLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwicGh4OmhpZGUtc3RhcnRcIikpO1xuICAgICAgICBpZiAoYmxvY2tpbmcgPT09IGZhbHNlKSB7XG4gICAgICAgICAgb25TdGFydCgpO1xuICAgICAgICAgIHNldFRpbWVvdXQob25FbmQsIHRpbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZpZXcudHJhbnNpdGlvbih0aW1lLCBvblN0YXJ0LCBvbkVuZCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChldmVudFR5cGUgPT09IFwicmVtb3ZlXCIpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgb25TdGFydCA9ICgpID0+IHtcbiAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhcbiAgICAgICAgICAgIGVsLFxuICAgICAgICAgICAgaW5TdGFydENsYXNzZXMsXG4gICAgICAgICAgICBvdXRDbGFzc2VzLmNvbmNhdChvdXRTdGFydENsYXNzZXMpLmNvbmNhdChvdXRFbmRDbGFzc2VzKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IHN0aWNreURpc3BsYXkgPSBkaXNwbGF5IHx8IHRoaXMuZGVmYXVsdERpc3BsYXkoZWwpO1xuICAgICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgICAgLy8gZmlyc3QgYWRkIHRoZSBzdGFydGluZyArIGFjdGl2ZSBjbGFzcywgVEhFTiBtYWtlIHRoZSBlbGVtZW50IHZpc2libGVcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSBpZiB3ZSB0b2dnbGVkIHRoZSB2aXNpYmlsaXR5IGVhcmxpZXIgY3NzIGFuaW1hdGlvbnNcbiAgICAgICAgICAgIC8vIHdvdWxkIGZsaWNrZXIsIGFzIHRoZSBlbGVtZW50IGJlY29tZXMgdmlzaWJsZSBiZWZvcmUgdGhlIGFjdGl2ZSBhbmltYXRpb25cbiAgICAgICAgICAgIC8vIGNsYXNzIGlzIHNldCAoc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNDU2KVxuICAgICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIGluQ2xhc3NlcywgW10pO1xuICAgICAgICAgICAgLy8gYWRkT3JSZW1vdmVDbGFzc2VzIHVzZXMgYSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgaXRzZWxmLCB0aGVyZWZvcmUgd2UgbmVlZCB0byBtb3ZlIHRoZSBwdXRTdGlja3lcbiAgICAgICAgICAgIC8vIGludG8gdGhlIG5leHQgcmVxdWVzdEFuaW1hdGlvbkZyYW1lLi4uXG4gICAgICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICAgICAgRE9NLnB1dFN0aWNreShcbiAgICAgICAgICAgICAgICBlbCxcbiAgICAgICAgICAgICAgICBcInRvZ2dsZVwiLFxuICAgICAgICAgICAgICAgIChjdXJyZW50RWwpID0+IChjdXJyZW50RWwuc3R5bGUuZGlzcGxheSA9IHN0aWNreURpc3BsYXkpLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgaW5FbmRDbGFzc2VzLCBpblN0YXJ0Q2xhc3Nlcyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3Qgb25FbmQgPSAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIFtdLCBpbkNsYXNzZXMuY29uY2F0KGluRW5kQ2xhc3NlcykpO1xuICAgICAgICAgIGVsLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwicGh4OnNob3ctZW5kXCIpKTtcbiAgICAgICAgfTtcbiAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1zdGFydFwiKSk7XG4gICAgICAgIGlmIChibG9ja2luZyA9PT0gZmFsc2UpIHtcbiAgICAgICAgICBvblN0YXJ0KCk7XG4gICAgICAgICAgc2V0VGltZW91dChvbkVuZCwgdGltZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmlldy50cmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRW5kKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodGhpcy5pc1Zpc2libGUoZWwpKSB7XG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgIGVsLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwicGh4OmhpZGUtc3RhcnRcIikpO1xuICAgICAgICAgIERPTS5wdXRTdGlja3koXG4gICAgICAgICAgICBlbCxcbiAgICAgICAgICAgIFwidG9nZ2xlXCIsXG4gICAgICAgICAgICAoY3VycmVudEVsKSA9PiAoY3VycmVudEVsLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIiksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBlbC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudChcInBoeDpoaWRlLWVuZFwiKSk7XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1zdGFydFwiKSk7XG4gICAgICAgICAgY29uc3Qgc3RpY2t5RGlzcGxheSA9IGRpc3BsYXkgfHwgdGhpcy5kZWZhdWx0RGlzcGxheShlbCk7XG4gICAgICAgICAgRE9NLnB1dFN0aWNreShcbiAgICAgICAgICAgIGVsLFxuICAgICAgICAgICAgXCJ0b2dnbGVcIixcbiAgICAgICAgICAgIChjdXJyZW50RWwpID0+IChjdXJyZW50RWwuc3R5bGUuZGlzcGxheSA9IHN0aWNreURpc3BsYXkpLFxuICAgICAgICAgICk7XG4gICAgICAgICAgZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoXCJwaHg6c2hvdy1lbmRcIikpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgdG9nZ2xlQ2xhc3NlcyhlbCwgY2xhc3NlcywgdHJhbnNpdGlvbiwgdGltZSwgdmlldywgYmxvY2tpbmcpIHtcbiAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgIGNvbnN0IFtwcmV2QWRkcywgcHJldlJlbW92ZXNdID0gRE9NLmdldFN0aWNreShlbCwgXCJjbGFzc2VzXCIsIFtbXSwgW11dKTtcbiAgICAgIGNvbnN0IG5ld0FkZHMgPSBjbGFzc2VzLmZpbHRlcihcbiAgICAgICAgKG5hbWUpID0+IHByZXZBZGRzLmluZGV4T2YobmFtZSkgPCAwICYmICFlbC5jbGFzc0xpc3QuY29udGFpbnMobmFtZSksXG4gICAgICApO1xuICAgICAgY29uc3QgbmV3UmVtb3ZlcyA9IGNsYXNzZXMuZmlsdGVyKFxuICAgICAgICAobmFtZSkgPT4gcHJldlJlbW92ZXMuaW5kZXhPZihuYW1lKSA8IDAgJiYgZWwuY2xhc3NMaXN0LmNvbnRhaW5zKG5hbWUpLFxuICAgICAgKTtcbiAgICAgIHRoaXMuYWRkT3JSZW1vdmVDbGFzc2VzKFxuICAgICAgICBlbCxcbiAgICAgICAgbmV3QWRkcyxcbiAgICAgICAgbmV3UmVtb3ZlcyxcbiAgICAgICAgdHJhbnNpdGlvbixcbiAgICAgICAgdGltZSxcbiAgICAgICAgdmlldyxcbiAgICAgICAgYmxvY2tpbmcsXG4gICAgICApO1xuICAgIH0pO1xuICB9LFxuXG4gIHRvZ2dsZUF0dHIoZWwsIGF0dHIsIHZhbDEsIHZhbDIpIHtcbiAgICBpZiAoZWwuaGFzQXR0cmlidXRlKGF0dHIpKSB7XG4gICAgICBpZiAodmFsMiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIHRvZ2dsZSBiZXR3ZWVuIHZhbDEgYW5kIHZhbDJcbiAgICAgICAgaWYgKGVsLmdldEF0dHJpYnV0ZShhdHRyKSA9PT0gdmFsMSkge1xuICAgICAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWwyXV0sIFtdKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNldE9yUmVtb3ZlQXR0cnMoZWwsIFtbYXR0ciwgdmFsMV1dLCBbXSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHJlbW92ZSBhdHRyXG4gICAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW10sIFthdHRyXSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWwxXV0sIFtdKTtcbiAgICB9XG4gIH0sXG5cbiAgYWRkT3JSZW1vdmVDbGFzc2VzKGVsLCBhZGRzLCByZW1vdmVzLCB0cmFuc2l0aW9uLCB0aW1lLCB2aWV3LCBibG9ja2luZykge1xuICAgIHRpbWUgPSB0aW1lIHx8IGRlZmF1bHRfdHJhbnNpdGlvbl90aW1lO1xuICAgIGNvbnN0IFt0cmFuc2l0aW9uUnVuLCB0cmFuc2l0aW9uU3RhcnQsIHRyYW5zaXRpb25FbmRdID0gdHJhbnNpdGlvbiB8fCBbXG4gICAgICBbXSxcbiAgICAgIFtdLFxuICAgICAgW10sXG4gICAgXTtcbiAgICBpZiAodHJhbnNpdGlvblJ1bi5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBvblN0YXJ0ID0gKCkgPT4ge1xuICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhcbiAgICAgICAgICBlbCxcbiAgICAgICAgICB0cmFuc2l0aW9uU3RhcnQsXG4gICAgICAgICAgW10uY29uY2F0KHRyYW5zaXRpb25SdW4pLmNvbmNhdCh0cmFuc2l0aW9uRW5kKSxcbiAgICAgICAgKTtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5hZGRPclJlbW92ZUNsYXNzZXMoZWwsIHRyYW5zaXRpb25SdW4sIFtdKTtcbiAgICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+XG4gICAgICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhlbCwgdHJhbnNpdGlvbkVuZCwgdHJhbnNpdGlvblN0YXJ0KSxcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgICBjb25zdCBvbkRvbmUgPSAoKSA9PlxuICAgICAgICB0aGlzLmFkZE9yUmVtb3ZlQ2xhc3NlcyhcbiAgICAgICAgICBlbCxcbiAgICAgICAgICBhZGRzLmNvbmNhdCh0cmFuc2l0aW9uRW5kKSxcbiAgICAgICAgICByZW1vdmVzLmNvbmNhdCh0cmFuc2l0aW9uUnVuKS5jb25jYXQodHJhbnNpdGlvblN0YXJ0KSxcbiAgICAgICAgKTtcbiAgICAgIGlmIChibG9ja2luZyA9PT0gZmFsc2UpIHtcbiAgICAgICAgb25TdGFydCgpO1xuICAgICAgICBzZXRUaW1lb3V0KG9uRG9uZSwgdGltZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2aWV3LnRyYW5zaXRpb24odGltZSwgb25TdGFydCwgb25Eb25lKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgIGNvbnN0IFtwcmV2QWRkcywgcHJldlJlbW92ZXNdID0gRE9NLmdldFN0aWNreShlbCwgXCJjbGFzc2VzXCIsIFtbXSwgW11dKTtcbiAgICAgIGNvbnN0IGtlZXBBZGRzID0gYWRkcy5maWx0ZXIoXG4gICAgICAgIChuYW1lKSA9PiBwcmV2QWRkcy5pbmRleE9mKG5hbWUpIDwgMCAmJiAhZWwuY2xhc3NMaXN0LmNvbnRhaW5zKG5hbWUpLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGtlZXBSZW1vdmVzID0gcmVtb3Zlcy5maWx0ZXIoXG4gICAgICAgIChuYW1lKSA9PiBwcmV2UmVtb3Zlcy5pbmRleE9mKG5hbWUpIDwgMCAmJiBlbC5jbGFzc0xpc3QuY29udGFpbnMobmFtZSksXG4gICAgICApO1xuICAgICAgY29uc3QgbmV3QWRkcyA9IHByZXZBZGRzXG4gICAgICAgIC5maWx0ZXIoKG5hbWUpID0+IHJlbW92ZXMuaW5kZXhPZihuYW1lKSA8IDApXG4gICAgICAgIC5jb25jYXQoa2VlcEFkZHMpO1xuICAgICAgY29uc3QgbmV3UmVtb3ZlcyA9IHByZXZSZW1vdmVzXG4gICAgICAgIC5maWx0ZXIoKG5hbWUpID0+IGFkZHMuaW5kZXhPZihuYW1lKSA8IDApXG4gICAgICAgIC5jb25jYXQoa2VlcFJlbW92ZXMpO1xuXG4gICAgICBET00ucHV0U3RpY2t5KGVsLCBcImNsYXNzZXNcIiwgKGN1cnJlbnRFbCkgPT4ge1xuICAgICAgICBjdXJyZW50RWwuY2xhc3NMaXN0LnJlbW92ZSguLi5uZXdSZW1vdmVzKTtcbiAgICAgICAgY3VycmVudEVsLmNsYXNzTGlzdC5hZGQoLi4ubmV3QWRkcyk7XG4gICAgICAgIHJldHVybiBbbmV3QWRkcywgbmV3UmVtb3Zlc107XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSxcblxuICBzZXRPclJlbW92ZUF0dHJzKGVsLCBzZXRzLCByZW1vdmVzKSB7XG4gICAgY29uc3QgW3ByZXZTZXRzLCBwcmV2UmVtb3Zlc10gPSBET00uZ2V0U3RpY2t5KGVsLCBcImF0dHJzXCIsIFtbXSwgW11dKTtcblxuICAgIGNvbnN0IGFsdGVyZWRBdHRycyA9IHNldHMubWFwKChbYXR0ciwgX3ZhbF0pID0+IGF0dHIpLmNvbmNhdChyZW1vdmVzKTtcbiAgICBjb25zdCBuZXdTZXRzID0gcHJldlNldHNcbiAgICAgIC5maWx0ZXIoKFthdHRyLCBfdmFsXSkgPT4gIWFsdGVyZWRBdHRycy5pbmNsdWRlcyhhdHRyKSlcbiAgICAgIC5jb25jYXQoc2V0cyk7XG4gICAgY29uc3QgbmV3UmVtb3ZlcyA9IHByZXZSZW1vdmVzXG4gICAgICAuZmlsdGVyKChhdHRyKSA9PiAhYWx0ZXJlZEF0dHJzLmluY2x1ZGVzKGF0dHIpKVxuICAgICAgLmNvbmNhdChyZW1vdmVzKTtcblxuICAgIERPTS5wdXRTdGlja3koZWwsIFwiYXR0cnNcIiwgKGN1cnJlbnRFbCkgPT4ge1xuICAgICAgbmV3UmVtb3Zlcy5mb3JFYWNoKChhdHRyKSA9PiBjdXJyZW50RWwucmVtb3ZlQXR0cmlidXRlKGF0dHIpKTtcbiAgICAgIG5ld1NldHMuZm9yRWFjaCgoW2F0dHIsIHZhbF0pID0+IGN1cnJlbnRFbC5zZXRBdHRyaWJ1dGUoYXR0ciwgdmFsKSk7XG4gICAgICByZXR1cm4gW25ld1NldHMsIG5ld1JlbW92ZXNdO1xuICAgIH0pO1xuICB9LFxuXG4gIGhhc0FsbENsYXNzZXMoZWwsIGNsYXNzZXMpIHtcbiAgICByZXR1cm4gY2xhc3Nlcy5ldmVyeSgobmFtZSkgPT4gZWwuY2xhc3NMaXN0LmNvbnRhaW5zKG5hbWUpKTtcbiAgfSxcblxuICBpc1RvZ2dsZWRPdXQoZWwsIG91dENsYXNzZXMpIHtcbiAgICByZXR1cm4gIXRoaXMuaXNWaXNpYmxlKGVsKSB8fCB0aGlzLmhhc0FsbENsYXNzZXMoZWwsIG91dENsYXNzZXMpO1xuICB9LFxuXG4gIGZpbHRlclRvRWxzKGxpdmVTb2NrZXQsIHNvdXJjZUVsLCB7IHRvIH0pIHtcbiAgICBjb25zdCBkZWZhdWx0UXVlcnkgPSAoKSA9PiB7XG4gICAgICBpZiAodHlwZW9mIHRvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHRvKTtcbiAgICAgIH0gZWxzZSBpZiAodG8uY2xvc2VzdCkge1xuICAgICAgICBjb25zdCB0b0VsID0gc291cmNlRWwuY2xvc2VzdCh0by5jbG9zZXN0KTtcbiAgICAgICAgcmV0dXJuIHRvRWwgPyBbdG9FbF0gOiBbXTtcbiAgICAgIH0gZWxzZSBpZiAodG8uaW5uZXIpIHtcbiAgICAgICAgcmV0dXJuIHNvdXJjZUVsLnF1ZXJ5U2VsZWN0b3JBbGwodG8uaW5uZXIpO1xuICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIHRvXG4gICAgICA/IGxpdmVTb2NrZXQuanNRdWVyeVNlbGVjdG9yQWxsKHNvdXJjZUVsLCB0bywgZGVmYXVsdFF1ZXJ5KVxuICAgICAgOiBbc291cmNlRWxdO1xuICB9LFxuXG4gIGRlZmF1bHREaXNwbGF5KGVsKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIHsgdHI6IFwidGFibGUtcm93XCIsIHRkOiBcInRhYmxlLWNlbGxcIiB9W2VsLnRhZ05hbWUudG9Mb3dlckNhc2UoKV0gfHwgXCJibG9ja1wiXG4gICAgKTtcbiAgfSxcblxuICB0cmFuc2l0aW9uQ2xhc3Nlcyh2YWwpIHtcbiAgICBpZiAoIXZhbCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgbGV0IFt0cmFucywgdFN0YXJ0LCB0RW5kXSA9IEFycmF5LmlzQXJyYXkodmFsKVxuICAgICAgPyB2YWxcbiAgICAgIDogW3ZhbC5zcGxpdChcIiBcIiksIFtdLCBbXV07XG4gICAgdHJhbnMgPSBBcnJheS5pc0FycmF5KHRyYW5zKSA/IHRyYW5zIDogdHJhbnMuc3BsaXQoXCIgXCIpO1xuICAgIHRTdGFydCA9IEFycmF5LmlzQXJyYXkodFN0YXJ0KSA/IHRTdGFydCA6IHRTdGFydC5zcGxpdChcIiBcIik7XG4gICAgdEVuZCA9IEFycmF5LmlzQXJyYXkodEVuZCkgPyB0RW5kIDogdEVuZC5zcGxpdChcIiBcIik7XG4gICAgcmV0dXJuIFt0cmFucywgdFN0YXJ0LCB0RW5kXTtcbiAgfSxcbn07XG5cbmV4cG9ydCBkZWZhdWx0IEpTO1xuIiwgImltcG9ydCBKUyBmcm9tIFwiLi9qc1wiO1xuaW1wb3J0IExpdmVTb2NrZXQgZnJvbSBcIi4vbGl2ZV9zb2NrZXRcIjtcblxudHlwZSBUcmFuc2l0aW9uID0gc3RyaW5nIHwgc3RyaW5nW107XG5cbi8vIEJhc2Ugb3B0aW9ucyBmb3IgY29tbWFuZHMgaW52b2x2aW5nIHRyYW5zaXRpb25zIGFuZCB0aW1pbmdcbnR5cGUgQmFzZU9wdHMgPSB7XG4gIC8qKlxuICAgKiBUaGUgQ1NTIHRyYW5zaXRpb24gY2xhc3NlcyB0byBzZXQuXG4gICAqIEFjY2VwdHMgYSBzdHJpbmcgb2YgY2xhc3NlcyBvciBhIDMtdHVwbGUgbGlrZTpcbiAgICogYFtcImVhc2Utb3V0IGR1cmF0aW9uLTMwMFwiLCBcIm9wYWNpdHktMFwiLCBcIm9wYWNpdHktMTAwXCJdYFxuICAgKi9cbiAgdHJhbnNpdGlvbj86IFRyYW5zaXRpb247XG4gIC8qKiBUaGUgdHJhbnNpdGlvbiBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMuIERlZmF1bHRzIDIwMC4gKi9cbiAgdGltZT86IG51bWJlcjtcbiAgLyoqIFdoZXRoZXIgdG8gYmxvY2sgVUkgZHVyaW5nIHRyYW5zaXRpb24uIERlZmF1bHRzIGB0cnVlYC4gKi9cbiAgYmxvY2tpbmc/OiBib29sZWFuO1xufTtcblxudHlwZSBTaG93T3B0cyA9IEJhc2VPcHRzICYge1xuICAvKiogVGhlIENTUyBkaXNwbGF5IHZhbHVlIHRvIHNldC4gRGVmYXVsdHMgXCJibG9ja1wiLiAqL1xuICBkaXNwbGF5Pzogc3RyaW5nO1xufTtcblxudHlwZSBUb2dnbGVPcHRzID0ge1xuICAvKiogVGhlIENTUyBkaXNwbGF5IHZhbHVlIHRvIHNldC4gRGVmYXVsdHMgXCJibG9ja1wiLiAqL1xuICBkaXNwbGF5Pzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIENTUyB0cmFuc2l0aW9uIGNsYXNzZXMgZm9yIHNob3dpbmcuXG4gICAqIEFjY2VwdHMgZWl0aGVyIHRoZSBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRvZ2dsaW5nIGluLCBvclxuICAgKiBhIDMtdHVwbGUgY29udGFpbmluZyB0aGUgdHJhbnNpdGlvbiBjbGFzcywgdGhlIGNsYXNzIHRvIGFwcGx5XG4gICAqIHRvIHN0YXJ0IHRoZSB0cmFuc2l0aW9uLCBhbmQgdGhlIGVuZGluZyB0cmFuc2l0aW9uIGNsYXNzLCBzdWNoIGFzOlxuICAgKiBgW1wiZWFzZS1vdXQgZHVyYXRpb24tMzAwXCIsIFwib3BhY2l0eS0wXCIsIFwib3BhY2l0eS0xMDBcIl1gXG4gICAqL1xuICBpbj86IFRyYW5zaXRpb247XG4gIC8qKlxuICAgKiBUaGUgQ1NTIHRyYW5zaXRpb24gY2xhc3NlcyBmb3IgaGlkaW5nLlxuICAgKiBBY2NlcHRzIGVpdGhlciBzdHJpbmcgb2YgY2xhc3NlcyB0byBhcHBseSB3aGVuIHRvZ2dsaW5nIG91dCwgb3JcbiAgICogYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgKiB0byBzdGFydCB0aGUgdHJhbnNpdGlvbiwgYW5kIHRoZSBlbmRpbmcgdHJhbnNpdGlvbiBjbGFzcywgc3VjaCBhczpcbiAgICogYFtcImVhc2Utb3V0IGR1cmF0aW9uLTMwMFwiLCBcIm9wYWNpdHktMTAwXCIsIFwib3BhY2l0eS0wXCJdYFxuICAgKi9cbiAgb3V0PzogVHJhbnNpdGlvbjtcbiAgLyoqIFRoZSB0cmFuc2l0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcy4gKi9cbiAgdGltZT86IG51bWJlcjtcbiAgLyoqIFdoZXRoZXIgdG8gYmxvY2sgVUkgZHVyaW5nIHRyYW5zaXRpb24uIERlZmF1bHRzIGB0cnVlYC4gKi9cbiAgYmxvY2tpbmc/OiBib29sZWFuO1xufTtcblxuLy8gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgJ3RyYW5zaXRpb24nIGNvbW1hbmRcbnR5cGUgVHJhbnNpdGlvbkNvbW1hbmRPcHRzID0ge1xuICAvKiogVGhlIHRyYW5zaXRpb24gZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzLiAqL1xuICB0aW1lPzogbnVtYmVyO1xuICAvKiogV2hldGhlciB0byBibG9jayBVSSBkdXJpbmcgdHJhbnNpdGlvbi4gRGVmYXVsdHMgYHRydWVgLiAqL1xuICBibG9ja2luZz86IGJvb2xlYW47XG59O1xuXG50eXBlIFB1c2hPcHRzID0ge1xuICAvKiogRGF0YSB0byBiZSBtZXJnZWQgaW50byB0aGUgZXZlbnQgcGF5bG9hZC4gKi9cbiAgdmFsdWU/OiBhbnk7XG4gIC8qKiBGb3IgdGFyZ2V0aW5nIGEgTGl2ZUNvbXBvbmVudCBieSBpdHMgSUQsIGEgY29tcG9uZW50IElEIChudW1iZXIpLCBvciBhIENTUyBzZWxlY3RvciBzdHJpbmcuICovXG4gIHRhcmdldD86IEhUTUxFbGVtZW50IHwgbnVtYmVyIHwgc3RyaW5nO1xuICAvKiogSW5kaWNhdGVzIGlmIGEgcGFnZSBsb2FkaW5nIHN0YXRlIHNob3VsZCBiZSBzaG93bi4gKi9cbiAgcGFnZV9sb2FkaW5nPzogYm9vbGVhbjtcbiAgW2tleTogc3RyaW5nXTogYW55OyAvLyBBbGxvdyBvdGhlciBwcm9wZXJ0aWVzIGxpa2UgJ2NpZCcsICdyZWRpcmVjdCcsIGV0Yy5cbn07XG5cbnR5cGUgTmF2aWdhdGlvbk9wdHMgPSB7XG4gIC8qKiBXaGV0aGVyIHRvIHJlcGxhY2UgdGhlIGN1cnJlbnQgaGlzdG9yeSBlbnRyeSBpbnN0ZWFkIG9mIHB1c2hpbmcgYSBuZXcgb25lLiAqL1xuICByZXBsYWNlPzogYm9vbGVhbjtcbn07XG5cbi8qKlxuICogUmVwcmVzZW50cyBhbGwgcG9zc2libGUgSlMgY29tbWFuZHMgdGhhdCBjYW4gYmUgZ2VuZXJhdGVkIGJ5IHRoZSBmYWN0b3J5LlxuICogVGhpcyBpcyB1c2VkIGFzIGEgYmFzZSBmb3IgTGl2ZVNvY2tldEpTQ29tbWFuZHMgYW5kIEhvb2tKU0NvbW1hbmRzLlxuICovXG5pbnRlcmZhY2UgQWxsSlNDb21tYW5kcyB7XG4gIC8qKlxuICAgKiBFeGVjdXRlcyBlbmNvZGVkIEphdmFTY3JpcHQgaW4gdGhlIGNvbnRleHQgb2YgdGhlIGVsZW1lbnQuXG4gICAqIFRoaXMgdmVyc2lvbiBpcyBmb3IgZ2VuZXJhbCB1c2UgdmlhIGxpdmVTb2NrZXQuanMoKS5cbiAgICpcbiAgICogQHBhcmFtIGVsIC0gVGhlIGVsZW1lbnQgaW4gd2hvc2UgY29udGV4dCB0byBleGVjdXRlIHRoZSBKYXZhU2NyaXB0LlxuICAgKiBAcGFyYW0gZW5jb2RlZEpTIC0gVGhlIGVuY29kZWQgSmF2YVNjcmlwdCBzdHJpbmcgdG8gZXhlY3V0ZS5cbiAgICovXG4gIGV4ZWMoZWw6IEhUTUxFbGVtZW50LCBlbmNvZGVkSlM6IHN0cmluZyk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFNob3dzIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIHNob3cuXG4gICAqIEBwYXJhbSB7U2hvd09wdHN9IFtvcHRzPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdzLlxuICAgKiAgIEFjY2VwdHM6IGBkaXNwbGF5YCwgYHRyYW5zaXRpb25gLCBgdGltZWAsIGFuZCBgYmxvY2tpbmdgLlxuICAgKi9cbiAgc2hvdyhlbDogSFRNTEVsZW1lbnQsIG9wdHM/OiBTaG93T3B0cyk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIEhpZGVzIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIGhpZGUuXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgdHJhbnNpdGlvbmAsIGB0aW1lYCwgYW5kIGBibG9ja2luZ2AuXG4gICAqL1xuICBoaWRlKGVsOiBIVE1MRWxlbWVudCwgb3B0cz86IEJhc2VPcHRzKTogdm9pZDtcblxuICAvKipcbiAgICogVG9nZ2xlcyB0aGUgdmlzaWJpbGl0eSBvZiBhbiBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gZWwgLSBUaGUgZWxlbWVudCB0byB0b2dnbGUuXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgZGlzcGxheWAsIGBpbmAsIGBvdXRgLCBgdGltZWAsIGFuZCBgYmxvY2tpbmdgLlxuICAgKi9cbiAgdG9nZ2xlKGVsOiBIVE1MRWxlbWVudCwgb3B0cz86IFRvZ2dsZU9wdHMpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBBZGRzIENTUyBjbGFzc2VzIHRvIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIGFkZCBjbGFzc2VzIHRvLlxuICAgKiBAcGFyYW0gbmFtZXMgLSBUaGUgY2xhc3MgbmFtZShzKSB0byBhZGQuXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgdHJhbnNpdGlvbmAsIGB0aW1lYCwgYW5kIGBibG9ja2luZ2AuXG4gICAqL1xuICBhZGRDbGFzcyhlbDogSFRNTEVsZW1lbnQsIG5hbWVzOiBzdHJpbmcgfCBzdHJpbmdbXSwgb3B0cz86IEJhc2VPcHRzKTogdm9pZDtcblxuICAvKipcbiAgICogUmVtb3ZlcyBDU1MgY2xhc3NlcyBmcm9tIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIHJlbW92ZSBjbGFzc2VzIGZyb20uXG4gICAqIEBwYXJhbSBuYW1lcyAtIFRoZSBjbGFzcyBuYW1lKHMpIHRvIHJlbW92ZS5cbiAgICogQHBhcmFtIFtvcHRzPXt9XSAtIE9wdGlvbmFsIHNldHRpbmdzLlxuICAgKiAgIEFjY2VwdHM6IGB0cmFuc2l0aW9uYCwgYHRpbWVgLCBhbmQgYGJsb2NraW5nYC5cbiAgICovXG4gIHJlbW92ZUNsYXNzKGVsOiBIVE1MRWxlbWVudCwgbmFtZXM6IHN0cmluZyB8IHN0cmluZ1tdLCBvcHRzPzogQmFzZU9wdHMpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUb2dnbGVzIENTUyBjbGFzc2VzIG9uIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIHRvZ2dsZSBjbGFzc2VzIG9uLlxuICAgKiBAcGFyYW0gbmFtZXMgLSBUaGUgY2xhc3MgbmFtZShzKSB0byB0b2dnbGUuXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgdHJhbnNpdGlvbmAsIGB0aW1lYCwgYW5kIGBibG9ja2luZ2AuXG4gICAqL1xuICB0b2dnbGVDbGFzcyhlbDogSFRNTEVsZW1lbnQsIG5hbWVzOiBzdHJpbmcgfCBzdHJpbmdbXSwgb3B0cz86IEJhc2VPcHRzKTogdm9pZDtcblxuICAvKipcbiAgICogQXBwbGllcyBhIENTUyB0cmFuc2l0aW9uIHRvIGFuIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSBlbCAtIFRoZSBlbGVtZW50IHRvIGFwcGx5IHRoZSB0cmFuc2l0aW9uIHRvLlxuICAgKiBAcGFyYW0gdHJhbnNpdGlvbiAtIFRoZSB0cmFuc2l0aW9uIGNsYXNzKGVzKSB0byBhcHBseS5cbiAgICogICBBY2NlcHRzIGEgc3RyaW5nIG9mIGNsYXNzZXMgdG8gYXBwbHkgd2hlbiB0cmFuc2l0aW9uaW5nIG9yXG4gICAqICAgYSAzLXR1cGxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zaXRpb24gY2xhc3MsIHRoZSBjbGFzcyB0byBhcHBseVxuICAgKiAgIHRvIHN0YXJ0IHRoZSB0cmFuc2l0aW9uLCBhbmQgdGhlIGVuZGluZyB0cmFuc2l0aW9uIGNsYXNzLCBzdWNoIGFzOlxuICAgKlxuICAgKiAgICAgICBbXCJlYXNlLW91dCBkdXJhdGlvbi0zMDBcIiwgXCJvcGFjaXR5LTEwMFwiLCBcIm9wYWNpdHktMFwiXVxuICAgKlxuICAgKiBAcGFyYW0gW29wdHM9e31dIC0gT3B0aW9uYWwgc2V0dGluZ3MgZm9yIHRpbWluZyBhbmQgYmxvY2tpbmcgYmVoYXZpb3IuXG4gICAqICAgQWNjZXB0czogYHRpbWVgIGFuZCBgYmxvY2tpbmdgLlxuICAgKi9cbiAgdHJhbnNpdGlvbihcbiAgICBlbDogSFRNTEVsZW1lbnQsXG4gICAgdHJhbnNpdGlvbjogc3RyaW5nIHwgc3RyaW5nW10sXG4gICAgb3B0cz86IFRyYW5zaXRpb25Db21tYW5kT3B0cyxcbiAgKTogdm9pZDtcblxuICAvKipcbiAgICogU2V0cyBhbiBhdHRyaWJ1dGUgb24gYW4gZWxlbWVudC5cbiAgICpcbiAgICogQHBhcmFtIGVsIC0gVGhlIGVsZW1lbnQgdG8gc2V0IHRoZSBhdHRyaWJ1dGUgb24uXG4gICAqIEBwYXJhbSBhdHRyIC0gVGhlIGF0dHJpYnV0ZSBuYW1lIHRvIHNldC5cbiAgICogQHBhcmFtIHZhbCAtIFRoZSB2YWx1ZSB0byBzZXQgZm9yIHRoZSBhdHRyaWJ1dGUuXG4gICAqL1xuICBzZXRBdHRyaWJ1dGUoZWw6IEhUTUxFbGVtZW50LCBhdHRyOiBzdHJpbmcsIHZhbDogc3RyaW5nKTogdm9pZDtcblxuICAvKipcbiAgICogUmVtb3ZlcyBhbiBhdHRyaWJ1dGUgZnJvbSBhbiBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gZWwgLSBUaGUgZWxlbWVudCB0byByZW1vdmUgdGhlIGF0dHJpYnV0ZSBmcm9tLlxuICAgKiBAcGFyYW0gYXR0ciAtIFRoZSBhdHRyaWJ1dGUgbmFtZSB0byByZW1vdmUuXG4gICAqL1xuICByZW1vdmVBdHRyaWJ1dGUoZWw6IEhUTUxFbGVtZW50LCBhdHRyOiBzdHJpbmcpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUb2dnbGVzIGFuIGF0dHJpYnV0ZSBvbiBhbiBlbGVtZW50IGJldHdlZW4gdHdvIHZhbHVlcy5cbiAgICpcbiAgICogQHBhcmFtIGVsIC0gVGhlIGVsZW1lbnQgdG8gdG9nZ2xlIHRoZSBhdHRyaWJ1dGUgb24uXG4gICAqIEBwYXJhbSBhdHRyIC0gVGhlIGF0dHJpYnV0ZSBuYW1lIHRvIHRvZ2dsZS5cbiAgICogQHBhcmFtIHZhbDEgLSBUaGUgZmlyc3QgdmFsdWUgdG8gdG9nZ2xlIGJldHdlZW4uXG4gICAqIEBwYXJhbSB2YWwyIC0gVGhlIHNlY29uZCB2YWx1ZSB0byB0b2dnbGUgYmV0d2Vlbi5cbiAgICovXG4gIHRvZ2dsZUF0dHJpYnV0ZShcbiAgICBlbDogSFRNTEVsZW1lbnQsXG4gICAgYXR0cjogc3RyaW5nLFxuICAgIHZhbDE6IHN0cmluZyxcbiAgICB2YWwyOiBzdHJpbmcsXG4gICk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFB1c2hlcyBhbiBldmVudCB0byB0aGUgc2VydmVyLlxuICAgKlxuICAgKiBAcGFyYW0gZWwgLSBBbiBlbGVtZW50IHRoYXQgYmVsb25ncyB0byB0aGUgdGFyZ2V0IExpdmVWaWV3IC8gTGl2ZUNvbXBvbmVudCBvciBhIGNvbXBvbmVudCBJRC5cbiAgICogICBUbyB0YXJnZXQgYSBMaXZlQ29tcG9uZW50IGJ5IGl0cyBJRCwgcGFzcyBhIHNlcGFyYXRlIGB0YXJnZXRgIGluIHRoZSBvcHRpb25zLlxuICAgKiBAcGFyYW0gdHlwZSAtIFRoZSBldmVudCBuYW1lIHRvIHB1c2guXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgdmFsdWVgLCBgdGFyZ2V0YCwgYHBhZ2VfbG9hZGluZ2AuXG4gICAqL1xuICBwdXNoKGVsOiBIVE1MRWxlbWVudCwgdHlwZTogc3RyaW5nLCBvcHRzPzogUHVzaE9wdHMpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBTZW5kcyBhIG5hdmlnYXRpb24gZXZlbnQgdG8gdGhlIHNlcnZlciBhbmQgdXBkYXRlcyB0aGUgYnJvd3NlcidzIHB1c2hTdGF0ZSBoaXN0b3J5LlxuICAgKlxuICAgKiBAcGFyYW0gaHJlZiAtIFRoZSBVUkwgdG8gbmF2aWdhdGUgdG8uXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgcmVwbGFjZWAuXG4gICAqL1xuICBuYXZpZ2F0ZShocmVmOiBzdHJpbmcsIG9wdHM/OiBOYXZpZ2F0aW9uT3B0cyk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFNlbmRzIGEgcGF0Y2ggZXZlbnQgdG8gdGhlIHNlcnZlciBhbmQgdXBkYXRlcyB0aGUgYnJvd3NlcidzIHB1c2hTdGF0ZSBoaXN0b3J5LlxuICAgKlxuICAgKiBAcGFyYW0gaHJlZiAtIFRoZSBVUkwgdG8gcGF0Y2ggdG8uXG4gICAqIEBwYXJhbSBbb3B0cz17fV0gLSBPcHRpb25hbCBzZXR0aW5ncy5cbiAgICogICBBY2NlcHRzOiBgcmVwbGFjZWAuXG4gICAqL1xuICBwYXRjaChocmVmOiBzdHJpbmcsIG9wdHM/OiBOYXZpZ2F0aW9uT3B0cyk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIE1hcmsgYXR0cmlidXRlcyBhcyBpZ25vcmVkLCBza2lwcGluZyB0aGVtIHdoZW4gcGF0Y2hpbmcgdGhlIERPTS5cbiAgICpcbiAgICogQHBhcmFtIGVsIC0gVGhlIGVsZW1lbnQgdG8gaWdub3JlIGF0dHJpYnV0ZXMgb24uXG4gICAqIEBwYXJhbSBhdHRycyAtIFRoZSBhdHRyaWJ1dGUgbmFtZSBvciBuYW1lcyB0byBpZ25vcmUuXG4gICAqL1xuICBpZ25vcmVBdHRyaWJ1dGVzKGVsOiBIVE1MRWxlbWVudCwgYXR0cnM6IHN0cmluZyB8IHN0cmluZ1tdKTogdm9pZDtcbn1cblxuZXhwb3J0IGRlZmF1bHQgKFxuICBsaXZlU29ja2V0OiBMaXZlU29ja2V0LFxuICBldmVudFR5cGU6IHN0cmluZyB8IG51bGwsXG4pOiBBbGxKU0NvbW1hbmRzID0+IHtcbiAgcmV0dXJuIHtcbiAgICBleGVjKGVsLCBlbmNvZGVkSlMpIHtcbiAgICAgIGxpdmVTb2NrZXQuZXhlY0pTKGVsLCBlbmNvZGVkSlMsIGV2ZW50VHlwZSk7XG4gICAgfSxcbiAgICBzaG93KGVsLCBvcHRzID0ge30pIHtcbiAgICAgIGNvbnN0IG93bmVyID0gbGl2ZVNvY2tldC5vd25lcihlbCk7XG4gICAgICBKUy5zaG93KFxuICAgICAgICBldmVudFR5cGUsXG4gICAgICAgIG93bmVyLFxuICAgICAgICBlbCxcbiAgICAgICAgb3B0cy5kaXNwbGF5LFxuICAgICAgICBKUy50cmFuc2l0aW9uQ2xhc3NlcyhvcHRzLnRyYW5zaXRpb24pLFxuICAgICAgICBvcHRzLnRpbWUsXG4gICAgICAgIG9wdHMuYmxvY2tpbmcsXG4gICAgICApO1xuICAgIH0sXG4gICAgaGlkZShlbCwgb3B0cyA9IHt9KSB7XG4gICAgICBjb25zdCBvd25lciA9IGxpdmVTb2NrZXQub3duZXIoZWwpO1xuICAgICAgSlMuaGlkZShcbiAgICAgICAgZXZlbnRUeXBlLFxuICAgICAgICBvd25lcixcbiAgICAgICAgZWwsXG4gICAgICAgIG51bGwsXG4gICAgICAgIEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMudHJhbnNpdGlvbiksXG4gICAgICAgIG9wdHMudGltZSxcbiAgICAgICAgb3B0cy5ibG9ja2luZyxcbiAgICAgICk7XG4gICAgfSxcbiAgICB0b2dnbGUoZWwsIG9wdHMgPSB7fSkge1xuICAgICAgY29uc3Qgb3duZXIgPSBsaXZlU29ja2V0Lm93bmVyKGVsKTtcbiAgICAgIGNvbnN0IGluVHJhbnNpdGlvbiA9IEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMuaW4pO1xuICAgICAgY29uc3Qgb3V0VHJhbnNpdGlvbiA9IEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMub3V0KTtcbiAgICAgIEpTLnRvZ2dsZShcbiAgICAgICAgZXZlbnRUeXBlLFxuICAgICAgICBvd25lcixcbiAgICAgICAgZWwsXG4gICAgICAgIG9wdHMuZGlzcGxheSxcbiAgICAgICAgaW5UcmFuc2l0aW9uLFxuICAgICAgICBvdXRUcmFuc2l0aW9uLFxuICAgICAgICBvcHRzLnRpbWUsXG4gICAgICAgIG9wdHMuYmxvY2tpbmcsXG4gICAgICApO1xuICAgIH0sXG4gICAgYWRkQ2xhc3MoZWwsIG5hbWVzLCBvcHRzID0ge30pIHtcbiAgICAgIGNvbnN0IGNsYXNzTmFtZXMgPSBBcnJheS5pc0FycmF5KG5hbWVzKSA/IG5hbWVzIDogbmFtZXMuc3BsaXQoXCIgXCIpO1xuICAgICAgY29uc3Qgb3duZXIgPSBsaXZlU29ja2V0Lm93bmVyKGVsKTtcbiAgICAgIEpTLmFkZE9yUmVtb3ZlQ2xhc3NlcyhcbiAgICAgICAgZWwsXG4gICAgICAgIGNsYXNzTmFtZXMsXG4gICAgICAgIFtdLFxuICAgICAgICBKUy50cmFuc2l0aW9uQ2xhc3NlcyhvcHRzLnRyYW5zaXRpb24pLFxuICAgICAgICBvcHRzLnRpbWUsXG4gICAgICAgIG93bmVyLFxuICAgICAgICBvcHRzLmJsb2NraW5nLFxuICAgICAgKTtcbiAgICB9LFxuICAgIHJlbW92ZUNsYXNzKGVsLCBuYW1lcywgb3B0cyA9IHt9KSB7XG4gICAgICBjb25zdCBjbGFzc05hbWVzID0gQXJyYXkuaXNBcnJheShuYW1lcykgPyBuYW1lcyA6IG5hbWVzLnNwbGl0KFwiIFwiKTtcbiAgICAgIGNvbnN0IG93bmVyID0gbGl2ZVNvY2tldC5vd25lcihlbCk7XG4gICAgICBKUy5hZGRPclJlbW92ZUNsYXNzZXMoXG4gICAgICAgIGVsLFxuICAgICAgICBbXSxcbiAgICAgICAgY2xhc3NOYW1lcyxcbiAgICAgICAgSlMudHJhbnNpdGlvbkNsYXNzZXMob3B0cy50cmFuc2l0aW9uKSxcbiAgICAgICAgb3B0cy50aW1lLFxuICAgICAgICBvd25lcixcbiAgICAgICAgb3B0cy5ibG9ja2luZyxcbiAgICAgICk7XG4gICAgfSxcbiAgICB0b2dnbGVDbGFzcyhlbCwgbmFtZXMsIG9wdHMgPSB7fSkge1xuICAgICAgY29uc3QgY2xhc3NOYW1lcyA9IEFycmF5LmlzQXJyYXkobmFtZXMpID8gbmFtZXMgOiBuYW1lcy5zcGxpdChcIiBcIik7XG4gICAgICBjb25zdCBvd25lciA9IGxpdmVTb2NrZXQub3duZXIoZWwpO1xuICAgICAgSlMudG9nZ2xlQ2xhc3NlcyhcbiAgICAgICAgZWwsXG4gICAgICAgIGNsYXNzTmFtZXMsXG4gICAgICAgIEpTLnRyYW5zaXRpb25DbGFzc2VzKG9wdHMudHJhbnNpdGlvbiksXG4gICAgICAgIG9wdHMudGltZSxcbiAgICAgICAgb3duZXIsXG4gICAgICAgIG9wdHMuYmxvY2tpbmcsXG4gICAgICApO1xuICAgIH0sXG4gICAgdHJhbnNpdGlvbihlbCwgdHJhbnNpdGlvbiwgb3B0cyA9IHt9KSB7XG4gICAgICBjb25zdCBvd25lciA9IGxpdmVTb2NrZXQub3duZXIoZWwpO1xuICAgICAgSlMuYWRkT3JSZW1vdmVDbGFzc2VzKFxuICAgICAgICBlbCxcbiAgICAgICAgW10sXG4gICAgICAgIFtdLFxuICAgICAgICBKUy50cmFuc2l0aW9uQ2xhc3Nlcyh0cmFuc2l0aW9uKSxcbiAgICAgICAgb3B0cy50aW1lLFxuICAgICAgICBvd25lcixcbiAgICAgICAgb3B0cy5ibG9ja2luZyxcbiAgICAgICk7XG4gICAgfSxcbiAgICBzZXRBdHRyaWJ1dGUoZWwsIGF0dHIsIHZhbCkge1xuICAgICAgSlMuc2V0T3JSZW1vdmVBdHRycyhlbCwgW1thdHRyLCB2YWxdXSwgW10pO1xuICAgIH0sXG4gICAgcmVtb3ZlQXR0cmlidXRlKGVsLCBhdHRyKSB7XG4gICAgICBKUy5zZXRPclJlbW92ZUF0dHJzKGVsLCBbXSwgW2F0dHJdKTtcbiAgICB9LFxuICAgIHRvZ2dsZUF0dHJpYnV0ZShlbCwgYXR0ciwgdmFsMSwgdmFsMikge1xuICAgICAgSlMudG9nZ2xlQXR0cihlbCwgYXR0ciwgdmFsMSwgdmFsMik7XG4gICAgfSxcbiAgICBwdXNoKGVsLCB0eXBlLCBvcHRzID0ge30pIHtcbiAgICAgIGxpdmVTb2NrZXQud2l0aGluT3duZXJzKGVsLCAodmlldykgPT4ge1xuICAgICAgICBjb25zdCBkYXRhID0gb3B0cy52YWx1ZSB8fCB7fTtcbiAgICAgICAgZGVsZXRlIG9wdHMudmFsdWU7XG4gICAgICAgIGxldCBlID0gbmV3IEN1c3RvbUV2ZW50KFwicGh4OmV4ZWNcIiwgeyBkZXRhaWw6IHsgc291cmNlRWxlbWVudDogZWwgfSB9KTtcbiAgICAgICAgSlMuZXhlYyhlLCBldmVudFR5cGUsIHR5cGUsIHZpZXcsIGVsLCBbXCJwdXNoXCIsIHsgZGF0YSwgLi4ub3B0cyB9XSk7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIG5hdmlnYXRlKGhyZWYsIG9wdHMgPSB7fSkge1xuICAgICAgY29uc3QgY3VzdG9tRXZlbnQgPSBuZXcgQ3VzdG9tRXZlbnQoXCJwaHg6ZXhlY1wiKTtcbiAgICAgIGxpdmVTb2NrZXQuaGlzdG9yeVJlZGlyZWN0KFxuICAgICAgICBjdXN0b21FdmVudCxcbiAgICAgICAgaHJlZixcbiAgICAgICAgb3B0cy5yZXBsYWNlID8gXCJyZXBsYWNlXCIgOiBcInB1c2hcIixcbiAgICAgICAgbnVsbCxcbiAgICAgICAgbnVsbCxcbiAgICAgICk7XG4gICAgfSxcbiAgICBwYXRjaChocmVmLCBvcHRzID0ge30pIHtcbiAgICAgIGNvbnN0IGN1c3RvbUV2ZW50ID0gbmV3IEN1c3RvbUV2ZW50KFwicGh4OmV4ZWNcIik7XG4gICAgICBsaXZlU29ja2V0LnB1c2hIaXN0b3J5UGF0Y2goXG4gICAgICAgIGN1c3RvbUV2ZW50LFxuICAgICAgICBocmVmLFxuICAgICAgICBvcHRzLnJlcGxhY2UgPyBcInJlcGxhY2VcIiA6IFwicHVzaFwiLFxuICAgICAgICBudWxsLFxuICAgICAgKTtcbiAgICB9LFxuICAgIGlnbm9yZUF0dHJpYnV0ZXMoZWwsIGF0dHJzKSB7XG4gICAgICBKUy5pZ25vcmVBdHRycyhlbCwgQXJyYXkuaXNBcnJheShhdHRycykgPyBhdHRycyA6IFthdHRyc10pO1xuICAgIH0sXG4gIH07XG59O1xuXG4vKipcbiAqIEpTQ29tbWFuZHMgZm9yIHVzZSB3aXRoIGBsaXZlU29ja2V0LmpzKClgLlxuICogSW5jbHVkZXMgdGhlIGdlbmVyYWwgYGV4ZWNgIGNvbW1hbmQgdGhhdCByZXF1aXJlcyBhbiBlbGVtZW50LlxuICovXG5leHBvcnQgdHlwZSBMaXZlU29ja2V0SlNDb21tYW5kcyA9IEFsbEpTQ29tbWFuZHM7XG5cbi8qKlxuICogSlNDb21tYW5kcyBmb3IgdXNlIHdpdGhpbiBhIEhvb2suXG4gKiBUaGUgYGV4ZWNgIGNvbW1hbmQgaXMgdGFpbG9yZWQgZm9yIGhvb2tzLCBub3QgcmVxdWlyaW5nIGFuIGV4cGxpY2l0IGVsZW1lbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSG9va0pTQ29tbWFuZHMgZXh0ZW5kcyBPbWl0PEFsbEpTQ29tbWFuZHMsIFwiZXhlY1wiPiB7XG4gIC8qKlxuICAgKiBFeGVjdXRlcyBlbmNvZGVkIEphdmFTY3JpcHQgaW4gdGhlIGNvbnRleHQgb2YgdGhlIGhvb2sncyBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RlZEpTIC0gVGhlIGVuY29kZWQgSmF2YVNjcmlwdCBzdHJpbmcgdG8gZXhlY3V0ZS5cbiAgICovXG4gIGV4ZWMoZW5jb2RlZEpTOiBzdHJpbmcpOiB2b2lkO1xufVxuIiwgImltcG9ydCBqc0NvbW1hbmRzLCB7IEhvb2tKU0NvbW1hbmRzIH0gZnJvbSBcIi4vanNfY29tbWFuZHNcIjtcbmltcG9ydCBET00gZnJvbSBcIi4vZG9tXCI7XG5pbXBvcnQgTGl2ZVNvY2tldCBmcm9tIFwiLi9saXZlX3NvY2tldFwiO1xuaW1wb3J0IFZpZXcgZnJvbSBcIi4vdmlld1wiO1xuXG5jb25zdCBIT09LX0lEID0gXCJob29rSWRcIjtcbmxldCB2aWV3SG9va0lEID0gMTtcblxuZXhwb3J0IHR5cGUgT25SZXBseSA9IChyZXBseTogYW55LCByZWY6IG51bWJlcikgPT4gYW55O1xuZXhwb3J0IHR5cGUgQ2FsbGJhY2tSZWYgPSB7IGV2ZW50OiBzdHJpbmc7IGNhbGxiYWNrOiAocGF5bG9hZDogYW55KSA9PiBhbnkgfTtcblxuZXhwb3J0IHR5cGUgUGh4VGFyZ2V0ID0gc3RyaW5nIHwgbnVtYmVyIHwgSFRNTEVsZW1lbnQ7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSG9va0ludGVyZmFjZSB7XG4gIC8qKlxuICAgKiBUaGUgRE9NIGVsZW1lbnQgdGhhdCB0aGUgaG9vayBpcyBhdHRhY2hlZCB0by5cbiAgICovXG4gIGVsOiBIVE1MRWxlbWVudDtcblxuICAvKipcbiAgICogVGhlIExpdmVTb2NrZXQgaW5zdGFuY2UgdGhhdCB0aGUgaG9vayBpcyBhdHRhY2hlZCB0by5cbiAgICovXG4gIGxpdmVTb2NrZXQ6IExpdmVTb2NrZXQ7XG5cbiAgLyoqXG4gICAqIFRoZSBtb3VudGVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBoYXMgYmVlbiBhZGRlZCB0byB0aGUgRE9NIGFuZCBpdHMgc2VydmVyIExpdmVWaWV3IGhhcyBmaW5pc2hlZCBtb3VudGluZy5cbiAgICovXG4gIG1vdW50ZWQ/OiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgYmVmb3JlVXBkYXRlIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBpcyBhYm91dCB0byBiZSB1cGRhdGVkIGluIHRoZSBET00uXG4gICAqIE5vdGU6IGFueSBjYWxsIGhlcmUgbXVzdCBiZSBzeW5jaHJvbm91cyBhcyB0aGUgb3BlcmF0aW9uIGNhbm5vdCBiZSBkZWZlcnJlZCBvciBjYW5jZWxsZWQuXG4gICAqL1xuICBiZWZvcmVVcGRhdGU/OiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgdXBkYXRlZCBjYWxsYmFjay5cbiAgICpcbiAgICogQ2FsbGVkIHdoZW4gdGhlIGVsZW1lbnQgaGFzIGJlZW4gdXBkYXRlZCBpbiB0aGUgRE9NIGJ5IHRoZSBzZXJ2ZXJcbiAgICovXG4gIHVwZGF0ZWQ/OiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgZGVzdHJveWVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBoYXMgYmVlbiByZW1vdmVkIGZyb20gdGhlIHBhZ2UsIGVpdGhlciBieSBhIHBhcmVudCB1cGRhdGUsIG9yIGJ5IHRoZSBwYXJlbnQgYmVpbmcgcmVtb3ZlZCBlbnRpcmVseVxuICAgKi9cbiAgZGVzdHJveWVkPzogKCkgPT4gdm9pZDtcblxuICAvKipcbiAgICogVGhlIGRpc2Nvbm5lY3RlZCBjYWxsYmFjay5cbiAgICpcbiAgICogQ2FsbGVkIHdoZW4gdGhlIGVsZW1lbnQncyBwYXJlbnQgTGl2ZVZpZXcgaGFzIGRpc2Nvbm5lY3RlZCBmcm9tIHRoZSBzZXJ2ZXIuXG4gICAqL1xuICBkaXNjb25uZWN0ZWQ/OiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVjb25uZWN0ZWQgY2FsbGJhY2suXG4gICAqXG4gICAqIENhbGxlZCB3aGVuIHRoZSBlbGVtZW50J3MgcGFyZW50IExpdmVWaWV3IGhhcyByZWNvbm5lY3RlZCB0byB0aGUgc2VydmVyLlxuICAgKi9cbiAgcmVjb25uZWN0ZWQ/OiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIG9iamVjdCB3aXRoIG1ldGhvZHMgdG8gbWFuaXBsdWF0ZSB0aGUgRE9NIGFuZCBleGVjdXRlIEphdmFTY3JpcHQuXG4gICAqIFRoZSBhcHBsaWVkIGNoYW5nZXMgaW50ZWdyYXRlIHdpdGggc2VydmVyIERPTSBwYXRjaGluZy5cbiAgICovXG4gIGpzKCk6IEhvb2tKU0NvbW1hbmRzO1xuXG4gIC8qKlxuICAgKiBQdXNoZXMgYW4gZXZlbnQgdG8gdGhlIHNlcnZlci5cbiAgICpcbiAgICogQHBhcmFtIGV2ZW50IC0gVGhlIGV2ZW50IG5hbWUuXG4gICAqIEBwYXJhbSBbcGF5bG9hZF0gLSBUaGUgcGF5bG9hZCB0byBzZW5kIHRvIHRoZSBzZXJ2ZXIuIERlZmF1bHRzIHRvIGFuIGVtcHR5IG9iamVjdC5cbiAgICogQHBhcmFtIFtvblJlcGx5XSAtIEEgY2FsbGJhY2sgdG8gaGFuZGxlIHRoZSBzZXJ2ZXIncyByZXBseS5cbiAgICpcbiAgICogV2hlbiBvblJlcGx5IGlzIG5vdCBwcm92aWRlZCwgdGhlIG1ldGhvZCByZXR1cm5zIGEgUHJvbWlzZSB0aGF0XG4gICAqIFdoZW4gb25SZXBseSBpcyBwcm92aWRlZCwgdGhlIG1ldGhvZCByZXR1cm5zIHZvaWQuXG4gICAqL1xuICBwdXNoRXZlbnQoZXZlbnQ6IHN0cmluZywgcGF5bG9hZDogYW55LCBvblJlcGx5OiBPblJlcGx5KTogdm9pZDtcbiAgcHVzaEV2ZW50KGV2ZW50OiBzdHJpbmcsIHBheWxvYWQ/OiBhbnkpOiBQcm9taXNlPGFueT47XG5cbiAgLyoqXG4gICAqIFB1c2hlZCBhIHRhcmdldGVkIGV2ZW50IHRvIHRoZSBzZXJ2ZXIuXG4gICAqXG4gICAqIEl0IHNlbmRzIHRoZSBldmVudCB0byB0aGUgTGl2ZUNvbXBvbmVudCBvciBMaXZlVmlldyB0aGUgYHNlbGVjdG9yT3JUYXJnZXRgIGlzIGRlZmluZWQgaW4sXG4gICAqIHdoZXJlIGl0cyB2YWx1ZSBjYW4gYmUgZWl0aGVyIGEgcXVlcnkgc2VsZWN0b3IsIGFuIGFjdHVhbCBET00gZWxlbWVudCwgb3IgYSBDSUQgKGNvbXBvbmVudCBpZClcbiAgICogcmV0dXJuZWQgYnkgdGhlIGBAbXlzZWxmYCBhc3NpZ24uXG4gICAqXG4gICAqIElmIHRoZSBxdWVyeSBzZWxlY3RvciByZXR1cm5zIG1vcmUgdGhhbiBvbmUgZWxlbWVudCBpdCB3aWxsIHNlbmQgdGhlIGV2ZW50IHRvIGFsbCBvZiB0aGVtLFxuICAgKiBldmVuIGlmIGFsbCB0aGUgZWxlbWVudHMgYXJlIGluIHRoZSBzYW1lIExpdmVDb21wb25lbnQgb3IgTGl2ZVZpZXcuIEJlY2F1c2Ugb2YgdGhpcyxcbiAgICogaWYgbm8gY2FsbGJhY2sgaXMgcGFzc2VkLCBhIHByb21pc2UgaXMgcmV0dXJuZWQgdGhhdCBtYXRjaGVzIHRoZSByZXR1cm4gdmFsdWUgb2ZcbiAgICogW2BQcm9taXNlLmFsbFNldHRsZWQoKWBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL1Byb21pc2UvYWxsU2V0dGxlZCNyZXR1cm5fdmFsdWUpLlxuICAgKiBJbmRpdmlkdWFsIGZ1bGZpbGxlZCB2YWx1ZXMgYXJlIG9mIHRoZSBmb3JtYXQgYHsgcmVwbHksIHJlZiB9YCwgd2hlcmUgYHJlcGx5YCBpcyB0aGUgc2VydmVyJ3MgcmVwbHkuXG4gICAqXG4gICAqIEBwYXJhbSBzZWxlY3Rvck9yVGFyZ2V0IC0gVGhlIHNlbGVjdG9yLCBlbGVtZW50LCBvciBDSUQgdG8gdGFyZ2V0LlxuICAgKiBAcGFyYW0gZXZlbnQgLSBUaGUgZXZlbnQgbmFtZS5cbiAgICogQHBhcmFtIFtwYXlsb2FkXSAtIFRoZSBwYXlsb2FkIHRvIHNlbmQgdG8gdGhlIHNlcnZlci4gRGVmYXVsdHMgdG8gYW4gZW1wdHkgb2JqZWN0LlxuICAgKiBAcGFyYW0gW29uUmVwbHldIC0gQSBjYWxsYmFjayB0byBoYW5kbGUgdGhlIHNlcnZlcidzIHJlcGx5LlxuICAgKlxuICAgKiBXaGVuIG9uUmVwbHkgaXMgbm90IHByb3ZpZGVkLCB0aGUgbWV0aG9kIHJldHVybnMgYSBQcm9taXNlLlxuICAgKiBXaGVuIG9uUmVwbHkgaXMgcHJvdmlkZWQsIHRoZSBtZXRob2QgcmV0dXJucyB2b2lkLlxuICAgKi9cbiAgcHVzaEV2ZW50VG8oXG4gICAgc2VsZWN0b3JPclRhcmdldDogUGh4VGFyZ2V0LFxuICAgIGV2ZW50OiBzdHJpbmcsXG4gICAgcGF5bG9hZDogb2JqZWN0LFxuICAgIG9uUmVwbHk6IE9uUmVwbHksXG4gICk6IHZvaWQ7XG4gIHB1c2hFdmVudFRvKFxuICAgIHNlbGVjdG9yT3JUYXJnZXQ6IFBoeFRhcmdldCxcbiAgICBldmVudDogc3RyaW5nLFxuICAgIHBheWxvYWQ/OiBvYmplY3QsXG4gICk6IFByb21pc2U8UHJvbWlzZVNldHRsZWRSZXN1bHQ8eyByZXBseTogYW55OyByZWY6IG51bWJlciB9PltdPjtcblxuICAvKipcbiAgICogQWxsb3dzIHRvIHJlZ2lzdGVyIGEgY2FsbGJhY2sgdG8gYmUgY2FsbGVkIHdoZW4gYW4gZXZlbnQgaXMgcmVjZWl2ZWQgZnJvbSB0aGUgc2VydmVyLlxuICAgKlxuICAgKiBUaGlzIGlzIHVzZWQgdG8gaGFuZGxlIGBwdXNoRXZlbnRgIGNhbGxzIGZyb20gdGhlIHNlcnZlci4gVGhlIGNhbGxiYWNrIGlzIGNhbGxlZCB3aXRoIHRoZSBwYXlsb2FkIGZyb20gdGhlIHNlcnZlci5cbiAgICpcbiAgICogQHBhcmFtIGV2ZW50IC0gVGhlIGV2ZW50IG5hbWUuXG4gICAqIEBwYXJhbSBjYWxsYmFjayAtIFRoZSBjYWxsYmFjayB0byBjYWxsIHdoZW4gdGhlIGV2ZW50IGlzIHJlY2VpdmVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIHJlZmVyZW5jZSB0byB0aGUgY2FsbGJhY2ssIHdoaWNoIGNhbiBiZSB1c2VkIGluIGByZW1vdmVIYW5kbGVFdmVudGAgdG8gcmVtb3ZlIHRoZSBjYWxsYmFjay5cbiAgICovXG4gIGhhbmRsZUV2ZW50KGV2ZW50OiBzdHJpbmcsIGNhbGxiYWNrOiAocGF5bG9hZDogYW55KSA9PiBhbnkpOiBDYWxsYmFja1JlZjtcblxuICAvKipcbiAgICogUmVtb3ZlcyBhIGNhbGxiYWNrIHJlZ2lzdGVyZWQgd2l0aCBgaGFuZGxlRXZlbnRgLlxuICAgKlxuICAgKiBAcGFyYW0gY2FsbGJhY2tSZWYgLSBUaGUgcmVmZXJlbmNlIHRvIHRoZSBjYWxsYmFjayB0byByZW1vdmUuXG4gICAqL1xuICByZW1vdmVIYW5kbGVFdmVudChyZWY6IENhbGxiYWNrUmVmKTogdm9pZDtcblxuICAvKipcbiAgICogQWxsb3dzIHRvIHRyaWdnZXIgYSBsaXZlIGZpbGUgdXBsb2FkLlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSAtIFRoZSB1cGxvYWQgbmFtZSBjb3JyZXNwb25kaW5nIHRvIHRoZSBgUGhvZW5peC5MaXZlVmlldy5hbGxvd191cGxvYWQvM2AgY2FsbC5cbiAgICogQHBhcmFtIGZpbGVzIC0gVGhlIGZpbGVzIHRvIHVwbG9hZC5cbiAgICovXG4gIHVwbG9hZChuYW1lOiBhbnksIGZpbGVzOiBhbnkpOiBhbnk7XG5cbiAgLyoqXG4gICAqIEFsbG93cyB0byB0cmlnZ2VyIGEgbGl2ZSBmaWxlIHVwbG9hZCB0byBhIHNwZWNpZmljIHRhcmdldC5cbiAgICpcbiAgICogQHBhcmFtIHNlbGVjdG9yT3JUYXJnZXQgLSBUaGUgdGFyZ2V0IHRvIHVwbG9hZCB0aGUgZmlsZXMgdG8uXG4gICAqIEBwYXJhbSBuYW1lIC0gVGhlIHVwbG9hZCBuYW1lIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGBQaG9lbml4LkxpdmVWaWV3LmFsbG93X3VwbG9hZC8zYCBjYWxsLlxuICAgKiBAcGFyYW0gZmlsZXMgLSBUaGUgZmlsZXMgdG8gdXBsb2FkLlxuICAgKi9cbiAgdXBsb2FkVG8oc2VsZWN0b3JPclRhcmdldDogUGh4VGFyZ2V0LCBuYW1lOiBhbnksIGZpbGVzOiBhbnkpOiBhbnk7XG5cbiAgLy8gYWxsb3cgdW5rbm93biBtZXRob2RzLCBhcyBwZW9wbGUgY2FuIGRlZmluZSB0aGVtIGluIHRoZWlyIGhvb2tzXG4gIFtrZXk6IFByb3BlcnR5S2V5XTogYW55O1xufVxuXG4vLyBiYXNlZCBvbiBodHRwczovL2dpdGh1Yi5jb20vRGVmaW5pdGVseVR5cGVkL0RlZmluaXRlbHlUeXBlZC9ibG9iL2ZhYzFhYTc1YWNkZGRiZjRmMWE5NWU5OGVlMjI5N2I1NGNlNGI0YzkvdHlwZXMvcGhvZW5peF9saXZlX3ZpZXcvaG9va3MuZC50cyNMMjZcbi8vIGxpY2Vuc2VkIHVuZGVyIE1JVFxuZXhwb3J0IGludGVyZmFjZSBIb29rPFQgPSBvYmplY3Q+IHtcbiAgLyoqXG4gICAqIFRoZSBtb3VudGVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBoYXMgYmVlbiBhZGRlZCB0byB0aGUgRE9NIGFuZCBpdHMgc2VydmVyIExpdmVWaWV3IGhhcyBmaW5pc2hlZCBtb3VudGluZy5cbiAgICovXG4gIG1vdW50ZWQ/OiAodGhpczogVCAmIEhvb2tJbnRlcmZhY2UpID0+IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFRoZSBiZWZvcmVVcGRhdGUgY2FsbGJhY2suXG4gICAqXG4gICAqIENhbGxlZCB3aGVuIHRoZSBlbGVtZW50IGlzIGFib3V0IHRvIGJlIHVwZGF0ZWQgaW4gdGhlIERPTS5cbiAgICogTm90ZTogYW55IGNhbGwgaGVyZSBtdXN0IGJlIHN5bmNocm9ub3VzIGFzIHRoZSBvcGVyYXRpb24gY2Fubm90IGJlIGRlZmVycmVkIG9yIGNhbmNlbGxlZC5cbiAgICovXG4gIGJlZm9yZVVwZGF0ZT86ICh0aGlzOiBUICYgSG9va0ludGVyZmFjZSkgPT4gdm9pZDtcblxuICAvKipcbiAgICogVGhlIHVwZGF0ZWQgY2FsbGJhY2suXG4gICAqXG4gICAqIENhbGxlZCB3aGVuIHRoZSBlbGVtZW50IGhhcyBiZWVuIHVwZGF0ZWQgaW4gdGhlIERPTSBieSB0aGUgc2VydmVyXG4gICAqL1xuICB1cGRhdGVkPzogKHRoaXM6IFQgJiBIb29rSW50ZXJmYWNlKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgZGVzdHJveWVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBoYXMgYmVlbiByZW1vdmVkIGZyb20gdGhlIHBhZ2UsIGVpdGhlciBieSBhIHBhcmVudCB1cGRhdGUsIG9yIGJ5IHRoZSBwYXJlbnQgYmVpbmcgcmVtb3ZlZCBlbnRpcmVseVxuICAgKi9cbiAgZGVzdHJveWVkPzogKHRoaXM6IFQgJiBIb29rSW50ZXJmYWNlKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBUaGUgZGlzY29ubmVjdGVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCdzIHBhcmVudCBMaXZlVmlldyBoYXMgZGlzY29ubmVjdGVkIGZyb20gdGhlIHNlcnZlci5cbiAgICovXG4gIGRpc2Nvbm5lY3RlZD86ICh0aGlzOiBUICYgSG9va0ludGVyZmFjZSkgPT4gdm9pZDtcblxuICAvKipcbiAgICogVGhlIHJlY29ubmVjdGVkIGNhbGxiYWNrLlxuICAgKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCdzIHBhcmVudCBMaXZlVmlldyBoYXMgcmVjb25uZWN0ZWQgdG8gdGhlIHNlcnZlci5cbiAgICovXG4gIHJlY29ubmVjdGVkPzogKHRoaXM6IFQgJiBIb29rSW50ZXJmYWNlKSA9PiB2b2lkO1xuXG4gIC8vIEFsbG93IGN1c3RvbSBtZXRob2RzIHdpdGggYW55IHNpZ25hdHVyZSBhbmQgY3VzdG9tIHByb3BlcnRpZXNcbiAgW2tleTogUHJvcGVydHlLZXldOiBhbnk7XG59XG5cbi8qKlxuICogQmFzZSBjbGFzcyBmb3IgTGl2ZVZpZXcgaG9va3MuIFVzZXJzIGV4dGVuZCB0aGlzIGNsYXNzIHRvIGRlZmluZSB0aGVpciBob29rcy5cbiAqXG4gKiBFeGFtcGxlOlxuICogYGBgdHlwZXNjcmlwdFxuICogY2xhc3MgTXlDdXN0b21Ib29rIGV4dGVuZHMgVmlld0hvb2sge1xuICogICBteVN0YXRlID0gXCJpbml0aWFsXCI7XG4gKlxuICogICBtb3VudGVkKCkge1xuICogICAgIGNvbnNvbGUubG9nKFwiSG9vayBtb3VudGVkIG9uIGVsZW1lbnQ6XCIsIHRoaXMuZWwpO1xuICogICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcbiAqICAgICAgIHRoaXMucHVzaEV2ZW50KFwiZWxlbWVudC1jbGlja2VkXCIsIHsgc3RhdGU6IHRoaXMubXlTdGF0ZSB9KTtcbiAqICAgICB9KTtcbiAqICAgfVxuICpcbiAqICAgdXBkYXRlZCgpIHtcbiAqICAgICBjb25zb2xlLmxvZyhcIkhvb2sgdXBkYXRlZFwiLCB0aGlzLmVsLmlkKTtcbiAqICAgfVxuICpcbiAqICAgbXlDdXN0b21NZXRob2Qoc29tZUFyZzogc3RyaW5nKSB7XG4gKiAgICAgY29uc29sZS5sb2coXCJteUN1c3RvbU1ldGhvZCBjYWxsZWQgd2l0aDpcIiwgc29tZUFyZywgXCJDdXJyZW50IHN0YXRlOlwiLCB0aGlzLm15U3RhdGUpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBUaGUgYHRoaXNgIGNvbnRleHQgd2l0aGluIHRoZSBob29rIG1ldGhvZHMgKG1vdW50ZWQsIHVwZGF0ZWQsIGN1c3RvbSBtZXRob2RzLCBldGMuKVxuICogd2lsbCByZWZlciB0byB0aGUgaG9vayBpbnN0YW5jZSwgcHJvdmlkaW5nIGFjY2VzcyB0byBgdGhpcy5lbGAsIGB0aGlzLmxpdmVTb2NrZXRgLFxuICogYHRoaXMucHVzaEV2ZW50KClgLCBldGMuLCBhcyB3ZWxsIGFzIGFueSBwcm9wZXJ0aWVzIG9yIG1ldGhvZHMgZGVmaW5lZCBvbiB0aGUgc3ViY2xhc3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBWaWV3SG9vayBpbXBsZW1lbnRzIEhvb2tJbnRlcmZhY2Uge1xuICBlbDogSFRNTEVsZW1lbnQ7XG4gIGxpdmVTb2NrZXQ6IExpdmVTb2NrZXQ7XG5cbiAgcHJpdmF0ZSBfX2xpc3RlbmVyczogU2V0PENhbGxiYWNrUmVmPjtcbiAgcHJpdmF0ZSBfX2lzRGlzY29ubmVjdGVkOiBib29sZWFuO1xuICBwcml2YXRlIF9fdmlldzogKCkgPT4gVmlldztcblxuICBzdGF0aWMgbWFrZUlEKCkge1xuICAgIHJldHVybiB2aWV3SG9va0lEKys7XG4gIH1cbiAgc3RhdGljIGVsZW1lbnRJRChlbDogSFRNTEVsZW1lbnQpIHtcbiAgICByZXR1cm4gRE9NLnByaXZhdGUoZWwsIEhPT0tfSUQpO1xuICB9XG5cbiAgY29uc3RydWN0b3IodmlldzogVmlldyB8IG51bGwsIGVsOiBIVE1MRWxlbWVudCwgY2FsbGJhY2tzPzogSG9vaykge1xuICAgIHRoaXMuZWwgPSBlbDtcbiAgICB0aGlzLl9fYXR0YWNoVmlldyh2aWV3KTtcbiAgICB0aGlzLl9fbGlzdGVuZXJzID0gbmV3IFNldCgpO1xuICAgIHRoaXMuX19pc0Rpc2Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIERPTS5wdXRQcml2YXRlKHRoaXMuZWwsIEhPT0tfSUQsIFZpZXdIb29rLm1ha2VJRCgpKTtcblxuICAgIGlmIChjYWxsYmFja3MpIHtcbiAgICAgIC8vIFRoaXMgaW5zdGFuY2UgaXMgZm9yIGFuIG9iamVjdC1saXRlcmFsIGhvb2suIENvcHkgbWV0aG9kcy9wcm9wZXJ0aWVzLlxuICAgICAgLy8gVGhlc2UgYXJlIHByb3BlcnRpZXMgdGhhdCBzaG91bGQgTk9UIGJlIG92ZXJyaWRkZW4gYnkgdGhlIGNhbGxiYWNrcyBvYmplY3QuXG4gICAgICBjb25zdCBwcm90ZWN0ZWRQcm9wcyA9IG5ldyBTZXQoW1xuICAgICAgICBcImVsXCIsXG4gICAgICAgIFwibGl2ZVNvY2tldFwiLFxuICAgICAgICBcIl9fdmlld1wiLFxuICAgICAgICBcIl9fbGlzdGVuZXJzXCIsXG4gICAgICAgIFwiX19pc0Rpc2Nvbm5lY3RlZFwiLFxuICAgICAgICBcImNvbnN0cnVjdG9yXCIsIC8vIFN0YW5kYXJkIG9iamVjdCBwcm9wZXJ0aWVzXG4gICAgICAgIC8vIENvcmUgVmlld0hvb2sgQVBJIG1ldGhvZHNcbiAgICAgICAgXCJqc1wiLFxuICAgICAgICBcInB1c2hFdmVudFwiLFxuICAgICAgICBcInB1c2hFdmVudFRvXCIsXG4gICAgICAgIFwiaGFuZGxlRXZlbnRcIixcbiAgICAgICAgXCJyZW1vdmVIYW5kbGVFdmVudFwiLFxuICAgICAgICBcInVwbG9hZFwiLFxuICAgICAgICBcInVwbG9hZFRvXCIsXG4gICAgICAgIC8vIEludGVybmFsIGxpZmVjeWNsZSBjYWxsZXJzXG4gICAgICAgIFwiX19tb3VudGVkXCIsXG4gICAgICAgIFwiX191cGRhdGVkXCIsXG4gICAgICAgIFwiX19iZWZvcmVVcGRhdGVcIixcbiAgICAgICAgXCJfX2Rlc3Ryb3llZFwiLFxuICAgICAgICBcIl9fcmVjb25uZWN0ZWRcIixcbiAgICAgICAgXCJfX2Rpc2Nvbm5lY3RlZFwiLFxuICAgICAgICBcIl9fY2xlYW51cF9fXCIsXG4gICAgICBdKTtcblxuICAgICAgZm9yIChjb25zdCBrZXkgaW4gY2FsbGJhY2tzKSB7XG4gICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoY2FsbGJhY2tzLCBrZXkpKSB7XG4gICAgICAgICAgKHRoaXMgYXMgYW55KVtrZXldID0gY2FsbGJhY2tzW2tleV07XG4gICAgICAgICAgLy8gZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LCB3ZSBhbGxvdyB0aGUgb3ZlcndyaXRlLCBidXQgd2UgbG9nIGEgd2FybmluZ1xuICAgICAgICAgIGlmIChwcm90ZWN0ZWRQcm9wcy5oYXMoa2V5KSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICBgSG9vayBvYmplY3QgZm9yIGVsZW1lbnQgIyR7ZWwuaWR9IG92ZXJ3cml0ZXMgY29yZSBwcm9wZXJ0eSAnJHtrZXl9JyFgLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgbGlmZWN5Y2xlTWV0aG9kczogKGtleW9mIEhvb2spW10gPSBbXG4gICAgICAgIFwibW91bnRlZFwiLFxuICAgICAgICBcImJlZm9yZVVwZGF0ZVwiLFxuICAgICAgICBcInVwZGF0ZWRcIixcbiAgICAgICAgXCJkZXN0cm95ZWRcIixcbiAgICAgICAgXCJkaXNjb25uZWN0ZWRcIixcbiAgICAgICAgXCJyZWNvbm5lY3RlZFwiLFxuICAgICAgXTtcbiAgICAgIGxpZmVjeWNsZU1ldGhvZHMuZm9yRWFjaCgobWV0aG9kTmFtZSkgPT4ge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgY2FsbGJhY2tzW21ldGhvZE5hbWVdICYmXG4gICAgICAgICAgdHlwZW9mIGNhbGxiYWNrc1ttZXRob2ROYW1lXSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICkge1xuICAgICAgICAgICh0aGlzIGFzIGFueSlbbWV0aG9kTmFtZV0gPSBjYWxsYmFja3NbbWV0aG9kTmFtZV07XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICAvLyBJZiAnY2FsbGJhY2tzJyBpcyBub3QgcHJvdmlkZWQsIHRoaXMgaXMgYW4gaW5zdGFuY2Ugb2YgYSB1c2VyLWRlZmluZWQgY2xhc3MgKGUuZy4sIE15SG9vaykuXG4gICAgLy8gSXRzIG1ldGhvZHMgKG1vdW50ZWQsIHVwZGF0ZWQsIGN1c3RvbSkgYXJlIGFscmVhZHkgcGFydCBvZiBpdHMgcHJvdG90eXBlIG9yIGluc3RhbmNlLFxuICAgIC8vIGFuZCB3aWxsIGNvcnJlY3RseSBvdmVycmlkZSB0aGUgZGVmYXVsdHMgZnJvbSBWaWV3SG9vay5wcm90b3R5cGUuXG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIF9fYXR0YWNoVmlldyh2aWV3OiBWaWV3IHwgbnVsbCkge1xuICAgIGlmICh2aWV3KSB7XG4gICAgICB0aGlzLl9fdmlldyA9ICgpID0+IHZpZXc7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQgPSB2aWV3LmxpdmVTb2NrZXQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX192aWV3ID0gKCkgPT4ge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYGhvb2sgbm90IHlldCBhdHRhY2hlZCB0byBhIGxpdmUgdmlldzogJHt0aGlzLmVsLm91dGVySFRNTH1gLFxuICAgICAgICApO1xuICAgICAgfTtcbiAgICAgIHRoaXMubGl2ZVNvY2tldCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLy8gRGVmYXVsdCBsaWZlY3ljbGUgbWV0aG9kc1xuICBtb3VudGVkKCk6IHZvaWQge31cbiAgYmVmb3JlVXBkYXRlKCk6IHZvaWQge31cbiAgdXBkYXRlZCgpOiB2b2lkIHt9XG4gIGRlc3Ryb3llZCgpOiB2b2lkIHt9XG4gIGRpc2Nvbm5lY3RlZCgpOiB2b2lkIHt9XG4gIHJlY29ubmVjdGVkKCk6IHZvaWQge31cblxuICAvLyBJbnRlcm5hbCBsaWZlY3ljbGUgY2FsbGVycyAtIGNhbGxlZCBieSB0aGUgVmlld1xuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX19tb3VudGVkKCkge1xuICAgIHRoaXMubW91bnRlZCgpO1xuICB9XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX191cGRhdGVkKCkge1xuICAgIHRoaXMudXBkYXRlZCgpO1xuICB9XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX19iZWZvcmVVcGRhdGUoKSB7XG4gICAgdGhpcy5iZWZvcmVVcGRhdGUoKTtcbiAgfVxuICAvKiogQGludGVybmFsICovXG4gIF9fZGVzdHJveWVkKCkge1xuICAgIHRoaXMuZGVzdHJveWVkKCk7XG4gICAgRE9NLmRlbGV0ZVByaXZhdGUodGhpcy5lbCwgSE9PS19JRCk7IC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9waG9lbml4ZnJhbWV3b3JrL3Bob2VuaXhfbGl2ZV92aWV3L2lzc3Vlcy8zNDk2XG4gIH1cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBfX3JlY29ubmVjdGVkKCkge1xuICAgIGlmICh0aGlzLl9faXNEaXNjb25uZWN0ZWQpIHtcbiAgICAgIHRoaXMuX19pc0Rpc2Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5yZWNvbm5lY3RlZCgpO1xuICAgIH1cbiAgfVxuICAvKiogQGludGVybmFsICovXG4gIF9fZGlzY29ubmVjdGVkKCkge1xuICAgIHRoaXMuX19pc0Rpc2Nvbm5lY3RlZCA9IHRydWU7XG4gICAgdGhpcy5kaXNjb25uZWN0ZWQoKTtcbiAgfVxuXG4gIGpzKCk6IEhvb2tKU0NvbW1hbmRzIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4uanNDb21tYW5kcyh0aGlzLl9fdmlldygpLmxpdmVTb2NrZXQsIFwiaG9va1wiKSxcbiAgICAgIGV4ZWM6IChlbmNvZGVkSlM6IHN0cmluZykgPT4ge1xuICAgICAgICB0aGlzLl9fdmlldygpLmxpdmVTb2NrZXQuZXhlY0pTKHRoaXMuZWwsIGVuY29kZWRKUywgXCJob29rXCIpO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHVzaEV2ZW50KGV2ZW50OiBzdHJpbmcsIHBheWxvYWQ/OiBhbnksIG9uUmVwbHk/OiBPblJlcGx5KSB7XG4gICAgY29uc3QgcHJvbWlzZSA9IHRoaXMuX192aWV3KCkucHVzaEhvb2tFdmVudChcbiAgICAgIHRoaXMuZWwsXG4gICAgICBudWxsLFxuICAgICAgZXZlbnQsXG4gICAgICBwYXlsb2FkIHx8IHt9LFxuICAgICk7XG4gICAgaWYgKG9uUmVwbHkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHByb21pc2UudGhlbigoeyByZXBseSB9KSA9PiByZXBseSk7XG4gICAgfVxuICAgIHByb21pc2UudGhlbigoeyByZXBseSwgcmVmIH0pID0+IG9uUmVwbHkocmVwbHksIHJlZikpLmNhdGNoKCgpID0+IHt9KTtcbiAgICByZXR1cm47XG4gIH1cblxuICBwdXNoRXZlbnRUbyhcbiAgICBzZWxlY3Rvck9yVGFyZ2V0OiBQaHhUYXJnZXQsXG4gICAgZXZlbnQ6IHN0cmluZyxcbiAgICBwYXlsb2FkPzogb2JqZWN0LFxuICAgIG9uUmVwbHk/OiBPblJlcGx5LFxuICApIHtcbiAgICBpZiAob25SZXBseSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0YXJnZXRQYWlyOiB7IHZpZXc6IFZpZXc7IHRhcmdldEN0eDogYW55IH1bXSA9IFtdO1xuICAgICAgdGhpcy5fX3ZpZXcoKS53aXRoaW5UYXJnZXRzKHNlbGVjdG9yT3JUYXJnZXQsICh2aWV3LCB0YXJnZXRDdHgpID0+IHtcbiAgICAgICAgdGFyZ2V0UGFpci5wdXNoKHsgdmlldywgdGFyZ2V0Q3R4IH0pO1xuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm9taXNlcyA9IHRhcmdldFBhaXIubWFwKCh7IHZpZXcsIHRhcmdldEN0eCB9KSA9PiB7XG4gICAgICAgIHJldHVybiB2aWV3LnB1c2hIb29rRXZlbnQodGhpcy5lbCwgdGFyZ2V0Q3R4LCBldmVudCwgcGF5bG9hZCB8fCB7fSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBQcm9taXNlLmFsbFNldHRsZWQocHJvbWlzZXMpO1xuICAgIH1cbiAgICB0aGlzLl9fdmlldygpLndpdGhpblRhcmdldHMoc2VsZWN0b3JPclRhcmdldCwgKHZpZXcsIHRhcmdldEN0eCkgPT4ge1xuICAgICAgdmlld1xuICAgICAgICAucHVzaEhvb2tFdmVudCh0aGlzLmVsLCB0YXJnZXRDdHgsIGV2ZW50LCBwYXlsb2FkIHx8IHt9KVxuICAgICAgICAudGhlbigoeyByZXBseSwgcmVmIH0pID0+IG9uUmVwbHkocmVwbHksIHJlZikpXG4gICAgICAgIC5jYXRjaCgoKSA9PiB7fSk7XG4gICAgfSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaGFuZGxlRXZlbnQoZXZlbnQ6IHN0cmluZywgY2FsbGJhY2s6IChwYXlsb2FkOiBhbnkpID0+IGFueSk6IENhbGxiYWNrUmVmIHtcbiAgICBjb25zdCBjYWxsYmFja1JlZjogQ2FsbGJhY2tSZWYgPSB7XG4gICAgICBldmVudCxcbiAgICAgIGNhbGxiYWNrOiAoY3VzdG9tRXZlbnQ6IEN1c3RvbUV2ZW50KSA9PiBjYWxsYmFjayhjdXN0b21FdmVudC5kZXRhaWwpLFxuICAgIH07XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICBgcGh4OiR7ZXZlbnR9YCxcbiAgICAgIGNhbGxiYWNrUmVmLmNhbGxiYWNrIGFzIEV2ZW50TGlzdGVuZXIsXG4gICAgKTtcbiAgICB0aGlzLl9fbGlzdGVuZXJzLmFkZChjYWxsYmFja1JlZik7XG4gICAgcmV0dXJuIGNhbGxiYWNrUmVmO1xuICB9XG5cbiAgcmVtb3ZlSGFuZGxlRXZlbnQocmVmOiBDYWxsYmFja1JlZik6IHZvaWQge1xuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKFxuICAgICAgYHBoeDoke3JlZi5ldmVudH1gLFxuICAgICAgcmVmLmNhbGxiYWNrIGFzIEV2ZW50TGlzdGVuZXIsXG4gICAgKTtcbiAgICB0aGlzLl9fbGlzdGVuZXJzLmRlbGV0ZShyZWYpO1xuICB9XG5cbiAgdXBsb2FkKG5hbWU6IHN0cmluZywgZmlsZXM6IEZpbGVMaXN0KTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5fX3ZpZXcoKS5kaXNwYXRjaFVwbG9hZHMobnVsbCwgbmFtZSwgZmlsZXMpO1xuICB9XG5cbiAgdXBsb2FkVG8oc2VsZWN0b3JPclRhcmdldDogUGh4VGFyZ2V0LCBuYW1lOiBzdHJpbmcsIGZpbGVzOiBGaWxlTGlzdCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX192aWV3KCkud2l0aGluVGFyZ2V0cyhzZWxlY3Rvck9yVGFyZ2V0LCAodmlldywgdGFyZ2V0Q3R4KSA9PiB7XG4gICAgICB2aWV3LmRpc3BhdGNoVXBsb2Fkcyh0YXJnZXRDdHgsIG5hbWUsIGZpbGVzKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgX19jbGVhbnVwX18oKSB7XG4gICAgdGhpcy5fX2xpc3RlbmVycy5mb3JFYWNoKChjYWxsYmFja1JlZikgPT5cbiAgICAgIHRoaXMucmVtb3ZlSGFuZGxlRXZlbnQoY2FsbGJhY2tSZWYpLFxuICAgICk7XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgSG9va3NPcHRpb25zID0gUmVjb3JkPHN0cmluZywgdHlwZW9mIFZpZXdIb29rIHwgSG9vaz47XG5cbmV4cG9ydCBkZWZhdWx0IFZpZXdIb29rO1xuIiwgImltcG9ydCB7XG4gIEJFRk9SRV9VTkxPQURfTE9BREVSX1RJTUVPVVQsXG4gIENIRUNLQUJMRV9JTlBVVFMsXG4gIENPTlNFQ1VUSVZFX1JFTE9BRFMsXG4gIFBIWF9BVVRPX1JFQ09WRVIsXG4gIFBIWF9DT01QT05FTlQsXG4gIFBIWF9WSUVXX1JFRixcbiAgUEhYX0NPTk5FQ1RFRF9DTEFTUyxcbiAgUEhYX0RJU0FCTEVfV0lUSCxcbiAgUEhYX0RJU0FCTEVfV0lUSF9SRVNUT1JFLFxuICBQSFhfRElTQUJMRUQsXG4gIFBIWF9MT0FESU5HX0NMQVNTLFxuICBQSFhfRVJST1JfQ0xBU1MsXG4gIFBIWF9DTElFTlRfRVJST1JfQ0xBU1MsXG4gIFBIWF9TRVJWRVJfRVJST1JfQ0xBU1MsXG4gIFBIWF9IQVNfRk9DVVNFRCxcbiAgUEhYX0hBU19TVUJNSVRURUQsXG4gIFBIWF9IT09LLFxuICBQSFhfUEFSRU5UX0lELFxuICBQSFhfUFJPR1JFU1MsXG4gIFBIWF9SRUFET05MWSxcbiAgUEhYX1JFRl9MT0FESU5HLFxuICBQSFhfUkVGX1NSQyxcbiAgUEhYX1JFRl9MT0NLLFxuICBQSFhfUk9PVF9JRCxcbiAgUEhYX1NFU1NJT04sXG4gIFBIWF9TVEFUSUMsXG4gIFBIWF9TVElDS1ksXG4gIFBIWF9UUkFDS19TVEFUSUMsXG4gIFBIWF9UUkFDS19VUExPQURTLFxuICBQSFhfVVBEQVRFLFxuICBQSFhfVVBMT0FEX1JFRixcbiAgUEhYX1ZJRVdfU0VMRUNUT1IsXG4gIFBIWF9NQUlOLFxuICBQSFhfTU9VTlRFRCxcbiAgUFVTSF9USU1FT1VULFxuICBQSFhfVklFV1BPUlRfVE9QLFxuICBQSFhfVklFV1BPUlRfQk9UVE9NLFxuICBNQVhfQ0hJTERfSk9JTl9BVFRFTVBUUyxcbiAgUEhYX0xWX1BJRCxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5cbmltcG9ydCB7XG4gIGNsb25lLFxuICBjbG9zZXN0UGh4QmluZGluZyxcbiAgaXNFbXB0eSxcbiAgaXNFcXVhbE9iaixcbiAgbG9nRXJyb3IsXG4gIG1heWJlLFxuICBpc0NpZCxcbn0gZnJvbSBcIi4vdXRpbHNcIjtcblxuaW1wb3J0IEJyb3dzZXIgZnJvbSBcIi4vYnJvd3NlclwiO1xuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIjtcbmltcG9ydCBFbGVtZW50UmVmIGZyb20gXCIuL2VsZW1lbnRfcmVmXCI7XG5pbXBvcnQgRE9NUGF0Y2ggZnJvbSBcIi4vZG9tX3BhdGNoXCI7XG5pbXBvcnQgTGl2ZVVwbG9hZGVyIGZyb20gXCIuL2xpdmVfdXBsb2FkZXJcIjtcbmltcG9ydCBSZW5kZXJlZCBmcm9tIFwiLi9yZW5kZXJlZFwiO1xuaW1wb3J0IHsgVmlld0hvb2sgfSBmcm9tIFwiLi92aWV3X2hvb2tcIjtcbmltcG9ydCBKUyBmcm9tIFwiLi9qc1wiO1xuXG5pbXBvcnQgbW9ycGhkb20gZnJvbSBcIm1vcnBoZG9tXCI7XG5cbmV4cG9ydCBjb25zdCBwcmVwZW5kRm9ybURhdGFLZXkgPSAoa2V5LCBwcmVmaXgpID0+IHtcbiAgY29uc3QgaXNBcnJheSA9IGtleS5lbmRzV2l0aChcIltdXCIpO1xuICAvLyBSZW1vdmUgdGhlIFwiW11cIiBpZiBpdCdzIGFuIGFycmF5XG4gIGxldCBiYXNlS2V5ID0gaXNBcnJheSA/IGtleS5zbGljZSgwLCAtMikgOiBrZXk7XG4gIC8vIFJlcGxhY2UgbGFzdCBvY2N1cnJlbmNlIG9mIGtleSBiZWZvcmUgYSBjbG9zaW5nIGJyYWNrZXQgb3IgdGhlIGVuZCB3aXRoIGtleSBwbHVzIHN1ZmZpeFxuICBiYXNlS2V5ID0gYmFzZUtleS5yZXBsYWNlKC8oW15cXFtcXF1dKykoXFxdPyQpLywgYCR7cHJlZml4fSQxJDJgKTtcbiAgLy8gQWRkIGJhY2sgdGhlIFwiW11cIiBpZiBpdCB3YXMgYW4gYXJyYXlcbiAgaWYgKGlzQXJyYXkpIHtcbiAgICBiYXNlS2V5ICs9IFwiW11cIjtcbiAgfVxuICByZXR1cm4gYmFzZUtleTtcbn07XG5cbmNvbnN0IHNlcmlhbGl6ZUZvcm0gPSAoZm9ybSwgb3B0cywgb25seU5hbWVzID0gW10pID0+IHtcbiAgY29uc3QgeyBzdWJtaXR0ZXIgfSA9IG9wdHM7XG5cbiAgLy8gV2UgbXVzdCBpbmplY3QgdGhlIHN1Ym1pdHRlciBpbiB0aGUgb3JkZXIgdGhhdCBpdCBleGlzdHMgaW4gdGhlIERPTVxuICAvLyByZWxhdGl2ZSB0byBvdGhlciBpbnB1dHMuIEZvciBleGFtcGxlLCBmb3IgY2hlY2tib3ggZ3JvdXBzLCB0aGUgb3JkZXIgbXVzdCBiZSBtYWludGFpbmVkLlxuICBsZXQgaW5qZWN0ZWRFbGVtZW50O1xuICBpZiAoc3VibWl0dGVyICYmIHN1Ym1pdHRlci5uYW1lKSB7XG4gICAgY29uc3QgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiaW5wdXRcIik7XG4gICAgaW5wdXQudHlwZSA9IFwiaGlkZGVuXCI7XG4gICAgLy8gc2V0IHRoZSBmb3JtIGF0dHJpYnV0ZSBpZiB0aGUgc3VibWl0dGVyIGhhcyBvbmU7XG4gICAgLy8gdGhpcyBjYW4gaGFwcGVuIGlmIHRoZSBlbGVtZW50IGlzIG91dHNpZGUgdGhlIGFjdHVhbCBmb3JtIGVsZW1lbnRcbiAgICBjb25zdCBmb3JtSWQgPSBzdWJtaXR0ZXIuZ2V0QXR0cmlidXRlKFwiZm9ybVwiKTtcbiAgICBpZiAoZm9ybUlkKSB7XG4gICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoXCJmb3JtXCIsIGZvcm1JZCk7XG4gICAgfVxuICAgIGlucHV0Lm5hbWUgPSBzdWJtaXR0ZXIubmFtZTtcbiAgICBpbnB1dC52YWx1ZSA9IHN1Ym1pdHRlci52YWx1ZTtcbiAgICBzdWJtaXR0ZXIucGFyZW50RWxlbWVudC5pbnNlcnRCZWZvcmUoaW5wdXQsIHN1Ym1pdHRlcik7XG4gICAgaW5qZWN0ZWRFbGVtZW50ID0gaW5wdXQ7XG4gIH1cblxuICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YShmb3JtKTtcbiAgY29uc3QgdG9SZW1vdmUgPSBbXTtcblxuICBmb3JtRGF0YS5mb3JFYWNoKCh2YWwsIGtleSwgX2luZGV4KSA9PiB7XG4gICAgaWYgKHZhbCBpbnN0YW5jZW9mIEZpbGUpIHtcbiAgICAgIHRvUmVtb3ZlLnB1c2goa2V5KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIENsZWFudXAgYWZ0ZXIgYnVpbGRpbmcgZmlsZURhdGFcbiAgdG9SZW1vdmUuZm9yRWFjaCgoa2V5KSA9PiBmb3JtRGF0YS5kZWxldGUoa2V5KSk7XG5cbiAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcygpO1xuXG4gIGNvbnN0IHsgaW5wdXRzVW51c2VkLCBvbmx5SGlkZGVuSW5wdXRzIH0gPSBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpLnJlZHVjZShcbiAgICAoYWNjLCBpbnB1dCkgPT4ge1xuICAgICAgY29uc3QgeyBpbnB1dHNVbnVzZWQsIG9ubHlIaWRkZW5JbnB1dHMgfSA9IGFjYztcbiAgICAgIGNvbnN0IGtleSA9IGlucHV0Lm5hbWU7XG4gICAgICBpZiAoIWtleSkge1xuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfVxuXG4gICAgICBpZiAoaW5wdXRzVW51c2VkW2tleV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpbnB1dHNVbnVzZWRba2V5XSA9IHRydWU7XG4gICAgICB9XG4gICAgICBpZiAob25seUhpZGRlbklucHV0c1trZXldID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgb25seUhpZGRlbklucHV0c1trZXldID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaXNVc2VkID1cbiAgICAgICAgRE9NLnByaXZhdGUoaW5wdXQsIFBIWF9IQVNfRk9DVVNFRCkgfHxcbiAgICAgICAgRE9NLnByaXZhdGUoaW5wdXQsIFBIWF9IQVNfU1VCTUlUVEVEKTtcbiAgICAgIGNvbnN0IGlzSGlkZGVuID0gaW5wdXQudHlwZSA9PT0gXCJoaWRkZW5cIjtcbiAgICAgIGlucHV0c1VudXNlZFtrZXldID0gaW5wdXRzVW51c2VkW2tleV0gJiYgIWlzVXNlZDtcbiAgICAgIG9ubHlIaWRkZW5JbnB1dHNba2V5XSA9IG9ubHlIaWRkZW5JbnB1dHNba2V5XSAmJiBpc0hpZGRlbjtcblxuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHsgaW5wdXRzVW51c2VkOiB7fSwgb25seUhpZGRlbklucHV0czoge30gfSxcbiAgKTtcblxuICBmb3IgKGNvbnN0IFtrZXksIHZhbF0gb2YgZm9ybURhdGEuZW50cmllcygpKSB7XG4gICAgaWYgKG9ubHlOYW1lcy5sZW5ndGggPT09IDAgfHwgb25seU5hbWVzLmluZGV4T2Yoa2V5KSA+PSAwKSB7XG4gICAgICBjb25zdCBpc1VudXNlZCA9IGlucHV0c1VudXNlZFtrZXldO1xuICAgICAgY29uc3QgaGlkZGVuID0gb25seUhpZGRlbklucHV0c1trZXldO1xuICAgICAgaWYgKGlzVW51c2VkICYmICEoc3VibWl0dGVyICYmIHN1Ym1pdHRlci5uYW1lID09IGtleSkgJiYgIWhpZGRlbikge1xuICAgICAgICBwYXJhbXMuYXBwZW5kKHByZXBlbmRGb3JtRGF0YUtleShrZXksIFwiX3VudXNlZF9cIiksIFwiXCIpO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiB2YWwgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgcGFyYW1zLmFwcGVuZChrZXksIHZhbCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gcmVtb3ZlIHRoZSBpbmplY3RlZCBlbGVtZW50IGFnYWluXG4gIC8vIChpdCB3b3VsZCBiZSByZW1vdmVkIGJ5IHRoZSBuZXh0IGRvbSBwYXRjaCBhbnl3YXksIGJ1dCB0aGlzIGlzIGNsZWFuZXIpXG4gIGlmIChzdWJtaXR0ZXIgJiYgaW5qZWN0ZWRFbGVtZW50KSB7XG4gICAgc3VibWl0dGVyLnBhcmVudEVsZW1lbnQucmVtb3ZlQ2hpbGQoaW5qZWN0ZWRFbGVtZW50KTtcbiAgfVxuXG4gIHJldHVybiBwYXJhbXMudG9TdHJpbmcoKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZpZXcge1xuICBzdGF0aWMgY2xvc2VzdFZpZXcoZWwpIHtcbiAgICBjb25zdCBsaXZlVmlld0VsID0gZWwuY2xvc2VzdChQSFhfVklFV19TRUxFQ1RPUik7XG4gICAgcmV0dXJuIGxpdmVWaWV3RWwgPyBET00ucHJpdmF0ZShsaXZlVmlld0VsLCBcInZpZXdcIikgOiBudWxsO1xuICB9XG5cbiAgY29uc3RydWN0b3IoZWwsIGxpdmVTb2NrZXQsIHBhcmVudFZpZXcsIGZsYXNoLCBsaXZlUmVmZXJlcikge1xuICAgIHRoaXMuaXNEZWFkID0gZmFsc2U7XG4gICAgdGhpcy5saXZlU29ja2V0ID0gbGl2ZVNvY2tldDtcbiAgICB0aGlzLmZsYXNoID0gZmxhc2g7XG4gICAgdGhpcy5wYXJlbnQgPSBwYXJlbnRWaWV3O1xuICAgIHRoaXMucm9vdCA9IHBhcmVudFZpZXcgPyBwYXJlbnRWaWV3LnJvb3QgOiB0aGlzO1xuICAgIHRoaXMuZWwgPSBlbDtcbiAgICAvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3Bob2VuaXhmcmFtZXdvcmsvcGhvZW5peF9saXZlX3ZpZXcvcHVsbC8zNzIxXG4gICAgLy8gY2hlY2sgaWYgdGhlIGVsZW1lbnQgaXMgYWxyZWFkeSBib3VuZCB0byBhIHZpZXdcbiAgICBjb25zdCBib3VuZFZpZXcgPSBET00ucHJpdmF0ZSh0aGlzLmVsLCBcInZpZXdcIik7XG4gICAgaWYgKGJvdW5kVmlldyAhPT0gdW5kZWZpbmVkICYmIGJvdW5kVmlldy5pc0RlYWQgIT09IHRydWUpIHtcbiAgICAgIGxvZ0Vycm9yKFxuICAgICAgICBgVGhlIERPTSBlbGVtZW50IGZvciB0aGlzIHZpZXcgaGFzIGFscmVhZHkgYmVlbiBib3VuZCB0byBhIHZpZXcuXG5cbiAgICAgICAgQW4gZWxlbWVudCBjYW4gb25seSBldmVyIGJlIGFzc29jaWF0ZWQgd2l0aCBhIHNpbmdsZSB2aWV3IVxuICAgICAgICBQbGVhc2UgZW5zdXJlIHRoYXQgeW91IGFyZSBub3QgdHJ5aW5nIHRvIGluaXRpYWxpemUgbXVsdGlwbGUgTGl2ZVNvY2tldHMgb24gdGhlIHNhbWUgcGFnZS5cbiAgICAgICAgVGhpcyBjb3VsZCBoYXBwZW4gaWYgeW91J3JlIGFjY2lkZW50YWxseSB0cnlpbmcgdG8gcmVuZGVyIHlvdXIgcm9vdCBsYXlvdXQgbW9yZSB0aGFuIG9uY2UuXG4gICAgICAgIEVuc3VyZSB0aGF0IHRoZSB0ZW1wbGF0ZSBzZXQgb24gdGhlIExpdmVWaWV3IGlzIGRpZmZlcmVudCB0aGFuIHRoZSByb290IGxheW91dC5cbiAgICAgIGAsXG4gICAgICAgIHsgdmlldzogYm91bmRWaWV3IH0sXG4gICAgICApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGJpbmQgbXVsdGlwbGUgdmlld3MgdG8gdGhlIHNhbWUgRE9NIGVsZW1lbnQuXCIpO1xuICAgIH1cbiAgICAvLyBiaW5kIHRoZSB2aWV3IHRvIHRoZSBlbGVtZW50XG4gICAgRE9NLnB1dFByaXZhdGUodGhpcy5lbCwgXCJ2aWV3XCIsIHRoaXMpO1xuICAgIHRoaXMuaWQgPSB0aGlzLmVsLmlkO1xuICAgIHRoaXMucmVmID0gMDtcbiAgICB0aGlzLmxhc3RBY2tSZWYgPSBudWxsO1xuICAgIHRoaXMuY2hpbGRKb2lucyA9IDA7XG4gICAgLyoqXG4gICAgICogQHR5cGUge1JldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbH1cbiAgICAgKi9cbiAgICB0aGlzLmxvYWRlclRpbWVyID0gbnVsbDtcbiAgICAvKipcbiAgICAgKiBAdHlwZSB7UmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsfVxuICAgICAqL1xuICAgIHRoaXMuZGlzY29ubmVjdGVkVGltZXIgPSBudWxsO1xuICAgIHRoaXMucGVuZGluZ0RpZmZzID0gW107XG4gICAgdGhpcy5wZW5kaW5nRm9ybXMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5yZWRpcmVjdCA9IGZhbHNlO1xuICAgIHRoaXMuaHJlZiA9IG51bGw7XG4gICAgdGhpcy5qb2luQ291bnQgPSB0aGlzLnBhcmVudCA/IHRoaXMucGFyZW50LmpvaW5Db3VudCAtIDEgOiAwO1xuICAgIHRoaXMuam9pbkF0dGVtcHRzID0gMDtcbiAgICB0aGlzLmpvaW5QZW5kaW5nID0gdHJ1ZTtcbiAgICB0aGlzLmRlc3Ryb3llZCA9IGZhbHNlO1xuICAgIHRoaXMuam9pbkNhbGxiYWNrID0gZnVuY3Rpb24gKG9uRG9uZSkge1xuICAgICAgb25Eb25lICYmIG9uRG9uZSgpO1xuICAgIH07XG4gICAgdGhpcy5zdG9wQ2FsbGJhY2sgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICB0aGlzLnBlbmRpbmdKb2luT3BzID0gdGhpcy5wYXJlbnQgPyBudWxsIDogW107XG4gICAgdGhpcy52aWV3SG9va3MgPSB7fTtcbiAgICB0aGlzLmZvcm1TdWJtaXRzID0gW107XG4gICAgdGhpcy5jaGlsZHJlbiA9IHRoaXMucGFyZW50ID8gbnVsbCA6IHt9O1xuICAgIHRoaXMucm9vdC5jaGlsZHJlblt0aGlzLmlkXSA9IHt9O1xuICAgIHRoaXMuZm9ybXNGb3JSZWNvdmVyeSA9IHt9O1xuICAgIHRoaXMuY2hhbm5lbCA9IHRoaXMubGl2ZVNvY2tldC5jaGFubmVsKGBsdjoke3RoaXMuaWR9YCwgKCkgPT4ge1xuICAgICAgY29uc3QgdXJsID0gdGhpcy5ocmVmICYmIHRoaXMuZXhwYW5kVVJMKHRoaXMuaHJlZik7XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZWRpcmVjdDogdGhpcy5yZWRpcmVjdCA/IHVybCA6IHVuZGVmaW5lZCxcbiAgICAgICAgdXJsOiB0aGlzLnJlZGlyZWN0ID8gdW5kZWZpbmVkIDogdXJsIHx8IHVuZGVmaW5lZCxcbiAgICAgICAgcGFyYW1zOiB0aGlzLmNvbm5lY3RQYXJhbXMobGl2ZVJlZmVyZXIpLFxuICAgICAgICBzZXNzaW9uOiB0aGlzLmdldFNlc3Npb24oKSxcbiAgICAgICAgc3RhdGljOiB0aGlzLmdldFN0YXRpYygpLFxuICAgICAgICBmbGFzaDogdGhpcy5mbGFzaCxcbiAgICAgICAgc3RpY2t5OiB0aGlzLmVsLmhhc0F0dHJpYnV0ZShQSFhfU1RJQ0tZKSxcbiAgICAgIH07XG4gICAgfSk7XG4gICAgdGhpcy5wb3J0YWxFbGVtZW50SWRzID0gbmV3IFNldCgpO1xuICB9XG5cbiAgc2V0SHJlZihocmVmKSB7XG4gICAgdGhpcy5ocmVmID0gaHJlZjtcbiAgfVxuXG4gIHNldFJlZGlyZWN0KGhyZWYpIHtcbiAgICB0aGlzLnJlZGlyZWN0ID0gdHJ1ZTtcbiAgICB0aGlzLmhyZWYgPSBocmVmO1xuICB9XG5cbiAgaXNNYWluKCkge1xuICAgIHJldHVybiB0aGlzLmVsLmhhc0F0dHJpYnV0ZShQSFhfTUFJTik7XG4gIH1cblxuICBjb25uZWN0UGFyYW1zKGxpdmVSZWZlcmVyKSB7XG4gICAgY29uc3QgcGFyYW1zID0gdGhpcy5saXZlU29ja2V0LnBhcmFtcyh0aGlzLmVsKTtcbiAgICBjb25zdCBtYW5pZmVzdCA9IERPTS5hbGwoZG9jdW1lbnQsIGBbJHt0aGlzLmJpbmRpbmcoUEhYX1RSQUNLX1NUQVRJQyl9XWApXG4gICAgICAubWFwKChub2RlKSA9PiBub2RlLnNyYyB8fCBub2RlLmhyZWYpXG4gICAgICAuZmlsdGVyKCh1cmwpID0+IHR5cGVvZiB1cmwgPT09IFwic3RyaW5nXCIpO1xuXG4gICAgaWYgKG1hbmlmZXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgIHBhcmFtc1tcIl90cmFja19zdGF0aWNcIl0gPSBtYW5pZmVzdDtcbiAgICB9XG4gICAgcGFyYW1zW1wiX21vdW50c1wiXSA9IHRoaXMuam9pbkNvdW50O1xuICAgIHBhcmFtc1tcIl9tb3VudF9hdHRlbXB0c1wiXSA9IHRoaXMuam9pbkF0dGVtcHRzO1xuICAgIHBhcmFtc1tcIl9saXZlX3JlZmVyZXJcIl0gPSBsaXZlUmVmZXJlcjtcbiAgICB0aGlzLmpvaW5BdHRlbXB0cysrO1xuXG4gICAgcmV0dXJuIHBhcmFtcztcbiAgfVxuXG4gIGlzQ29ubmVjdGVkKCkge1xuICAgIHJldHVybiB0aGlzLmNoYW5uZWwuY2FuUHVzaCgpO1xuICB9XG5cbiAgZ2V0U2Vzc2lvbigpIHtcbiAgICByZXR1cm4gdGhpcy5lbC5nZXRBdHRyaWJ1dGUoUEhYX1NFU1NJT04pO1xuICB9XG5cbiAgZ2V0U3RhdGljKCkge1xuICAgIGNvbnN0IHZhbCA9IHRoaXMuZWwuZ2V0QXR0cmlidXRlKFBIWF9TVEFUSUMpO1xuICAgIHJldHVybiB2YWwgPT09IFwiXCIgPyBudWxsIDogdmFsO1xuICB9XG5cbiAgZGVzdHJveShjYWxsYmFjayA9IGZ1bmN0aW9uICgpIHt9KSB7XG4gICAgdGhpcy5kZXN0cm95QWxsQ2hpbGRyZW4oKTtcbiAgICB0aGlzLmRlc3Ryb3lQb3J0YWxFbGVtZW50cygpO1xuICAgIHRoaXMuZGVzdHJveWVkID0gdHJ1ZTtcbiAgICBET00uZGVsZXRlUHJpdmF0ZSh0aGlzLmVsLCBcInZpZXdcIik7XG4gICAgZGVsZXRlIHRoaXMucm9vdC5jaGlsZHJlblt0aGlzLmlkXTtcbiAgICBpZiAodGhpcy5wYXJlbnQpIHtcbiAgICAgIGRlbGV0ZSB0aGlzLnJvb3QuY2hpbGRyZW5bdGhpcy5wYXJlbnQuaWRdW3RoaXMuaWRdO1xuICAgIH1cbiAgICBjbGVhclRpbWVvdXQodGhpcy5sb2FkZXJUaW1lcik7XG4gICAgY29uc3Qgb25GaW5pc2hlZCA9ICgpID0+IHtcbiAgICAgIGNhbGxiYWNrKCk7XG4gICAgICBmb3IgKGNvbnN0IGlkIGluIHRoaXMudmlld0hvb2tzKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveUhvb2sodGhpcy52aWV3SG9va3NbaWRdKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgRE9NLm1hcmtQaHhDaGlsZERlc3Ryb3llZCh0aGlzLmVsKTtcblxuICAgIHRoaXMubG9nKFwiZGVzdHJveWVkXCIsICgpID0+IFtcInRoZSBjaGlsZCBoYXMgYmVlbiByZW1vdmVkIGZyb20gdGhlIHBhcmVudFwiXSk7XG4gICAgdGhpcy5jaGFubmVsXG4gICAgICAubGVhdmUoKVxuICAgICAgLnJlY2VpdmUoXCJva1wiLCBvbkZpbmlzaGVkKVxuICAgICAgLnJlY2VpdmUoXCJlcnJvclwiLCBvbkZpbmlzaGVkKVxuICAgICAgLnJlY2VpdmUoXCJ0aW1lb3V0XCIsIG9uRmluaXNoZWQpO1xuICB9XG5cbiAgc2V0Q29udGFpbmVyQ2xhc3NlcyguLi5jbGFzc2VzKSB7XG4gICAgdGhpcy5lbC5jbGFzc0xpc3QucmVtb3ZlKFxuICAgICAgUEhYX0NPTk5FQ1RFRF9DTEFTUyxcbiAgICAgIFBIWF9MT0FESU5HX0NMQVNTLFxuICAgICAgUEhYX0VSUk9SX0NMQVNTLFxuICAgICAgUEhYX0NMSUVOVF9FUlJPUl9DTEFTUyxcbiAgICAgIFBIWF9TRVJWRVJfRVJST1JfQ0xBU1MsXG4gICAgKTtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdC5hZGQoLi4uY2xhc3Nlcyk7XG4gIH1cblxuICBzaG93TG9hZGVyKHRpbWVvdXQpIHtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5sb2FkZXJUaW1lcik7XG4gICAgaWYgKHRpbWVvdXQpIHtcbiAgICAgIHRoaXMubG9hZGVyVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHRoaXMuc2hvd0xvYWRlcigpLCB0aW1lb3V0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBpZCBpbiB0aGlzLnZpZXdIb29rcykge1xuICAgICAgICB0aGlzLnZpZXdIb29rc1tpZF0uX19kaXNjb25uZWN0ZWQoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuc2V0Q29udGFpbmVyQ2xhc3NlcyhQSFhfTE9BRElOR19DTEFTUyk7XG4gICAgfVxuICB9XG5cbiAgZXhlY0FsbChiaW5kaW5nKSB7XG4gICAgRE9NLmFsbCh0aGlzLmVsLCBgWyR7YmluZGluZ31dYCwgKGVsKSA9PlxuICAgICAgdGhpcy5saXZlU29ja2V0LmV4ZWNKUyhlbCwgZWwuZ2V0QXR0cmlidXRlKGJpbmRpbmcpKSxcbiAgICApO1xuICB9XG5cbiAgaGlkZUxvYWRlcigpIHtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5sb2FkZXJUaW1lcik7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuZGlzY29ubmVjdGVkVGltZXIpO1xuICAgIHRoaXMuc2V0Q29udGFpbmVyQ2xhc3NlcyhQSFhfQ09OTkVDVEVEX0NMQVNTKTtcbiAgICB0aGlzLmV4ZWNBbGwodGhpcy5iaW5kaW5nKFwiY29ubmVjdGVkXCIpKTtcbiAgfVxuXG4gIHRyaWdnZXJSZWNvbm5lY3RlZCgpIHtcbiAgICBmb3IgKGNvbnN0IGlkIGluIHRoaXMudmlld0hvb2tzKSB7XG4gICAgICB0aGlzLnZpZXdIb29rc1tpZF0uX19yZWNvbm5lY3RlZCgpO1xuICAgIH1cbiAgfVxuXG4gIGxvZyhraW5kLCBtc2dDYWxsYmFjaykge1xuICAgIHRoaXMubGl2ZVNvY2tldC5sb2codGhpcywga2luZCwgbXNnQ2FsbGJhY2spO1xuICB9XG5cbiAgdHJhbnNpdGlvbih0aW1lLCBvblN0YXJ0LCBvbkRvbmUgPSBmdW5jdGlvbiAoKSB7fSkge1xuICAgIHRoaXMubGl2ZVNvY2tldC50cmFuc2l0aW9uKHRpbWUsIG9uU3RhcnQsIG9uRG9uZSk7XG4gIH1cblxuICAvLyBjYWxscyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgdmlldyBhbmQgdGFyZ2V0IGVsZW1lbnQgZm9yIHRoZSBnaXZlbiBwaHhUYXJnZXRcbiAgLy8gdGFyZ2V0cyBjYW4gYmU6XG4gIC8vICAqIGFuIGVsZW1lbnQgaXRzZWxmLCB0aGVuIGl0IGlzIHNpbXBseSBwYXNzZWQgdG8gbGl2ZVNvY2tldC5vd25lcjtcbiAgLy8gICogYSBDSUQgKENvbXBvbmVudCBJRCksIHRoZW4gd2UgZmlyc3Qgc2VhcmNoIHRoZSBjb21wb25lbnQncyBlbGVtZW50IGluIHRoZSBET01cbiAgLy8gICogYSBzZWxlY3RvciwgdGhlbiB3ZSBzZWFyY2ggdGhlIHNlbGVjdG9yIGluIHRoZSBET00gYW5kIGNhbGwgdGhlIGNhbGxiYWNrXG4gIC8vICAgIGZvciBlYWNoIGVsZW1lbnQgZm91bmQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBvd25lciB2aWV3XG4gIHdpdGhpblRhcmdldHMocGh4VGFyZ2V0LCBjYWxsYmFjaywgZG9tID0gZG9jdW1lbnQpIHtcbiAgICAvLyBpbiB0aGUgZm9ybSByZWNvdmVyeSBjYXNlIHdlIHNlYXJjaCBpbiBhIHRlbXBsYXRlIGZyYWdtZW50IGluc3RlYWQgb2ZcbiAgICAvLyB0aGUgcmVhbCBkb20sIHRoZXJlZm9yZSB3ZSBvcHRpb25hbGx5IHBhc3MgZG9tIGFuZCB2aWV3RWxcblxuICAgIGlmIChwaHhUYXJnZXQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCB8fCBwaHhUYXJnZXQgaW5zdGFuY2VvZiBTVkdFbGVtZW50KSB7XG4gICAgICByZXR1cm4gdGhpcy5saXZlU29ja2V0Lm93bmVyKHBoeFRhcmdldCwgKHZpZXcpID0+XG4gICAgICAgIGNhbGxiYWNrKHZpZXcsIHBoeFRhcmdldCksXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChpc0NpZChwaHhUYXJnZXQpKSB7XG4gICAgICBjb25zdCB0YXJnZXRzID0gRE9NLmZpbmRDb21wb25lbnROb2RlTGlzdCh0aGlzLmlkLCBwaHhUYXJnZXQsIGRvbSk7XG4gICAgICBpZiAodGFyZ2V0cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgbG9nRXJyb3IoYG5vIGNvbXBvbmVudCBmb3VuZCBtYXRjaGluZyBwaHgtdGFyZ2V0IG9mICR7cGh4VGFyZ2V0fWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2FsbGJhY2sodGhpcywgcGFyc2VJbnQocGh4VGFyZ2V0KSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHRhcmdldHMgPSBBcnJheS5mcm9tKGRvbS5xdWVyeVNlbGVjdG9yQWxsKHBoeFRhcmdldCkpO1xuICAgICAgaWYgKHRhcmdldHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGxvZ0Vycm9yKFxuICAgICAgICAgIGBub3RoaW5nIGZvdW5kIG1hdGNoaW5nIHRoZSBwaHgtdGFyZ2V0IHNlbGVjdG9yIFwiJHtwaHhUYXJnZXR9XCJgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgdGFyZ2V0cy5mb3JFYWNoKCh0YXJnZXQpID0+XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5vd25lcih0YXJnZXQsICh2aWV3KSA9PiBjYWxsYmFjayh2aWV3LCB0YXJnZXQpKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXBwbHlEaWZmKHR5cGUsIHJhd0RpZmYsIGNhbGxiYWNrKSB7XG4gICAgdGhpcy5sb2codHlwZSwgKCkgPT4gW1wiXCIsIGNsb25lKHJhd0RpZmYpXSk7XG4gICAgY29uc3QgeyBkaWZmLCByZXBseSwgZXZlbnRzLCB0aXRsZSB9ID0gUmVuZGVyZWQuZXh0cmFjdChyYXdEaWZmKTtcbiAgICBjYWxsYmFjayh7IGRpZmYsIHJlcGx5LCBldmVudHMgfSk7XG4gICAgaWYgKHR5cGVvZiB0aXRsZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlID09IFwibW91bnRcIikge1xuICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiBET00ucHV0VGl0bGUodGl0bGUpKTtcbiAgICB9XG4gIH1cblxuICBvbkpvaW4ocmVzcCkge1xuICAgIGNvbnN0IHsgcmVuZGVyZWQsIGNvbnRhaW5lciwgbGl2ZXZpZXdfdmVyc2lvbiwgcGlkIH0gPSByZXNwO1xuICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgIGNvbnN0IFt0YWcsIGF0dHJzXSA9IGNvbnRhaW5lcjtcbiAgICAgIHRoaXMuZWwgPSBET00ucmVwbGFjZVJvb3RDb250YWluZXIodGhpcy5lbCwgdGFnLCBhdHRycyk7XG4gICAgfVxuICAgIHRoaXMuY2hpbGRKb2lucyA9IDA7XG4gICAgdGhpcy5qb2luUGVuZGluZyA9IHRydWU7XG4gICAgdGhpcy5mbGFzaCA9IG51bGw7XG4gICAgaWYgKHRoaXMucm9vdCA9PT0gdGhpcykge1xuICAgICAgdGhpcy5mb3Jtc0ZvclJlY292ZXJ5ID0gdGhpcy5nZXRGb3Jtc0ZvclJlY292ZXJ5KCk7XG4gICAgfVxuICAgIGlmICh0aGlzLmlzTWFpbigpICYmIHdpbmRvdy5oaXN0b3J5LnN0YXRlID09PSBudWxsKSB7XG4gICAgICAvLyBzZXQgaW5pdGlhbCBoaXN0b3J5IGVudHJ5IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHBhZ2UgbG9hZCAobm8gaGlzdG9yeSlcbiAgICAgIEJyb3dzZXIucHVzaFN0YXRlKFwicmVwbGFjZVwiLCB7XG4gICAgICAgIHR5cGU6IFwicGF0Y2hcIixcbiAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLmxpdmVTb2NrZXQuY3VycmVudEhpc3RvcnlQb3NpdGlvbixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChsaXZldmlld192ZXJzaW9uICE9PSB0aGlzLmxpdmVTb2NrZXQudmVyc2lvbigpKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICBgTGl2ZVZpZXcgYXNzZXQgdmVyc2lvbiBtaXNtYXRjaC4gSmF2YVNjcmlwdCB2ZXJzaW9uICR7dGhpcy5saXZlU29ja2V0LnZlcnNpb24oKX0gdnMuIHNlcnZlciAke2xpdmV2aWV3X3ZlcnNpb259LiBUbyBhdm9pZCBpc3N1ZXMsIHBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIGFzc2V0cyB1c2UgdGhlIHNhbWUgdmVyc2lvbiBhcyB0aGUgc2VydmVyLmAsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFRoZSBwaWQgaXMgb25seSBzZW50IGlmXG4gICAgLy9cbiAgICAvLyAgICBjb25maWcgOnBob2VuaXhfbGl2ZV92aWV3LCA6ZGVidWdfYXR0cmlidXRlc1xuICAgIC8vXG4gICAgLy8gaWYgc2V0IHRvIHRydWUuIEl0IGlzIHRvIGhlbHAgZGVidWdnaW5nIGluIGRldmVsb3BtZW50LlxuICAgIGlmIChwaWQpIHtcbiAgICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKFBIWF9MVl9QSUQsIHBpZCk7XG4gICAgfVxuXG4gICAgQnJvd3Nlci5kcm9wTG9jYWwoXG4gICAgICB0aGlzLmxpdmVTb2NrZXQubG9jYWxTdG9yYWdlLFxuICAgICAgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLFxuICAgICAgQ09OU0VDVVRJVkVfUkVMT0FEUyxcbiAgICApO1xuICAgIHRoaXMuYXBwbHlEaWZmKFwibW91bnRcIiwgcmVuZGVyZWQsICh7IGRpZmYsIGV2ZW50cyB9KSA9PiB7XG4gICAgICB0aGlzLnJlbmRlcmVkID0gbmV3IFJlbmRlcmVkKHRoaXMuaWQsIGRpZmYpO1xuICAgICAgY29uc3QgW2h0bWwsIHN0cmVhbXNdID0gdGhpcy5yZW5kZXJDb250YWluZXIobnVsbCwgXCJqb2luXCIpO1xuICAgICAgdGhpcy5kcm9wUGVuZGluZ1JlZnMoKTtcbiAgICAgIHRoaXMuam9pbkNvdW50Kys7XG4gICAgICB0aGlzLmpvaW5BdHRlbXB0cyA9IDA7XG5cbiAgICAgIHRoaXMubWF5YmVSZWNvdmVyRm9ybXMoaHRtbCwgKCkgPT4ge1xuICAgICAgICB0aGlzLm9uSm9pbkNvbXBsZXRlKHJlc3AsIGh0bWwsIHN0cmVhbXMsIGV2ZW50cyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGRyb3BQZW5kaW5nUmVmcygpIHtcbiAgICBET00uYWxsKGRvY3VtZW50LCBgWyR7UEhYX1JFRl9TUkN9PVwiJHt0aGlzLnJlZlNyYygpfVwiXWAsIChlbCkgPT4ge1xuICAgICAgZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUZfTE9BRElORyk7XG4gICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoUEhYX1JFRl9TUkMpO1xuICAgICAgZWwucmVtb3ZlQXR0cmlidXRlKFBIWF9SRUZfTE9DSyk7XG4gICAgfSk7XG4gIH1cblxuICBvbkpvaW5Db21wbGV0ZSh7IGxpdmVfcGF0Y2ggfSwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKSB7XG4gICAgLy8gSW4gb3JkZXIgdG8gcHJvdmlkZSBhIGJldHRlciBleHBlcmllbmNlLCB3ZSB3YW50IHRvIGpvaW5cbiAgICAvLyBhbGwgTGl2ZVZpZXdzIGZpcnN0IGFuZCBvbmx5IHRoZW4gYXBwbHkgdGhlaXIgcGF0Y2hlcy5cbiAgICBpZiAodGhpcy5qb2luQ291bnQgPiAxIHx8ICh0aGlzLnBhcmVudCAmJiAhdGhpcy5wYXJlbnQuaXNKb2luUGVuZGluZygpKSkge1xuICAgICAgcmV0dXJuIHRoaXMuYXBwbHlKb2luUGF0Y2gobGl2ZV9wYXRjaCwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKTtcbiAgICB9XG5cbiAgICAvLyBPbmUgZG93bnNpZGUgb2YgdGhpcyBhcHByb2FjaCBpcyB0aGF0IHdlIG5lZWQgdG8gZmluZCBwaHhDaGlsZHJlblxuICAgIC8vIGluIHRoZSBodG1sIGZyYWdtZW50LCBpbnN0ZWFkIG9mIGRpcmVjdGx5IG9uIHRoZSBET00uIFRoZSBmcmFnbWVudFxuICAgIC8vIGFsc28gZG9lcyBub3QgaW5jbHVkZSBQSFhfU1RBVElDLCBzbyB3ZSBuZWVkIHRvIGNvcHkgaXQgb3ZlciBmcm9tXG4gICAgLy8gdGhlIERPTS5cbiAgICBjb25zdCBuZXdDaGlsZHJlbiA9IERPTS5maW5kUGh4Q2hpbGRyZW5JbkZyYWdtZW50KGh0bWwsIHRoaXMuaWQpLmZpbHRlcihcbiAgICAgICh0b0VsKSA9PiB7XG4gICAgICAgIGNvbnN0IGZyb21FbCA9IHRvRWwuaWQgJiYgdGhpcy5lbC5xdWVyeVNlbGVjdG9yKGBbaWQ9XCIke3RvRWwuaWR9XCJdYCk7XG4gICAgICAgIGNvbnN0IHBoeFN0YXRpYyA9IGZyb21FbCAmJiBmcm9tRWwuZ2V0QXR0cmlidXRlKFBIWF9TVEFUSUMpO1xuICAgICAgICBpZiAocGh4U3RhdGljKSB7XG4gICAgICAgICAgdG9FbC5zZXRBdHRyaWJ1dGUoUEhYX1NUQVRJQywgcGh4U3RhdGljKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBzZXQgUEhYX1JPT1RfSUQgdG8gcHJldmVudCBldmVudHMgZnJvbSBiZWluZyBkaXNwYXRjaGVkIHRvIHRoZSByb290IHZpZXdcbiAgICAgICAgLy8gd2hpbGUgdGhlIGNoaWxkIGpvaW4gaXMgc3RpbGwgcGVuZGluZ1xuICAgICAgICBpZiAoZnJvbUVsKSB7XG4gICAgICAgICAgZnJvbUVsLnNldEF0dHJpYnV0ZShQSFhfUk9PVF9JRCwgdGhpcy5yb290LmlkKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5qb2luQ2hpbGQodG9FbCk7XG4gICAgICB9LFxuICAgICk7XG5cbiAgICBpZiAobmV3Q2hpbGRyZW4ubGVuZ3RoID09PSAwKSB7XG4gICAgICBpZiAodGhpcy5wYXJlbnQpIHtcbiAgICAgICAgdGhpcy5yb290LnBlbmRpbmdKb2luT3BzLnB1c2goW1xuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgKCkgPT4gdGhpcy5hcHBseUpvaW5QYXRjaChsaXZlX3BhdGNoLCBodG1sLCBzdHJlYW1zLCBldmVudHMpLFxuICAgICAgICBdKTtcbiAgICAgICAgdGhpcy5wYXJlbnQuYWNrSm9pbih0aGlzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMub25BbGxDaGlsZEpvaW5zQ29tcGxldGUoKTtcbiAgICAgICAgdGhpcy5hcHBseUpvaW5QYXRjaChsaXZlX3BhdGNoLCBodG1sLCBzdHJlYW1zLCBldmVudHMpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJvb3QucGVuZGluZ0pvaW5PcHMucHVzaChbXG4gICAgICAgIHRoaXMsXG4gICAgICAgICgpID0+IHRoaXMuYXBwbHlKb2luUGF0Y2gobGl2ZV9wYXRjaCwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKSxcbiAgICAgIF0pO1xuICAgIH1cbiAgfVxuXG4gIGF0dGFjaFRydWVEb2NFbCgpIHtcbiAgICB0aGlzLmVsID0gRE9NLmJ5SWQodGhpcy5pZCk7XG4gICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoUEhYX1JPT1RfSUQsIHRoaXMucm9vdC5pZCk7XG4gIH1cblxuICAvLyB0aGlzIGlzIGludm9rZWQgZm9yIGRlYWQgYW5kIGxpdmUgdmlld3MsIHNvIHdlIG11c3QgZmlsdGVyIGJ5XG4gIC8vIGJ5IG93bmVyIHRvIGVuc3VyZSB3ZSBhcmVuJ3QgZHVwbGljYXRpbmcgaG9va3MgYWNyb3NzIGRpc2Nvbm5lY3RcbiAgLy8gYW5kIGNvbm5lY3RlZCBzdGF0ZXMuIFRoaXMgYWxzbyBoYW5kbGVzIGNhc2VzIHdoZXJlIGhvb2tzIGV4aXN0XG4gIC8vIGluIGEgcm9vdCBsYXlvdXQgd2l0aCBhIExWIGluIHRoZSBib2R5XG4gIGV4ZWNOZXdNb3VudGVkKHBhcmVudCA9IGRvY3VtZW50KSB7XG4gICAgbGV0IHBoeFZpZXdwb3J0VG9wID0gdGhpcy5iaW5kaW5nKFBIWF9WSUVXUE9SVF9UT1ApO1xuICAgIGxldCBwaHhWaWV3cG9ydEJvdHRvbSA9IHRoaXMuYmluZGluZyhQSFhfVklFV1BPUlRfQk9UVE9NKTtcbiAgICB0aGlzLmFsbChcbiAgICAgIHBhcmVudCxcbiAgICAgIGBbJHtwaHhWaWV3cG9ydFRvcH1dLCBbJHtwaHhWaWV3cG9ydEJvdHRvbX1dYCxcbiAgICAgIChob29rRWwpID0+IHtcbiAgICAgICAgRE9NLm1haW50YWluUHJpdmF0ZUhvb2tzKFxuICAgICAgICAgIGhvb2tFbCxcbiAgICAgICAgICBob29rRWwsXG4gICAgICAgICAgcGh4Vmlld3BvcnRUb3AsXG4gICAgICAgICAgcGh4Vmlld3BvcnRCb3R0b20sXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubWF5YmVBZGROZXdIb29rKGhvb2tFbCk7XG4gICAgICB9LFxuICAgICk7XG4gICAgdGhpcy5hbGwoXG4gICAgICBwYXJlbnQsXG4gICAgICBgWyR7dGhpcy5iaW5kaW5nKFBIWF9IT09LKX1dLCBbZGF0YS1waHgtJHtQSFhfSE9PS31dYCxcbiAgICAgIChob29rRWwpID0+IHtcbiAgICAgICAgdGhpcy5tYXliZUFkZE5ld0hvb2soaG9va0VsKTtcbiAgICAgIH0sXG4gICAgKTtcbiAgICB0aGlzLmFsbChwYXJlbnQsIGBbJHt0aGlzLmJpbmRpbmcoUEhYX01PVU5URUQpfV1gLCAoZWwpID0+IHtcbiAgICAgIHRoaXMubWF5YmVNb3VudGVkKGVsKTtcbiAgICB9KTtcbiAgfVxuXG4gIGFsbChwYXJlbnQsIHNlbGVjdG9yLCBjYWxsYmFjaykge1xuICAgIERPTS5hbGwocGFyZW50LCBzZWxlY3RvciwgKGVsKSA9PiB7XG4gICAgICBpZiAodGhpcy5vd25zRWxlbWVudChlbCkpIHtcbiAgICAgICAgY2FsbGJhY2soZWwpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgYXBwbHlKb2luUGF0Y2gobGl2ZV9wYXRjaCwgaHRtbCwgc3RyZWFtcywgZXZlbnRzKSB7XG4gICAgdGhpcy5hdHRhY2hUcnVlRG9jRWwoKTtcbiAgICBjb25zdCBwYXRjaCA9IG5ldyBET01QYXRjaCh0aGlzLCB0aGlzLmVsLCB0aGlzLmlkLCBodG1sLCBzdHJlYW1zLCBudWxsKTtcbiAgICBwYXRjaC5tYXJrUHJ1bmFibGVDb250ZW50Rm9yUmVtb3ZhbCgpO1xuICAgIHRoaXMucGVyZm9ybVBhdGNoKHBhdGNoLCBmYWxzZSwgdHJ1ZSk7XG4gICAgdGhpcy5qb2luTmV3Q2hpbGRyZW4oKTtcbiAgICB0aGlzLmV4ZWNOZXdNb3VudGVkKCk7XG5cbiAgICB0aGlzLmpvaW5QZW5kaW5nID0gZmFsc2U7XG4gICAgdGhpcy5saXZlU29ja2V0LmRpc3BhdGNoRXZlbnRzKGV2ZW50cyk7XG4gICAgdGhpcy5hcHBseVBlbmRpbmdVcGRhdGVzKCk7XG5cbiAgICBpZiAobGl2ZV9wYXRjaCkge1xuICAgICAgY29uc3QgeyBraW5kLCB0byB9ID0gbGl2ZV9wYXRjaDtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC5oaXN0b3J5UGF0Y2godG8sIGtpbmQpO1xuICAgIH1cbiAgICB0aGlzLmhpZGVMb2FkZXIoKTtcbiAgICBpZiAodGhpcy5qb2luQ291bnQgPiAxKSB7XG4gICAgICB0aGlzLnRyaWdnZXJSZWNvbm5lY3RlZCgpO1xuICAgIH1cbiAgICB0aGlzLnN0b3BDYWxsYmFjaygpO1xuICB9XG5cbiAgdHJpZ2dlckJlZm9yZVVwZGF0ZUhvb2soZnJvbUVsLCB0b0VsKSB7XG4gICAgdGhpcy5saXZlU29ja2V0LnRyaWdnZXJET00oXCJvbkJlZm9yZUVsVXBkYXRlZFwiLCBbZnJvbUVsLCB0b0VsXSk7XG4gICAgY29uc3QgaG9vayA9IHRoaXMuZ2V0SG9vayhmcm9tRWwpO1xuICAgIGNvbnN0IGlzSWdub3JlZCA9IGhvb2sgJiYgRE9NLmlzSWdub3JlZChmcm9tRWwsIHRoaXMuYmluZGluZyhQSFhfVVBEQVRFKSk7XG4gICAgaWYgKFxuICAgICAgaG9vayAmJlxuICAgICAgIWZyb21FbC5pc0VxdWFsTm9kZSh0b0VsKSAmJlxuICAgICAgIShpc0lnbm9yZWQgJiYgaXNFcXVhbE9iaihmcm9tRWwuZGF0YXNldCwgdG9FbC5kYXRhc2V0KSlcbiAgICApIHtcbiAgICAgIGhvb2suX19iZWZvcmVVcGRhdGUoKTtcbiAgICAgIHJldHVybiBob29rO1xuICAgIH1cbiAgfVxuXG4gIG1heWJlTW91bnRlZChlbCkge1xuICAgIGNvbnN0IHBoeE1vdW50ZWQgPSBlbC5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFBIWF9NT1VOVEVEKSk7XG4gICAgY29uc3QgaGFzQmVlbkludm9rZWQgPSBwaHhNb3VudGVkICYmIERPTS5wcml2YXRlKGVsLCBcIm1vdW50ZWRcIik7XG4gICAgaWYgKHBoeE1vdW50ZWQgJiYgIWhhc0JlZW5JbnZva2VkKSB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQuZXhlY0pTKGVsLCBwaHhNb3VudGVkKTtcbiAgICAgIERPTS5wdXRQcml2YXRlKGVsLCBcIm1vdW50ZWRcIiwgdHJ1ZSk7XG4gICAgfVxuICB9XG5cbiAgbWF5YmVBZGROZXdIb29rKGVsKSB7XG4gICAgY29uc3QgbmV3SG9vayA9IHRoaXMuYWRkSG9vayhlbCk7XG4gICAgaWYgKG5ld0hvb2spIHtcbiAgICAgIG5ld0hvb2suX19tb3VudGVkKCk7XG4gICAgfVxuICB9XG5cbiAgcGVyZm9ybVBhdGNoKHBhdGNoLCBwcnVuZUNpZHMsIGlzSm9pblBhdGNoID0gZmFsc2UpIHtcbiAgICBjb25zdCByZW1vdmVkRWxzID0gW107XG4gICAgbGV0IHBoeENoaWxkcmVuQWRkZWQgPSBmYWxzZTtcbiAgICBjb25zdCB1cGRhdGVkSG9va0lkcyA9IG5ldyBTZXQoKTtcblxuICAgIHRoaXMubGl2ZVNvY2tldC50cmlnZ2VyRE9NKFwib25QYXRjaFN0YXJ0XCIsIFtwYXRjaC50YXJnZXRDb250YWluZXJdKTtcblxuICAgIHBhdGNoLmFmdGVyKFwiYWRkZWRcIiwgKGVsKSA9PiB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQudHJpZ2dlckRPTShcIm9uTm9kZUFkZGVkXCIsIFtlbF0pO1xuICAgICAgY29uc3QgcGh4Vmlld3BvcnRUb3AgPSB0aGlzLmJpbmRpbmcoUEhYX1ZJRVdQT1JUX1RPUCk7XG4gICAgICBjb25zdCBwaHhWaWV3cG9ydEJvdHRvbSA9IHRoaXMuYmluZGluZyhQSFhfVklFV1BPUlRfQk9UVE9NKTtcbiAgICAgIERPTS5tYWludGFpblByaXZhdGVIb29rcyhlbCwgZWwsIHBoeFZpZXdwb3J0VG9wLCBwaHhWaWV3cG9ydEJvdHRvbSk7XG4gICAgICB0aGlzLm1heWJlQWRkTmV3SG9vayhlbCk7XG4gICAgICBpZiAoZWwuZ2V0QXR0cmlidXRlKSB7XG4gICAgICAgIHRoaXMubWF5YmVNb3VudGVkKGVsKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHBhdGNoLmFmdGVyKFwicGh4Q2hpbGRBZGRlZFwiLCAoZWwpID0+IHtcbiAgICAgIGlmIChET00uaXNQaHhTdGlja3koZWwpKSB7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5qb2luUm9vdFZpZXdzKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwaHhDaGlsZHJlbkFkZGVkID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHBhdGNoLmJlZm9yZShcInVwZGF0ZWRcIiwgKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgY29uc3QgaG9vayA9IHRoaXMudHJpZ2dlckJlZm9yZVVwZGF0ZUhvb2soZnJvbUVsLCB0b0VsKTtcbiAgICAgIGlmIChob29rKSB7XG4gICAgICAgIHVwZGF0ZWRIb29rSWRzLmFkZChmcm9tRWwuaWQpO1xuICAgICAgfVxuICAgICAgLy8gdHJpZ2dlciBKUyBzcGVjaWZpYyB1cGRhdGUgbG9naWMgKGZvciBleGFtcGxlIGZvciBKUy5pZ25vcmVfYXR0cmlidXRlcylcbiAgICAgIEpTLm9uQmVmb3JlRWxVcGRhdGVkKGZyb21FbCwgdG9FbCk7XG4gICAgfSk7XG5cbiAgICBwYXRjaC5hZnRlcihcInVwZGF0ZWRcIiwgKGVsKSA9PiB7XG4gICAgICBpZiAodXBkYXRlZEhvb2tJZHMuaGFzKGVsLmlkKSkge1xuICAgICAgICB0aGlzLmdldEhvb2soZWwpLl9fdXBkYXRlZCgpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcGF0Y2guYWZ0ZXIoXCJkaXNjYXJkZWRcIiwgKGVsKSA9PiB7XG4gICAgICBpZiAoZWwubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFKSB7XG4gICAgICAgIHJlbW92ZWRFbHMucHVzaChlbCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBwYXRjaC5hZnRlcihcInRyYW5zaXRpb25zRGlzY2FyZGVkXCIsIChlbHMpID0+XG4gICAgICB0aGlzLmFmdGVyRWxlbWVudHNSZW1vdmVkKGVscywgcHJ1bmVDaWRzKSxcbiAgICApO1xuICAgIHBhdGNoLnBlcmZvcm0oaXNKb2luUGF0Y2gpO1xuICAgIHRoaXMuYWZ0ZXJFbGVtZW50c1JlbW92ZWQocmVtb3ZlZEVscywgcHJ1bmVDaWRzKTtcblxuICAgIHRoaXMubGl2ZVNvY2tldC50cmlnZ2VyRE9NKFwib25QYXRjaEVuZFwiLCBbcGF0Y2gudGFyZ2V0Q29udGFpbmVyXSk7XG4gICAgcmV0dXJuIHBoeENoaWxkcmVuQWRkZWQ7XG4gIH1cblxuICBhZnRlckVsZW1lbnRzUmVtb3ZlZChlbGVtZW50cywgcHJ1bmVDaWRzKSB7XG4gICAgY29uc3QgZGVzdHJveWVkQ0lEcyA9IFtdO1xuICAgIGVsZW1lbnRzLmZvckVhY2goKHBhcmVudCkgPT4ge1xuICAgICAgY29uc3QgY29tcG9uZW50cyA9IERPTS5hbGwoXG4gICAgICAgIHBhcmVudCxcbiAgICAgICAgYFske1BIWF9WSUVXX1JFRn09XCIke3RoaXMuaWR9XCJdWyR7UEhYX0NPTVBPTkVOVH1dYCxcbiAgICAgICk7XG4gICAgICBjb25zdCBob29rcyA9IERPTS5hbGwoXG4gICAgICAgIHBhcmVudCxcbiAgICAgICAgYFske3RoaXMuYmluZGluZyhQSFhfSE9PSyl9XSwgW2RhdGEtcGh4LWhvb2tdYCxcbiAgICAgICk7XG4gICAgICBjb21wb25lbnRzLmNvbmNhdChwYXJlbnQpLmZvckVhY2goKGVsKSA9PiB7XG4gICAgICAgIGNvbnN0IGNpZCA9IHRoaXMuY29tcG9uZW50SUQoZWwpO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgaXNDaWQoY2lkKSAmJlxuICAgICAgICAgIGRlc3Ryb3llZENJRHMuaW5kZXhPZihjaWQpID09PSAtMSAmJlxuICAgICAgICAgIGVsLmdldEF0dHJpYnV0ZShQSFhfVklFV19SRUYpID09PSB0aGlzLmlkXG4gICAgICAgICkge1xuICAgICAgICAgIGRlc3Ryb3llZENJRHMucHVzaChjaWQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGhvb2tzLmNvbmNhdChwYXJlbnQpLmZvckVhY2goKGhvb2tFbCkgPT4ge1xuICAgICAgICBjb25zdCBob29rID0gdGhpcy5nZXRIb29rKGhvb2tFbCk7XG4gICAgICAgIGhvb2sgJiYgdGhpcy5kZXN0cm95SG9vayhob29rKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIC8vIFdlIHNob3VsZCBub3QgcHJ1bmVDaWRzIG9uIGpvaW5zLiBPdGhlcndpc2UsIGluIGNhc2Ugb2ZcbiAgICAvLyByZWpvaW5zLCB3ZSBtYXkgbm90aWZ5IGNpZHMgdGhhdCBubyBsb25nZXIgYmVsb25nIHRvIHRoZVxuICAgIC8vIGN1cnJlbnQgTGl2ZVZpZXcgdG8gYmUgcmVtb3ZlZC5cbiAgICBpZiAocHJ1bmVDaWRzKSB7XG4gICAgICB0aGlzLm1heWJlUHVzaENvbXBvbmVudHNEZXN0cm95ZWQoZGVzdHJveWVkQ0lEcyk7XG4gICAgfVxuICB9XG5cbiAgam9pbk5ld0NoaWxkcmVuKCkge1xuICAgIERPTS5maW5kUGh4Q2hpbGRyZW4oZG9jdW1lbnQsIHRoaXMuaWQpLmZvckVhY2goKGVsKSA9PiB0aGlzLmpvaW5DaGlsZChlbCkpO1xuICB9XG5cbiAgbWF5YmVSZWNvdmVyRm9ybXMoaHRtbCwgY2FsbGJhY2spIHtcbiAgICBjb25zdCBwaHhDaGFuZ2UgPSB0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIik7XG4gICAgY29uc3Qgb2xkRm9ybXMgPSB0aGlzLnJvb3QuZm9ybXNGb3JSZWNvdmVyeTtcbiAgICAvLyBTbyB3aHkgZG8gd2UgY3JlYXRlIGEgdGVtcGxhdGUgZWxlbWVudCBoZXJlP1xuICAgIC8vIE9uZSB3YXkgdG8gcmVjb3ZlciBmb3JtcyB3b3VsZCBiZSB0byBpbW1lZGlhdGVseSBhcHBseSB0aGUgbW91bnRcbiAgICAvLyBwYXRjaCBhbmQgdGhlbiBhZnRlcndhcmRzIHJlY292ZXIgdGhlIGZvcm1zLiBIb3dldmVyLCB0aGlzIHdvdWxkXG4gICAgLy8gY2F1c2UgYSBmbGlja2VyLCBiZWNhdXNlIHRoZSBtb3VudCBwYXRjaCB3b3VsZCByZW1vdmUgdGhlIGZvcm0gY29udGVudFxuICAgIC8vIHVudGlsIGl0IGlzIHJlc3RvcmVkLiBUaGVyZWZvcmUgTFYgZGVjaWRlZCB0byBkbyBmb3JtIHJlY292ZXJ5IHdpdGggdGhlXG4gICAgLy8gcmF3IEhUTUwgYmVmb3JlIGl0IGlzIGFwcGxpZWQgYW5kIGRlbGF5IHRoZSBtb3VudCBwYXRjaCB1bnRpbCB0aGUgZm9ybVxuICAgIC8vIHJlY292ZXJ5IGV2ZW50cyBhcmUgZG9uZS5cbiAgICBjb25zdCB0ZW1wbGF0ZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0ZW1wbGF0ZVwiKTtcbiAgICB0ZW1wbGF0ZS5pbm5lckhUTUwgPSBodG1sO1xuICAgIC8vIGJlY2F1c2Ugd2Ugd29yayB3aXRoIGEgdGVtcGxhdGUgZWxlbWVudCwgd2UgbXVzdCBtYW51YWxseSBjb3B5IHRoZSBhdHRyaWJ1dGVzXG4gICAgLy8gb3RoZXJ3aXNlIHRoZSBvd25lciAvIHRhcmdldCBoZWxwZXJzIGRvbid0IHdvcmsgcHJvcGVybHlcbiAgICBjb25zdCByb290RWwgPSB0ZW1wbGF0ZS5jb250ZW50LmZpcnN0RWxlbWVudENoaWxkO1xuICAgIHJvb3RFbC5pZCA9IHRoaXMuaWQ7XG4gICAgcm9vdEVsLnNldEF0dHJpYnV0ZShQSFhfUk9PVF9JRCwgdGhpcy5yb290LmlkKTtcbiAgICByb290RWwuc2V0QXR0cmlidXRlKFBIWF9TRVNTSU9OLCB0aGlzLmdldFNlc3Npb24oKSk7XG4gICAgcm9vdEVsLnNldEF0dHJpYnV0ZShQSFhfU1RBVElDLCB0aGlzLmdldFN0YXRpYygpKTtcbiAgICByb290RWwuc2V0QXR0cmlidXRlKFBIWF9QQVJFTlRfSUQsIHRoaXMucGFyZW50ID8gdGhpcy5wYXJlbnQuaWQgOiBudWxsKTtcblxuICAgIC8vIHdlIGdvIG92ZXIgYWxsIGZvcm0gZWxlbWVudHMgaW4gdGhlIG5ldyBIVE1MIGZvciB0aGUgTFZcbiAgICAvLyBhbmQgbG9vayBmb3Igb2xkIGZvcm1zIGluIHRoZSBgZm9ybXNGb3JSZWNvdmVyeWAgb2JqZWN0O1xuICAgIC8vIHRoZSBmb3Jtc0ZvclJlY292ZXJ5IGNhbiBhbHNvIGNvbnRhaW4gZm9ybXMgZnJvbSBjaGlsZCB2aWV3c1xuICAgIGNvbnN0IGZvcm1zVG9SZWNvdmVyID1cbiAgICAgIC8vIHdlIGdvIG92ZXIgYWxsIGZvcm1zIGluIHRoZSBuZXcgRE9NOyBiZWNhdXNlIHRoaXMgaXMgb25seSB0aGUgSFRNTCBmb3IgdGhlIGN1cnJlbnRcbiAgICAgIC8vIHZpZXcsIHdlIGNhbiBiZSBzdXJlIHRoYXQgYWxsIGZvcm1zIGFyZSBvd25lZCBieSB0aGlzIHZpZXc6XG4gICAgICBET00uYWxsKHRlbXBsYXRlLmNvbnRlbnQsIFwiZm9ybVwiKVxuICAgICAgICAvLyBvbmx5IHJlY292ZXIgZm9ybXMgdGhhdCBoYXZlIGFuIGlkIGFuZCBhcmUgaW4gdGhlIG9sZCBET01cbiAgICAgICAgLmZpbHRlcigobmV3Rm9ybSkgPT4gbmV3Rm9ybS5pZCAmJiBvbGRGb3Jtc1tuZXdGb3JtLmlkXSlcbiAgICAgICAgLy8gYWJhbmRvbiBmb3JtcyB3ZSBhbHJlYWR5IHRyaWVkIHRvIHJlY292ZXIgdG8gcHJldmVudCBsb29waW5nIGEgZmFpbGVkIHN0YXRlXG4gICAgICAgIC5maWx0ZXIoKG5ld0Zvcm0pID0+ICF0aGlzLnBlbmRpbmdGb3Jtcy5oYXMobmV3Rm9ybS5pZCkpXG4gICAgICAgIC8vIG9ubHkgcmVjb3ZlciBpZiB0aGUgZm9ybSBoYXMgdGhlIHNhbWUgcGh4LWNoYW5nZSB2YWx1ZVxuICAgICAgICAuZmlsdGVyKFxuICAgICAgICAgIChuZXdGb3JtKSA9PlxuICAgICAgICAgICAgb2xkRm9ybXNbbmV3Rm9ybS5pZF0uZ2V0QXR0cmlidXRlKHBoeENoYW5nZSkgPT09XG4gICAgICAgICAgICBuZXdGb3JtLmdldEF0dHJpYnV0ZShwaHhDaGFuZ2UpLFxuICAgICAgICApXG4gICAgICAgIC5tYXAoKG5ld0Zvcm0pID0+IHtcbiAgICAgICAgICByZXR1cm4gW29sZEZvcm1zW25ld0Zvcm0uaWRdLCBuZXdGb3JtXTtcbiAgICAgICAgfSk7XG5cbiAgICBpZiAoZm9ybXNUb1JlY292ZXIubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gY2FsbGJhY2soKTtcbiAgICB9XG5cbiAgICBmb3Jtc1RvUmVjb3Zlci5mb3JFYWNoKChbb2xkRm9ybSwgbmV3Rm9ybV0sIGkpID0+IHtcbiAgICAgIHRoaXMucGVuZGluZ0Zvcm1zLmFkZChuZXdGb3JtLmlkKTtcbiAgICAgIC8vIGl0IGlzIGltcG9ydGFudCB0byB1c2UgdGhlIGZpcnN0RWxlbWVudENoaWxkIG9mIHRoZSB0ZW1wbGF0ZSBjb250ZW50XG4gICAgICAvLyBiZWNhdXNlIHdoZW4gdHJhdmVyc2luZyBhIGRvY3VtZW50RnJhZ21lbnQgdXNpbmcgcGFyZW50Tm9kZSwgd2Ugd29uJ3QgZXZlciBhcnJpdmUgYXRcbiAgICAgIC8vIHRoZSBmcmFnbWVudDsgYXMgdGhlIHRlbXBsYXRlIGlzIGFsd2F5cyBhIExpdmVWaWV3LCB3ZSBjYW4gYmUgc3VyZSB0aGF0IHRoZXJlIGlzIG9ubHlcbiAgICAgIC8vIG9uZSBjaGlsZCBvbiB0aGUgcm9vdCBsZXZlbFxuICAgICAgdGhpcy5wdXNoRm9ybVJlY292ZXJ5KFxuICAgICAgICBvbGRGb3JtLFxuICAgICAgICBuZXdGb3JtLFxuICAgICAgICB0ZW1wbGF0ZS5jb250ZW50LmZpcnN0RWxlbWVudENoaWxkLFxuICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nRm9ybXMuZGVsZXRlKG5ld0Zvcm0uaWQpO1xuICAgICAgICAgIC8vIHdlIG9ubHkgY2FsbCB0aGUgY2FsbGJhY2sgb25jZSBhbGwgZm9ybXMgaGF2ZSBiZWVuIHJlY292ZXJlZFxuICAgICAgICAgIGlmIChpID09PSBmb3Jtc1RvUmVjb3Zlci5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBnZXRDaGlsZEJ5SWQoaWQpIHtcbiAgICByZXR1cm4gdGhpcy5yb290LmNoaWxkcmVuW3RoaXMuaWRdW2lkXTtcbiAgfVxuXG4gIGdldERlc2NlbmRlbnRCeUVsKGVsKSB7XG4gICAgaWYgKGVsLmlkID09PSB0aGlzLmlkKSB7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMuY2hpbGRyZW5bZWwuZ2V0QXR0cmlidXRlKFBIWF9QQVJFTlRfSUQpXT8uW2VsLmlkXTtcbiAgICB9XG4gIH1cblxuICBkZXN0cm95RGVzY2VuZGVudChpZCkge1xuICAgIGZvciAoY29uc3QgcGFyZW50SWQgaW4gdGhpcy5yb290LmNoaWxkcmVuKSB7XG4gICAgICBmb3IgKGNvbnN0IGNoaWxkSWQgaW4gdGhpcy5yb290LmNoaWxkcmVuW3BhcmVudElkXSkge1xuICAgICAgICBpZiAoY2hpbGRJZCA9PT0gaWQpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5yb290LmNoaWxkcmVuW3BhcmVudElkXVtjaGlsZElkXS5kZXN0cm95KCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBqb2luQ2hpbGQoZWwpIHtcbiAgICBjb25zdCBjaGlsZCA9IHRoaXMuZ2V0Q2hpbGRCeUlkKGVsLmlkKTtcbiAgICBpZiAoIWNoaWxkKSB7XG4gICAgICBjb25zdCB2aWV3ID0gbmV3IFZpZXcoZWwsIHRoaXMubGl2ZVNvY2tldCwgdGhpcyk7XG4gICAgICB0aGlzLnJvb3QuY2hpbGRyZW5bdGhpcy5pZF1bdmlldy5pZF0gPSB2aWV3O1xuICAgICAgdmlldy5qb2luKCk7XG4gICAgICB0aGlzLmNoaWxkSm9pbnMrKztcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIGlzSm9pblBlbmRpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuam9pblBlbmRpbmc7XG4gIH1cblxuICBhY2tKb2luKF9jaGlsZCkge1xuICAgIHRoaXMuY2hpbGRKb2lucy0tO1xuXG4gICAgaWYgKHRoaXMuY2hpbGRKb2lucyA9PT0gMCkge1xuICAgICAgaWYgKHRoaXMucGFyZW50KSB7XG4gICAgICAgIHRoaXMucGFyZW50LmFja0pvaW4odGhpcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLm9uQWxsQ2hpbGRKb2luc0NvbXBsZXRlKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgb25BbGxDaGlsZEpvaW5zQ29tcGxldGUoKSB7XG4gICAgLy8gd2UgY2FuIGNsZWFyIHBlbmRpbmcgZm9ybSByZWNvdmVyaWVzIG5vdyB0aGF0IHdlJ3ZlIGpvaW5lZC5cbiAgICAvLyBUaGV5IGVpdGhlciBhbGwgcmVzb2x2ZWQgb3Igd2VyZSBhYmFuZG9uZWRcbiAgICB0aGlzLnBlbmRpbmdGb3Jtcy5jbGVhcigpO1xuICAgIC8vIHdlIGNhbiBhbHNvIGNsZWFyIHRoZSBmb3Jtc0ZvclJlY292ZXJ5IG9iamVjdCB0byBub3Qga2VlcCBvbGQgZm9ybSBlbGVtZW50cyBhcm91bmRcbiAgICB0aGlzLmZvcm1zRm9yUmVjb3ZlcnkgPSB7fTtcbiAgICB0aGlzLmpvaW5DYWxsYmFjaygoKSA9PiB7XG4gICAgICB0aGlzLnBlbmRpbmdKb2luT3BzLmZvckVhY2goKFt2aWV3LCBvcF0pID0+IHtcbiAgICAgICAgaWYgKCF2aWV3LmlzRGVzdHJveWVkKCkpIHtcbiAgICAgICAgICBvcCgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMucGVuZGluZ0pvaW5PcHMgPSBbXTtcbiAgICB9KTtcbiAgfVxuXG4gIHVwZGF0ZShkaWZmLCBldmVudHMpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLmlzSm9pblBlbmRpbmcoKSB8fFxuICAgICAgKHRoaXMubGl2ZVNvY2tldC5oYXNQZW5kaW5nTGluaygpICYmIHRoaXMucm9vdC5pc01haW4oKSlcbiAgICApIHtcbiAgICAgIHJldHVybiB0aGlzLnBlbmRpbmdEaWZmcy5wdXNoKHsgZGlmZiwgZXZlbnRzIH0pO1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyZWQubWVyZ2VEaWZmKGRpZmYpO1xuICAgIGxldCBwaHhDaGlsZHJlbkFkZGVkID0gZmFsc2U7XG5cbiAgICAvLyBXaGVuIHRoZSBkaWZmIG9ubHkgY29udGFpbnMgY29tcG9uZW50IGRpZmZzLCB0aGVuIHdhbGsgY29tcG9uZW50c1xuICAgIC8vIGFuZCBwYXRjaCBvbmx5IHRoZSBwYXJlbnQgY29tcG9uZW50IGNvbnRhaW5lcnMgZm91bmQgaW4gdGhlIGRpZmYuXG4gICAgLy8gT3RoZXJ3aXNlLCBwYXRjaCBlbnRpcmUgTFYgY29udGFpbmVyLlxuICAgIGlmICh0aGlzLnJlbmRlcmVkLmlzQ29tcG9uZW50T25seURpZmYoZGlmZikpIHtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC50aW1lKFwiY29tcG9uZW50IHBhdGNoIGNvbXBsZXRlXCIsICgpID0+IHtcbiAgICAgICAgY29uc3QgcGFyZW50Q2lkcyA9IERPTS5maW5kRXhpc3RpbmdQYXJlbnRDSURzKFxuICAgICAgICAgIHRoaXMuaWQsXG4gICAgICAgICAgdGhpcy5yZW5kZXJlZC5jb21wb25lbnRDSURzKGRpZmYpLFxuICAgICAgICApO1xuICAgICAgICBwYXJlbnRDaWRzLmZvckVhY2goKHBhcmVudENJRCkgPT4ge1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHRoaXMuY29tcG9uZW50UGF0Y2goXG4gICAgICAgICAgICAgIHRoaXMucmVuZGVyZWQuZ2V0Q29tcG9uZW50KGRpZmYsIHBhcmVudENJRCksXG4gICAgICAgICAgICAgIHBhcmVudENJRCxcbiAgICAgICAgICAgIClcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHBoeENoaWxkcmVuQWRkZWQgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKCFpc0VtcHR5KGRpZmYpKSB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQudGltZShcImZ1bGwgcGF0Y2ggY29tcGxldGVcIiwgKCkgPT4ge1xuICAgICAgICBjb25zdCBbaHRtbCwgc3RyZWFtc10gPSB0aGlzLnJlbmRlckNvbnRhaW5lcihkaWZmLCBcInVwZGF0ZVwiKTtcbiAgICAgICAgY29uc3QgcGF0Y2ggPSBuZXcgRE9NUGF0Y2godGhpcywgdGhpcy5lbCwgdGhpcy5pZCwgaHRtbCwgc3RyZWFtcywgbnVsbCk7XG4gICAgICAgIHBoeENoaWxkcmVuQWRkZWQgPSB0aGlzLnBlcmZvcm1QYXRjaChwYXRjaCwgdHJ1ZSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLmxpdmVTb2NrZXQuZGlzcGF0Y2hFdmVudHMoZXZlbnRzKTtcbiAgICBpZiAocGh4Q2hpbGRyZW5BZGRlZCkge1xuICAgICAgdGhpcy5qb2luTmV3Q2hpbGRyZW4oKTtcbiAgICB9XG4gIH1cblxuICByZW5kZXJDb250YWluZXIoZGlmZiwga2luZCkge1xuICAgIHJldHVybiB0aGlzLmxpdmVTb2NrZXQudGltZShgdG9TdHJpbmcgZGlmZiAoJHtraW5kfSlgLCAoKSA9PiB7XG4gICAgICBjb25zdCB0YWcgPSB0aGlzLmVsLnRhZ05hbWU7XG4gICAgICAvLyBEb24ndCBza2lwIGFueSBjb21wb25lbnQgaW4gdGhlIGRpZmYgbm9yIGFueSBtYXJrZWQgYXMgcHJ1bmVkXG4gICAgICAvLyAoYXMgdGhleSBtYXkgaGF2ZSBiZWVuIGFkZGVkIGJhY2spXG4gICAgICBjb25zdCBjaWRzID0gZGlmZiA/IHRoaXMucmVuZGVyZWQuY29tcG9uZW50Q0lEcyhkaWZmKSA6IG51bGw7XG4gICAgICBjb25zdCB7IGJ1ZmZlcjogaHRtbCwgc3RyZWFtcyB9ID0gdGhpcy5yZW5kZXJlZC50b1N0cmluZyhjaWRzKTtcbiAgICAgIHJldHVybiBbYDwke3RhZ30+JHtodG1sfTwvJHt0YWd9PmAsIHN0cmVhbXNdO1xuICAgIH0pO1xuICB9XG5cbiAgY29tcG9uZW50UGF0Y2goZGlmZiwgY2lkKSB7XG4gICAgaWYgKGlzRW1wdHkoZGlmZikpIHJldHVybiBmYWxzZTtcbiAgICBjb25zdCB7IGJ1ZmZlcjogaHRtbCwgc3RyZWFtcyB9ID0gdGhpcy5yZW5kZXJlZC5jb21wb25lbnRUb1N0cmluZyhjaWQpO1xuICAgIGNvbnN0IHBhdGNoID0gbmV3IERPTVBhdGNoKHRoaXMsIHRoaXMuZWwsIHRoaXMuaWQsIGh0bWwsIHN0cmVhbXMsIGNpZCk7XG4gICAgY29uc3QgY2hpbGRyZW5BZGRlZCA9IHRoaXMucGVyZm9ybVBhdGNoKHBhdGNoLCB0cnVlKTtcbiAgICByZXR1cm4gY2hpbGRyZW5BZGRlZDtcbiAgfVxuXG4gIGdldEhvb2soZWwpIHtcbiAgICByZXR1cm4gdGhpcy52aWV3SG9va3NbVmlld0hvb2suZWxlbWVudElEKGVsKV07XG4gIH1cblxuICBhZGRIb29rKGVsKSB7XG4gICAgY29uc3QgaG9va0VsSWQgPSBWaWV3SG9vay5lbGVtZW50SUQoZWwpO1xuXG4gICAgLy8gb25seSBldmVyIHRyeSB0byBhZGQgaG9va3MgdG8gZWxlbWVudHMgb3duZWQgYnkgdGhpcyB2aWV3XG4gICAgaWYgKGVsLmdldEF0dHJpYnV0ZSAmJiAhdGhpcy5vd25zRWxlbWVudChlbCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaG9va0VsSWQgJiYgIXRoaXMudmlld0hvb2tzW2hvb2tFbElkXSkge1xuICAgICAgLy8gaG9vayBjcmVhdGVkLCBidXQgbm90IGF0dGFjaGVkIChjcmVhdGVIb29rIGZvciB3ZWIgY29tcG9uZW50KVxuICAgICAgY29uc3QgaG9vayA9XG4gICAgICAgIERPTS5nZXRDdXN0b21FbEhvb2soZWwpIHx8XG4gICAgICAgIGxvZ0Vycm9yKGBubyBob29rIGZvdW5kIGZvciBjdXN0b20gZWxlbWVudDogJHtlbC5pZH1gKTtcbiAgICAgIHRoaXMudmlld0hvb2tzW2hvb2tFbElkXSA9IGhvb2s7XG4gICAgICBob29rLl9fYXR0YWNoVmlldyh0aGlzKTtcbiAgICAgIHJldHVybiBob29rO1xuICAgIH0gZWxzZSBpZiAoaG9va0VsSWQgfHwgIWVsLmdldEF0dHJpYnV0ZSkge1xuICAgICAgLy8gbm8gaG9vayBmb3VuZFxuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBuZXcgaG9vayBmb3VuZCB3aXRoIHBoeC1ob29rIGF0dHJpYnV0ZVxuICAgICAgY29uc3QgaG9va05hbWUgPVxuICAgICAgICBlbC5nZXRBdHRyaWJ1dGUoYGRhdGEtcGh4LSR7UEhYX0hPT0t9YCkgfHxcbiAgICAgICAgZWwuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfSE9PSykpO1xuXG4gICAgICBpZiAoIWhvb2tOYW1lKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaG9va0RlZmluaXRpb24gPSB0aGlzLmxpdmVTb2NrZXQuZ2V0SG9va0RlZmluaXRpb24oaG9va05hbWUpO1xuXG4gICAgICBpZiAoaG9va0RlZmluaXRpb24pIHtcbiAgICAgICAgaWYgKCFlbC5pZCkge1xuICAgICAgICAgIGxvZ0Vycm9yKFxuICAgICAgICAgICAgYG5vIERPTSBJRCBmb3IgaG9vayBcIiR7aG9va05hbWV9XCIuIEhvb2tzIHJlcXVpcmUgYSB1bmlxdWUgSUQgb24gZWFjaCBlbGVtZW50LmAsXG4gICAgICAgICAgICBlbCxcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBob29rSW5zdGFuY2U7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdHlwZW9mIGhvb2tEZWZpbml0aW9uID09PSBcImZ1bmN0aW9uXCIgJiZcbiAgICAgICAgICAgIGhvb2tEZWZpbml0aW9uLnByb3RvdHlwZSBpbnN0YW5jZW9mIFZpZXdIb29rXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBJdCdzIGEgY2xhc3MgY29uc3RydWN0b3IgKHN1YmNsYXNzIG9mIFZpZXdIb29rKVxuICAgICAgICAgICAgaG9va0luc3RhbmNlID0gbmV3IGhvb2tEZWZpbml0aW9uKHRoaXMsIGVsKTsgLy8gYHRoaXNgIGlzIHRoZSBWaWV3IGluc3RhbmNlXG4gICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBob29rRGVmaW5pdGlvbiA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgaG9va0RlZmluaXRpb24gIT09IG51bGxcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIEl0J3MgYW4gb2JqZWN0IGxpdGVyYWwsIHBhc3MgaXQgdG8gdGhlIFZpZXdIb29rIGNvbnN0cnVjdG9yIGZvciB3cmFwcGluZ1xuICAgICAgICAgICAgaG9va0luc3RhbmNlID0gbmV3IFZpZXdIb29rKHRoaXMsIGVsLCBob29rRGVmaW5pdGlvbik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxvZ0Vycm9yKFxuICAgICAgICAgICAgICBgSW52YWxpZCBob29rIGRlZmluaXRpb24gZm9yIFwiJHtob29rTmFtZX1cIi4gRXhwZWN0ZWQgYSBjbGFzcyBleHRlbmRpbmcgVmlld0hvb2sgb3IgYW4gb2JqZWN0IGRlZmluaXRpb24uYCxcbiAgICAgICAgICAgICAgZWwsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKTtcbiAgICAgICAgICBsb2dFcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBob29rIFwiJHtob29rTmFtZX1cIjogJHtlcnJvck1lc3NhZ2V9YCwgZWwpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMudmlld0hvb2tzW1ZpZXdIb29rLmVsZW1lbnRJRChob29rSW5zdGFuY2UuZWwpXSA9IGhvb2tJbnN0YW5jZTtcbiAgICAgICAgcmV0dXJuIGhvb2tJbnN0YW5jZTtcbiAgICAgIH0gZWxzZSBpZiAoaG9va05hbWUgIT09IG51bGwpIHtcbiAgICAgICAgbG9nRXJyb3IoYHVua25vd24gaG9vayBmb3VuZCBmb3IgXCIke2hvb2tOYW1lfVwiYCwgZWwpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGRlc3Ryb3lIb29rKGhvb2spIHtcbiAgICAvLyBfX2Rlc3Ryb3llZCBjbGVhcnMgdGhlIGVsZW1lbnRJRCBmcm9tIHRoZSBob29rLCB0aGVyZWZvcmVcbiAgICAvLyB3ZSBuZWVkIHRvIGdldCBpdCBiZWZvcmUgY2FsbGluZyBfX2Rlc3Ryb3llZFxuICAgIGNvbnN0IGhvb2tJZCA9IFZpZXdIb29rLmVsZW1lbnRJRChob29rLmVsKTtcbiAgICBob29rLl9fZGVzdHJveWVkKCk7XG4gICAgaG9vay5fX2NsZWFudXBfXygpO1xuICAgIGRlbGV0ZSB0aGlzLnZpZXdIb29rc1tob29rSWRdO1xuICB9XG5cbiAgYXBwbHlQZW5kaW5nVXBkYXRlcygpIHtcbiAgICAvLyBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyB3aGVyZSB3ZSBtaWdodCBzdGlsbCBiZSBwZW5kaW5nIGEgbmV3XG4gICAgLy8gbmF2aWdhdGlvbiBhZnRlciBhcHBseWluZyB0aGUgY3VycmVudCBvbmU7XG4gICAgLy8gaWYgd2UgY2FsbCB1cGRhdGUgYW5kIGEgcGVuZGluZ0RpZmYgaXMgbm90IGFwcGxpZWQsIGl0IHdvdWxkXG4gICAgLy8gYmUgc2lsZW50bHkgZHJvcHBlZCBvdGhlcndpc2UsIGFzIHVwZGF0ZSB3b3VsZCBwdXNoIGl0IGJhY2sgdG9cbiAgICAvLyBwZW5kaW5nRGlmZnMsIGJ1dCB3ZSBjbGVhciBpdCBpbW1lZGlhdGVseSBhZnRlclxuICAgIGlmICh0aGlzLmxpdmVTb2NrZXQuaGFzUGVuZGluZ0xpbmsoKSAmJiB0aGlzLnJvb3QuaXNNYWluKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5wZW5kaW5nRGlmZnMuZm9yRWFjaCgoeyBkaWZmLCBldmVudHMgfSkgPT4gdGhpcy51cGRhdGUoZGlmZiwgZXZlbnRzKSk7XG4gICAgdGhpcy5wZW5kaW5nRGlmZnMgPSBbXTtcbiAgICB0aGlzLmVhY2hDaGlsZCgoY2hpbGQpID0+IGNoaWxkLmFwcGx5UGVuZGluZ1VwZGF0ZXMoKSk7XG4gIH1cblxuICBlYWNoQ2hpbGQoY2FsbGJhY2spIHtcbiAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXMucm9vdC5jaGlsZHJlblt0aGlzLmlkXSB8fCB7fTtcbiAgICBmb3IgKGNvbnN0IGlkIGluIGNoaWxkcmVuKSB7XG4gICAgICBjYWxsYmFjayh0aGlzLmdldENoaWxkQnlJZChpZCkpO1xuICAgIH1cbiAgfVxuXG4gIG9uQ2hhbm5lbChldmVudCwgY2IpIHtcbiAgICB0aGlzLmxpdmVTb2NrZXQub25DaGFubmVsKHRoaXMuY2hhbm5lbCwgZXZlbnQsIChyZXNwKSA9PiB7XG4gICAgICBpZiAodGhpcy5pc0pvaW5QZW5kaW5nKCkpIHtcbiAgICAgICAgdGhpcy5yb290LnBlbmRpbmdKb2luT3BzLnB1c2goW3RoaXMsICgpID0+IGNiKHJlc3ApXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiBjYihyZXNwKSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBiaW5kQ2hhbm5lbCgpIHtcbiAgICAvLyBUaGUgZGlmZiBldmVudCBzaG91bGQgYmUgaGFuZGxlZCBieSB0aGUgcmVndWxhciB1cGRhdGUgb3BlcmF0aW9ucy5cbiAgICAvLyBBbGwgb3RoZXIgb3BlcmF0aW9ucyBhcmUgcXVldWVkIHRvIGJlIGFwcGxpZWQgb25seSBhZnRlciBqb2luLlxuICAgIHRoaXMubGl2ZVNvY2tldC5vbkNoYW5uZWwodGhpcy5jaGFubmVsLCBcImRpZmZcIiwgKHJhd0RpZmYpID0+IHtcbiAgICAgIHRoaXMubGl2ZVNvY2tldC5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHtcbiAgICAgICAgdGhpcy5hcHBseURpZmYoXCJ1cGRhdGVcIiwgcmF3RGlmZiwgKHsgZGlmZiwgZXZlbnRzIH0pID0+XG4gICAgICAgICAgdGhpcy51cGRhdGUoZGlmZiwgZXZlbnRzKSxcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIHRoaXMub25DaGFubmVsKFwicmVkaXJlY3RcIiwgKHsgdG8sIGZsYXNoIH0pID0+XG4gICAgICB0aGlzLm9uUmVkaXJlY3QoeyB0bywgZmxhc2ggfSksXG4gICAgKTtcbiAgICB0aGlzLm9uQ2hhbm5lbChcImxpdmVfcGF0Y2hcIiwgKHJlZGlyKSA9PiB0aGlzLm9uTGl2ZVBhdGNoKHJlZGlyKSk7XG4gICAgdGhpcy5vbkNoYW5uZWwoXCJsaXZlX3JlZGlyZWN0XCIsIChyZWRpcikgPT4gdGhpcy5vbkxpdmVSZWRpcmVjdChyZWRpcikpO1xuICAgIHRoaXMuY2hhbm5lbC5vbkVycm9yKChyZWFzb24pID0+IHRoaXMub25FcnJvcihyZWFzb24pKTtcbiAgICB0aGlzLmNoYW5uZWwub25DbG9zZSgocmVhc29uKSA9PiB0aGlzLm9uQ2xvc2UocmVhc29uKSk7XG4gIH1cblxuICBkZXN0cm95QWxsQ2hpbGRyZW4oKSB7XG4gICAgdGhpcy5lYWNoQ2hpbGQoKGNoaWxkKSA9PiBjaGlsZC5kZXN0cm95KCkpO1xuICB9XG5cbiAgb25MaXZlUmVkaXJlY3QocmVkaXIpIHtcbiAgICBjb25zdCB7IHRvLCBraW5kLCBmbGFzaCB9ID0gcmVkaXI7XG4gICAgY29uc3QgdXJsID0gdGhpcy5leHBhbmRVUkwodG8pO1xuICAgIGNvbnN0IGUgPSBuZXcgQ3VzdG9tRXZlbnQoXCJwaHg6c2VydmVyLW5hdmlnYXRlXCIsIHtcbiAgICAgIGRldGFpbDogeyB0bywga2luZCwgZmxhc2ggfSxcbiAgICB9KTtcbiAgICB0aGlzLmxpdmVTb2NrZXQuaGlzdG9yeVJlZGlyZWN0KGUsIHVybCwga2luZCwgZmxhc2gpO1xuICB9XG5cbiAgb25MaXZlUGF0Y2gocmVkaXIpIHtcbiAgICBjb25zdCB7IHRvLCBraW5kIH0gPSByZWRpcjtcbiAgICB0aGlzLmhyZWYgPSB0aGlzLmV4cGFuZFVSTCh0byk7XG4gICAgdGhpcy5saXZlU29ja2V0Lmhpc3RvcnlQYXRjaCh0bywga2luZCk7XG4gIH1cblxuICBleHBhbmRVUkwodG8pIHtcbiAgICByZXR1cm4gdG8uc3RhcnRzV2l0aChcIi9cIilcbiAgICAgID8gYCR7d2luZG93LmxvY2F0aW9uLnByb3RvY29sfS8vJHt3aW5kb3cubG9jYXRpb24uaG9zdH0ke3RvfWBcbiAgICAgIDogdG87XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHt7dG86IHN0cmluZywgZmxhc2g/OiBzdHJpbmcsIHJlbG9hZFRva2VuPzogc3RyaW5nfX0gcmVkaXJlY3RcbiAgICovXG4gIG9uUmVkaXJlY3QoeyB0bywgZmxhc2gsIHJlbG9hZFRva2VuIH0pIHtcbiAgICB0aGlzLmxpdmVTb2NrZXQucmVkaXJlY3QodG8sIGZsYXNoLCByZWxvYWRUb2tlbik7XG4gIH1cblxuICBpc0Rlc3Ryb3llZCgpIHtcbiAgICByZXR1cm4gdGhpcy5kZXN0cm95ZWQ7XG4gIH1cblxuICBqb2luRGVhZCgpIHtcbiAgICB0aGlzLmlzRGVhZCA9IHRydWU7XG4gIH1cblxuICBqb2luUHVzaCgpIHtcbiAgICB0aGlzLmpvaW5QdXNoID0gdGhpcy5qb2luUHVzaCB8fCB0aGlzLmNoYW5uZWwuam9pbigpO1xuICAgIHJldHVybiB0aGlzLmpvaW5QdXNoO1xuICB9XG5cbiAgam9pbihjYWxsYmFjaykge1xuICAgIHRoaXMuc2hvd0xvYWRlcih0aGlzLmxpdmVTb2NrZXQubG9hZGVyVGltZW91dCk7XG4gICAgdGhpcy5iaW5kQ2hhbm5lbCgpO1xuICAgIGlmICh0aGlzLmlzTWFpbigpKSB7XG4gICAgICB0aGlzLnN0b3BDYWxsYmFjayA9IHRoaXMubGl2ZVNvY2tldC53aXRoUGFnZUxvYWRpbmcoe1xuICAgICAgICB0bzogdGhpcy5ocmVmLFxuICAgICAgICBraW5kOiBcImluaXRpYWxcIixcbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLmpvaW5DYWxsYmFjayA9IChvbkRvbmUpID0+IHtcbiAgICAgIG9uRG9uZSA9IG9uRG9uZSB8fCBmdW5jdGlvbiAoKSB7fTtcbiAgICAgIGNhbGxiYWNrID8gY2FsbGJhY2sodGhpcy5qb2luQ291bnQsIG9uRG9uZSkgOiBvbkRvbmUoKTtcbiAgICB9O1xuXG4gICAgdGhpcy53cmFwUHVzaCgoKSA9PiB0aGlzLmNoYW5uZWwuam9pbigpLCB7XG4gICAgICBvazogKHJlc3ApID0+IHRoaXMubGl2ZVNvY2tldC5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHRoaXMub25Kb2luKHJlc3ApKSxcbiAgICAgIGVycm9yOiAoZXJyb3IpID0+IHRoaXMub25Kb2luRXJyb3IoZXJyb3IpLFxuICAgICAgdGltZW91dDogKCkgPT4gdGhpcy5vbkpvaW5FcnJvcih7IHJlYXNvbjogXCJ0aW1lb3V0XCIgfSksXG4gICAgfSk7XG4gIH1cblxuICBvbkpvaW5FcnJvcihyZXNwKSB7XG4gICAgaWYgKHJlc3AucmVhc29uID09PSBcInJlbG9hZFwiKSB7XG4gICAgICB0aGlzLmxvZyhcImVycm9yXCIsICgpID0+IFtcbiAgICAgICAgYGZhaWxlZCBtb3VudCB3aXRoICR7cmVzcC5zdGF0dXN9LiBGYWxsaW5nIGJhY2sgdG8gcGFnZSByZWxvYWRgLFxuICAgICAgICByZXNwLFxuICAgICAgXSk7XG4gICAgICB0aGlzLm9uUmVkaXJlY3QoeyB0bzogdGhpcy5yb290LmhyZWYsIHJlbG9hZFRva2VuOiByZXNwLnRva2VuIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSBpZiAocmVzcC5yZWFzb24gPT09IFwidW5hdXRob3JpemVkXCIgfHwgcmVzcC5yZWFzb24gPT09IFwic3RhbGVcIikge1xuICAgICAgdGhpcy5sb2coXCJlcnJvclwiLCAoKSA9PiBbXG4gICAgICAgIFwidW5hdXRob3JpemVkIGxpdmVfcmVkaXJlY3QuIEZhbGxpbmcgYmFjayB0byBwYWdlIHJlcXVlc3RcIixcbiAgICAgICAgcmVzcCxcbiAgICAgIF0pO1xuICAgICAgdGhpcy5vblJlZGlyZWN0KHsgdG86IHRoaXMucm9vdC5ocmVmLCBmbGFzaDogdGhpcy5mbGFzaCB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHJlc3AucmVkaXJlY3QgfHwgcmVzcC5saXZlX3JlZGlyZWN0KSB7XG4gICAgICB0aGlzLmpvaW5QZW5kaW5nID0gZmFsc2U7XG4gICAgICB0aGlzLmNoYW5uZWwubGVhdmUoKTtcbiAgICB9XG4gICAgaWYgKHJlc3AucmVkaXJlY3QpIHtcbiAgICAgIHJldHVybiB0aGlzLm9uUmVkaXJlY3QocmVzcC5yZWRpcmVjdCk7XG4gICAgfVxuICAgIGlmIChyZXNwLmxpdmVfcmVkaXJlY3QpIHtcbiAgICAgIHJldHVybiB0aGlzLm9uTGl2ZVJlZGlyZWN0KHJlc3AubGl2ZV9yZWRpcmVjdCk7XG4gICAgfVxuICAgIHRoaXMubG9nKFwiZXJyb3JcIiwgKCkgPT4gW1widW5hYmxlIHRvIGpvaW5cIiwgcmVzcF0pO1xuICAgIGlmICh0aGlzLmlzTWFpbigpKSB7XG4gICAgICB0aGlzLmRpc3BsYXlFcnJvcihbXG4gICAgICAgIFBIWF9MT0FESU5HX0NMQVNTLFxuICAgICAgICBQSFhfRVJST1JfQ0xBU1MsXG4gICAgICAgIFBIWF9TRVJWRVJfRVJST1JfQ0xBU1MsXG4gICAgICBdKTtcbiAgICAgIGlmICh0aGlzLmxpdmVTb2NrZXQuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVsb2FkV2l0aEppdHRlcih0aGlzKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHRoaXMuam9pbkF0dGVtcHRzID49IE1BWF9DSElMRF9KT0lOX0FUVEVNUFRTKSB7XG4gICAgICAgIC8vIHB1dCB0aGUgcm9vdCByZXZpZXcgaW50byBwZXJtYW5lbnQgZXJyb3Igc3RhdGUsIGJ1dCBkb24ndCBkZXN0cm95IGl0IGFzIGl0IGNhbiByZW1haW4gYWN0aXZlXG4gICAgICAgIHRoaXMucm9vdC5kaXNwbGF5RXJyb3IoW1xuICAgICAgICAgIFBIWF9MT0FESU5HX0NMQVNTLFxuICAgICAgICAgIFBIWF9FUlJPUl9DTEFTUyxcbiAgICAgICAgICBQSFhfU0VSVkVSX0VSUk9SX0NMQVNTLFxuICAgICAgICBdKTtcbiAgICAgICAgdGhpcy5sb2coXCJlcnJvclwiLCAoKSA9PiBbXG4gICAgICAgICAgYGdpdmluZyB1cCB0cnlpbmcgdG8gbW91bnQgYWZ0ZXIgJHtNQVhfQ0hJTERfSk9JTl9BVFRFTVBUU30gdHJpZXNgLFxuICAgICAgICAgIHJlc3AsXG4gICAgICAgIF0pO1xuICAgICAgICB0aGlzLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRydWVDaGlsZEVsID0gRE9NLmJ5SWQodGhpcy5lbC5pZCk7XG4gICAgICBpZiAodHJ1ZUNoaWxkRWwpIHtcbiAgICAgICAgRE9NLm1lcmdlQXR0cnModHJ1ZUNoaWxkRWwsIHRoaXMuZWwpO1xuICAgICAgICB0aGlzLmRpc3BsYXlFcnJvcihbXG4gICAgICAgICAgUEhYX0xPQURJTkdfQ0xBU1MsXG4gICAgICAgICAgUEhYX0VSUk9SX0NMQVNTLFxuICAgICAgICAgIFBIWF9TRVJWRVJfRVJST1JfQ0xBU1MsXG4gICAgICAgIF0pO1xuICAgICAgICB0aGlzLmVsID0gdHJ1ZUNoaWxkRWw7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBvbkNsb3NlKHJlYXNvbikge1xuICAgIGlmICh0aGlzLmlzRGVzdHJveWVkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKFxuICAgICAgdGhpcy5pc01haW4oKSAmJlxuICAgICAgdGhpcy5saXZlU29ja2V0Lmhhc1BlbmRpbmdMaW5rKCkgJiZcbiAgICAgIHJlYXNvbiAhPT0gXCJsZWF2ZVwiXG4gICAgKSB7XG4gICAgICByZXR1cm4gdGhpcy5saXZlU29ja2V0LnJlbG9hZFdpdGhKaXR0ZXIodGhpcyk7XG4gICAgfVxuICAgIHRoaXMuZGVzdHJveUFsbENoaWxkcmVuKCk7XG4gICAgdGhpcy5saXZlU29ja2V0LmRyb3BBY3RpdmVFbGVtZW50KHRoaXMpO1xuICAgIGlmICh0aGlzLmxpdmVTb2NrZXQuaXNVbmxvYWRlZCgpKSB7XG4gICAgICB0aGlzLnNob3dMb2FkZXIoQkVGT1JFX1VOTE9BRF9MT0FERVJfVElNRU9VVCk7XG4gICAgfVxuICB9XG5cbiAgb25FcnJvcihyZWFzb24pIHtcbiAgICB0aGlzLm9uQ2xvc2UocmVhc29uKTtcbiAgICBpZiAodGhpcy5saXZlU29ja2V0LmlzQ29ubmVjdGVkKCkpIHtcbiAgICAgIHRoaXMubG9nKFwiZXJyb3JcIiwgKCkgPT4gW1widmlldyBjcmFzaGVkXCIsIHJlYXNvbl0pO1xuICAgIH1cbiAgICBpZiAoIXRoaXMubGl2ZVNvY2tldC5pc1VubG9hZGVkKCkpIHtcbiAgICAgIGlmICh0aGlzLmxpdmVTb2NrZXQuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICB0aGlzLmRpc3BsYXlFcnJvcihbXG4gICAgICAgICAgUEhYX0xPQURJTkdfQ0xBU1MsXG4gICAgICAgICAgUEhYX0VSUk9SX0NMQVNTLFxuICAgICAgICAgIFBIWF9TRVJWRVJfRVJST1JfQ0xBU1MsXG4gICAgICAgIF0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5kaXNwbGF5RXJyb3IoW1xuICAgICAgICAgIFBIWF9MT0FESU5HX0NMQVNTLFxuICAgICAgICAgIFBIWF9FUlJPUl9DTEFTUyxcbiAgICAgICAgICBQSFhfQ0xJRU5UX0VSUk9SX0NMQVNTLFxuICAgICAgICBdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBkaXNwbGF5RXJyb3IoY2xhc3Nlcykge1xuICAgIGlmICh0aGlzLmlzTWFpbigpKSB7XG4gICAgICBET00uZGlzcGF0Y2hFdmVudCh3aW5kb3csIFwicGh4OnBhZ2UtbG9hZGluZy1zdGFydFwiLCB7XG4gICAgICAgIGRldGFpbDogeyB0bzogdGhpcy5ocmVmLCBraW5kOiBcImVycm9yXCIgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLnNob3dMb2FkZXIoKTtcbiAgICB0aGlzLnNldENvbnRhaW5lckNsYXNzZXMoLi4uY2xhc3Nlcyk7XG4gICAgdGhpcy5kZWxheWVkRGlzY29ubmVjdGVkKCk7XG4gIH1cblxuICBkZWxheWVkRGlzY29ubmVjdGVkKCkge1xuICAgIHRoaXMuZGlzY29ubmVjdGVkVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuZXhlY0FsbCh0aGlzLmJpbmRpbmcoXCJkaXNjb25uZWN0ZWRcIikpO1xuICAgIH0sIHRoaXMubGl2ZVNvY2tldC5kaXNjb25uZWN0ZWRUaW1lb3V0KTtcbiAgfVxuXG4gIHdyYXBQdXNoKGNhbGxlclB1c2gsIHJlY2VpdmVzKSB7XG4gICAgY29uc3QgbGF0ZW5jeSA9IHRoaXMubGl2ZVNvY2tldC5nZXRMYXRlbmN5U2ltKCk7XG4gICAgY29uc3Qgd2l0aExhdGVuY3kgPSBsYXRlbmN5XG4gICAgICA/IChjYikgPT4gc2V0VGltZW91dCgoKSA9PiAhdGhpcy5pc0Rlc3Ryb3llZCgpICYmIGNiKCksIGxhdGVuY3kpXG4gICAgICA6IChjYikgPT4gIXRoaXMuaXNEZXN0cm95ZWQoKSAmJiBjYigpO1xuXG4gICAgd2l0aExhdGVuY3koKCkgPT4ge1xuICAgICAgY2FsbGVyUHVzaCgpXG4gICAgICAgIC5yZWNlaXZlKFwib2tcIiwgKHJlc3ApID0+XG4gICAgICAgICAgd2l0aExhdGVuY3koKCkgPT4gcmVjZWl2ZXMub2sgJiYgcmVjZWl2ZXMub2socmVzcCkpLFxuICAgICAgICApXG4gICAgICAgIC5yZWNlaXZlKFwiZXJyb3JcIiwgKHJlYXNvbikgPT5cbiAgICAgICAgICB3aXRoTGF0ZW5jeSgoKSA9PiByZWNlaXZlcy5lcnJvciAmJiByZWNlaXZlcy5lcnJvcihyZWFzb24pKSxcbiAgICAgICAgKVxuICAgICAgICAucmVjZWl2ZShcInRpbWVvdXRcIiwgKCkgPT5cbiAgICAgICAgICB3aXRoTGF0ZW5jeSgoKSA9PiByZWNlaXZlcy50aW1lb3V0ICYmIHJlY2VpdmVzLnRpbWVvdXQoKSksXG4gICAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwdXNoV2l0aFJlcGx5KHJlZkdlbmVyYXRvciwgZXZlbnQsIHBheWxvYWQpIHtcbiAgICBpZiAoIXRoaXMuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIm5vIGNvbm5lY3Rpb25cIikpO1xuICAgIH1cblxuICAgIGNvbnN0IFtyZWYsIFtlbF0sIG9wdHNdID0gcmVmR2VuZXJhdG9yXG4gICAgICA/IHJlZkdlbmVyYXRvcih7IHBheWxvYWQgfSlcbiAgICAgIDogW251bGwsIFtdLCB7fV07XG4gICAgY29uc3Qgb2xkSm9pbkNvdW50ID0gdGhpcy5qb2luQ291bnQ7XG4gICAgbGV0IG9uTG9hZGluZ0RvbmUgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICBpZiAob3B0cy5wYWdlX2xvYWRpbmcpIHtcbiAgICAgIG9uTG9hZGluZ0RvbmUgPSB0aGlzLmxpdmVTb2NrZXQud2l0aFBhZ2VMb2FkaW5nKHtcbiAgICAgICAga2luZDogXCJlbGVtZW50XCIsXG4gICAgICAgIHRhcmdldDogZWwsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHBheWxvYWQuY2lkICE9PSBcIm51bWJlclwiKSB7XG4gICAgICBkZWxldGUgcGF5bG9hZC5jaWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMud3JhcFB1c2goKCkgPT4gdGhpcy5jaGFubmVsLnB1c2goZXZlbnQsIHBheWxvYWQsIFBVU0hfVElNRU9VVCksIHtcbiAgICAgICAgb2s6IChyZXNwKSA9PiB7XG4gICAgICAgICAgaWYgKHJlZiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5sYXN0QWNrUmVmID0gcmVmO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBmaW5pc2ggPSAoaG9va1JlcGx5KSA9PiB7XG4gICAgICAgICAgICBpZiAocmVzcC5yZWRpcmVjdCkge1xuICAgICAgICAgICAgICB0aGlzLm9uUmVkaXJlY3QocmVzcC5yZWRpcmVjdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocmVzcC5saXZlX3BhdGNoKSB7XG4gICAgICAgICAgICAgIHRoaXMub25MaXZlUGF0Y2gocmVzcC5saXZlX3BhdGNoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChyZXNwLmxpdmVfcmVkaXJlY3QpIHtcbiAgICAgICAgICAgICAgdGhpcy5vbkxpdmVSZWRpcmVjdChyZXNwLmxpdmVfcmVkaXJlY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb25Mb2FkaW5nRG9uZSgpO1xuICAgICAgICAgICAgcmVzb2x2ZSh7IHJlc3A6IHJlc3AsIHJlcGx5OiBob29rUmVwbHksIHJlZiB9KTtcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmIChyZXNwLmRpZmYpIHtcbiAgICAgICAgICAgIHRoaXMubGl2ZVNvY2tldC5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHtcbiAgICAgICAgICAgICAgdGhpcy5hcHBseURpZmYoXCJ1cGRhdGVcIiwgcmVzcC5kaWZmLCAoeyBkaWZmLCByZXBseSwgZXZlbnRzIH0pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVmICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGF5bG9hZC5ldmVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlKGRpZmYsIGV2ZW50cyk7XG4gICAgICAgICAgICAgICAgZmluaXNoKHJlcGx5KTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHJlZiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGF5bG9hZC5ldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmaW5pc2gobnVsbCk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogKHJlYXNvbikgPT4gcmVqZWN0KG5ldyBFcnJvcihgZmFpbGVkIHdpdGggcmVhc29uOiAke3JlYXNvbn1gKSksXG4gICAgICAgIHRpbWVvdXQ6ICgpID0+IHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwidGltZW91dFwiKSk7XG4gICAgICAgICAgaWYgKHRoaXMuam9pbkNvdW50ID09PSBvbGRKb2luQ291bnQpIHtcbiAgICAgICAgICAgIHRoaXMubGl2ZVNvY2tldC5yZWxvYWRXaXRoSml0dGVyKHRoaXMsICgpID0+IHtcbiAgICAgICAgICAgICAgdGhpcy5sb2coXCJ0aW1lb3V0XCIsICgpID0+IFtcbiAgICAgICAgICAgICAgICBcInJlY2VpdmVkIHRpbWVvdXQgd2hpbGUgY29tbXVuaWNhdGluZyB3aXRoIHNlcnZlci4gRmFsbGluZyBiYWNrIHRvIGhhcmQgcmVmcmVzaCBmb3IgcmVjb3ZlcnlcIixcbiAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHVuZG9SZWZzKHJlZiwgcGh4RXZlbnQsIG9ubHlFbHMpIHtcbiAgICBpZiAoIXRoaXMuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH0gLy8gZXhpdCBpZiBleHRlcm5hbCBmb3JtIHRyaWdnZXJlZFxuICAgIGNvbnN0IHNlbGVjdG9yID0gYFske1BIWF9SRUZfU1JDfT1cIiR7dGhpcy5yZWZTcmMoKX1cIl1gO1xuXG4gICAgaWYgKG9ubHlFbHMpIHtcbiAgICAgIG9ubHlFbHMgPSBuZXcgU2V0KG9ubHlFbHMpO1xuICAgICAgRE9NLmFsbChkb2N1bWVudCwgc2VsZWN0b3IsIChwYXJlbnQpID0+IHtcbiAgICAgICAgaWYgKG9ubHlFbHMgJiYgIW9ubHlFbHMuaGFzKHBhcmVudCkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gdW5kbyBhbnkgY2hpbGQgcmVmcyB3aXRoaW4gcGFyZW50IGZpcnN0XG4gICAgICAgIERPTS5hbGwocGFyZW50LCBzZWxlY3RvciwgKGNoaWxkKSA9PlxuICAgICAgICAgIHRoaXMudW5kb0VsUmVmKGNoaWxkLCByZWYsIHBoeEV2ZW50KSxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy51bmRvRWxSZWYocGFyZW50LCByZWYsIHBoeEV2ZW50KTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBET00uYWxsKGRvY3VtZW50LCBzZWxlY3RvciwgKGVsKSA9PiB0aGlzLnVuZG9FbFJlZihlbCwgcmVmLCBwaHhFdmVudCkpO1xuICAgIH1cbiAgfVxuXG4gIHVuZG9FbFJlZihlbCwgcmVmLCBwaHhFdmVudCkge1xuICAgIGNvbnN0IGVsUmVmID0gbmV3IEVsZW1lbnRSZWYoZWwpO1xuXG4gICAgZWxSZWYubWF5YmVVbmRvKHJlZiwgcGh4RXZlbnQsIChjbG9uZWRUcmVlKSA9PiB7XG4gICAgICAvLyB3ZSBuZWVkIHRvIHBlcmZvcm0gYSBmdWxsIHBhdGNoIG9uIHVubG9ja2VkIGVsZW1lbnRzXG4gICAgICAvLyB0byBwZXJmb3JtIGFsbCB0aGUgbmVjZXNzYXJ5IGxvZ2ljIChsaWtlIGNhbGxpbmcgdXBkYXRlZCBmb3IgaG9va3MsIGV0Yy4pXG4gICAgICBjb25zdCBwYXRjaCA9IG5ldyBET01QYXRjaCh0aGlzLCBlbCwgdGhpcy5pZCwgY2xvbmVkVHJlZSwgW10sIG51bGwsIHtcbiAgICAgICAgdW5kb1JlZjogcmVmLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwaHhDaGlsZHJlbkFkZGVkID0gdGhpcy5wZXJmb3JtUGF0Y2gocGF0Y2gsIHRydWUpO1xuICAgICAgRE9NLmFsbChlbCwgYFske1BIWF9SRUZfU1JDfT1cIiR7dGhpcy5yZWZTcmMoKX1cIl1gLCAoY2hpbGQpID0+XG4gICAgICAgIHRoaXMudW5kb0VsUmVmKGNoaWxkLCByZWYsIHBoeEV2ZW50KSxcbiAgICAgICk7XG4gICAgICBpZiAocGh4Q2hpbGRyZW5BZGRlZCkge1xuICAgICAgICB0aGlzLmpvaW5OZXdDaGlsZHJlbigpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcmVmU3JjKCkge1xuICAgIHJldHVybiB0aGlzLmVsLmlkO1xuICB9XG5cbiAgcHV0UmVmKGVsZW1lbnRzLCBwaHhFdmVudCwgZXZlbnRUeXBlLCBvcHRzID0ge30pIHtcbiAgICBjb25zdCBuZXdSZWYgPSB0aGlzLnJlZisrO1xuICAgIGNvbnN0IGRpc2FibGVXaXRoID0gdGhpcy5iaW5kaW5nKFBIWF9ESVNBQkxFX1dJVEgpO1xuICAgIGlmIChvcHRzLmxvYWRpbmcpIHtcbiAgICAgIGNvbnN0IGxvYWRpbmdFbHMgPSBET00uYWxsKGRvY3VtZW50LCBvcHRzLmxvYWRpbmcpLm1hcCgoZWwpID0+IHtcbiAgICAgICAgcmV0dXJuIHsgZWwsIGxvY2s6IHRydWUsIGxvYWRpbmc6IHRydWUgfTtcbiAgICAgIH0pO1xuICAgICAgZWxlbWVudHMgPSBlbGVtZW50cy5jb25jYXQobG9hZGluZ0Vscyk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCB7IGVsLCBsb2NrLCBsb2FkaW5nIH0gb2YgZWxlbWVudHMpIHtcbiAgICAgIGlmICghbG9jayAmJiAhbG9hZGluZykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJwdXRSZWYgcmVxdWlyZXMgbG9jayBvciBsb2FkaW5nXCIpO1xuICAgICAgfVxuICAgICAgZWwuc2V0QXR0cmlidXRlKFBIWF9SRUZfU1JDLCB0aGlzLnJlZlNyYygpKTtcbiAgICAgIGlmIChsb2FkaW5nKSB7XG4gICAgICAgIGVsLnNldEF0dHJpYnV0ZShQSFhfUkVGX0xPQURJTkcsIG5ld1JlZik7XG4gICAgICB9XG4gICAgICBpZiAobG9jaykge1xuICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoUEhYX1JFRl9MT0NLLCBuZXdSZWYpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgICFsb2FkaW5nIHx8XG4gICAgICAgIChvcHRzLnN1Ym1pdHRlciAmJiAhKGVsID09PSBvcHRzLnN1Ym1pdHRlciB8fCBlbCA9PT0gb3B0cy5mb3JtKSlcbiAgICAgICkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbG9ja0NvbXBsZXRlUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoYHBoeDp1bmRvLWxvY2s6JHtuZXdSZWZ9YCwgKCkgPT4gcmVzb2x2ZShkZXRhaWwpLCB7XG4gICAgICAgICAgb25jZTogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbG9hZGluZ0NvbXBsZXRlUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgYHBoeDp1bmRvLWxvYWRpbmc6JHtuZXdSZWZ9YCxcbiAgICAgICAgICAoKSA9PiByZXNvbHZlKGRldGFpbCksXG4gICAgICAgICAgeyBvbmNlOiB0cnVlIH0sXG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgZWwuY2xhc3NMaXN0LmFkZChgcGh4LSR7ZXZlbnRUeXBlfS1sb2FkaW5nYCk7XG4gICAgICBjb25zdCBkaXNhYmxlVGV4dCA9IGVsLmdldEF0dHJpYnV0ZShkaXNhYmxlV2l0aCk7XG4gICAgICBpZiAoZGlzYWJsZVRleHQgIT09IG51bGwpIHtcbiAgICAgICAgaWYgKCFlbC5nZXRBdHRyaWJ1dGUoUEhYX0RJU0FCTEVfV0lUSF9SRVNUT1JFKSkge1xuICAgICAgICAgIGVsLnNldEF0dHJpYnV0ZShQSFhfRElTQUJMRV9XSVRIX1JFU1RPUkUsIGVsLmlubmVyVGV4dCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRpc2FibGVUZXh0ICE9PSBcIlwiKSB7XG4gICAgICAgICAgZWwuaW5uZXJUZXh0ID0gZGlzYWJsZVRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUEhYX0RJU0FCTEVEIGNvdWxkIGhhdmUgYWxyZWFkeSBiZWVuIHNldCBpbiBkaXNhYmxlRm9ybVxuICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoXG4gICAgICAgICAgUEhYX0RJU0FCTEVELFxuICAgICAgICAgIGVsLmdldEF0dHJpYnV0ZShQSFhfRElTQUJMRUQpIHx8IGVsLmRpc2FibGVkLFxuICAgICAgICApO1xuICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoXCJkaXNhYmxlZFwiLCBcIlwiKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGV0YWlsID0ge1xuICAgICAgICBldmVudDogcGh4RXZlbnQsXG4gICAgICAgIGV2ZW50VHlwZTogZXZlbnRUeXBlLFxuICAgICAgICByZWY6IG5ld1JlZixcbiAgICAgICAgaXNMb2FkaW5nOiBsb2FkaW5nLFxuICAgICAgICBpc0xvY2tlZDogbG9jayxcbiAgICAgICAgbG9ja0VsZW1lbnRzOiBlbGVtZW50cy5maWx0ZXIoKHsgbG9jayB9KSA9PiBsb2NrKS5tYXAoKHsgZWwgfSkgPT4gZWwpLFxuICAgICAgICBsb2FkaW5nRWxlbWVudHM6IGVsZW1lbnRzXG4gICAgICAgICAgLmZpbHRlcigoeyBsb2FkaW5nIH0pID0+IGxvYWRpbmcpXG4gICAgICAgICAgLm1hcCgoeyBlbCB9KSA9PiBlbCksXG4gICAgICAgIHVubG9jazogKGVscykgPT4ge1xuICAgICAgICAgIGVscyA9IEFycmF5LmlzQXJyYXkoZWxzKSA/IGVscyA6IFtlbHNdO1xuICAgICAgICAgIHRoaXMudW5kb1JlZnMobmV3UmVmLCBwaHhFdmVudCwgZWxzKTtcbiAgICAgICAgfSxcbiAgICAgICAgbG9ja0NvbXBsZXRlOiBsb2NrQ29tcGxldGVQcm9taXNlLFxuICAgICAgICBsb2FkaW5nQ29tcGxldGU6IGxvYWRpbmdDb21wbGV0ZVByb21pc2UsXG4gICAgICAgIGxvY2s6IChsb2NrRWwpID0+IHtcbiAgICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzQWNrZWQobmV3UmVmKSkge1xuICAgICAgICAgICAgICByZXR1cm4gcmVzb2x2ZShkZXRhaWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbG9ja0VsLnNldEF0dHJpYnV0ZShQSFhfUkVGX0xPQ0ssIG5ld1JlZik7XG4gICAgICAgICAgICBsb2NrRWwuc2V0QXR0cmlidXRlKFBIWF9SRUZfU1JDLCB0aGlzLnJlZlNyYygpKTtcbiAgICAgICAgICAgIGxvY2tFbC5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICBgcGh4OmxvY2stc3RvcDoke25ld1JlZn1gLFxuICAgICAgICAgICAgICAoKSA9PiByZXNvbHZlKGRldGFpbCksXG4gICAgICAgICAgICAgIHsgb25jZTogdHJ1ZSB9LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBpZiAob3B0cy5wYXlsb2FkKSB7XG4gICAgICAgIGRldGFpbFtcInBheWxvYWRcIl0gPSBvcHRzLnBheWxvYWQ7XG4gICAgICB9XG4gICAgICBpZiAob3B0cy50YXJnZXQpIHtcbiAgICAgICAgZGV0YWlsW1widGFyZ2V0XCJdID0gb3B0cy50YXJnZXQ7XG4gICAgICB9XG4gICAgICBpZiAob3B0cy5vcmlnaW5hbEV2ZW50KSB7XG4gICAgICAgIGRldGFpbFtcIm9yaWdpbmFsRXZlbnRcIl0gPSBvcHRzLm9yaWdpbmFsRXZlbnQ7XG4gICAgICB9XG4gICAgICBlbC5kaXNwYXRjaEV2ZW50KFxuICAgICAgICBuZXcgQ3VzdG9tRXZlbnQoXCJwaHg6cHVzaFwiLCB7XG4gICAgICAgICAgZGV0YWlsOiBkZXRhaWwsXG4gICAgICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgICAgICBjYW5jZWxhYmxlOiBmYWxzZSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgICAgaWYgKHBoeEV2ZW50KSB7XG4gICAgICAgIGVsLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgbmV3IEN1c3RvbUV2ZW50KGBwaHg6cHVzaDoke3BoeEV2ZW50fWAsIHtcbiAgICAgICAgICAgIGRldGFpbDogZGV0YWlsLFxuICAgICAgICAgICAgYnViYmxlczogdHJ1ZSxcbiAgICAgICAgICAgIGNhbmNlbGFibGU6IGZhbHNlLFxuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gW25ld1JlZiwgZWxlbWVudHMubWFwKCh7IGVsIH0pID0+IGVsKSwgb3B0c107XG4gIH1cblxuICBpc0Fja2VkKHJlZikge1xuICAgIHJldHVybiB0aGlzLmxhc3RBY2tSZWYgIT09IG51bGwgJiYgdGhpcy5sYXN0QWNrUmVmID49IHJlZjtcbiAgfVxuXG4gIGNvbXBvbmVudElEKGVsKSB7XG4gICAgY29uc3QgY2lkID0gZWwuZ2V0QXR0cmlidXRlICYmIGVsLmdldEF0dHJpYnV0ZShQSFhfQ09NUE9ORU5UKTtcbiAgICByZXR1cm4gY2lkID8gcGFyc2VJbnQoY2lkKSA6IG51bGw7XG4gIH1cblxuICB0YXJnZXRDb21wb25lbnRJRCh0YXJnZXQsIHRhcmdldEN0eCwgb3B0cyA9IHt9KSB7XG4gICAgaWYgKGlzQ2lkKHRhcmdldEN0eCkpIHtcbiAgICAgIHJldHVybiB0YXJnZXRDdHg7XG4gICAgfVxuXG4gICAgY29uc3QgY2lkT3JTZWxlY3RvciA9XG4gICAgICBvcHRzLnRhcmdldCB8fCB0YXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcInRhcmdldFwiKSk7XG4gICAgaWYgKGlzQ2lkKGNpZE9yU2VsZWN0b3IpKSB7XG4gICAgICByZXR1cm4gcGFyc2VJbnQoY2lkT3JTZWxlY3Rvcik7XG4gICAgfSBlbHNlIGlmICh0YXJnZXRDdHggJiYgKGNpZE9yU2VsZWN0b3IgIT09IG51bGwgfHwgb3B0cy50YXJnZXQpKSB7XG4gICAgICByZXR1cm4gdGhpcy5jbG9zZXN0Q29tcG9uZW50SUQodGFyZ2V0Q3R4KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgY2xvc2VzdENvbXBvbmVudElEKHRhcmdldEN0eCkge1xuICAgIGlmIChpc0NpZCh0YXJnZXRDdHgpKSB7XG4gICAgICByZXR1cm4gdGFyZ2V0Q3R4O1xuICAgIH0gZWxzZSBpZiAodGFyZ2V0Q3R4KSB7XG4gICAgICByZXR1cm4gbWF5YmUoXG4gICAgICAgIHRhcmdldEN0eC5jbG9zZXN0KGBbJHtQSFhfQ09NUE9ORU5UfV1gKSxcbiAgICAgICAgKGVsKSA9PiB0aGlzLm93bnNFbGVtZW50KGVsKSAmJiB0aGlzLmNvbXBvbmVudElEKGVsKSxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHB1c2hIb29rRXZlbnQoZWwsIHRhcmdldEN0eCwgZXZlbnQsIHBheWxvYWQpIHtcbiAgICBpZiAoIXRoaXMuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgdGhpcy5sb2coXCJob29rXCIsICgpID0+IFtcbiAgICAgICAgXCJ1bmFibGUgdG8gcHVzaCBob29rIGV2ZW50LiBMaXZlVmlldyBub3QgY29ubmVjdGVkXCIsXG4gICAgICAgIGV2ZW50LFxuICAgICAgICBwYXlsb2FkLFxuICAgICAgXSk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoXG4gICAgICAgIG5ldyBFcnJvcihcInVuYWJsZSB0byBwdXNoIGhvb2sgZXZlbnQuIExpdmVWaWV3IG5vdCBjb25uZWN0ZWRcIiksXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlZkdlbmVyYXRvciA9ICgpID0+XG4gICAgICB0aGlzLnB1dFJlZihbeyBlbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZSB9XSwgZXZlbnQsIFwiaG9va1wiLCB7XG4gICAgICAgIHBheWxvYWQsXG4gICAgICAgIHRhcmdldDogdGFyZ2V0Q3R4LFxuICAgICAgfSk7XG5cbiAgICByZXR1cm4gdGhpcy5wdXNoV2l0aFJlcGx5KHJlZkdlbmVyYXRvciwgXCJldmVudFwiLCB7XG4gICAgICB0eXBlOiBcImhvb2tcIixcbiAgICAgIGV2ZW50OiBldmVudCxcbiAgICAgIHZhbHVlOiBwYXlsb2FkLFxuICAgICAgY2lkOiB0aGlzLmNsb3Nlc3RDb21wb25lbnRJRCh0YXJnZXRDdHgpLFxuICAgIH0pLnRoZW4oKHsgcmVzcDogX3Jlc3AsIHJlcGx5LCByZWYgfSkgPT4gKHsgcmVwbHksIHJlZiB9KSk7XG4gIH1cblxuICBleHRyYWN0TWV0YShlbCwgbWV0YSwgdmFsdWUpIHtcbiAgICBjb25zdCBwcmVmaXggPSB0aGlzLmJpbmRpbmcoXCJ2YWx1ZS1cIik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbC5hdHRyaWJ1dGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoIW1ldGEpIHtcbiAgICAgICAgbWV0YSA9IHt9O1xuICAgICAgfVxuICAgICAgY29uc3QgbmFtZSA9IGVsLmF0dHJpYnV0ZXNbaV0ubmFtZTtcbiAgICAgIGlmIChuYW1lLnN0YXJ0c1dpdGgocHJlZml4KSkge1xuICAgICAgICBtZXRhW25hbWUucmVwbGFjZShwcmVmaXgsIFwiXCIpXSA9IGVsLmdldEF0dHJpYnV0ZShuYW1lKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGVsLnZhbHVlICE9PSB1bmRlZmluZWQgJiYgIShlbCBpbnN0YW5jZW9mIEhUTUxGb3JtRWxlbWVudCkpIHtcbiAgICAgIGlmICghbWV0YSkge1xuICAgICAgICBtZXRhID0ge307XG4gICAgICB9XG4gICAgICBtZXRhLnZhbHVlID0gZWwudmFsdWU7XG5cbiAgICAgIGlmIChcbiAgICAgICAgZWwudGFnTmFtZSA9PT0gXCJJTlBVVFwiICYmXG4gICAgICAgIENIRUNLQUJMRV9JTlBVVFMuaW5kZXhPZihlbC50eXBlKSA+PSAwICYmXG4gICAgICAgICFlbC5jaGVja2VkXG4gICAgICApIHtcbiAgICAgICAgZGVsZXRlIG1ldGEudmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh2YWx1ZSkge1xuICAgICAgaWYgKCFtZXRhKSB7XG4gICAgICAgIG1ldGEgPSB7fTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3Qga2V5IGluIHZhbHVlKSB7XG4gICAgICAgIG1ldGFba2V5XSA9IHZhbHVlW2tleV07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBtZXRhO1xuICB9XG5cbiAgcHVzaEV2ZW50KHR5cGUsIGVsLCB0YXJnZXRDdHgsIHBoeEV2ZW50LCBtZXRhLCBvcHRzID0ge30sIG9uUmVwbHkpIHtcbiAgICB0aGlzLnB1c2hXaXRoUmVwbHkoXG4gICAgICAobWF5YmVQYXlsb2FkKSA9PlxuICAgICAgICB0aGlzLnB1dFJlZihbeyBlbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZSB9XSwgcGh4RXZlbnQsIHR5cGUsIHtcbiAgICAgICAgICAuLi5vcHRzLFxuICAgICAgICAgIHBheWxvYWQ6IG1heWJlUGF5bG9hZD8ucGF5bG9hZCxcbiAgICAgICAgfSksXG4gICAgICBcImV2ZW50XCIsXG4gICAgICB7XG4gICAgICAgIHR5cGU6IHR5cGUsXG4gICAgICAgIGV2ZW50OiBwaHhFdmVudCxcbiAgICAgICAgdmFsdWU6IHRoaXMuZXh0cmFjdE1ldGEoZWwsIG1ldGEsIG9wdHMudmFsdWUpLFxuICAgICAgICBjaWQ6IHRoaXMudGFyZ2V0Q29tcG9uZW50SUQoZWwsIHRhcmdldEN0eCwgb3B0cyksXG4gICAgICB9LFxuICAgIClcbiAgICAgIC50aGVuKCh7IHJlcGx5IH0pID0+IG9uUmVwbHkgJiYgb25SZXBseShyZXBseSkpXG4gICAgICAuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIGV2ZW50XCIsIGVycm9yKSk7XG4gIH1cblxuICBwdXNoRmlsZVByb2dyZXNzKGZpbGVFbCwgZW50cnlSZWYsIHByb2dyZXNzLCBvblJlcGx5ID0gZnVuY3Rpb24gKCkge30pIHtcbiAgICB0aGlzLmxpdmVTb2NrZXQud2l0aGluT3duZXJzKGZpbGVFbC5mb3JtLCAodmlldywgdGFyZ2V0Q3R4KSA9PiB7XG4gICAgICB2aWV3XG4gICAgICAgIC5wdXNoV2l0aFJlcGx5KG51bGwsIFwicHJvZ3Jlc3NcIiwge1xuICAgICAgICAgIGV2ZW50OiBmaWxlRWwuZ2V0QXR0cmlidXRlKHZpZXcuYmluZGluZyhQSFhfUFJPR1JFU1MpKSxcbiAgICAgICAgICByZWY6IGZpbGVFbC5nZXRBdHRyaWJ1dGUoUEhYX1VQTE9BRF9SRUYpLFxuICAgICAgICAgIGVudHJ5X3JlZjogZW50cnlSZWYsXG4gICAgICAgICAgcHJvZ3Jlc3M6IHByb2dyZXNzLFxuICAgICAgICAgIGNpZDogdmlldy50YXJnZXRDb21wb25lbnRJRChmaWxlRWwuZm9ybSwgdGFyZ2V0Q3R4KSxcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oKCkgPT4gb25SZXBseSgpKVxuICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIGZpbGUgcHJvZ3Jlc3NcIiwgZXJyb3IpKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1c2hJbnB1dChpbnB1dEVsLCB0YXJnZXRDdHgsIGZvcmNlQ2lkLCBwaHhFdmVudCwgb3B0cywgY2FsbGJhY2spIHtcbiAgICBpZiAoIWlucHV0RWwuZm9ybSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiZm9ybSBldmVudHMgcmVxdWlyZSB0aGUgaW5wdXQgdG8gYmUgaW5zaWRlIGEgZm9ybVwiKTtcbiAgICB9XG5cbiAgICBsZXQgdXBsb2FkcztcbiAgICBjb25zdCBjaWQgPSBpc0NpZChmb3JjZUNpZClcbiAgICAgID8gZm9yY2VDaWRcbiAgICAgIDogdGhpcy50YXJnZXRDb21wb25lbnRJRChpbnB1dEVsLmZvcm0sIHRhcmdldEN0eCwgb3B0cyk7XG4gICAgY29uc3QgcmVmR2VuZXJhdG9yID0gKG1heWJlUGF5bG9hZCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMucHV0UmVmKFxuICAgICAgICBbXG4gICAgICAgICAgeyBlbDogaW5wdXRFbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZSB9LFxuICAgICAgICAgIHsgZWw6IGlucHV0RWwuZm9ybSwgbG9hZGluZzogdHJ1ZSwgbG9jazogdHJ1ZSB9LFxuICAgICAgICBdLFxuICAgICAgICBwaHhFdmVudCxcbiAgICAgICAgXCJjaGFuZ2VcIixcbiAgICAgICAgeyAuLi5vcHRzLCBwYXlsb2FkOiBtYXliZVBheWxvYWQ/LnBheWxvYWQgfSxcbiAgICAgICk7XG4gICAgfTtcbiAgICBsZXQgZm9ybURhdGE7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMuZXh0cmFjdE1ldGEoaW5wdXRFbC5mb3JtLCB7fSwgb3B0cy52YWx1ZSk7XG4gICAgY29uc3Qgc2VyaWFsaXplT3B0cyA9IHt9O1xuICAgIGlmIChpbnB1dEVsIGluc3RhbmNlb2YgSFRNTEJ1dHRvbkVsZW1lbnQpIHtcbiAgICAgIHNlcmlhbGl6ZU9wdHMuc3VibWl0dGVyID0gaW5wdXRFbDtcbiAgICB9XG4gICAgaWYgKGlucHV0RWwuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcImNoYW5nZVwiKSkpIHtcbiAgICAgIGZvcm1EYXRhID0gc2VyaWFsaXplRm9ybShpbnB1dEVsLmZvcm0sIHNlcmlhbGl6ZU9wdHMsIFtpbnB1dEVsLm5hbWVdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9ybURhdGEgPSBzZXJpYWxpemVGb3JtKGlucHV0RWwuZm9ybSwgc2VyaWFsaXplT3B0cyk7XG4gICAgfVxuICAgIGlmIChcbiAgICAgIERPTS5pc1VwbG9hZElucHV0KGlucHV0RWwpICYmXG4gICAgICBpbnB1dEVsLmZpbGVzICYmXG4gICAgICBpbnB1dEVsLmZpbGVzLmxlbmd0aCA+IDBcbiAgICApIHtcbiAgICAgIExpdmVVcGxvYWRlci50cmFja0ZpbGVzKGlucHV0RWwsIEFycmF5LmZyb20oaW5wdXRFbC5maWxlcykpO1xuICAgIH1cbiAgICB1cGxvYWRzID0gTGl2ZVVwbG9hZGVyLnNlcmlhbGl6ZVVwbG9hZHMoaW5wdXRFbCk7XG5cbiAgICBjb25zdCBldmVudCA9IHtcbiAgICAgIHR5cGU6IFwiZm9ybVwiLFxuICAgICAgZXZlbnQ6IHBoeEV2ZW50LFxuICAgICAgdmFsdWU6IGZvcm1EYXRhLFxuICAgICAgbWV0YToge1xuICAgICAgICAvLyBubyB0YXJnZXQgd2FzIGltcGxpY2l0bHkgc2VudCBhcyBcInVuZGVmaW5lZFwiIGluIExWIDw9IDEuMC41LCB0aGVyZWZvcmVcbiAgICAgICAgLy8gd2UgaGF2ZSB0byBrZWVwIGl0LiBJbiAxLjAuNiB3ZSBzd2l0Y2hlZCBmcm9tIHBhc3NpbmcgbWV0YSBhcyBVUkwgZW5jb2RlZCBkYXRhXG4gICAgICAgIC8vIHRvIHBhc3NpbmcgaXQgZGlyZWN0bHkgaW4gdGhlIGV2ZW50LCBidXQgdGhlIEpTT04gZW5jb2RlIHdvdWxkIGRyb3Aga2V5cyB3aXRoXG4gICAgICAgIC8vIHVuZGVmaW5lZCB2YWx1ZXMuXG4gICAgICAgIF90YXJnZXQ6IG9wdHMuX3RhcmdldCB8fCBcInVuZGVmaW5lZFwiLFxuICAgICAgICAuLi5tZXRhLFxuICAgICAgfSxcbiAgICAgIHVwbG9hZHM6IHVwbG9hZHMsXG4gICAgICBjaWQ6IGNpZCxcbiAgICB9O1xuICAgIHRoaXMucHVzaFdpdGhSZXBseShyZWZHZW5lcmF0b3IsIFwiZXZlbnRcIiwgZXZlbnQpXG4gICAgICAudGhlbigoeyByZXNwIH0pID0+IHtcbiAgICAgICAgaWYgKERPTS5pc1VwbG9hZElucHV0KGlucHV0RWwpICYmIERPTS5pc0F1dG9VcGxvYWQoaW5wdXRFbCkpIHtcbiAgICAgICAgICAvLyB0aGUgZWxlbWVudCBjb3VsZCBiZSBpbnNpZGUgYSBsb2NrZWQgcGFyZW50IGZvciBvdGhlciB1bnJlbGF0ZWQgY2hhbmdlcztcbiAgICAgICAgICAvLyB3ZSBjYW4gb25seSBzdGFydCB1cGxvYWRzIHdoZW4gdGhlIHRyZWUgaXMgdW5sb2NrZWQgYW5kIHRoZVxuICAgICAgICAgIC8vIG5lY2Vzc2FyeSBkYXRhIGF0dHJpYnV0ZXMgYXJlIHNldCBpbiB0aGUgcmVhbCBET01cbiAgICAgICAgICBFbGVtZW50UmVmLm9uVW5sb2NrKGlucHV0RWwsICgpID0+IHtcbiAgICAgICAgICAgIGlmIChMaXZlVXBsb2FkZXIuZmlsZXNBd2FpdGluZ1ByZWZsaWdodChpbnB1dEVsKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIGNvbnN0IFtyZWYsIF9lbHNdID0gcmVmR2VuZXJhdG9yKCk7XG4gICAgICAgICAgICAgIHRoaXMudW5kb1JlZnMocmVmLCBwaHhFdmVudCwgW2lucHV0RWwuZm9ybV0pO1xuICAgICAgICAgICAgICB0aGlzLnVwbG9hZEZpbGVzKFxuICAgICAgICAgICAgICAgIGlucHV0RWwuZm9ybSxcbiAgICAgICAgICAgICAgICBwaHhFdmVudCxcbiAgICAgICAgICAgICAgICB0YXJnZXRDdHgsXG4gICAgICAgICAgICAgICAgcmVmLFxuICAgICAgICAgICAgICAgIGNpZCxcbiAgICAgICAgICAgICAgICAoX3VwbG9hZHMpID0+IHtcbiAgICAgICAgICAgICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKHJlc3ApO1xuICAgICAgICAgICAgICAgICAgdGhpcy50cmlnZ2VyQXdhaXRpbmdTdWJtaXQoaW5wdXRFbC5mb3JtLCBwaHhFdmVudCk7XG4gICAgICAgICAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGh4RXZlbnQpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2socmVzcCk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKGVycm9yKSA9PiBsb2dFcnJvcihcIkZhaWxlZCB0byBwdXNoIGlucHV0IGV2ZW50XCIsIGVycm9yKSk7XG4gIH1cblxuICB0cmlnZ2VyQXdhaXRpbmdTdWJtaXQoZm9ybUVsLCBwaHhFdmVudCkge1xuICAgIGNvbnN0IGF3YWl0aW5nU3VibWl0ID0gdGhpcy5nZXRTY2hlZHVsZWRTdWJtaXQoZm9ybUVsKTtcbiAgICBpZiAoYXdhaXRpbmdTdWJtaXQpIHtcbiAgICAgIGNvbnN0IFtfZWwsIF9yZWYsIF9vcHRzLCBjYWxsYmFja10gPSBhd2FpdGluZ1N1Ym1pdDtcbiAgICAgIHRoaXMuY2FuY2VsU3VibWl0KGZvcm1FbCwgcGh4RXZlbnQpO1xuICAgICAgY2FsbGJhY2soKTtcbiAgICB9XG4gIH1cblxuICBnZXRTY2hlZHVsZWRTdWJtaXQoZm9ybUVsKSB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybVN1Ym1pdHMuZmluZCgoW2VsLCBfcmVmLCBfb3B0cywgX2NhbGxiYWNrXSkgPT5cbiAgICAgIGVsLmlzU2FtZU5vZGUoZm9ybUVsKSxcbiAgICApO1xuICB9XG5cbiAgc2NoZWR1bGVTdWJtaXQoZm9ybUVsLCByZWYsIG9wdHMsIGNhbGxiYWNrKSB7XG4gICAgaWYgKHRoaXMuZ2V0U2NoZWR1bGVkU3VibWl0KGZvcm1FbCkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICB0aGlzLmZvcm1TdWJtaXRzLnB1c2goW2Zvcm1FbCwgcmVmLCBvcHRzLCBjYWxsYmFja10pO1xuICB9XG5cbiAgY2FuY2VsU3VibWl0KGZvcm1FbCwgcGh4RXZlbnQpIHtcbiAgICB0aGlzLmZvcm1TdWJtaXRzID0gdGhpcy5mb3JtU3VibWl0cy5maWx0ZXIoXG4gICAgICAoW2VsLCByZWYsIF9vcHRzLCBfY2FsbGJhY2tdKSA9PiB7XG4gICAgICAgIGlmIChlbC5pc1NhbWVOb2RlKGZvcm1FbCkpIHtcbiAgICAgICAgICB0aGlzLnVuZG9SZWZzKHJlZiwgcGh4RXZlbnQpO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICB9XG5cbiAgZGlzYWJsZUZvcm0oZm9ybUVsLCBwaHhFdmVudCwgb3B0cyA9IHt9KSB7XG4gICAgY29uc3QgZmlsdGVySWdub3JlZCA9IChlbCkgPT4ge1xuICAgICAgY29uc3QgdXNlcklnbm9yZWQgPSBjbG9zZXN0UGh4QmluZGluZyhcbiAgICAgICAgZWwsXG4gICAgICAgIGAke3RoaXMuYmluZGluZyhQSFhfVVBEQVRFKX09aWdub3JlYCxcbiAgICAgICAgZWwuZm9ybSxcbiAgICAgICk7XG4gICAgICByZXR1cm4gIShcbiAgICAgICAgdXNlcklnbm9yZWQgfHwgY2xvc2VzdFBoeEJpbmRpbmcoZWwsIFwiZGF0YS1waHgtdXBkYXRlPWlnbm9yZVwiLCBlbC5mb3JtKVxuICAgICAgKTtcbiAgICB9O1xuICAgIGNvbnN0IGZpbHRlckRpc2FibGVzID0gKGVsKSA9PiB7XG4gICAgICByZXR1cm4gZWwuaGFzQXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfRElTQUJMRV9XSVRIKSk7XG4gICAgfTtcbiAgICBjb25zdCBmaWx0ZXJCdXR0b24gPSAoZWwpID0+IGVsLnRhZ05hbWUgPT0gXCJCVVRUT05cIjtcblxuICAgIGNvbnN0IGZpbHRlcklucHV0ID0gKGVsKSA9PlxuICAgICAgW1wiSU5QVVRcIiwgXCJURVhUQVJFQVwiLCBcIlNFTEVDVFwiXS5pbmNsdWRlcyhlbC50YWdOYW1lKTtcblxuICAgIGNvbnN0IGZvcm1FbGVtZW50cyA9IEFycmF5LmZyb20oZm9ybUVsLmVsZW1lbnRzKTtcbiAgICBjb25zdCBkaXNhYmxlcyA9IGZvcm1FbGVtZW50cy5maWx0ZXIoZmlsdGVyRGlzYWJsZXMpO1xuICAgIGNvbnN0IGJ1dHRvbnMgPSBmb3JtRWxlbWVudHMuZmlsdGVyKGZpbHRlckJ1dHRvbikuZmlsdGVyKGZpbHRlcklnbm9yZWQpO1xuICAgIGNvbnN0IGlucHV0cyA9IGZvcm1FbGVtZW50cy5maWx0ZXIoZmlsdGVySW5wdXQpLmZpbHRlcihmaWx0ZXJJZ25vcmVkKTtcblxuICAgIGJ1dHRvbnMuZm9yRWFjaCgoYnV0dG9uKSA9PiB7XG4gICAgICBidXR0b24uc2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRCwgYnV0dG9uLmRpc2FibGVkKTtcbiAgICAgIGJ1dHRvbi5kaXNhYmxlZCA9IHRydWU7XG4gICAgfSk7XG4gICAgaW5wdXRzLmZvckVhY2goKGlucHV0KSA9PiB7XG4gICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoUEhYX1JFQURPTkxZLCBpbnB1dC5yZWFkT25seSk7XG4gICAgICBpbnB1dC5yZWFkT25seSA9IHRydWU7XG4gICAgICBpZiAoaW5wdXQuZmlsZXMpIHtcbiAgICAgICAgaW5wdXQuc2V0QXR0cmlidXRlKFBIWF9ESVNBQkxFRCwgaW5wdXQuZGlzYWJsZWQpO1xuICAgICAgICBpbnB1dC5kaXNhYmxlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSk7XG4gICAgY29uc3QgZm9ybUVscyA9IGRpc2FibGVzXG4gICAgICAuY29uY2F0KGJ1dHRvbnMpXG4gICAgICAuY29uY2F0KGlucHV0cylcbiAgICAgIC5tYXAoKGVsKSA9PiB7XG4gICAgICAgIHJldHVybiB7IGVsLCBsb2FkaW5nOiB0cnVlLCBsb2NrOiB0cnVlIH07XG4gICAgICB9KTtcblxuICAgIC8vIHdlIHJldmVyc2UgdGhlIG9yZGVyIHNvIGZvcm0gY2hpbGRyZW4gYXJlIGFscmVhZHkgbG9ja2VkIGJ5IHRoZSB0aW1lXG4gICAgLy8gdGhlIGZvcm0gaXMgbG9ja2VkXG4gICAgY29uc3QgZWxzID0gW3sgZWw6IGZvcm1FbCwgbG9hZGluZzogdHJ1ZSwgbG9jazogZmFsc2UgfV1cbiAgICAgIC5jb25jYXQoZm9ybUVscylcbiAgICAgIC5yZXZlcnNlKCk7XG4gICAgcmV0dXJuIHRoaXMucHV0UmVmKGVscywgcGh4RXZlbnQsIFwic3VibWl0XCIsIG9wdHMpO1xuICB9XG5cbiAgcHVzaEZvcm1TdWJtaXQoZm9ybUVsLCB0YXJnZXRDdHgsIHBoeEV2ZW50LCBzdWJtaXR0ZXIsIG9wdHMsIG9uUmVwbHkpIHtcbiAgICBjb25zdCByZWZHZW5lcmF0b3IgPSAobWF5YmVQYXlsb2FkKSA9PlxuICAgICAgdGhpcy5kaXNhYmxlRm9ybShmb3JtRWwsIHBoeEV2ZW50LCB7XG4gICAgICAgIC4uLm9wdHMsXG4gICAgICAgIGZvcm06IGZvcm1FbCxcbiAgICAgICAgcGF5bG9hZDogbWF5YmVQYXlsb2FkPy5wYXlsb2FkLFxuICAgICAgICBzdWJtaXR0ZXI6IHN1Ym1pdHRlcixcbiAgICAgIH0pO1xuICAgIC8vIHN0b3JlIHRoZSBzdWJtaXR0ZXIgaW4gdGhlIGZvcm0gZWxlbWVudCBpbiBvcmRlciB0byB0cmlnZ2VyIGl0XG4gICAgLy8gZm9yIHBoeC10cmlnZ2VyLWFjdGlvblxuICAgIERPTS5wdXRQcml2YXRlKGZvcm1FbCwgXCJzdWJtaXR0ZXJcIiwgc3VibWl0dGVyKTtcbiAgICBjb25zdCBjaWQgPSB0aGlzLnRhcmdldENvbXBvbmVudElEKGZvcm1FbCwgdGFyZ2V0Q3R4KTtcbiAgICBpZiAoTGl2ZVVwbG9hZGVyLmhhc1VwbG9hZHNJblByb2dyZXNzKGZvcm1FbCkpIHtcbiAgICAgIGNvbnN0IFtyZWYsIF9lbHNdID0gcmVmR2VuZXJhdG9yKCk7XG4gICAgICBjb25zdCBwdXNoID0gKCkgPT5cbiAgICAgICAgdGhpcy5wdXNoRm9ybVN1Ym1pdChcbiAgICAgICAgICBmb3JtRWwsXG4gICAgICAgICAgdGFyZ2V0Q3R4LFxuICAgICAgICAgIHBoeEV2ZW50LFxuICAgICAgICAgIHN1Ym1pdHRlcixcbiAgICAgICAgICBvcHRzLFxuICAgICAgICAgIG9uUmVwbHksXG4gICAgICAgICk7XG4gICAgICByZXR1cm4gdGhpcy5zY2hlZHVsZVN1Ym1pdChmb3JtRWwsIHJlZiwgb3B0cywgcHVzaCk7XG4gICAgfSBlbHNlIGlmIChMaXZlVXBsb2FkZXIuaW5wdXRzQXdhaXRpbmdQcmVmbGlnaHQoZm9ybUVsKS5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBbcmVmLCBlbHNdID0gcmVmR2VuZXJhdG9yKCk7XG4gICAgICBjb25zdCBwcm94eVJlZkdlbiA9ICgpID0+IFtyZWYsIGVscywgb3B0c107XG4gICAgICB0aGlzLnVwbG9hZEZpbGVzKGZvcm1FbCwgcGh4RXZlbnQsIHRhcmdldEN0eCwgcmVmLCBjaWQsIChfdXBsb2FkcykgPT4ge1xuICAgICAgICAvLyBpZiB3ZSBzdGlsbCBoYXZpbmcgcGVuZGluZyBwcmVmbGlnaHRzIGl0IG1lYW5zIHdlIGhhdmUgaW52YWxpZCBlbnRyaWVzXG4gICAgICAgIC8vIGFuZCB0aGUgcGh4LXN1Ym1pdCBjYW5ub3QgYmUgY29tcGxldGVkXG4gICAgICAgIGlmIChMaXZlVXBsb2FkZXIuaW5wdXRzQXdhaXRpbmdQcmVmbGlnaHQoZm9ybUVsKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudW5kb1JlZnMocmVmLCBwaHhFdmVudCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbWV0YSA9IHRoaXMuZXh0cmFjdE1ldGEoZm9ybUVsLCB7fSwgb3B0cy52YWx1ZSk7XG4gICAgICAgIGNvbnN0IGZvcm1EYXRhID0gc2VyaWFsaXplRm9ybShmb3JtRWwsIHsgc3VibWl0dGVyIH0pO1xuICAgICAgICB0aGlzLnB1c2hXaXRoUmVwbHkocHJveHlSZWZHZW4sIFwiZXZlbnRcIiwge1xuICAgICAgICAgIHR5cGU6IFwiZm9ybVwiLFxuICAgICAgICAgIGV2ZW50OiBwaHhFdmVudCxcbiAgICAgICAgICB2YWx1ZTogZm9ybURhdGEsXG4gICAgICAgICAgbWV0YTogbWV0YSxcbiAgICAgICAgICBjaWQ6IGNpZCxcbiAgICAgICAgfSlcbiAgICAgICAgICAudGhlbigoeyByZXNwIH0pID0+IG9uUmVwbHkocmVzcCkpXG4gICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBmb3JtIHN1Ym1pdFwiLCBlcnJvcikpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgICEoXG4gICAgICAgIGZvcm1FbC5oYXNBdHRyaWJ1dGUoUEhYX1JFRl9TUkMpICYmXG4gICAgICAgIGZvcm1FbC5jbGFzc0xpc3QuY29udGFpbnMoXCJwaHgtc3VibWl0LWxvYWRpbmdcIilcbiAgICAgIClcbiAgICApIHtcbiAgICAgIGNvbnN0IG1ldGEgPSB0aGlzLmV4dHJhY3RNZXRhKGZvcm1FbCwge30sIG9wdHMudmFsdWUpO1xuICAgICAgY29uc3QgZm9ybURhdGEgPSBzZXJpYWxpemVGb3JtKGZvcm1FbCwgeyBzdWJtaXR0ZXIgfSk7XG4gICAgICB0aGlzLnB1c2hXaXRoUmVwbHkocmVmR2VuZXJhdG9yLCBcImV2ZW50XCIsIHtcbiAgICAgICAgdHlwZTogXCJmb3JtXCIsXG4gICAgICAgIGV2ZW50OiBwaHhFdmVudCxcbiAgICAgICAgdmFsdWU6IGZvcm1EYXRhLFxuICAgICAgICBtZXRhOiBtZXRhLFxuICAgICAgICBjaWQ6IGNpZCxcbiAgICAgIH0pXG4gICAgICAgIC50aGVuKCh7IHJlc3AgfSkgPT4gb25SZXBseShyZXNwKSlcbiAgICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3IoXCJGYWlsZWQgdG8gcHVzaCBmb3JtIHN1Ym1pdFwiLCBlcnJvcikpO1xuICAgIH1cbiAgfVxuXG4gIHVwbG9hZEZpbGVzKGZvcm1FbCwgcGh4RXZlbnQsIHRhcmdldEN0eCwgcmVmLCBjaWQsIG9uQ29tcGxldGUpIHtcbiAgICBjb25zdCBqb2luQ291bnRBdFVwbG9hZCA9IHRoaXMuam9pbkNvdW50O1xuICAgIGNvbnN0IGlucHV0RWxzID0gTGl2ZVVwbG9hZGVyLmFjdGl2ZUZpbGVJbnB1dHMoZm9ybUVsKTtcbiAgICBsZXQgbnVtRmlsZUlucHV0c0luUHJvZ3Jlc3MgPSBpbnB1dEVscy5sZW5ndGg7XG5cbiAgICAvLyBnZXQgZWFjaCBmaWxlIGlucHV0XG4gICAgaW5wdXRFbHMuZm9yRWFjaCgoaW5wdXRFbCkgPT4ge1xuICAgICAgY29uc3QgdXBsb2FkZXIgPSBuZXcgTGl2ZVVwbG9hZGVyKGlucHV0RWwsIHRoaXMsICgpID0+IHtcbiAgICAgICAgbnVtRmlsZUlucHV0c0luUHJvZ3Jlc3MtLTtcbiAgICAgICAgaWYgKG51bUZpbGVJbnB1dHNJblByb2dyZXNzID09PSAwKSB7XG4gICAgICAgICAgb25Db21wbGV0ZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgZW50cmllcyA9IHVwbG9hZGVyXG4gICAgICAgIC5lbnRyaWVzKClcbiAgICAgICAgLm1hcCgoZW50cnkpID0+IGVudHJ5LnRvUHJlZmxpZ2h0UGF5bG9hZCgpKTtcblxuICAgICAgaWYgKGVudHJpZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIG51bUZpbGVJbnB1dHNJblByb2dyZXNzLS07XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICAgICAgcmVmOiBpbnB1dEVsLmdldEF0dHJpYnV0ZShQSFhfVVBMT0FEX1JFRiksXG4gICAgICAgIGVudHJpZXM6IGVudHJpZXMsXG4gICAgICAgIGNpZDogdGhpcy50YXJnZXRDb21wb25lbnRJRChpbnB1dEVsLmZvcm0sIHRhcmdldEN0eCksXG4gICAgICB9O1xuXG4gICAgICB0aGlzLmxvZyhcInVwbG9hZFwiLCAoKSA9PiBbXCJzZW5kaW5nIHByZWZsaWdodCByZXF1ZXN0XCIsIHBheWxvYWRdKTtcblxuICAgICAgdGhpcy5wdXNoV2l0aFJlcGx5KG51bGwsIFwiYWxsb3dfdXBsb2FkXCIsIHBheWxvYWQpXG4gICAgICAgIC50aGVuKCh7IHJlc3AgfSkgPT4ge1xuICAgICAgICAgIHRoaXMubG9nKFwidXBsb2FkXCIsICgpID0+IFtcImdvdCBwcmVmbGlnaHQgcmVzcG9uc2VcIiwgcmVzcF0pO1xuICAgICAgICAgIC8vIHRoZSBwcmVmbGlnaHQgd2lsbCByZWplY3QgZW50cmllcyBiZXlvbmQgdGhlIG1heCBlbnRyaWVzXG4gICAgICAgICAgLy8gc28gd2UgZXJyb3IgYW5kIGNhbmNlbCBlbnRyaWVzIG9uIHRoZSBjbGllbnQgdGhhdCBhcmUgbWlzc2luZyBmcm9tIHRoZSByZXNwb25zZVxuICAgICAgICAgIHVwbG9hZGVyLmVudHJpZXMoKS5mb3JFYWNoKChlbnRyeSkgPT4ge1xuICAgICAgICAgICAgaWYgKHJlc3AuZW50cmllcyAmJiAhcmVzcC5lbnRyaWVzW2VudHJ5LnJlZl0pIHtcbiAgICAgICAgICAgICAgdGhpcy5oYW5kbGVGYWlsZWRFbnRyeVByZWZsaWdodChcbiAgICAgICAgICAgICAgICBlbnRyeS5yZWYsXG4gICAgICAgICAgICAgICAgXCJmYWlsZWQgcHJlZmxpZ2h0XCIsXG4gICAgICAgICAgICAgICAgdXBsb2FkZXIsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgLy8gZm9yIGF1dG8gdXBsb2Fkcywgd2UgbWF5IGhhdmUgYW4gZW1wdHkgZW50cmllcyByZXNwb25zZSBmcm9tIHRoZSBzZXJ2ZXJcbiAgICAgICAgICAvLyBmb3IgZm9ybSBzdWJtaXRzIHRoYXQgY29udGFpbiBpbnZhbGlkIGVudHJpZXNcbiAgICAgICAgICBpZiAocmVzcC5lcnJvciB8fCBPYmplY3Qua2V5cyhyZXNwLmVudHJpZXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy51bmRvUmVmcyhyZWYsIHBoeEV2ZW50KTtcbiAgICAgICAgICAgIGNvbnN0IGVycm9ycyA9IHJlc3AuZXJyb3IgfHwgW107XG4gICAgICAgICAgICBlcnJvcnMubWFwKChbZW50cnlfcmVmLCByZWFzb25dKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuaGFuZGxlRmFpbGVkRW50cnlQcmVmbGlnaHQoZW50cnlfcmVmLCByZWFzb24sIHVwbG9hZGVyKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBvbkVycm9yID0gKGNhbGxiYWNrKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuY2hhbm5lbC5vbkVycm9yKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5qb2luQ291bnQgPT09IGpvaW5Db3VudEF0VXBsb2FkKSB7XG4gICAgICAgICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdXBsb2FkZXIuaW5pdEFkYXB0ZXJVcGxvYWQocmVzcCwgb25FcnJvciwgdGhpcy5saXZlU29ja2V0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaCgoZXJyb3IpID0+IGxvZ0Vycm9yKFwiRmFpbGVkIHRvIHB1c2ggdXBsb2FkXCIsIGVycm9yKSk7XG4gICAgfSk7XG4gIH1cblxuICBoYW5kbGVGYWlsZWRFbnRyeVByZWZsaWdodCh1cGxvYWRSZWYsIHJlYXNvbiwgdXBsb2FkZXIpIHtcbiAgICBpZiAodXBsb2FkZXIuaXNBdXRvVXBsb2FkKCkpIHtcbiAgICAgIC8vIHVwbG9hZFJlZiBtYXkgYmUgdG9wIGxldmVsIHVwbG9hZCBjb25maWcgcmVmIG9yIGVudHJ5IHJlZlxuICAgICAgY29uc3QgZW50cnkgPSB1cGxvYWRlclxuICAgICAgICAuZW50cmllcygpXG4gICAgICAgIC5maW5kKChlbnRyeSkgPT4gZW50cnkucmVmID09PSB1cGxvYWRSZWYudG9TdHJpbmcoKSk7XG4gICAgICBpZiAoZW50cnkpIHtcbiAgICAgICAgZW50cnkuY2FuY2VsKCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHVwbG9hZGVyLmVudHJpZXMoKS5tYXAoKGVudHJ5KSA9PiBlbnRyeS5jYW5jZWwoKSk7XG4gICAgfVxuICAgIHRoaXMubG9nKFwidXBsb2FkXCIsICgpID0+IFtgZXJyb3IgZm9yIGVudHJ5ICR7dXBsb2FkUmVmfWAsIHJlYXNvbl0pO1xuICB9XG5cbiAgZGlzcGF0Y2hVcGxvYWRzKHRhcmdldEN0eCwgbmFtZSwgZmlsZXNPckJsb2JzKSB7XG4gICAgY29uc3QgdGFyZ2V0RWxlbWVudCA9IHRoaXMudGFyZ2V0Q3R4RWxlbWVudCh0YXJnZXRDdHgpIHx8IHRoaXMuZWw7XG4gICAgY29uc3QgaW5wdXRzID0gRE9NLmZpbmRVcGxvYWRJbnB1dHModGFyZ2V0RWxlbWVudCkuZmlsdGVyKFxuICAgICAgKGVsKSA9PiBlbC5uYW1lID09PSBuYW1lLFxuICAgICk7XG4gICAgaWYgKGlucHV0cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGxvZ0Vycm9yKGBubyBsaXZlIGZpbGUgaW5wdXRzIGZvdW5kIG1hdGNoaW5nIHRoZSBuYW1lIFwiJHtuYW1lfVwiYCk7XG4gICAgfSBlbHNlIGlmIChpbnB1dHMubGVuZ3RoID4gMSkge1xuICAgICAgbG9nRXJyb3IoYGR1cGxpY2F0ZSBsaXZlIGZpbGUgaW5wdXRzIGZvdW5kIG1hdGNoaW5nIHRoZSBuYW1lIFwiJHtuYW1lfVwiYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIERPTS5kaXNwYXRjaEV2ZW50KGlucHV0c1swXSwgUEhYX1RSQUNLX1VQTE9BRFMsIHtcbiAgICAgICAgZGV0YWlsOiB7IGZpbGVzOiBmaWxlc09yQmxvYnMgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHRhcmdldEN0eEVsZW1lbnQodGFyZ2V0Q3R4KSB7XG4gICAgaWYgKGlzQ2lkKHRhcmdldEN0eCkpIHtcbiAgICAgIGNvbnN0IFt0YXJnZXRdID0gRE9NLmZpbmRDb21wb25lbnROb2RlTGlzdCh0aGlzLmlkLCB0YXJnZXRDdHgpO1xuICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9IGVsc2UgaWYgKHRhcmdldEN0eCkge1xuICAgICAgcmV0dXJuIHRhcmdldEN0eDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHVzaEZvcm1SZWNvdmVyeShvbGRGb3JtLCBuZXdGb3JtLCB0ZW1wbGF0ZURvbSwgY2FsbGJhY2spIHtcbiAgICAvLyB3ZSBhcmUgb25seSByZWNvdmVyaW5nIGZvcm1zIGluc2lkZSB0aGUgY3VycmVudCB2aWV3LCB0aGVyZWZvcmUgaXQgaXMgc2FmZSB0b1xuICAgIC8vIHNraXAgd2l0aGluT3duZXJzIGhlcmUgYW5kIGFsd2F5cyB1c2UgdGhpcyB3aGVuIHJlZmVycmluZyB0byB0aGUgdmlld1xuICAgIGNvbnN0IHBoeENoYW5nZSA9IHRoaXMuYmluZGluZyhcImNoYW5nZVwiKTtcbiAgICBjb25zdCBwaHhUYXJnZXQgPSBuZXdGb3JtLmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoXCJ0YXJnZXRcIikpIHx8IG5ld0Zvcm07XG4gICAgY29uc3QgcGh4RXZlbnQgPVxuICAgICAgbmV3Rm9ybS5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFBIWF9BVVRPX1JFQ09WRVIpKSB8fFxuICAgICAgbmV3Rm9ybS5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwiY2hhbmdlXCIpKTtcbiAgICBjb25zdCBpbnB1dHMgPSBBcnJheS5mcm9tKG9sZEZvcm0uZWxlbWVudHMpLmZpbHRlcihcbiAgICAgIChlbCkgPT4gRE9NLmlzRm9ybUlucHV0KGVsKSAmJiBlbC5uYW1lICYmICFlbC5oYXNBdHRyaWJ1dGUocGh4Q2hhbmdlKSxcbiAgICApO1xuICAgIGlmIChpbnB1dHMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjYWxsYmFjaygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHdlIG11c3QgY2xlYXIgdHJhY2tlZCB1cGxvYWRzIGJlZm9yZSByZWNvdmVyeSBhcyB0aGV5IG5vIGxvbmdlciBoYXZlIHZhbGlkIHJlZnNcbiAgICBpbnB1dHMuZm9yRWFjaChcbiAgICAgIChpbnB1dCkgPT5cbiAgICAgICAgaW5wdXQuaGFzQXR0cmlidXRlKFBIWF9VUExPQURfUkVGKSAmJiBMaXZlVXBsb2FkZXIuY2xlYXJGaWxlcyhpbnB1dCksXG4gICAgKTtcbiAgICAvLyBwdXNoSW5wdXQgYXNzdW1lcyB0aGF0IHRoZXJlIGlzIGEgc291cmNlIGVsZW1lbnQgdGhhdCBpbml0aWF0ZWQgdGhlIGNoYW5nZTtcbiAgICAvLyBiZWNhdXNlIHRoaXMgaXMgbm90IHRoZSBjYXNlIHdoZW4gd2UgcmVjb3ZlciBmb3Jtcywgd2UgcHJvdmlkZSB0aGUgZmlyc3QgaW5wdXQgd2UgZmluZFxuICAgIGNvbnN0IGlucHV0ID0gaW5wdXRzLmZpbmQoKGVsKSA9PiBlbC50eXBlICE9PSBcImhpZGRlblwiKSB8fCBpbnB1dHNbMF07XG5cbiAgICAvLyBpbiB0aGUgY2FzZSB0aGF0IHRoZXJlIGFyZSBtdWx0aXBsZSB0YXJnZXRzLCB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIHBlbmRpbmcgcmVjb3ZlcnkgZXZlbnRzXG4gICAgLy8gYW5kIG9ubHkgY2FsbCB0aGUgY2FsbGJhY2sgb25jZSBhbGwgZXZlbnRzIGhhdmUgYmVlbiBwcm9jZXNzZWRcbiAgICBsZXQgcGVuZGluZyA9IDA7XG4gICAgLy8gd2l0aGluVGFyZ2V0cyhwaHhUYXJnZXQsIGNhbGxiYWNrLCBkb20sIHZpZXdFbClcbiAgICB0aGlzLndpdGhpblRhcmdldHMoXG4gICAgICBwaHhUYXJnZXQsXG4gICAgICAodGFyZ2V0VmlldywgdGFyZ2V0Q3R4KSA9PiB7XG4gICAgICAgIGNvbnN0IGNpZCA9IHRoaXMudGFyZ2V0Q29tcG9uZW50SUQobmV3Rm9ybSwgdGFyZ2V0Q3R4KTtcbiAgICAgICAgcGVuZGluZysrO1xuICAgICAgICBsZXQgZSA9IG5ldyBDdXN0b21FdmVudChcInBoeDpmb3JtLXJlY292ZXJ5XCIsIHtcbiAgICAgICAgICBkZXRhaWw6IHsgc291cmNlRWxlbWVudDogb2xkRm9ybSB9LFxuICAgICAgICB9KTtcbiAgICAgICAgSlMuZXhlYyhlLCBcImNoYW5nZVwiLCBwaHhFdmVudCwgdGhpcywgaW5wdXQsIFtcbiAgICAgICAgICBcInB1c2hcIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBfdGFyZ2V0OiBpbnB1dC5uYW1lLFxuICAgICAgICAgICAgdGFyZ2V0VmlldyxcbiAgICAgICAgICAgIHRhcmdldEN0eCxcbiAgICAgICAgICAgIG5ld0NpZDogY2lkLFxuICAgICAgICAgICAgY2FsbGJhY2s6ICgpID0+IHtcbiAgICAgICAgICAgICAgcGVuZGluZy0tO1xuICAgICAgICAgICAgICBpZiAocGVuZGluZyA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSk7XG4gICAgICB9LFxuICAgICAgdGVtcGxhdGVEb20sXG4gICAgKTtcbiAgfVxuXG4gIHB1c2hMaW5rUGF0Y2goZSwgaHJlZiwgdGFyZ2V0RWwsIGNhbGxiYWNrKSB7XG4gICAgY29uc3QgbGlua1JlZiA9IHRoaXMubGl2ZVNvY2tldC5zZXRQZW5kaW5nTGluayhocmVmKTtcbiAgICAvLyBvbmx5IGFkZCBsb2FkaW5nIHN0YXRlcyBpZiBldmVudCBpcyB0cnVzdGVkIChpdCB3YXMgdHJpZ2dlcmVkIGJ5IHVzZXIsIHN1Y2ggYXMgY2xpY2spIGFuZFxuICAgIC8vIGl0J3Mgbm90IGEgZm9yd2FyZC9iYWNrIG5hdmlnYXRpb24gZnJvbSBwb3BzdGF0ZVxuICAgIGNvbnN0IGxvYWRpbmcgPSBlLmlzVHJ1c3RlZCAmJiBlLnR5cGUgIT09IFwicG9wc3RhdGVcIjtcbiAgICBjb25zdCByZWZHZW4gPSB0YXJnZXRFbFxuICAgICAgPyAoKSA9PlxuICAgICAgICAgIHRoaXMucHV0UmVmKFxuICAgICAgICAgICAgW3sgZWw6IHRhcmdldEVsLCBsb2FkaW5nOiBsb2FkaW5nLCBsb2NrOiB0cnVlIH1dLFxuICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgIFwiY2xpY2tcIixcbiAgICAgICAgICApXG4gICAgICA6IG51bGw7XG4gICAgY29uc3QgZmFsbGJhY2sgPSAoKSA9PiB0aGlzLmxpdmVTb2NrZXQucmVkaXJlY3Qod2luZG93LmxvY2F0aW9uLmhyZWYpO1xuICAgIGNvbnN0IHVybCA9IGhyZWYuc3RhcnRzV2l0aChcIi9cIilcbiAgICAgID8gYCR7bG9jYXRpb24ucHJvdG9jb2x9Ly8ke2xvY2F0aW9uLmhvc3R9JHtocmVmfWBcbiAgICAgIDogaHJlZjtcblxuICAgIHRoaXMucHVzaFdpdGhSZXBseShyZWZHZW4sIFwibGl2ZV9wYXRjaFwiLCB7IHVybCB9KS50aGVuKFxuICAgICAgKHsgcmVzcCB9KSA9PiB7XG4gICAgICAgIHRoaXMubGl2ZVNvY2tldC5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHtcbiAgICAgICAgICBpZiAocmVzcC5saW5rX3JlZGlyZWN0KSB7XG4gICAgICAgICAgICB0aGlzLmxpdmVTb2NrZXQucmVwbGFjZU1haW4oaHJlZiwgbnVsbCwgY2FsbGJhY2ssIGxpbmtSZWYpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy5saXZlU29ja2V0LmNvbW1pdFBlbmRpbmdMaW5rKGxpbmtSZWYpKSB7XG4gICAgICAgICAgICAgIHRoaXMuaHJlZiA9IGhyZWY7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmFwcGx5UGVuZGluZ1VwZGF0ZXMoKTtcbiAgICAgICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKGxpbmtSZWYpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgICAgKHsgZXJyb3I6IF9lcnJvciwgdGltZW91dDogX3RpbWVvdXQgfSkgPT4gZmFsbGJhY2soKSxcbiAgICApO1xuICB9XG5cbiAgZ2V0Rm9ybXNGb3JSZWNvdmVyeSgpIHtcbiAgICAvLyBGb3JtIHJlY292ZXJ5IGlzIGNvbXBsZXggaW4gTGl2ZVZpZXc6XG4gICAgLy8gV2Ugd2FudCB0byBzdXBwb3J0IG5lc3RlZCBMaXZlVmlld3MgYW5kIGFsc28gcHJvdmlkZSBhIGdvb2QgdXNlciBleHBlcmllbmNlLlxuICAgIC8vIFRoZXJlZm9yZSwgd2hlbiB0aGUgY2hhbm5lbCByZWpvaW5zLCB3ZSBjb3B5IGFsbCBmb3JtcyB0aGF0IGFyZSBlbGlnaWJsZSBmb3JcbiAgICAvLyByZWNvdmVyeSB0byBiZSBhYmxlIHRvIGFjY2VzcyB0aGVtIGxhdGVyLlxuICAgIC8vIFdoeSBkbyB3ZSBuZWVkIHRvIGNvcHkgdGhlbT8gQmVjYXVzZSB3aGVuIHRoZSBtYWluIExpdmVWaWV3IGpvaW5zLCBhbnkgZm9ybXNcbiAgICAvLyBpbiBuZXN0ZWQgTGl2ZVZpZXdzIHdvdWxkIGJlIGxvc3QuXG4gICAgLy9cbiAgICAvLyBXZSBzaG91bGQgcmV3b3JrIHRoaXMgaW4gdGhlIGZ1dHVyZSB0byBzZXJpYWxpemUgdGhlIGZvcm0gcGF5bG9hZCBoZXJlXG4gICAgLy8gaW5zdGVhZCBvZiBjbG9uaW5nIHRoZSBET00gbm9kZXMsIGJ1dCBtYWtpbmcgdGhpcyB3b3JrIGNvcnJlY3RseSBpcyB0ZWRpb3VzLFxuICAgIC8vIGFzIHNlbmRpbmcgdGhlIGNvcnJlY3QgZm9ybSBwYXlsb2FkIHJlbGllcyBvbiBKUy5wdXNoIHRvIGV4dHJhY3QgdmFsdWVzXG4gICAgLy8gZnJvbSBKUyBjb21tYW5kcyAocGh4LWNoYW5nZT17SlMucHVzaChcImV2ZW50XCIsIHZhbHVlOiAuLi4sIHRhcmdldDogLi4uKX0pLFxuICAgIC8vIGFzIHdlbGwgYXMgdmlldy5wdXNoSW5wdXQsIHdoaWNoIGV4cGVjdHMgRE9NIGVsZW1lbnRzLlxuXG4gICAgaWYgKHRoaXMuam9pbkNvdW50ID09PSAwKSB7XG4gICAgICByZXR1cm4ge307XG4gICAgfVxuXG4gICAgY29uc3QgcGh4Q2hhbmdlID0gdGhpcy5iaW5kaW5nKFwiY2hhbmdlXCIpO1xuXG4gICAgcmV0dXJuIERPTS5hbGwodGhpcy5lbCwgYGZvcm1bJHtwaHhDaGFuZ2V9XWApXG4gICAgICAuZmlsdGVyKChmb3JtKSA9PiBmb3JtLmlkKVxuICAgICAgLmZpbHRlcigoZm9ybSkgPT4gZm9ybS5lbGVtZW50cy5sZW5ndGggPiAwKVxuICAgICAgLmZpbHRlcihcbiAgICAgICAgKGZvcm0pID0+XG4gICAgICAgICAgZm9ybS5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFBIWF9BVVRPX1JFQ09WRVIpKSAhPT0gXCJpZ25vcmVcIixcbiAgICAgIClcbiAgICAgIC5tYXAoKGZvcm0pID0+IHtcbiAgICAgICAgLy8gV2UgbmVlZCB0byBjbG9uZSB0aGUgd2hvbGUgZm9ybSwgYXMgcmVseWluZyBvbiBmb3JtLmVsZW1lbnRzIGNhbiBsZWFkIHRvXG4gICAgICAgIC8vIHNpdHVhdGlvbnMgd2hlcmUgd2UgaGF2ZVxuICAgICAgICAvL1xuICAgICAgICAvLyAgIDxmb3JtPjxmaWVsZHNldCBkaXNhYmxlZD48aW5wdXQgbmFtZT1cImZvb1wiIHZhbHVlPVwiYmFyXCI+PC9maWVsZHNldD48L2Zvcm0+XG4gICAgICAgIC8vXG4gICAgICAgIC8vIGFuZCBmb3JtLmVsZW1lbnRzIHJldHVybnMgYm90aCB0aGUgZmllbGRzZXQgYW5kIHRoZSBpbnB1dCBzZXBhcmF0ZWx5LlxuICAgICAgICAvLyBCZWNhdXNlIHRoZSBmaWVsZHNldCBpcyBkaXNhYmxlZCwgdGhlIGlucHV0IHNob3VsZCBOT1QgYmUgc2VudCB0aG91Z2guXG4gICAgICAgIC8vIFdlIGNhbiBvbmx5IHJlbGlhYmx5IHNlcmlhbGl6ZSB0aGUgZm9ybSBieSBjbG9uaW5nIGl0IGZ1bGx5LlxuICAgICAgICBjb25zdCBjbG9uZWRGb3JtID0gZm9ybS5jbG9uZU5vZGUodHJ1ZSk7XG4gICAgICAgIC8vIHdlIGNhbGwgbW9ycGhkb20gdG8gY29weSBhbnkgc3BlY2lhbCBzdGF0ZVxuICAgICAgICAvLyBsaWtlIHRoZSBzZWxlY3RlZCBvcHRpb24gb2YgYSA8c2VsZWN0PiBlbGVtZW50O1xuICAgICAgICAvLyBhbnkgYWxzbyBjb3B5IG92ZXIgcHJpdmF0ZXMgKHdoaWNoIGNvbnRhaW4gaW5mb3JtYXRpb24gYWJvdXQgdG91Y2hlZCBmaWVsZHMpXG4gICAgICAgIG1vcnBoZG9tKGNsb25lZEZvcm0sIGZvcm0sIHtcbiAgICAgICAgICBvbkJlZm9yZUVsVXBkYXRlZDogKGZyb21FbCwgdG9FbCkgPT4ge1xuICAgICAgICAgICAgRE9NLmNvcHlQcml2YXRlcyhmcm9tRWwsIHRvRWwpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIG5leHQgdXAsIHdlIGFsc28gbmVlZCB0byBjbG9uZSBhbnkgZWxlbWVudHMgd2l0aCBmb3JtPVwiaWRcIiBwYXJhbWV0ZXJcbiAgICAgICAgY29uc3QgZXh0ZXJuYWxFbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXG4gICAgICAgICAgYFtmb3JtPVwiJHtmb3JtLmlkfVwiXWAsXG4gICAgICAgICk7XG4gICAgICAgIEFycmF5LmZyb20oZXh0ZXJuYWxFbGVtZW50cykuZm9yRWFjaCgoZWwpID0+IHtcbiAgICAgICAgICBpZiAoZm9ybS5jb250YWlucyhlbCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgY2xvbmVkRWwgPSBlbC5jbG9uZU5vZGUodHJ1ZSk7XG4gICAgICAgICAgbW9ycGhkb20oY2xvbmVkRWwsIGVsKTtcbiAgICAgICAgICBET00uY29weVByaXZhdGVzKGNsb25lZEVsLCBlbCk7XG4gICAgICAgICAgY2xvbmVkRm9ybS5hcHBlbmRDaGlsZChjbG9uZWRFbCk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY2xvbmVkRm9ybTtcbiAgICAgIH0pXG4gICAgICAucmVkdWNlKChhY2MsIGZvcm0pID0+IHtcbiAgICAgICAgYWNjW2Zvcm0uaWRdID0gZm9ybTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sIHt9KTtcbiAgfVxuXG4gIG1heWJlUHVzaENvbXBvbmVudHNEZXN0cm95ZWQoZGVzdHJveWVkQ0lEcykge1xuICAgIGxldCB3aWxsRGVzdHJveUNJRHMgPSBkZXN0cm95ZWRDSURzLmZpbHRlcigoY2lkKSA9PiB7XG4gICAgICByZXR1cm4gRE9NLmZpbmRDb21wb25lbnROb2RlTGlzdCh0aGlzLmVsLCBjaWQpLmxlbmd0aCA9PT0gMDtcbiAgICB9KTtcblxuICAgIGNvbnN0IG9uRXJyb3IgPSAoZXJyb3IpID0+IHtcbiAgICAgIGlmICghdGhpcy5pc0Rlc3Ryb3llZCgpKSB7XG4gICAgICAgIGxvZ0Vycm9yKFwiRmFpbGVkIHRvIHB1c2ggY29tcG9uZW50cyBkZXN0cm95ZWRcIiwgZXJyb3IpO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAod2lsbERlc3Ryb3lDSURzLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIHdlIG11c3QgcmVzZXQgdGhlIHJlbmRlciBjaGFuZ2UgdHJhY2tpbmcgZm9yIGNpZHMgdGhhdFxuICAgICAgLy8gY291bGQgYmUgYWRkZWQgYmFjayBmcm9tIHRoZSBzZXJ2ZXIgc28gd2UgZG9uJ3Qgc2tpcCB0aGVtXG4gICAgICB3aWxsRGVzdHJveUNJRHMuZm9yRWFjaCgoY2lkKSA9PiB0aGlzLnJlbmRlcmVkLnJlc2V0UmVuZGVyKGNpZCkpO1xuXG4gICAgICB0aGlzLnB1c2hXaXRoUmVwbHkobnVsbCwgXCJjaWRzX3dpbGxfZGVzdHJveVwiLCB7IGNpZHM6IHdpbGxEZXN0cm95Q0lEcyB9KVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgLy8gd2UgbXVzdCB3YWl0IGZvciBwZW5kaW5nIHRyYW5zaXRpb25zIHRvIGNvbXBsZXRlIGJlZm9yZSBkZXRlcm1pbmluZ1xuICAgICAgICAgIC8vIGlmIHRoZSBjaWRzIHdlcmUgYWRkZWQgYmFjayB0byB0aGUgRE9NIGluIHRoZSBtZWFudGltZSAoIzMxMzkpXG4gICAgICAgICAgdGhpcy5saXZlU29ja2V0LnJlcXVlc3RET01VcGRhdGUoKCkgPT4ge1xuICAgICAgICAgICAgLy8gU2VlIGlmIGFueSBvZiB0aGUgY2lkcyB3ZSB3YW50ZWQgdG8gZGVzdHJveSB3ZXJlIGFkZGVkIGJhY2ssXG4gICAgICAgICAgICAvLyBpZiB0aGV5IHdlcmUgYWRkZWQgYmFjaywgd2UgZG9uJ3QgYWN0dWFsbHkgZGVzdHJveSB0aGVtLlxuICAgICAgICAgICAgbGV0IGNvbXBsZXRlbHlEZXN0cm95Q0lEcyA9IHdpbGxEZXN0cm95Q0lEcy5maWx0ZXIoKGNpZCkgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gRE9NLmZpbmRDb21wb25lbnROb2RlTGlzdCh0aGlzLmVsLCBjaWQpLmxlbmd0aCA9PT0gMDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAoY29tcGxldGVseURlc3Ryb3lDSURzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgdGhpcy5wdXNoV2l0aFJlcGx5KG51bGwsIFwiY2lkc19kZXN0cm95ZWRcIiwge1xuICAgICAgICAgICAgICAgIGNpZHM6IGNvbXBsZXRlbHlEZXN0cm95Q0lEcyxcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudGhlbigoeyByZXNwIH0pID0+IHtcbiAgICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZWQucHJ1bmVDSURzKHJlc3AuY2lkcyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuY2F0Y2gob25FcnJvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaChvbkVycm9yKTtcbiAgICB9XG4gIH1cblxuICBvd25zRWxlbWVudChlbCkge1xuICAgIGxldCBwYXJlbnRWaWV3RWwgPSBET00uY2xvc2VzdFZpZXdFbChlbCk7XG4gICAgcmV0dXJuIChcbiAgICAgIGVsLmdldEF0dHJpYnV0ZShQSFhfUEFSRU5UX0lEKSA9PT0gdGhpcy5pZCB8fFxuICAgICAgKHBhcmVudFZpZXdFbCAmJiBwYXJlbnRWaWV3RWwuaWQgPT09IHRoaXMuaWQpIHx8XG4gICAgICAoIXBhcmVudFZpZXdFbCAmJiB0aGlzLmlzRGVhZClcbiAgICApO1xuICB9XG5cbiAgc3VibWl0Rm9ybShmb3JtLCB0YXJnZXRDdHgsIHBoeEV2ZW50LCBzdWJtaXR0ZXIsIG9wdHMgPSB7fSkge1xuICAgIERPTS5wdXRQcml2YXRlKGZvcm0sIFBIWF9IQVNfU1VCTUlUVEVELCB0cnVlKTtcbiAgICBjb25zdCBpbnB1dHMgPSBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpO1xuICAgIGlucHV0cy5mb3JFYWNoKChpbnB1dCkgPT4gRE9NLnB1dFByaXZhdGUoaW5wdXQsIFBIWF9IQVNfU1VCTUlUVEVELCB0cnVlKSk7XG4gICAgdGhpcy5saXZlU29ja2V0LmJsdXJBY3RpdmVFbGVtZW50KHRoaXMpO1xuICAgIHRoaXMucHVzaEZvcm1TdWJtaXQoZm9ybSwgdGFyZ2V0Q3R4LCBwaHhFdmVudCwgc3VibWl0dGVyLCBvcHRzLCAoKSA9PiB7XG4gICAgICB0aGlzLmxpdmVTb2NrZXQucmVzdG9yZVByZXZpb3VzbHlBY3RpdmVGb2N1cygpO1xuICAgIH0pO1xuICB9XG5cbiAgYmluZGluZyhraW5kKSB7XG4gICAgcmV0dXJuIHRoaXMubGl2ZVNvY2tldC5iaW5kaW5nKGtpbmQpO1xuICB9XG5cbiAgLy8gcGh4LXBvcnRhbFxuICBwdXNoUG9ydGFsRWxlbWVudElkKGlkKSB7XG4gICAgdGhpcy5wb3J0YWxFbGVtZW50SWRzLmFkZChpZCk7XG4gIH1cblxuICBkcm9wUG9ydGFsRWxlbWVudElkKGlkKSB7XG4gICAgdGhpcy5wb3J0YWxFbGVtZW50SWRzLmRlbGV0ZShpZCk7XG4gIH1cblxuICBkZXN0cm95UG9ydGFsRWxlbWVudHMoKSB7XG4gICAgdGhpcy5wb3J0YWxFbGVtZW50SWRzLmZvckVhY2goKGlkKSA9PiB7XG4gICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKTtcbiAgICAgIGlmIChlbCkge1xuICAgICAgICBlbC5yZW1vdmUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuIiwgImltcG9ydCB7XG4gIEJJTkRJTkdfUFJFRklYLFxuICBDT05TRUNVVElWRV9SRUxPQURTLFxuICBERUZBVUxUUyxcbiAgRkFJTFNBRkVfSklUVEVSLFxuICBMT0FERVJfVElNRU9VVCxcbiAgRElTQ09OTkVDVEVEX1RJTUVPVVQsXG4gIE1BWF9SRUxPQURTLFxuICBQSFhfREVCT1VOQ0UsXG4gIFBIWF9EUk9QX1RBUkdFVCxcbiAgUEhYX0hBU19GT0NVU0VELFxuICBQSFhfS0VZLFxuICBQSFhfTElOS19TVEFURSxcbiAgUEhYX0xJVkVfTElOSyxcbiAgUEhYX0xWX0RFQlVHLFxuICBQSFhfTFZfTEFURU5DWV9TSU0sXG4gIFBIWF9MVl9QUk9GSUxFLFxuICBQSFhfTFZfSElTVE9SWV9QT1NJVElPTixcbiAgUEhYX01BSU4sXG4gIFBIWF9QQVJFTlRfSUQsXG4gIFBIWF9WSUVXX1NFTEVDVE9SLFxuICBQSFhfUk9PVF9JRCxcbiAgUEhYX1RIUk9UVExFLFxuICBQSFhfVFJBQ0tfVVBMT0FEUyxcbiAgUEhYX1NFU1NJT04sXG4gIFJFTE9BRF9KSVRURVJfTUlOLFxuICBSRUxPQURfSklUVEVSX01BWCxcbiAgUEhYX1JFRl9TUkMsXG4gIFBIWF9SRUxPQURfU1RBVFVTLFxuICBQSFhfUlVOVElNRV9IT09LLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuaW1wb3J0IHtcbiAgY2xvbmUsXG4gIGNsb3Nlc3RQaHhCaW5kaW5nLFxuICBjbG9zdXJlLFxuICBkZWJ1ZyxcbiAgbWF5YmUsXG4gIGxvZ0Vycm9yLFxufSBmcm9tIFwiLi91dGlsc1wiO1xuXG5pbXBvcnQgQnJvd3NlciBmcm9tIFwiLi9icm93c2VyXCI7XG5pbXBvcnQgRE9NIGZyb20gXCIuL2RvbVwiO1xuaW1wb3J0IEhvb2tzIGZyb20gXCIuL2hvb2tzXCI7XG5pbXBvcnQgTGl2ZVVwbG9hZGVyIGZyb20gXCIuL2xpdmVfdXBsb2FkZXJcIjtcbmltcG9ydCBWaWV3IGZyb20gXCIuL3ZpZXdcIjtcbmltcG9ydCBKUyBmcm9tIFwiLi9qc1wiO1xuaW1wb3J0IGpzQ29tbWFuZHMgZnJvbSBcIi4vanNfY29tbWFuZHNcIjtcblxuZXhwb3J0IGNvbnN0IGlzVXNlZElucHV0ID0gKGVsKSA9PiBET00uaXNVc2VkSW5wdXQoZWwpO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBMaXZlU29ja2V0IHtcbiAgY29uc3RydWN0b3IodXJsLCBwaHhTb2NrZXQsIG9wdHMgPSB7fSkge1xuICAgIHRoaXMudW5sb2FkZWQgPSBmYWxzZTtcbiAgICBpZiAoIXBoeFNvY2tldCB8fCBwaHhTb2NrZXQuY29uc3RydWN0b3IubmFtZSA9PT0gXCJPYmplY3RcIikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBcbiAgICAgIGEgcGhvZW5peCBTb2NrZXQgbXVzdCBiZSBwcm92aWRlZCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHRvIHRoZSBMaXZlU29ja2V0IGNvbnN0cnVjdG9yLiBGb3IgZXhhbXBsZTpcblxuICAgICAgICAgIGltcG9ydCB7U29ja2V0fSBmcm9tIFwicGhvZW5peFwiXG4gICAgICAgICAgaW1wb3J0IHtMaXZlU29ja2V0fSBmcm9tIFwicGhvZW5peF9saXZlX3ZpZXdcIlxuICAgICAgICAgIGxldCBsaXZlU29ja2V0ID0gbmV3IExpdmVTb2NrZXQoXCIvbGl2ZVwiLCBTb2NrZXQsIHsuLi59KVxuICAgICAgYCk7XG4gICAgfVxuICAgIHRoaXMuc29ja2V0ID0gbmV3IHBoeFNvY2tldCh1cmwsIG9wdHMpO1xuICAgIHRoaXMuYmluZGluZ1ByZWZpeCA9IG9wdHMuYmluZGluZ1ByZWZpeCB8fCBCSU5ESU5HX1BSRUZJWDtcbiAgICB0aGlzLm9wdHMgPSBvcHRzO1xuICAgIHRoaXMucGFyYW1zID0gY2xvc3VyZShvcHRzLnBhcmFtcyB8fCB7fSk7XG4gICAgdGhpcy52aWV3TG9nZ2VyID0gb3B0cy52aWV3TG9nZ2VyO1xuICAgIHRoaXMubWV0YWRhdGFDYWxsYmFja3MgPSBvcHRzLm1ldGFkYXRhIHx8IHt9O1xuICAgIHRoaXMuZGVmYXVsdHMgPSBPYmplY3QuYXNzaWduKGNsb25lKERFRkFVTFRTKSwgb3B0cy5kZWZhdWx0cyB8fCB7fSk7XG4gICAgdGhpcy5wcmV2QWN0aXZlID0gbnVsbDtcbiAgICB0aGlzLnNpbGVuY2VkID0gZmFsc2U7XG4gICAgdGhpcy5tYWluID0gbnVsbDtcbiAgICB0aGlzLm91dGdvaW5nTWFpbkVsID0gbnVsbDtcbiAgICB0aGlzLmNsaWNrU3RhcnRlZEF0VGFyZ2V0ID0gbnVsbDtcbiAgICB0aGlzLmxpbmtSZWYgPSAxO1xuICAgIHRoaXMucm9vdHMgPSB7fTtcbiAgICB0aGlzLmhyZWYgPSB3aW5kb3cubG9jYXRpb24uaHJlZjtcbiAgICB0aGlzLnBlbmRpbmdMaW5rID0gbnVsbDtcbiAgICB0aGlzLmN1cnJlbnRMb2NhdGlvbiA9IGNsb25lKHdpbmRvdy5sb2NhdGlvbik7XG4gICAgdGhpcy5ob29rcyA9IG9wdHMuaG9va3MgfHwge307XG4gICAgdGhpcy51cGxvYWRlcnMgPSBvcHRzLnVwbG9hZGVycyB8fCB7fTtcbiAgICB0aGlzLmxvYWRlclRpbWVvdXQgPSBvcHRzLmxvYWRlclRpbWVvdXQgfHwgTE9BREVSX1RJTUVPVVQ7XG4gICAgdGhpcy5kaXNjb25uZWN0ZWRUaW1lb3V0ID0gb3B0cy5kaXNjb25uZWN0ZWRUaW1lb3V0IHx8IERJU0NPTk5FQ1RFRF9USU1FT1VUO1xuICAgIC8qKlxuICAgICAqIEB0eXBlIHtSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGx9XG4gICAgICovXG4gICAgdGhpcy5yZWxvYWRXaXRoSml0dGVyVGltZXIgPSBudWxsO1xuICAgIHRoaXMubWF4UmVsb2FkcyA9IG9wdHMubWF4UmVsb2FkcyB8fCBNQVhfUkVMT0FEUztcbiAgICB0aGlzLnJlbG9hZEppdHRlck1pbiA9IG9wdHMucmVsb2FkSml0dGVyTWluIHx8IFJFTE9BRF9KSVRURVJfTUlOO1xuICAgIHRoaXMucmVsb2FkSml0dGVyTWF4ID0gb3B0cy5yZWxvYWRKaXR0ZXJNYXggfHwgUkVMT0FEX0pJVFRFUl9NQVg7XG4gICAgdGhpcy5mYWlsc2FmZUppdHRlciA9IG9wdHMuZmFpbHNhZmVKaXR0ZXIgfHwgRkFJTFNBRkVfSklUVEVSO1xuICAgIHRoaXMubG9jYWxTdG9yYWdlID0gb3B0cy5sb2NhbFN0b3JhZ2UgfHwgd2luZG93LmxvY2FsU3RvcmFnZTtcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlID0gb3B0cy5zZXNzaW9uU3RvcmFnZSB8fCB3aW5kb3cuc2Vzc2lvblN0b3JhZ2U7XG4gICAgdGhpcy5ib3VuZFRvcExldmVsRXZlbnRzID0gZmFsc2U7XG4gICAgdGhpcy5ib3VuZEV2ZW50TmFtZXMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5ibG9ja1BoeENoYW5nZVdoaWxlQ29tcG9zaW5nID1cbiAgICAgIG9wdHMuYmxvY2tQaHhDaGFuZ2VXaGlsZUNvbXBvc2luZyB8fCBmYWxzZTtcbiAgICB0aGlzLnNlcnZlckNsb3NlUmVmID0gbnVsbDtcbiAgICB0aGlzLmRvbUNhbGxiYWNrcyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7XG4gICAgICAgIGpzUXVlcnlTZWxlY3RvckFsbDogbnVsbCxcbiAgICAgICAgb25QYXRjaFN0YXJ0OiBjbG9zdXJlKCksXG4gICAgICAgIG9uUGF0Y2hFbmQ6IGNsb3N1cmUoKSxcbiAgICAgICAgb25Ob2RlQWRkZWQ6IGNsb3N1cmUoKSxcbiAgICAgICAgb25CZWZvcmVFbFVwZGF0ZWQ6IGNsb3N1cmUoKSxcbiAgICAgIH0sXG4gICAgICBvcHRzLmRvbSB8fCB7fSxcbiAgICApO1xuICAgIHRoaXMudHJhbnNpdGlvbnMgPSBuZXcgVHJhbnNpdGlvblNldCgpO1xuICAgIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbiA9XG4gICAgICBwYXJzZUludCh0aGlzLnNlc3Npb25TdG9yYWdlLmdldEl0ZW0oUEhYX0xWX0hJU1RPUllfUE9TSVRJT04pKSB8fCAwO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGFnZWhpZGVcIiwgKF9lKSA9PiB7XG4gICAgICB0aGlzLnVubG9hZGVkID0gdHJ1ZTtcbiAgICB9KTtcbiAgICB0aGlzLnNvY2tldC5vbk9wZW4oKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuaXNVbmxvYWRlZCgpKSB7XG4gICAgICAgIC8vIHJlbG9hZCBwYWdlIGlmIGJlaW5nIHJlc3RvcmVkIGZyb20gYmFjay9mb3J3YXJkIGNhY2hlIGFuZCBicm93c2VyIGRvZXMgbm90IGVtaXQgXCJwYWdlc2hvd1wiXG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8vIHB1YmxpY1xuXG4gIHZlcnNpb24oKSB7XG4gICAgcmV0dXJuIExWX1ZTTjtcbiAgfVxuXG4gIGlzUHJvZmlsZUVuYWJsZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShQSFhfTFZfUFJPRklMRSkgPT09IFwidHJ1ZVwiO1xuICB9XG5cbiAgaXNEZWJ1Z0VuYWJsZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShQSFhfTFZfREVCVUcpID09PSBcInRydWVcIjtcbiAgfVxuXG4gIGlzRGVidWdEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFBIWF9MVl9ERUJVRykgPT09IFwiZmFsc2VcIjtcbiAgfVxuXG4gIGVuYWJsZURlYnVnKCkge1xuICAgIHRoaXMuc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShQSFhfTFZfREVCVUcsIFwidHJ1ZVwiKTtcbiAgfVxuXG4gIGVuYWJsZVByb2ZpbGluZygpIHtcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oUEhYX0xWX1BST0ZJTEUsIFwidHJ1ZVwiKTtcbiAgfVxuXG4gIGRpc2FibGVEZWJ1ZygpIHtcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oUEhYX0xWX0RFQlVHLCBcImZhbHNlXCIpO1xuICB9XG5cbiAgZGlzYWJsZVByb2ZpbGluZygpIHtcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oUEhYX0xWX1BST0ZJTEUpO1xuICB9XG5cbiAgZW5hYmxlTGF0ZW5jeVNpbSh1cHBlckJvdW5kTXMpIHtcbiAgICB0aGlzLmVuYWJsZURlYnVnKCk7XG4gICAgY29uc29sZS5sb2coXG4gICAgICBcImxhdGVuY3kgc2ltdWxhdG9yIGVuYWJsZWQgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGlzIGJyb3dzZXIgc2Vzc2lvbi4gQ2FsbCBkaXNhYmxlTGF0ZW5jeVNpbSgpIHRvIGRpc2FibGVcIixcbiAgICApO1xuICAgIHRoaXMuc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShQSFhfTFZfTEFURU5DWV9TSU0sIHVwcGVyQm91bmRNcyk7XG4gIH1cblxuICBkaXNhYmxlTGF0ZW5jeVNpbSgpIHtcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oUEhYX0xWX0xBVEVOQ1lfU0lNKTtcbiAgfVxuXG4gIGdldExhdGVuY3lTaW0oKSB7XG4gICAgY29uc3Qgc3RyID0gdGhpcy5zZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFBIWF9MVl9MQVRFTkNZX1NJTSk7XG4gICAgcmV0dXJuIHN0ciA/IHBhcnNlSW50KHN0cikgOiBudWxsO1xuICB9XG5cbiAgZ2V0U29ja2V0KCkge1xuICAgIHJldHVybiB0aGlzLnNvY2tldDtcbiAgfVxuXG4gIGNvbm5lY3QoKSB7XG4gICAgLy8gZW5hYmxlIGRlYnVnIGJ5IGRlZmF1bHQgaWYgb24gbG9jYWxob3N0IGFuZCBub3QgZXhwbGljaXRseSBkaXNhYmxlZFxuICAgIGlmICh3aW5kb3cubG9jYXRpb24uaG9zdG5hbWUgPT09IFwibG9jYWxob3N0XCIgJiYgIXRoaXMuaXNEZWJ1Z0Rpc2FibGVkKCkpIHtcbiAgICAgIHRoaXMuZW5hYmxlRGVidWcoKTtcbiAgICB9XG4gICAgY29uc3QgZG9Db25uZWN0ID0gKCkgPT4ge1xuICAgICAgdGhpcy5yZXNldFJlbG9hZFN0YXR1cygpO1xuICAgICAgaWYgKHRoaXMuam9pblJvb3RWaWV3cygpKSB7XG4gICAgICAgIHRoaXMuYmluZFRvcExldmVsRXZlbnRzKCk7XG4gICAgICAgIHRoaXMuc29ja2V0LmNvbm5lY3QoKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5tYWluKSB7XG4gICAgICAgIHRoaXMuc29ja2V0LmNvbm5lY3QoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYmluZFRvcExldmVsRXZlbnRzKHsgZGVhZDogdHJ1ZSB9KTtcbiAgICAgIH1cbiAgICAgIHRoaXMuam9pbkRlYWRWaWV3KCk7XG4gICAgfTtcbiAgICBpZiAoXG4gICAgICBbXCJjb21wbGV0ZVwiLCBcImxvYWRlZFwiLCBcImludGVyYWN0aXZlXCJdLmluZGV4T2YoZG9jdW1lbnQucmVhZHlTdGF0ZSkgPj0gMFxuICAgICkge1xuICAgICAgZG9Db25uZWN0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJET01Db250ZW50TG9hZGVkXCIsICgpID0+IGRvQ29ubmVjdCgpKTtcbiAgICB9XG4gIH1cblxuICBkaXNjb25uZWN0KGNhbGxiYWNrKSB7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMucmVsb2FkV2l0aEppdHRlclRpbWVyKTtcbiAgICAvLyByZW1vdmUgdGhlIHNvY2tldCBjbG9zZSBsaXN0ZW5lciB0byBhdm9pZCB0cnlpbmcgdG8gaGFuZGxlXG4gICAgLy8gYSBzZXJ2ZXIgY2xvc2UgZXZlbnQgd2hlbiBpdCBpcyBhY3R1YWxseSBjYXVzZWQgYnkgdXMgZGlzY29ubmVjdGluZ1xuICAgIGlmICh0aGlzLnNlcnZlckNsb3NlUmVmKSB7XG4gICAgICB0aGlzLnNvY2tldC5vZmYodGhpcy5zZXJ2ZXJDbG9zZVJlZik7XG4gICAgICB0aGlzLnNlcnZlckNsb3NlUmVmID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5zb2NrZXQuZGlzY29ubmVjdChjYWxsYmFjayk7XG4gIH1cblxuICByZXBsYWNlVHJhbnNwb3J0KHRyYW5zcG9ydCkge1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlbG9hZFdpdGhKaXR0ZXJUaW1lcik7XG4gICAgdGhpcy5zb2NrZXQucmVwbGFjZVRyYW5zcG9ydCh0cmFuc3BvcnQpO1xuICAgIHRoaXMuY29ubmVjdCgpO1xuICB9XG5cbiAgZXhlY0pTKGVsLCBlbmNvZGVkSlMsIGV2ZW50VHlwZSA9IG51bGwpIHtcbiAgICBjb25zdCBlID0gbmV3IEN1c3RvbUV2ZW50KFwicGh4OmV4ZWNcIiwgeyBkZXRhaWw6IHsgc291cmNlRWxlbWVudDogZWwgfSB9KTtcbiAgICB0aGlzLm93bmVyKGVsLCAodmlldykgPT4gSlMuZXhlYyhlLCBldmVudFR5cGUsIGVuY29kZWRKUywgdmlldywgZWwpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIG9iamVjdCB3aXRoIG1ldGhvZHMgdG8gbWFuaXBsdWF0ZSB0aGUgRE9NIGFuZCBleGVjdXRlIEphdmFTY3JpcHQuXG4gICAqIFRoZSBhcHBsaWVkIGNoYW5nZXMgaW50ZWdyYXRlIHdpdGggc2VydmVyIERPTSBwYXRjaGluZy5cbiAgICpcbiAgICogQHJldHVybnMge2ltcG9ydChcIi4vanNfY29tbWFuZHNcIikuTGl2ZVNvY2tldEpTQ29tbWFuZHN9XG4gICAqL1xuICBqcygpIHtcbiAgICByZXR1cm4ganNDb21tYW5kcyh0aGlzLCBcImpzXCIpO1xuICB9XG5cbiAgLy8gcHJpdmF0ZVxuXG4gIHVubG9hZCgpIHtcbiAgICBpZiAodGhpcy51bmxvYWRlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy5tYWluICYmIHRoaXMuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgdGhpcy5sb2codGhpcy5tYWluLCBcInNvY2tldFwiLCAoKSA9PiBbXCJkaXNjb25uZWN0IGZvciBwYWdlIG5hdlwiXSk7XG4gICAgfVxuICAgIHRoaXMudW5sb2FkZWQgPSB0cnVlO1xuICAgIHRoaXMuZGVzdHJveUFsbFZpZXdzKCk7XG4gICAgdGhpcy5kaXNjb25uZWN0KCk7XG4gIH1cblxuICB0cmlnZ2VyRE9NKGtpbmQsIGFyZ3MpIHtcbiAgICB0aGlzLmRvbUNhbGxiYWNrc1traW5kXSguLi5hcmdzKTtcbiAgfVxuXG4gIHRpbWUobmFtZSwgZnVuYykge1xuICAgIGlmICghdGhpcy5pc1Byb2ZpbGVFbmFibGVkKCkgfHwgIWNvbnNvbGUudGltZSkge1xuICAgICAgcmV0dXJuIGZ1bmMoKTtcbiAgICB9XG4gICAgY29uc29sZS50aW1lKG5hbWUpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGZ1bmMoKTtcbiAgICBjb25zb2xlLnRpbWVFbmQobmFtZSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGxvZyh2aWV3LCBraW5kLCBtc2dDYWxsYmFjaykge1xuICAgIGlmICh0aGlzLnZpZXdMb2dnZXIpIHtcbiAgICAgIGNvbnN0IFttc2csIG9ial0gPSBtc2dDYWxsYmFjaygpO1xuICAgICAgdGhpcy52aWV3TG9nZ2VyKHZpZXcsIGtpbmQsIG1zZywgb2JqKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNEZWJ1Z0VuYWJsZWQoKSkge1xuICAgICAgY29uc3QgW21zZywgb2JqXSA9IG1zZ0NhbGxiYWNrKCk7XG4gICAgICBkZWJ1Zyh2aWV3LCBraW5kLCBtc2csIG9iaik7XG4gICAgfVxuICB9XG5cbiAgcmVxdWVzdERPTVVwZGF0ZShjYWxsYmFjaykge1xuICAgIHRoaXMudHJhbnNpdGlvbnMuYWZ0ZXIoY2FsbGJhY2spO1xuICB9XG5cbiAgYXN5bmNUcmFuc2l0aW9uKHByb21pc2UpIHtcbiAgICB0aGlzLnRyYW5zaXRpb25zLmFkZEFzeW5jVHJhbnNpdGlvbihwcm9taXNlKTtcbiAgfVxuXG4gIHRyYW5zaXRpb24odGltZSwgb25TdGFydCwgb25Eb25lID0gZnVuY3Rpb24gKCkge30pIHtcbiAgICB0aGlzLnRyYW5zaXRpb25zLmFkZFRyYW5zaXRpb24odGltZSwgb25TdGFydCwgb25Eb25lKTtcbiAgfVxuXG4gIG9uQ2hhbm5lbChjaGFubmVsLCBldmVudCwgY2IpIHtcbiAgICBjaGFubmVsLm9uKGV2ZW50LCAoZGF0YSkgPT4ge1xuICAgICAgY29uc3QgbGF0ZW5jeSA9IHRoaXMuZ2V0TGF0ZW5jeVNpbSgpO1xuICAgICAgaWYgKCFsYXRlbmN5KSB7XG4gICAgICAgIGNiKGRhdGEpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiBjYihkYXRhKSwgbGF0ZW5jeSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZWxvYWRXaXRoSml0dGVyKHZpZXcsIGxvZykge1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnJlbG9hZFdpdGhKaXR0ZXJUaW1lcik7XG4gICAgdGhpcy5kaXNjb25uZWN0KCk7XG4gICAgY29uc3QgbWluTXMgPSB0aGlzLnJlbG9hZEppdHRlck1pbjtcbiAgICBjb25zdCBtYXhNcyA9IHRoaXMucmVsb2FkSml0dGVyTWF4O1xuICAgIGxldCBhZnRlck1zID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogKG1heE1zIC0gbWluTXMgKyAxKSkgKyBtaW5NcztcbiAgICBjb25zdCB0cmllcyA9IEJyb3dzZXIudXBkYXRlTG9jYWwoXG4gICAgICB0aGlzLmxvY2FsU3RvcmFnZSxcbiAgICAgIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSxcbiAgICAgIENPTlNFQ1VUSVZFX1JFTE9BRFMsXG4gICAgICAwLFxuICAgICAgKGNvdW50KSA9PiBjb3VudCArIDEsXG4gICAgKTtcbiAgICBpZiAodHJpZXMgPj0gdGhpcy5tYXhSZWxvYWRzKSB7XG4gICAgICBhZnRlck1zID0gdGhpcy5mYWlsc2FmZUppdHRlcjtcbiAgICB9XG4gICAgdGhpcy5yZWxvYWRXaXRoSml0dGVyVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIC8vIGlmIHZpZXcgaGFzIHJlY292ZXJlZCwgc3VjaCBhcyB0cmFuc3BvcnQgcmVwbGFjZWQsIHRoZW4gY2FuY2VsXG4gICAgICBpZiAodmlldy5pc0Rlc3Ryb3llZCgpIHx8IHZpZXcuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB2aWV3LmRlc3Ryb3koKTtcbiAgICAgIGxvZ1xuICAgICAgICA/IGxvZygpXG4gICAgICAgIDogdGhpcy5sb2codmlldywgXCJqb2luXCIsICgpID0+IFtcbiAgICAgICAgICAgIGBlbmNvdW50ZXJlZCAke3RyaWVzfSBjb25zZWN1dGl2ZSByZWxvYWRzYCxcbiAgICAgICAgICBdKTtcbiAgICAgIGlmICh0cmllcyA+PSB0aGlzLm1heFJlbG9hZHMpIHtcbiAgICAgICAgdGhpcy5sb2codmlldywgXCJqb2luXCIsICgpID0+IFtcbiAgICAgICAgICBgZXhjZWVkZWQgJHt0aGlzLm1heFJlbG9hZHN9IGNvbnNlY3V0aXZlIHJlbG9hZHMuIEVudGVyaW5nIGZhaWxzYWZlIG1vZGVgLFxuICAgICAgICBdKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmhhc1BlbmRpbmdMaW5rKCkpIHtcbiAgICAgICAgd2luZG93LmxvY2F0aW9uID0gdGhpcy5wZW5kaW5nTGluaztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcbiAgICAgIH1cbiAgICB9LCBhZnRlck1zKTtcbiAgfVxuXG4gIGdldEhvb2tEZWZpbml0aW9uKG5hbWUpIHtcbiAgICBpZiAoIW5hbWUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMubWF5YmVJbnRlcm5hbEhvb2sobmFtZSkgfHxcbiAgICAgIHRoaXMuaG9va3NbbmFtZV0gfHxcbiAgICAgIHRoaXMubWF5YmVSdW50aW1lSG9vayhuYW1lKVxuICAgICk7XG4gIH1cblxuICBtYXliZUludGVybmFsSG9vayhuYW1lKSB7XG4gICAgcmV0dXJuIG5hbWUgJiYgbmFtZS5zdGFydHNXaXRoKFwiUGhvZW5peC5cIikgJiYgSG9va3NbbmFtZS5zcGxpdChcIi5cIilbMV1dO1xuICB9XG5cbiAgbWF5YmVSdW50aW1lSG9vayhuYW1lKSB7XG4gICAgY29uc3QgcnVudGltZUhvb2sgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxuICAgICAgYHNjcmlwdFske1BIWF9SVU5USU1FX0hPT0t9PVwiJHtDU1MuZXNjYXBlKG5hbWUpfVwiXWAsXG4gICAgKTtcbiAgICBpZiAoIXJ1bnRpbWVIb29rKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBjYWxsYmFja3MgPSB3aW5kb3dbYHBoeF9ob29rXyR7bmFtZX1gXTtcbiAgICBpZiAoIWNhbGxiYWNrcyB8fCB0eXBlb2YgY2FsbGJhY2tzICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIGxvZ0Vycm9yKFwiYSBydW50aW1lIGhvb2sgbXVzdCBiZSBhIGZ1bmN0aW9uXCIsIHJ1bnRpbWVIb29rKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgaG9va0RlZmluaXRvbiA9IGNhbGxiYWNrcygpO1xuICAgIGlmIChcbiAgICAgIGhvb2tEZWZpbml0b24gJiZcbiAgICAgICh0eXBlb2YgaG9va0RlZmluaXRvbiA9PT0gXCJvYmplY3RcIiB8fCB0eXBlb2YgaG9va0RlZmluaXRvbiA9PT0gXCJmdW5jdGlvblwiKVxuICAgICkge1xuICAgICAgcmV0dXJuIGhvb2tEZWZpbml0b247XG4gICAgfVxuICAgIGxvZ0Vycm9yKFxuICAgICAgXCJydW50aW1lIGhvb2sgbXVzdCByZXR1cm4gYW4gb2JqZWN0IHdpdGggaG9vayBjYWxsYmFja3Mgb3IgYW4gaW5zdGFuY2Ugb2YgVmlld0hvb2tcIixcbiAgICAgIHJ1bnRpbWVIb29rLFxuICAgICk7XG4gIH1cblxuICBpc1VubG9hZGVkKCkge1xuICAgIHJldHVybiB0aGlzLnVubG9hZGVkO1xuICB9XG5cbiAgaXNDb25uZWN0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuc29ja2V0LmlzQ29ubmVjdGVkKCk7XG4gIH1cblxuICBnZXRCaW5kaW5nUHJlZml4KCkge1xuICAgIHJldHVybiB0aGlzLmJpbmRpbmdQcmVmaXg7XG4gIH1cblxuICBiaW5kaW5nKGtpbmQpIHtcbiAgICByZXR1cm4gYCR7dGhpcy5nZXRCaW5kaW5nUHJlZml4KCl9JHtraW5kfWA7XG4gIH1cblxuICBjaGFubmVsKHRvcGljLCBwYXJhbXMpIHtcbiAgICByZXR1cm4gdGhpcy5zb2NrZXQuY2hhbm5lbCh0b3BpYywgcGFyYW1zKTtcbiAgfVxuXG4gIGpvaW5EZWFkVmlldygpIHtcbiAgICBjb25zdCBib2R5ID0gZG9jdW1lbnQuYm9keTtcbiAgICBpZiAoXG4gICAgICBib2R5ICYmXG4gICAgICAhdGhpcy5pc1BoeFZpZXcoYm9keSkgJiZcbiAgICAgICF0aGlzLmlzUGh4Vmlldyhkb2N1bWVudC5maXJzdEVsZW1lbnRDaGlsZClcbiAgICApIHtcbiAgICAgIGNvbnN0IHZpZXcgPSB0aGlzLm5ld1Jvb3RWaWV3KGJvZHkpO1xuICAgICAgdmlldy5zZXRIcmVmKHRoaXMuZ2V0SHJlZigpKTtcbiAgICAgIHZpZXcuam9pbkRlYWQoKTtcbiAgICAgIGlmICghdGhpcy5tYWluKSB7XG4gICAgICAgIHRoaXMubWFpbiA9IHZpZXc7XG4gICAgICB9XG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgdmlldy5leGVjTmV3TW91bnRlZCgpO1xuICAgICAgICAvLyByZXN0b3JlIHNjcm9sbCBwb3NpdGlvbiB3aGVuIG5hdmlnYXRpbmcgZnJvbSBhbiBleHRlcm5hbCAvIG5vbi1saXZlIHBhZ2VcbiAgICAgICAgdGhpcy5tYXliZVNjcm9sbChoaXN0b3J5LnN0YXRlPy5zY3JvbGwpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgam9pblJvb3RWaWV3cygpIHtcbiAgICBsZXQgcm9vdHNGb3VuZCA9IGZhbHNlO1xuICAgIERPTS5hbGwoXG4gICAgICBkb2N1bWVudCxcbiAgICAgIGAke1BIWF9WSUVXX1NFTEVDVE9SfTpub3QoWyR7UEhYX1BBUkVOVF9JRH1dKWAsXG4gICAgICAocm9vdEVsKSA9PiB7XG4gICAgICAgIGlmICghdGhpcy5nZXRSb290QnlJZChyb290RWwuaWQpKSB7XG4gICAgICAgICAgY29uc3QgdmlldyA9IHRoaXMubmV3Um9vdFZpZXcocm9vdEVsKTtcbiAgICAgICAgICAvLyBzdGlja2llcyBjYW5ub3QgYmUgbW91bnRlZCBhdCB0aGUgcm91dGVyIGFuZCB0aGVyZWZvcmUgc2hvdWxkIG5vdFxuICAgICAgICAgIC8vIGdldCBhIGhyZWYgc2V0IG9uIHRoZW1cbiAgICAgICAgICBpZiAoIURPTS5pc1BoeFN0aWNreShyb290RWwpKSB7XG4gICAgICAgICAgICB2aWV3LnNldEhyZWYodGhpcy5nZXRIcmVmKCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB2aWV3LmpvaW4oKTtcbiAgICAgICAgICBpZiAocm9vdEVsLmhhc0F0dHJpYnV0ZShQSFhfTUFJTikpIHtcbiAgICAgICAgICAgIHRoaXMubWFpbiA9IHZpZXc7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJvb3RzRm91bmQgPSB0cnVlO1xuICAgICAgfSxcbiAgICApO1xuICAgIHJldHVybiByb290c0ZvdW5kO1xuICB9XG5cbiAgcmVkaXJlY3QodG8sIGZsYXNoLCByZWxvYWRUb2tlbikge1xuICAgIGlmIChyZWxvYWRUb2tlbikge1xuICAgICAgQnJvd3Nlci5zZXRDb29raWUoUEhYX1JFTE9BRF9TVEFUVVMsIHJlbG9hZFRva2VuLCA2MCk7XG4gICAgfVxuICAgIHRoaXMudW5sb2FkKCk7XG4gICAgQnJvd3Nlci5yZWRpcmVjdCh0bywgZmxhc2gpO1xuICB9XG5cbiAgcmVwbGFjZU1haW4oXG4gICAgaHJlZixcbiAgICBmbGFzaCxcbiAgICBjYWxsYmFjayA9IG51bGwsXG4gICAgbGlua1JlZiA9IHRoaXMuc2V0UGVuZGluZ0xpbmsoaHJlZiksXG4gICkge1xuICAgIGNvbnN0IGxpdmVSZWZlcmVyID0gdGhpcy5jdXJyZW50TG9jYXRpb24uaHJlZjtcbiAgICB0aGlzLm91dGdvaW5nTWFpbkVsID0gdGhpcy5vdXRnb2luZ01haW5FbCB8fCB0aGlzLm1haW4uZWw7XG5cbiAgICBjb25zdCBzdGlja2llcyA9IERPTS5maW5kUGh4U3RpY2t5KGRvY3VtZW50KSB8fCBbXTtcbiAgICBjb25zdCByZW1vdmVFbHMgPSBET00uYWxsKFxuICAgICAgdGhpcy5vdXRnb2luZ01haW5FbCxcbiAgICAgIGBbJHt0aGlzLmJpbmRpbmcoXCJyZW1vdmVcIil9XWAsXG4gICAgKS5maWx0ZXIoKGVsKSA9PiAhRE9NLmlzQ2hpbGRPZkFueShlbCwgc3RpY2tpZXMpKTtcblxuICAgIGNvbnN0IG5ld01haW5FbCA9IERPTS5jbG9uZU5vZGUodGhpcy5vdXRnb2luZ01haW5FbCwgXCJcIik7XG4gICAgdGhpcy5tYWluLnNob3dMb2FkZXIodGhpcy5sb2FkZXJUaW1lb3V0KTtcbiAgICB0aGlzLm1haW4uZGVzdHJveSgpO1xuXG4gICAgdGhpcy5tYWluID0gdGhpcy5uZXdSb290VmlldyhuZXdNYWluRWwsIGZsYXNoLCBsaXZlUmVmZXJlcik7XG4gICAgdGhpcy5tYWluLnNldFJlZGlyZWN0KGhyZWYpO1xuICAgIHRoaXMudHJhbnNpdGlvblJlbW92ZXMocmVtb3ZlRWxzKTtcbiAgICB0aGlzLm1haW4uam9pbigoam9pbkNvdW50LCBvbkRvbmUpID0+IHtcbiAgICAgIGlmIChqb2luQ291bnQgPT09IDEgJiYgdGhpcy5jb21taXRQZW5kaW5nTGluayhsaW5rUmVmKSkge1xuICAgICAgICB0aGlzLnJlcXVlc3RET01VcGRhdGUoKCkgPT4ge1xuICAgICAgICAgIC8vIHJlbW92ZSBwaHgtcmVtb3ZlIGVscyByaWdodCBiZWZvcmUgd2UgcmVwbGFjZSB0aGUgbWFpbiBlbGVtZW50XG4gICAgICAgICAgcmVtb3ZlRWxzLmZvckVhY2goKGVsKSA9PiBlbC5yZW1vdmUoKSk7XG4gICAgICAgICAgc3RpY2tpZXMuZm9yRWFjaCgoZWwpID0+IG5ld01haW5FbC5hcHBlbmRDaGlsZChlbCkpO1xuICAgICAgICAgIHRoaXMub3V0Z29pbmdNYWluRWwucmVwbGFjZVdpdGgobmV3TWFpbkVsKTtcbiAgICAgICAgICB0aGlzLm91dGdvaW5nTWFpbkVsID0gbnVsbDtcbiAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhsaW5rUmVmKTtcbiAgICAgICAgICBvbkRvbmUoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICB0cmFuc2l0aW9uUmVtb3ZlcyhlbGVtZW50cywgY2FsbGJhY2spIHtcbiAgICBjb25zdCByZW1vdmVBdHRyID0gdGhpcy5iaW5kaW5nKFwicmVtb3ZlXCIpO1xuICAgIGNvbnN0IHNpbGVuY2VFdmVudHMgPSAoZSkgPT4ge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICB9O1xuICAgIGVsZW1lbnRzLmZvckVhY2goKGVsKSA9PiB7XG4gICAgICAvLyBwcmV2ZW50IGFsbCBsaXN0ZW5lcnMgd2UgY2FyZSBhYm91dCBmcm9tIGJ1YmJsaW5nIHRvIHdpbmRvd1xuICAgICAgLy8gc2luY2Ugd2UgYXJlIHJlbW92aW5nIHRoZSBlbGVtZW50XG4gICAgICBmb3IgKGNvbnN0IGV2ZW50IG9mIHRoaXMuYm91bmRFdmVudE5hbWVzKSB7XG4gICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIHNpbGVuY2VFdmVudHMsIHRydWUpO1xuICAgICAgfVxuICAgICAgdGhpcy5leGVjSlMoZWwsIGVsLmdldEF0dHJpYnV0ZShyZW1vdmVBdHRyKSwgXCJyZW1vdmVcIik7XG4gICAgfSk7XG4gICAgLy8gcmVtb3ZlIHRoZSBzaWxlbmNlZCBsaXN0ZW5lcnMgd2hlbiB0cmFuc2l0aW9ucyBhcmUgZG9uZSBpbmNhc2UgdGhlIGVsZW1lbnQgaXMgcmUtdXNlZFxuICAgIC8vIGFuZCBjYWxsIGNhbGxlcidzIGNhbGxiYWNrIGFzIHNvb24gYXMgd2UgYXJlIGRvbmUgd2l0aCB0cmFuc2l0aW9uc1xuICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICBlbGVtZW50cy5mb3JFYWNoKChlbCkgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IGV2ZW50IG9mIHRoaXMuYm91bmRFdmVudE5hbWVzKSB7XG4gICAgICAgICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgc2lsZW5jZUV2ZW50cywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIGlzUGh4VmlldyhlbCkge1xuICAgIHJldHVybiBlbC5nZXRBdHRyaWJ1dGUgJiYgZWwuZ2V0QXR0cmlidXRlKFBIWF9TRVNTSU9OKSAhPT0gbnVsbDtcbiAgfVxuXG4gIG5ld1Jvb3RWaWV3KGVsLCBmbGFzaCwgbGl2ZVJlZmVyZXIpIHtcbiAgICBjb25zdCB2aWV3ID0gbmV3IFZpZXcoZWwsIHRoaXMsIG51bGwsIGZsYXNoLCBsaXZlUmVmZXJlcik7XG4gICAgdGhpcy5yb290c1t2aWV3LmlkXSA9IHZpZXc7XG4gICAgcmV0dXJuIHZpZXc7XG4gIH1cblxuICBvd25lcihjaGlsZEVsLCBjYWxsYmFjaykge1xuICAgIGxldCB2aWV3O1xuICAgIGNvbnN0IHZpZXdFbCA9IERPTS5jbG9zZXN0Vmlld0VsKGNoaWxkRWwpO1xuICAgIGlmICh2aWV3RWwpIHtcbiAgICAgIC8vIGl0IGNhbiBoYXBwZW4gdGhhdCB3ZSBmaW5kIGEgdmlldyB0aGF0IGlzIGFscmVhZHkgZGVzdHJveWVkO1xuICAgICAgLy8gaW4gdGhhdCBjYXNlIHdlIERPIE5PVCB3YW50IHRvIGZhbGxiYWNrIHRvIHRoZSBtYWluIGVsZW1lbnRcbiAgICAgIHZpZXcgPSB0aGlzLmdldFZpZXdCeUVsKHZpZXdFbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZpZXcgPSB0aGlzLm1haW47XG4gICAgfVxuICAgIHJldHVybiB2aWV3ICYmIGNhbGxiYWNrID8gY2FsbGJhY2sodmlldykgOiB2aWV3O1xuICB9XG5cbiAgd2l0aGluT3duZXJzKGNoaWxkRWwsIGNhbGxiYWNrKSB7XG4gICAgdGhpcy5vd25lcihjaGlsZEVsLCAodmlldykgPT4gY2FsbGJhY2sodmlldywgY2hpbGRFbCkpO1xuICB9XG5cbiAgZ2V0Vmlld0J5RWwoZWwpIHtcbiAgICBjb25zdCByb290SWQgPSBlbC5nZXRBdHRyaWJ1dGUoUEhYX1JPT1RfSUQpO1xuICAgIHJldHVybiBtYXliZSh0aGlzLmdldFJvb3RCeUlkKHJvb3RJZCksIChyb290KSA9PlxuICAgICAgcm9vdC5nZXREZXNjZW5kZW50QnlFbChlbCksXG4gICAgKTtcbiAgfVxuXG4gIGdldFJvb3RCeUlkKGlkKSB7XG4gICAgcmV0dXJuIHRoaXMucm9vdHNbaWRdO1xuICB9XG5cbiAgZGVzdHJveUFsbFZpZXdzKCkge1xuICAgIGZvciAoY29uc3QgaWQgaW4gdGhpcy5yb290cykge1xuICAgICAgdGhpcy5yb290c1tpZF0uZGVzdHJveSgpO1xuICAgICAgZGVsZXRlIHRoaXMucm9vdHNbaWRdO1xuICAgIH1cbiAgICB0aGlzLm1haW4gPSBudWxsO1xuICB9XG5cbiAgZGVzdHJveVZpZXdCeUVsKGVsKSB7XG4gICAgY29uc3Qgcm9vdCA9IHRoaXMuZ2V0Um9vdEJ5SWQoZWwuZ2V0QXR0cmlidXRlKFBIWF9ST09UX0lEKSk7XG4gICAgaWYgKHJvb3QgJiYgcm9vdC5pZCA9PT0gZWwuaWQpIHtcbiAgICAgIHJvb3QuZGVzdHJveSgpO1xuICAgICAgZGVsZXRlIHRoaXMucm9vdHNbcm9vdC5pZF07XG4gICAgfSBlbHNlIGlmIChyb290KSB7XG4gICAgICByb290LmRlc3Ryb3lEZXNjZW5kZW50KGVsLmlkKTtcbiAgICB9XG4gIH1cblxuICBnZXRBY3RpdmVFbGVtZW50KCkge1xuICAgIHJldHVybiBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuICB9XG5cbiAgZHJvcEFjdGl2ZUVsZW1lbnQodmlldykge1xuICAgIGlmICh0aGlzLnByZXZBY3RpdmUgJiYgdmlldy5vd25zRWxlbWVudCh0aGlzLnByZXZBY3RpdmUpKSB7XG4gICAgICB0aGlzLnByZXZBY3RpdmUgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHJlc3RvcmVQcmV2aW91c2x5QWN0aXZlRm9jdXMoKSB7XG4gICAgaWYgKFxuICAgICAgdGhpcy5wcmV2QWN0aXZlICYmXG4gICAgICB0aGlzLnByZXZBY3RpdmUgIT09IGRvY3VtZW50LmJvZHkgJiZcbiAgICAgIHRoaXMucHJldkFjdGl2ZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50XG4gICAgKSB7XG4gICAgICB0aGlzLnByZXZBY3RpdmUuZm9jdXMoKTtcbiAgICB9XG4gIH1cblxuICBibHVyQWN0aXZlRWxlbWVudCgpIHtcbiAgICB0aGlzLnByZXZBY3RpdmUgPSB0aGlzLmdldEFjdGl2ZUVsZW1lbnQoKTtcbiAgICBpZiAoXG4gICAgICB0aGlzLnByZXZBY3RpdmUgIT09IGRvY3VtZW50LmJvZHkgJiZcbiAgICAgIHRoaXMucHJldkFjdGl2ZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50XG4gICAgKSB7XG4gICAgICB0aGlzLnByZXZBY3RpdmUuYmx1cigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3tkZWFkPzogYm9vbGVhbn19IFtvcHRpb25zPXt9XVxuICAgKi9cbiAgYmluZFRvcExldmVsRXZlbnRzKHsgZGVhZCB9ID0ge30pIHtcbiAgICBpZiAodGhpcy5ib3VuZFRvcExldmVsRXZlbnRzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5ib3VuZFRvcExldmVsRXZlbnRzID0gdHJ1ZTtcbiAgICAvLyBlbnRlciBmYWlsc2FmZSByZWxvYWQgaWYgc2VydmVyIGhhcyBnb25lIGF3YXkgaW50ZW50aW9uYWxseSwgc3VjaCBhcyBcImRpc2Nvbm5lY3RcIiBicm9hZGNhc3RcbiAgICB0aGlzLnNlcnZlckNsb3NlUmVmID0gdGhpcy5zb2NrZXQub25DbG9zZSgoZXZlbnQpID0+IHtcbiAgICAgIC8vIGZhaWxzYWZlIHJlbG9hZCBpZiBub3JtYWwgY2xvc3VyZSBhbmQgd2Ugc3RpbGwgaGF2ZSBhIG1haW4gTFZcbiAgICAgIGlmIChldmVudCAmJiBldmVudC5jb2RlID09PSAxMDAwICYmIHRoaXMubWFpbikge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWxvYWRXaXRoSml0dGVyKHRoaXMubWFpbik7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgZnVuY3Rpb24gKCkge30pOyAvLyBlbnN1cmUgYWxsIGNsaWNrIGV2ZW50cyBidWJibGUgZm9yIG1vYmlsZSBTYWZhcmlcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIFwicGFnZXNob3dcIixcbiAgICAgIChlKSA9PiB7XG4gICAgICAgIGlmIChlLnBlcnNpc3RlZCkge1xuICAgICAgICAgIC8vIHJlbG9hZCBwYWdlIGlmIGJlaW5nIHJlc3RvcmVkIGZyb20gYmFjay9mb3J3YXJkIGNhY2hlXG4gICAgICAgICAgdGhpcy5nZXRTb2NrZXQoKS5kaXNjb25uZWN0KCk7XG4gICAgICAgICAgdGhpcy53aXRoUGFnZUxvYWRpbmcoeyB0bzogd2luZG93LmxvY2F0aW9uLmhyZWYsIGtpbmQ6IFwicmVkaXJlY3RcIiB9KTtcbiAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB0cnVlLFxuICAgICk7XG4gICAgaWYgKCFkZWFkKSB7XG4gICAgICB0aGlzLmJpbmROYXYoKTtcbiAgICB9XG4gICAgdGhpcy5iaW5kQ2xpY2tzKCk7XG4gICAgaWYgKCFkZWFkKSB7XG4gICAgICB0aGlzLmJpbmRGb3JtcygpO1xuICAgIH1cbiAgICB0aGlzLmJpbmQoXG4gICAgICB7IGtleXVwOiBcImtleXVwXCIsIGtleWRvd246IFwia2V5ZG93blwiIH0sXG4gICAgICAoZSwgdHlwZSwgdmlldywgdGFyZ2V0RWwsIHBoeEV2ZW50LCBfcGh4VGFyZ2V0KSA9PiB7XG4gICAgICAgIGNvbnN0IG1hdGNoS2V5ID0gdGFyZ2V0RWwuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfS0VZKSk7XG4gICAgICAgIGNvbnN0IHByZXNzZWRLZXkgPSBlLmtleSAmJiBlLmtleS50b0xvd2VyQ2FzZSgpOyAvLyBjaHJvbWUgY2xpY2tlZCBhdXRvY29tcGxldGVzIHNlbmQgYSBrZXlkb3duIHdpdGhvdXQga2V5XG4gICAgICAgIGlmIChtYXRjaEtleSAmJiBtYXRjaEtleS50b0xvd2VyQ2FzZSgpICE9PSBwcmVzc2VkS2V5KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGF0YSA9IHsga2V5OiBlLmtleSwgLi4udGhpcy5ldmVudE1ldGEodHlwZSwgZSwgdGFyZ2V0RWwpIH07XG4gICAgICAgIEpTLmV4ZWMoZSwgdHlwZSwgcGh4RXZlbnQsIHZpZXcsIHRhcmdldEVsLCBbXCJwdXNoXCIsIHsgZGF0YSB9XSk7XG4gICAgICB9LFxuICAgICk7XG4gICAgdGhpcy5iaW5kKFxuICAgICAgeyBibHVyOiBcImZvY3Vzb3V0XCIsIGZvY3VzOiBcImZvY3VzaW5cIiB9LFxuICAgICAgKGUsIHR5cGUsIHZpZXcsIHRhcmdldEVsLCBwaHhFdmVudCwgcGh4VGFyZ2V0KSA9PiB7XG4gICAgICAgIGlmICghcGh4VGFyZ2V0KSB7XG4gICAgICAgICAgY29uc3QgZGF0YSA9IHsga2V5OiBlLmtleSwgLi4udGhpcy5ldmVudE1ldGEodHlwZSwgZSwgdGFyZ2V0RWwpIH07XG4gICAgICAgICAgSlMuZXhlYyhlLCB0eXBlLCBwaHhFdmVudCwgdmlldywgdGFyZ2V0RWwsIFtcInB1c2hcIiwgeyBkYXRhIH1dKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICAgIHRoaXMuYmluZChcbiAgICAgIHsgYmx1cjogXCJibHVyXCIsIGZvY3VzOiBcImZvY3VzXCIgfSxcbiAgICAgIChlLCB0eXBlLCB2aWV3LCB0YXJnZXRFbCwgcGh4RXZlbnQsIHBoeFRhcmdldCkgPT4ge1xuICAgICAgICAvLyBibHVyIGFuZCBmb2N1cyBhcmUgdHJpZ2dlcmVkIG9uIGRvY3VtZW50IGFuZCB3aW5kb3cuIERpc2NhcmQgb25lIHRvIGF2b2lkIGR1cHNcbiAgICAgICAgaWYgKHBoeFRhcmdldCA9PT0gXCJ3aW5kb3dcIikge1xuICAgICAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLmV2ZW50TWV0YSh0eXBlLCBlLCB0YXJnZXRFbCk7XG4gICAgICAgICAgSlMuZXhlYyhlLCB0eXBlLCBwaHhFdmVudCwgdmlldywgdGFyZ2V0RWwsIFtcInB1c2hcIiwgeyBkYXRhIH1dKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICAgIHRoaXMub24oXCJkcmFnb3ZlclwiLCAoZSkgPT4gZS5wcmV2ZW50RGVmYXVsdCgpKTtcbiAgICB0aGlzLm9uKFwiZHJvcFwiLCAoZSkgPT4ge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgY29uc3QgZHJvcFRhcmdldElkID0gbWF5YmUoXG4gICAgICAgIGNsb3Nlc3RQaHhCaW5kaW5nKGUudGFyZ2V0LCB0aGlzLmJpbmRpbmcoUEhYX0RST1BfVEFSR0VUKSksXG4gICAgICAgICh0cnVlVGFyZ2V0KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHRydWVUYXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhQSFhfRFJPUF9UQVJHRVQpKTtcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICBjb25zdCBkcm9wVGFyZ2V0ID0gZHJvcFRhcmdldElkICYmIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRyb3BUYXJnZXRJZCk7XG4gICAgICBjb25zdCBmaWxlcyA9IEFycmF5LmZyb20oZS5kYXRhVHJhbnNmZXIuZmlsZXMgfHwgW10pO1xuICAgICAgaWYgKFxuICAgICAgICAhZHJvcFRhcmdldCB8fFxuICAgICAgICAhKGRyb3BUYXJnZXQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50KSB8fFxuICAgICAgICBkcm9wVGFyZ2V0LmRpc2FibGVkIHx8XG4gICAgICAgIGZpbGVzLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgICAhKGRyb3BUYXJnZXQuZmlsZXMgaW5zdGFuY2VvZiBGaWxlTGlzdClcbiAgICAgICkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIExpdmVVcGxvYWRlci50cmFja0ZpbGVzKGRyb3BUYXJnZXQsIGZpbGVzLCBlLmRhdGFUcmFuc2Zlcik7XG4gICAgICBkcm9wVGFyZ2V0LmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KFwiaW5wdXRcIiwgeyBidWJibGVzOiB0cnVlIH0pKTtcbiAgICB9KTtcbiAgICB0aGlzLm9uKFBIWF9UUkFDS19VUExPQURTLCAoZSkgPT4ge1xuICAgICAgY29uc3QgdXBsb2FkVGFyZ2V0ID0gZS50YXJnZXQ7XG4gICAgICBpZiAoIURPTS5pc1VwbG9hZElucHV0KHVwbG9hZFRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgZmlsZXMgPSBBcnJheS5mcm9tKGUuZGV0YWlsLmZpbGVzIHx8IFtdKS5maWx0ZXIoXG4gICAgICAgIChmKSA9PiBmIGluc3RhbmNlb2YgRmlsZSB8fCBmIGluc3RhbmNlb2YgQmxvYixcbiAgICAgICk7XG4gICAgICBMaXZlVXBsb2FkZXIudHJhY2tGaWxlcyh1cGxvYWRUYXJnZXQsIGZpbGVzKTtcbiAgICAgIHVwbG9hZFRhcmdldC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudChcImlucHV0XCIsIHsgYnViYmxlczogdHJ1ZSB9KSk7XG4gICAgfSk7XG4gIH1cblxuICBldmVudE1ldGEoZXZlbnROYW1lLCBlLCB0YXJnZXRFbCkge1xuICAgIGNvbnN0IGNhbGxiYWNrID0gdGhpcy5tZXRhZGF0YUNhbGxiYWNrc1tldmVudE5hbWVdO1xuICAgIHJldHVybiBjYWxsYmFjayA/IGNhbGxiYWNrKGUsIHRhcmdldEVsKSA6IHt9O1xuICB9XG5cbiAgc2V0UGVuZGluZ0xpbmsoaHJlZikge1xuICAgIHRoaXMubGlua1JlZisrO1xuICAgIHRoaXMucGVuZGluZ0xpbmsgPSBocmVmO1xuICAgIHRoaXMucmVzZXRSZWxvYWRTdGF0dXMoKTtcbiAgICByZXR1cm4gdGhpcy5saW5rUmVmO1xuICB9XG5cbiAgLy8gYW55dGltZSB3ZSBhcmUgbmF2aWdhdGluZyBvciBjb25uZWN0aW5nLCBkcm9wIHJlbG9hZCBjb29raWUgaW4gY2FzZVxuICAvLyB3ZSBpc3N1ZSB0aGUgY29va2llIGJ1dCB0aGUgbmV4dCByZXF1ZXN0IHdhcyBpbnRlcnJ1cHRlZCBhbmQgdGhlIHNlcnZlciBuZXZlciBkcm9wcGVkIGl0XG4gIHJlc2V0UmVsb2FkU3RhdHVzKCkge1xuICAgIEJyb3dzZXIuZGVsZXRlQ29va2llKFBIWF9SRUxPQURfU1RBVFVTKTtcbiAgfVxuXG4gIGNvbW1pdFBlbmRpbmdMaW5rKGxpbmtSZWYpIHtcbiAgICBpZiAodGhpcy5saW5rUmVmICE9PSBsaW5rUmVmKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaHJlZiA9IHRoaXMucGVuZGluZ0xpbms7XG4gICAgICB0aGlzLnBlbmRpbmdMaW5rID0gbnVsbDtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIGdldEhyZWYoKSB7XG4gICAgcmV0dXJuIHRoaXMuaHJlZjtcbiAgfVxuXG4gIGhhc1BlbmRpbmdMaW5rKCkge1xuICAgIHJldHVybiAhIXRoaXMucGVuZGluZ0xpbms7XG4gIH1cblxuICBiaW5kKGV2ZW50cywgY2FsbGJhY2spIHtcbiAgICBmb3IgKGNvbnN0IGV2ZW50IGluIGV2ZW50cykge1xuICAgICAgY29uc3QgYnJvd3NlckV2ZW50TmFtZSA9IGV2ZW50c1tldmVudF07XG5cbiAgICAgIHRoaXMub24oYnJvd3NlckV2ZW50TmFtZSwgKGUpID0+IHtcbiAgICAgICAgY29uc3QgYmluZGluZyA9IHRoaXMuYmluZGluZyhldmVudCk7XG4gICAgICAgIGNvbnN0IHdpbmRvd0JpbmRpbmcgPSB0aGlzLmJpbmRpbmcoYHdpbmRvdy0ke2V2ZW50fWApO1xuICAgICAgICBjb25zdCB0YXJnZXRQaHhFdmVudCA9XG4gICAgICAgICAgZS50YXJnZXQuZ2V0QXR0cmlidXRlICYmIGUudGFyZ2V0LmdldEF0dHJpYnV0ZShiaW5kaW5nKTtcbiAgICAgICAgaWYgKHRhcmdldFBoeEV2ZW50KSB7XG4gICAgICAgICAgdGhpcy5kZWJvdW5jZShlLnRhcmdldCwgZSwgYnJvd3NlckV2ZW50TmFtZSwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy53aXRoaW5Pd25lcnMoZS50YXJnZXQsICh2aWV3KSA9PiB7XG4gICAgICAgICAgICAgIGNhbGxiYWNrKGUsIGV2ZW50LCB2aWV3LCBlLnRhcmdldCwgdGFyZ2V0UGh4RXZlbnQsIG51bGwpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgRE9NLmFsbChkb2N1bWVudCwgYFske3dpbmRvd0JpbmRpbmd9XWAsIChlbCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGh4RXZlbnQgPSBlbC5nZXRBdHRyaWJ1dGUod2luZG93QmluZGluZyk7XG4gICAgICAgICAgICB0aGlzLmRlYm91bmNlKGVsLCBlLCBicm93c2VyRXZlbnROYW1lLCAoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMud2l0aGluT3duZXJzKGVsLCAodmlldykgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGUsIGV2ZW50LCB2aWV3LCBlbCwgcGh4RXZlbnQsIFwid2luZG93XCIpO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBiaW5kQ2xpY2tzKCkge1xuICAgIHRoaXMub24oXCJtb3VzZWRvd25cIiwgKGUpID0+ICh0aGlzLmNsaWNrU3RhcnRlZEF0VGFyZ2V0ID0gZS50YXJnZXQpKTtcbiAgICB0aGlzLmJpbmRDbGljayhcImNsaWNrXCIsIFwiY2xpY2tcIik7XG4gIH1cblxuICBiaW5kQ2xpY2soZXZlbnROYW1lLCBiaW5kaW5nTmFtZSkge1xuICAgIGNvbnN0IGNsaWNrID0gdGhpcy5iaW5kaW5nKGJpbmRpbmdOYW1lKTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIGV2ZW50TmFtZSxcbiAgICAgIChlKSA9PiB7XG4gICAgICAgIGxldCB0YXJnZXQgPSBudWxsO1xuICAgICAgICAvLyBhIHN5bnRoZXRpYyBjbGljayBldmVudCAoZGV0YWlsIDApIHdpbGwgbm90IGhhdmUgY2F1c2VkIGEgbW91c2Vkb3duIGV2ZW50LFxuICAgICAgICAvLyB0aGVyZWZvcmUgdGhlIGNsaWNrU3RhcnRlZEF0VGFyZ2V0IGlzIHN0YWxlXG4gICAgICAgIGlmIChlLmRldGFpbCA9PT0gMCkgdGhpcy5jbGlja1N0YXJ0ZWRBdFRhcmdldCA9IGUudGFyZ2V0O1xuICAgICAgICBjb25zdCBjbGlja1N0YXJ0ZWRBdFRhcmdldCA9IHRoaXMuY2xpY2tTdGFydGVkQXRUYXJnZXQgfHwgZS50YXJnZXQ7XG4gICAgICAgIC8vIHdoZW4gc2VhcmNoaW5nIHRoZSB0YXJnZXQgZm9yIHRoZSBjbGljayBldmVudCwgd2UgYWx3YXlzIHdhbnQgdG9cbiAgICAgICAgLy8gdXNlIHRoZSBhY3R1YWwgZXZlbnQgdGFyZ2V0LCBzZWUgIzMzNzJcbiAgICAgICAgdGFyZ2V0ID0gY2xvc2VzdFBoeEJpbmRpbmcoZS50YXJnZXQsIGNsaWNrKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaENsaWNrQXdheShlLCBjbGlja1N0YXJ0ZWRBdFRhcmdldCk7XG4gICAgICAgIHRoaXMuY2xpY2tTdGFydGVkQXRUYXJnZXQgPSBudWxsO1xuICAgICAgICBjb25zdCBwaHhFdmVudCA9IHRhcmdldCAmJiB0YXJnZXQuZ2V0QXR0cmlidXRlKGNsaWNrKTtcbiAgICAgICAgaWYgKCFwaHhFdmVudCkge1xuICAgICAgICAgIGlmIChET00uaXNOZXdQYWdlQ2xpY2soZSwgd2luZG93LmxvY2F0aW9uKSkge1xuICAgICAgICAgICAgdGhpcy51bmxvYWQoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRhcmdldC5nZXRBdHRyaWJ1dGUoXCJocmVmXCIpID09PSBcIiNcIikge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG5vb3AgaWYgd2UgYXJlIGluIHRoZSBtaWRkbGUgb2YgYXdhaXRpbmcgYW4gYWNrIGZvciB0aGlzIGVsIGFscmVhZHlcbiAgICAgICAgaWYgKHRhcmdldC5oYXNBdHRyaWJ1dGUoUEhYX1JFRl9TUkMpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5kZWJvdW5jZSh0YXJnZXQsIGUsIFwiY2xpY2tcIiwgKCkgPT4ge1xuICAgICAgICAgIHRoaXMud2l0aGluT3duZXJzKHRhcmdldCwgKHZpZXcpID0+IHtcbiAgICAgICAgICAgIEpTLmV4ZWMoZSwgXCJjbGlja1wiLCBwaHhFdmVudCwgdmlldywgdGFyZ2V0LCBbXG4gICAgICAgICAgICAgIFwicHVzaFwiLFxuICAgICAgICAgICAgICB7IGRhdGE6IHRoaXMuZXZlbnRNZXRhKFwiY2xpY2tcIiwgZSwgdGFyZ2V0KSB9LFxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIGZhbHNlLFxuICAgICk7XG4gIH1cblxuICBkaXNwYXRjaENsaWNrQXdheShlLCBjbGlja1N0YXJ0ZWRBdCkge1xuICAgIGNvbnN0IHBoeENsaWNrQXdheSA9IHRoaXMuYmluZGluZyhcImNsaWNrLWF3YXlcIik7XG4gICAgRE9NLmFsbChkb2N1bWVudCwgYFske3BoeENsaWNrQXdheX1dYCwgKGVsKSA9PiB7XG4gICAgICBpZiAoIShlbC5pc1NhbWVOb2RlKGNsaWNrU3RhcnRlZEF0KSB8fCBlbC5jb250YWlucyhjbGlja1N0YXJ0ZWRBdCkpKSB7XG4gICAgICAgIHRoaXMud2l0aGluT3duZXJzKGVsLCAodmlldykgPT4ge1xuICAgICAgICAgIGNvbnN0IHBoeEV2ZW50ID0gZWwuZ2V0QXR0cmlidXRlKHBoeENsaWNrQXdheSk7XG4gICAgICAgICAgaWYgKEpTLmlzVmlzaWJsZShlbCkgJiYgSlMuaXNJblZpZXdwb3J0KGVsKSkge1xuICAgICAgICAgICAgSlMuZXhlYyhlLCBcImNsaWNrXCIsIHBoeEV2ZW50LCB2aWV3LCBlbCwgW1xuICAgICAgICAgICAgICBcInB1c2hcIixcbiAgICAgICAgICAgICAgeyBkYXRhOiB0aGlzLmV2ZW50TWV0YShcImNsaWNrXCIsIGUsIGUudGFyZ2V0KSB9LFxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGJpbmROYXYoKSB7XG4gICAgaWYgKCFCcm93c2VyLmNhblB1c2hTdGF0ZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uKSB7XG4gICAgICBoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uID0gXCJtYW51YWxcIjtcbiAgICB9XG4gICAgbGV0IHNjcm9sbFRpbWVyID0gbnVsbDtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCAoX2UpID0+IHtcbiAgICAgIGNsZWFyVGltZW91dChzY3JvbGxUaW1lcik7XG4gICAgICBzY3JvbGxUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBCcm93c2VyLnVwZGF0ZUN1cnJlbnRTdGF0ZSgoc3RhdGUpID0+XG4gICAgICAgICAgT2JqZWN0LmFzc2lnbihzdGF0ZSwgeyBzY3JvbGw6IHdpbmRvdy5zY3JvbGxZIH0pLFxuICAgICAgICApO1xuICAgICAgfSwgMTAwKTtcbiAgICB9KTtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgIFwicG9wc3RhdGVcIixcbiAgICAgIChldmVudCkgPT4ge1xuICAgICAgICBpZiAoIXRoaXMucmVnaXN0ZXJOZXdMb2NhdGlvbih3aW5kb3cubG9jYXRpb24pKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYmFja1R5cGUsIGlkLCBzY3JvbGwsIHBvc2l0aW9uIH0gPSBldmVudC5zdGF0ZSB8fCB7fTtcbiAgICAgICAgY29uc3QgaHJlZiA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmO1xuXG4gICAgICAgIC8vIENvbXBhcmUgcG9zaXRpb25zIHRvIGRldGVybWluZSBkaXJlY3Rpb25cbiAgICAgICAgY29uc3QgaXNGb3J3YXJkID0gcG9zaXRpb24gPiB0aGlzLmN1cnJlbnRIaXN0b3J5UG9zaXRpb247XG4gICAgICAgIGNvbnN0IG5hdlR5cGUgPSBpc0ZvcndhcmQgPyB0eXBlIDogYmFja1R5cGUgfHwgdHlwZTtcblxuICAgICAgICAvLyBVcGRhdGUgY3VycmVudCBwb3NpdGlvblxuICAgICAgICB0aGlzLmN1cnJlbnRIaXN0b3J5UG9zaXRpb24gPSBwb3NpdGlvbiB8fCAwO1xuICAgICAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oXG4gICAgICAgICAgUEhYX0xWX0hJU1RPUllfUE9TSVRJT04sXG4gICAgICAgICAgdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICk7XG5cbiAgICAgICAgRE9NLmRpc3BhdGNoRXZlbnQod2luZG93LCBcInBoeDpuYXZpZ2F0ZVwiLCB7XG4gICAgICAgICAgZGV0YWlsOiB7XG4gICAgICAgICAgICBocmVmLFxuICAgICAgICAgICAgcGF0Y2g6IG5hdlR5cGUgPT09IFwicGF0Y2hcIixcbiAgICAgICAgICAgIHBvcDogdHJ1ZSxcbiAgICAgICAgICAgIGRpcmVjdGlvbjogaXNGb3J3YXJkID8gXCJmb3J3YXJkXCIgOiBcImJhY2t3YXJkXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgY29uc3QgY2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1heWJlU2Nyb2xsKHNjcm9sbCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLm1haW4uaXNDb25uZWN0ZWQoKSAmJlxuICAgICAgICAgICAgbmF2VHlwZSA9PT0gXCJwYXRjaFwiICYmXG4gICAgICAgICAgICBpZCA9PT0gdGhpcy5tYWluLmlkXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLm1haW4ucHVzaExpbmtQYXRjaChldmVudCwgaHJlZiwgbnVsbCwgY2FsbGJhY2spO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnJlcGxhY2VNYWluKGhyZWYsIG51bGwsIGNhbGxiYWNrKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIGZhbHNlLFxuICAgICk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICBcImNsaWNrXCIsXG4gICAgICAoZSkgPT4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBjbG9zZXN0UGh4QmluZGluZyhlLnRhcmdldCwgUEhYX0xJVkVfTElOSyk7XG4gICAgICAgIGNvbnN0IHR5cGUgPSB0YXJnZXQgJiYgdGFyZ2V0LmdldEF0dHJpYnV0ZShQSFhfTElWRV9MSU5LKTtcbiAgICAgICAgaWYgKCF0eXBlIHx8ICF0aGlzLmlzQ29ubmVjdGVkKCkgfHwgIXRoaXMubWFpbiB8fCBET00ud2FudHNOZXdUYWIoZSkpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBXaGVuIHdyYXBwaW5nIGFuIFNWRyBlbGVtZW50IGluIGFuIGFuY2hvciB0YWcsIHRoZSBocmVmIGNhbiBiZSBhbiBTVkdBbmltYXRlZFN0cmluZ1xuICAgICAgICBjb25zdCBocmVmID1cbiAgICAgICAgICB0YXJnZXQuaHJlZiBpbnN0YW5jZW9mIFNWR0FuaW1hdGVkU3RyaW5nXG4gICAgICAgICAgICA/IHRhcmdldC5ocmVmLmJhc2VWYWxcbiAgICAgICAgICAgIDogdGFyZ2V0LmhyZWY7XG5cbiAgICAgICAgY29uc3QgbGlua1N0YXRlID0gdGFyZ2V0LmdldEF0dHJpYnV0ZShQSFhfTElOS19TVEFURSk7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTsgLy8gZG8gbm90IGJ1YmJsZSBjbGljayB0byByZWd1bGFyIHBoeC1jbGljayBiaW5kaW5nc1xuICAgICAgICBpZiAodGhpcy5wZW5kaW5nTGluayA9PT0gaHJlZikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVxdWVzdERPTVVwZGF0ZSgoKSA9PiB7XG4gICAgICAgICAgaWYgKHR5cGUgPT09IFwicGF0Y2hcIikge1xuICAgICAgICAgICAgdGhpcy5wdXNoSGlzdG9yeVBhdGNoKGUsIGhyZWYsIGxpbmtTdGF0ZSwgdGFyZ2V0KTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHR5cGUgPT09IFwicmVkaXJlY3RcIikge1xuICAgICAgICAgICAgdGhpcy5oaXN0b3J5UmVkaXJlY3QoZSwgaHJlZiwgbGlua1N0YXRlLCBudWxsLCB0YXJnZXQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgIGBleHBlY3RlZCAke1BIWF9MSVZFX0xJTkt9IHRvIGJlIFwicGF0Y2hcIiBvciBcInJlZGlyZWN0XCIsIGdvdDogJHt0eXBlfWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBwaHhDbGljayA9IHRhcmdldC5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwiY2xpY2tcIikpO1xuICAgICAgICAgIGlmIChwaHhDbGljaykge1xuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0RE9NVXBkYXRlKCgpID0+IHRoaXMuZXhlY0pTKHRhcmdldCwgcGh4Q2xpY2ssIFwiY2xpY2tcIikpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgICAgZmFsc2UsXG4gICAgKTtcbiAgfVxuXG4gIG1heWJlU2Nyb2xsKHNjcm9sbCkge1xuICAgIGlmICh0eXBlb2Ygc2Nyb2xsID09PSBcIm51bWJlclwiKSB7XG4gICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICB3aW5kb3cuc2Nyb2xsVG8oMCwgc2Nyb2xsKTtcbiAgICAgIH0pOyAvLyB0aGUgYm9keSBuZWVkcyB0byByZW5kZXIgYmVmb3JlIHdlIHNjcm9sbC5cbiAgICB9XG4gIH1cblxuICBkaXNwYXRjaEV2ZW50KGV2ZW50LCBwYXlsb2FkID0ge30pIHtcbiAgICBET00uZGlzcGF0Y2hFdmVudCh3aW5kb3csIGBwaHg6JHtldmVudH1gLCB7IGRldGFpbDogcGF5bG9hZCB9KTtcbiAgfVxuXG4gIGRpc3BhdGNoRXZlbnRzKGV2ZW50cykge1xuICAgIGV2ZW50cy5mb3JFYWNoKChbZXZlbnQsIHBheWxvYWRdKSA9PiB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQsIHBheWxvYWQpKTtcbiAgfVxuXG4gIHdpdGhQYWdlTG9hZGluZyhpbmZvLCBjYWxsYmFjaykge1xuICAgIERPTS5kaXNwYXRjaEV2ZW50KHdpbmRvdywgXCJwaHg6cGFnZS1sb2FkaW5nLXN0YXJ0XCIsIHsgZGV0YWlsOiBpbmZvIH0pO1xuICAgIGNvbnN0IGRvbmUgPSAoKSA9PlxuICAgICAgRE9NLmRpc3BhdGNoRXZlbnQod2luZG93LCBcInBoeDpwYWdlLWxvYWRpbmctc3RvcFwiLCB7IGRldGFpbDogaW5mbyB9KTtcbiAgICByZXR1cm4gY2FsbGJhY2sgPyBjYWxsYmFjayhkb25lKSA6IGRvbmU7XG4gIH1cblxuICBwdXNoSGlzdG9yeVBhdGNoKGUsIGhyZWYsIGxpbmtTdGF0ZSwgdGFyZ2V0RWwpIHtcbiAgICBpZiAoIXRoaXMuaXNDb25uZWN0ZWQoKSB8fCAhdGhpcy5tYWluLmlzTWFpbigpKSB7XG4gICAgICByZXR1cm4gQnJvd3Nlci5yZWRpcmVjdChocmVmKTtcbiAgICB9XG5cbiAgICB0aGlzLndpdGhQYWdlTG9hZGluZyh7IHRvOiBocmVmLCBraW5kOiBcInBhdGNoXCIgfSwgKGRvbmUpID0+IHtcbiAgICAgIHRoaXMubWFpbi5wdXNoTGlua1BhdGNoKGUsIGhyZWYsIHRhcmdldEVsLCAobGlua1JlZikgPT4ge1xuICAgICAgICB0aGlzLmhpc3RvcnlQYXRjaChocmVmLCBsaW5rU3RhdGUsIGxpbmtSZWYpO1xuICAgICAgICBkb25lKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGhpc3RvcnlQYXRjaChocmVmLCBsaW5rU3RhdGUsIGxpbmtSZWYgPSB0aGlzLnNldFBlbmRpbmdMaW5rKGhyZWYpKSB7XG4gICAgaWYgKCF0aGlzLmNvbW1pdFBlbmRpbmdMaW5rKGxpbmtSZWYpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSW5jcmVtZW50IHBvc2l0aW9uIGZvciBuZXcgc3RhdGVcbiAgICB0aGlzLmN1cnJlbnRIaXN0b3J5UG9zaXRpb24rKztcbiAgICB0aGlzLnNlc3Npb25TdG9yYWdlLnNldEl0ZW0oXG4gICAgICBQSFhfTFZfSElTVE9SWV9QT1NJVElPTixcbiAgICAgIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbi50b1N0cmluZygpLFxuICAgICk7XG5cbiAgICAvLyBzdG9yZSB0aGUgdHlwZSBmb3IgYmFjayBuYXZpZ2F0aW9uXG4gICAgQnJvd3Nlci51cGRhdGVDdXJyZW50U3RhdGUoKHN0YXRlKSA9PiAoeyAuLi5zdGF0ZSwgYmFja1R5cGU6IFwicGF0Y2hcIiB9KSk7XG5cbiAgICBCcm93c2VyLnB1c2hTdGF0ZShcbiAgICAgIGxpbmtTdGF0ZSxcbiAgICAgIHtcbiAgICAgICAgdHlwZTogXCJwYXRjaFwiLFxuICAgICAgICBpZDogdGhpcy5tYWluLmlkLFxuICAgICAgICBwb3NpdGlvbjogdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uLFxuICAgICAgfSxcbiAgICAgIGhyZWYsXG4gICAgKTtcblxuICAgIERPTS5kaXNwYXRjaEV2ZW50KHdpbmRvdywgXCJwaHg6bmF2aWdhdGVcIiwge1xuICAgICAgZGV0YWlsOiB7IHBhdGNoOiB0cnVlLCBocmVmLCBwb3A6IGZhbHNlLCBkaXJlY3Rpb246IFwiZm9yd2FyZFwiIH0sXG4gICAgfSk7XG4gICAgdGhpcy5yZWdpc3Rlck5ld0xvY2F0aW9uKHdpbmRvdy5sb2NhdGlvbik7XG4gIH1cblxuICBoaXN0b3J5UmVkaXJlY3QoZSwgaHJlZiwgbGlua1N0YXRlLCBmbGFzaCwgdGFyZ2V0RWwpIHtcbiAgICBjb25zdCBjbGlja0xvYWRpbmcgPSB0YXJnZXRFbCAmJiBlLmlzVHJ1c3RlZCAmJiBlLnR5cGUgIT09IFwicG9wc3RhdGVcIjtcbiAgICBpZiAoY2xpY2tMb2FkaW5nKSB7XG4gICAgICB0YXJnZXRFbC5jbGFzc0xpc3QuYWRkKFwicGh4LWNsaWNrLWxvYWRpbmdcIik7XG4gICAgfVxuICAgIGlmICghdGhpcy5pc0Nvbm5lY3RlZCgpIHx8ICF0aGlzLm1haW4uaXNNYWluKCkpIHtcbiAgICAgIHJldHVybiBCcm93c2VyLnJlZGlyZWN0KGhyZWYsIGZsYXNoKTtcbiAgICB9XG5cbiAgICAvLyBjb252ZXJ0IHRvIGZ1bGwgaHJlZiBpZiBvbmx5IHBhdGggcHJlZml4XG4gICAgaWYgKC9eXFwvJHxeXFwvW15cXC9dKy4qJC8udGVzdChocmVmKSkge1xuICAgICAgY29uc3QgeyBwcm90b2NvbCwgaG9zdCB9ID0gd2luZG93LmxvY2F0aW9uO1xuICAgICAgaHJlZiA9IGAke3Byb3RvY29sfS8vJHtob3N0fSR7aHJlZn1gO1xuICAgIH1cbiAgICBjb25zdCBzY3JvbGwgPSB3aW5kb3cuc2Nyb2xsWTtcbiAgICB0aGlzLndpdGhQYWdlTG9hZGluZyh7IHRvOiBocmVmLCBraW5kOiBcInJlZGlyZWN0XCIgfSwgKGRvbmUpID0+IHtcbiAgICAgIHRoaXMucmVwbGFjZU1haW4oaHJlZiwgZmxhc2gsIChsaW5rUmVmKSA9PiB7XG4gICAgICAgIGlmIChsaW5rUmVmID09PSB0aGlzLmxpbmtSZWYpIHtcbiAgICAgICAgICAvLyBJbmNyZW1lbnQgcG9zaXRpb24gZm9yIG5ldyBzdGF0ZVxuICAgICAgICAgIHRoaXMuY3VycmVudEhpc3RvcnlQb3NpdGlvbisrO1xuICAgICAgICAgIHRoaXMuc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShcbiAgICAgICAgICAgIFBIWF9MVl9ISVNUT1JZX1BPU0lUSU9OLFxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SGlzdG9yeVBvc2l0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIHN0b3JlIHRoZSB0eXBlIGZvciBiYWNrIG5hdmlnYXRpb25cbiAgICAgICAgICBCcm93c2VyLnVwZGF0ZUN1cnJlbnRTdGF0ZSgoc3RhdGUpID0+ICh7XG4gICAgICAgICAgICAuLi5zdGF0ZSxcbiAgICAgICAgICAgIGJhY2tUeXBlOiBcInJlZGlyZWN0XCIsXG4gICAgICAgICAgfSkpO1xuXG4gICAgICAgICAgQnJvd3Nlci5wdXNoU3RhdGUoXG4gICAgICAgICAgICBsaW5rU3RhdGUsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHR5cGU6IFwicmVkaXJlY3RcIixcbiAgICAgICAgICAgICAgaWQ6IHRoaXMubWFpbi5pZCxcbiAgICAgICAgICAgICAgc2Nyb2xsOiBzY3JvbGwsXG4gICAgICAgICAgICAgIHBvc2l0aW9uOiB0aGlzLmN1cnJlbnRIaXN0b3J5UG9zaXRpb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgaHJlZixcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgRE9NLmRpc3BhdGNoRXZlbnQod2luZG93LCBcInBoeDpuYXZpZ2F0ZVwiLCB7XG4gICAgICAgICAgICBkZXRhaWw6IHsgaHJlZiwgcGF0Y2g6IGZhbHNlLCBwb3A6IGZhbHNlLCBkaXJlY3Rpb246IFwiZm9yd2FyZFwiIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy5yZWdpc3Rlck5ld0xvY2F0aW9uKHdpbmRvdy5sb2NhdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZXhwbGljaXRseSB1bmRvIGNsaWNrLWxvYWRpbmcgY2xhc3NcbiAgICAgICAgLy8gKGluIGNhc2UgaXQgb3JpZ2luYXRlZCBpbiBhIHN0aWNreSBsaXZlIHZpZXcsIG90aGVyd2lzZSBpdCB3b3VsZCBiZSByZW1vdmVkIGFueXdheSlcbiAgICAgICAgaWYgKGNsaWNrTG9hZGluZykge1xuICAgICAgICAgIHRhcmdldEVsLmNsYXNzTGlzdC5yZW1vdmUoXCJwaHgtY2xpY2stbG9hZGluZ1wiKTtcbiAgICAgICAgfVxuICAgICAgICBkb25lKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHJlZ2lzdGVyTmV3TG9jYXRpb24obmV3TG9jYXRpb24pIHtcbiAgICBjb25zdCB7IHBhdGhuYW1lLCBzZWFyY2ggfSA9IHRoaXMuY3VycmVudExvY2F0aW9uO1xuICAgIGlmIChwYXRobmFtZSArIHNlYXJjaCA9PT0gbmV3TG9jYXRpb24ucGF0aG5hbWUgKyBuZXdMb2NhdGlvbi5zZWFyY2gpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jdXJyZW50TG9jYXRpb24gPSBjbG9uZShuZXdMb2NhdGlvbik7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICBiaW5kRm9ybXMoKSB7XG4gICAgbGV0IGl0ZXJhdGlvbnMgPSAwO1xuICAgIGxldCBleHRlcm5hbEZvcm1TdWJtaXR0ZWQgPSBmYWxzZTtcblxuICAgIC8vIGRpc2FibGUgZm9ybXMgb24gc3VibWl0IHRoYXQgdHJhY2sgcGh4LWNoYW5nZSBidXQgcGVyZm9ybSBleHRlcm5hbCBzdWJtaXRcbiAgICB0aGlzLm9uKFwic3VibWl0XCIsIChlKSA9PiB7XG4gICAgICBjb25zdCBwaHhTdWJtaXQgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUodGhpcy5iaW5kaW5nKFwic3VibWl0XCIpKTtcbiAgICAgIGNvbnN0IHBoeENoYW5nZSA9IGUudGFyZ2V0LmdldEF0dHJpYnV0ZSh0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIikpO1xuICAgICAgaWYgKCFleHRlcm5hbEZvcm1TdWJtaXR0ZWQgJiYgcGh4Q2hhbmdlICYmICFwaHhTdWJtaXQpIHtcbiAgICAgICAgZXh0ZXJuYWxGb3JtU3VibWl0dGVkID0gdHJ1ZTtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLndpdGhpbk93bmVycyhlLnRhcmdldCwgKHZpZXcpID0+IHtcbiAgICAgICAgICB2aWV3LmRpc2FibGVGb3JtKGUudGFyZ2V0KTtcbiAgICAgICAgICAvLyBzYWZhcmkgbmVlZHMgbmV4dCB0aWNrXG4gICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICAgICAgICBpZiAoRE9NLmlzVW5sb2FkYWJsZUZvcm1TdWJtaXQoZSkpIHtcbiAgICAgICAgICAgICAgdGhpcy51bmxvYWQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGUudGFyZ2V0LnN1Ym1pdCgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMub24oXCJzdWJtaXRcIiwgKGUpID0+IHtcbiAgICAgIGNvbnN0IHBoeEV2ZW50ID0gZS50YXJnZXQuZ2V0QXR0cmlidXRlKHRoaXMuYmluZGluZyhcInN1Ym1pdFwiKSk7XG4gICAgICBpZiAoIXBoeEV2ZW50KSB7XG4gICAgICAgIGlmIChET00uaXNVbmxvYWRhYmxlRm9ybVN1Ym1pdChlKSkge1xuICAgICAgICAgIHRoaXMudW5sb2FkKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgZS50YXJnZXQuZGlzYWJsZWQgPSB0cnVlO1xuICAgICAgdGhpcy53aXRoaW5Pd25lcnMoZS50YXJnZXQsICh2aWV3KSA9PiB7XG4gICAgICAgIEpTLmV4ZWMoZSwgXCJzdWJtaXRcIiwgcGh4RXZlbnQsIHZpZXcsIGUudGFyZ2V0LCBbXG4gICAgICAgICAgXCJwdXNoXCIsXG4gICAgICAgICAgeyBzdWJtaXR0ZXI6IGUuc3VibWl0dGVyIH0sXG4gICAgICAgIF0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBmb3IgKGNvbnN0IHR5cGUgb2YgW1wiY2hhbmdlXCIsIFwiaW5wdXRcIl0pIHtcbiAgICAgIHRoaXMub24odHlwZSwgKGUpID0+IHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGUgaW5zdGFuY2VvZiBDdXN0b21FdmVudCAmJlxuICAgICAgICAgIChlLnRhcmdldCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgfHxcbiAgICAgICAgICAgIGUudGFyZ2V0IGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQgfHxcbiAgICAgICAgICAgIGUudGFyZ2V0IGluc3RhbmNlb2YgSFRNTFRleHRBcmVhRWxlbWVudCkgJiZcbiAgICAgICAgICBlLnRhcmdldC5mb3JtID09PSB1bmRlZmluZWRcbiAgICAgICAgKSB7XG4gICAgICAgICAgLy8gdGhyb3cgb24gaW52YWxpZCBKUy5kaXNwYXRjaCB0YXJnZXQgYW5kIG5vb3AgaWYgQ3VzdG9tRXZlbnQgdHJpZ2dlcmVkIG91dHNpZGUgSlMuZGlzcGF0Y2hcbiAgICAgICAgICBpZiAoZS5kZXRhaWwgJiYgZS5kZXRhaWwuZGlzcGF0Y2hlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgZGlzcGF0Y2hpbmcgYSBjdXN0b20gJHt0eXBlfSBldmVudCBpcyBvbmx5IHN1cHBvcnRlZCBvbiBpbnB1dCBlbGVtZW50cyBpbnNpZGUgYSBmb3JtYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwaHhDaGFuZ2UgPSB0aGlzLmJpbmRpbmcoXCJjaGFuZ2VcIik7XG4gICAgICAgIGNvbnN0IGlucHV0ID0gZS50YXJnZXQ7XG4gICAgICAgIGlmICh0aGlzLmJsb2NrUGh4Q2hhbmdlV2hpbGVDb21wb3NpbmcgJiYgZS5pc0NvbXBvc2luZykge1xuICAgICAgICAgIGNvbnN0IGtleSA9IGBjb21wb3NpdGlvbi1saXN0ZW5lci0ke3R5cGV9YDtcbiAgICAgICAgICBpZiAoIURPTS5wcml2YXRlKGlucHV0LCBrZXkpKSB7XG4gICAgICAgICAgICBET00ucHV0UHJpdmF0ZShpbnB1dCwga2V5LCB0cnVlKTtcbiAgICAgICAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgICAgIFwiY29tcG9zaXRpb25lbmRcIixcbiAgICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIHRyaWdnZXIgYSBuZXcgaW5wdXQvY2hhbmdlIGV2ZW50XG4gICAgICAgICAgICAgICAgaW5wdXQuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQodHlwZSwgeyBidWJibGVzOiB0cnVlIH0pKTtcbiAgICAgICAgICAgICAgICBET00uZGVsZXRlUHJpdmF0ZShpbnB1dCwga2V5KTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgeyBvbmNlOiB0cnVlIH0sXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgaW5wdXRFdmVudCA9IGlucHV0LmdldEF0dHJpYnV0ZShwaHhDaGFuZ2UpO1xuICAgICAgICBjb25zdCBmb3JtRXZlbnQgPSBpbnB1dC5mb3JtICYmIGlucHV0LmZvcm0uZ2V0QXR0cmlidXRlKHBoeENoYW5nZSk7XG4gICAgICAgIGNvbnN0IHBoeEV2ZW50ID0gaW5wdXRFdmVudCB8fCBmb3JtRXZlbnQ7XG4gICAgICAgIGlmICghcGh4RXZlbnQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFxuICAgICAgICAgIGlucHV0LnR5cGUgPT09IFwibnVtYmVyXCIgJiZcbiAgICAgICAgICBpbnB1dC52YWxpZGl0eSAmJlxuICAgICAgICAgIGlucHV0LnZhbGlkaXR5LmJhZElucHV0XG4gICAgICAgICkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRpc3BhdGNoZXIgPSBpbnB1dEV2ZW50ID8gaW5wdXQgOiBpbnB1dC5mb3JtO1xuICAgICAgICBjb25zdCBjdXJyZW50SXRlcmF0aW9ucyA9IGl0ZXJhdGlvbnM7XG4gICAgICAgIGl0ZXJhdGlvbnMrKztcbiAgICAgICAgY29uc3QgeyBhdDogYXQsIHR5cGU6IGxhc3RUeXBlIH0gPVxuICAgICAgICAgIERPTS5wcml2YXRlKGlucHV0LCBcInByZXYtaXRlcmF0aW9uXCIpIHx8IHt9O1xuICAgICAgICAvLyBCcm93c2VycyBzaG91bGQgYWx3YXlzIGZpcmUgYXQgbGVhc3Qgb25lIFwiaW5wdXRcIiBldmVudCBiZWZvcmUgZXZlcnkgXCJjaGFuZ2VcIlxuICAgICAgICAvLyBJZ25vcmUgXCJjaGFuZ2VcIiBldmVudHMsIHVubGVzcyB0aGVyZSB3YXMgbm8gcHJpb3IgXCJpbnB1dFwiIGV2ZW50LlxuICAgICAgICAvLyBUaGlzIGNvdWxkIGhhcHBlbiBpZiB1c2VyIGNvZGUgdHJpZ2dlcnMgYSBcImNoYW5nZVwiIGV2ZW50LCBvciBpZiB0aGUgYnJvd3NlciBpcyBub24tY29uZm9ybWluZy5cbiAgICAgICAgaWYgKFxuICAgICAgICAgIGF0ID09PSBjdXJyZW50SXRlcmF0aW9ucyAtIDEgJiZcbiAgICAgICAgICB0eXBlID09PSBcImNoYW5nZVwiICYmXG4gICAgICAgICAgbGFzdFR5cGUgPT09IFwiaW5wdXRcIlxuICAgICAgICApIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBET00ucHV0UHJpdmF0ZShpbnB1dCwgXCJwcmV2LWl0ZXJhdGlvblwiLCB7XG4gICAgICAgICAgYXQ6IGN1cnJlbnRJdGVyYXRpb25zLFxuICAgICAgICAgIHR5cGU6IHR5cGUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuZGVib3VuY2UoaW5wdXQsIGUsIHR5cGUsICgpID0+IHtcbiAgICAgICAgICB0aGlzLndpdGhpbk93bmVycyhkaXNwYXRjaGVyLCAodmlldykgPT4ge1xuICAgICAgICAgICAgRE9NLnB1dFByaXZhdGUoaW5wdXQsIFBIWF9IQVNfRk9DVVNFRCwgdHJ1ZSk7XG4gICAgICAgICAgICBKUy5leGVjKGUsIFwiY2hhbmdlXCIsIHBoeEV2ZW50LCB2aWV3LCBpbnB1dCwgW1xuICAgICAgICAgICAgICBcInB1c2hcIixcbiAgICAgICAgICAgICAgeyBfdGFyZ2V0OiBlLnRhcmdldC5uYW1lLCBkaXNwYXRjaGVyOiBkaXNwYXRjaGVyIH0sXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5vbihcInJlc2V0XCIsIChlKSA9PiB7XG4gICAgICBjb25zdCBmb3JtID0gZS50YXJnZXQ7XG4gICAgICBET00ucmVzZXRGb3JtKGZvcm0pO1xuICAgICAgY29uc3QgaW5wdXQgPSBBcnJheS5mcm9tKGZvcm0uZWxlbWVudHMpLmZpbmQoKGVsKSA9PiBlbC50eXBlID09PSBcInJlc2V0XCIpO1xuICAgICAgaWYgKGlucHV0KSB7XG4gICAgICAgIC8vIHdhaXQgdW50aWwgbmV4dCB0aWNrIHRvIGdldCB1cGRhdGVkIGlucHV0IHZhbHVlXG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4ge1xuICAgICAgICAgIGlucHV0LmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgRXZlbnQoXCJpbnB1dFwiLCB7IGJ1YmJsZXM6IHRydWUsIGNhbmNlbGFibGU6IGZhbHNlIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgZGVib3VuY2UoZWwsIGV2ZW50LCBldmVudFR5cGUsIGNhbGxiYWNrKSB7XG4gICAgaWYgKGV2ZW50VHlwZSA9PT0gXCJibHVyXCIgfHwgZXZlbnRUeXBlID09PSBcImZvY3Vzb3V0XCIpIHtcbiAgICAgIHJldHVybiBjYWxsYmFjaygpO1xuICAgIH1cblxuICAgIGNvbnN0IHBoeERlYm91bmNlID0gdGhpcy5iaW5kaW5nKFBIWF9ERUJPVU5DRSk7XG4gICAgY29uc3QgcGh4VGhyb3R0bGUgPSB0aGlzLmJpbmRpbmcoUEhYX1RIUk9UVExFKTtcbiAgICBjb25zdCBkZWZhdWx0RGVib3VuY2UgPSB0aGlzLmRlZmF1bHRzLmRlYm91bmNlLnRvU3RyaW5nKCk7XG4gICAgY29uc3QgZGVmYXVsdFRocm90dGxlID0gdGhpcy5kZWZhdWx0cy50aHJvdHRsZS50b1N0cmluZygpO1xuXG4gICAgdGhpcy53aXRoaW5Pd25lcnMoZWwsICh2aWV3KSA9PiB7XG4gICAgICBjb25zdCBhc3luY0ZpbHRlciA9ICgpID0+XG4gICAgICAgICF2aWV3LmlzRGVzdHJveWVkKCkgJiYgZG9jdW1lbnQuYm9keS5jb250YWlucyhlbCk7XG4gICAgICBET00uZGVib3VuY2UoXG4gICAgICAgIGVsLFxuICAgICAgICBldmVudCxcbiAgICAgICAgcGh4RGVib3VuY2UsXG4gICAgICAgIGRlZmF1bHREZWJvdW5jZSxcbiAgICAgICAgcGh4VGhyb3R0bGUsXG4gICAgICAgIGRlZmF1bHRUaHJvdHRsZSxcbiAgICAgICAgYXN5bmNGaWx0ZXIsXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIHNpbGVuY2VFdmVudHMoY2FsbGJhY2spIHtcbiAgICB0aGlzLnNpbGVuY2VkID0gdHJ1ZTtcbiAgICBjYWxsYmFjaygpO1xuICAgIHRoaXMuc2lsZW5jZWQgPSBmYWxzZTtcbiAgfVxuXG4gIG9uKGV2ZW50LCBjYWxsYmFjaykge1xuICAgIHRoaXMuYm91bmRFdmVudE5hbWVzLmFkZChldmVudCk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIChlKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc2lsZW5jZWQpIHtcbiAgICAgICAgY2FsbGJhY2soZSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBqc1F1ZXJ5U2VsZWN0b3JBbGwoc291cmNlRWwsIHF1ZXJ5LCBkZWZhdWx0UXVlcnkpIHtcbiAgICBjb25zdCBhbGwgPSB0aGlzLmRvbUNhbGxiYWNrcy5qc1F1ZXJ5U2VsZWN0b3JBbGw7XG4gICAgcmV0dXJuIGFsbCA/IGFsbChzb3VyY2VFbCwgcXVlcnksIGRlZmF1bHRRdWVyeSkgOiBkZWZhdWx0UXVlcnkoKTtcbiAgfVxufVxuXG5jbGFzcyBUcmFuc2l0aW9uU2V0IHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy50cmFuc2l0aW9ucyA9IG5ldyBTZXQoKTtcbiAgICB0aGlzLnByb21pc2VzID0gbmV3IFNldCgpO1xuICAgIHRoaXMucGVuZGluZ09wcyA9IFtdO1xuICB9XG5cbiAgcmVzZXQoKSB7XG4gICAgdGhpcy50cmFuc2l0aW9ucy5mb3JFYWNoKCh0aW1lcikgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgIHRoaXMudHJhbnNpdGlvbnMuZGVsZXRlKHRpbWVyKTtcbiAgICB9KTtcbiAgICB0aGlzLnByb21pc2VzLmNsZWFyKCk7XG4gICAgdGhpcy5mbHVzaFBlbmRpbmdPcHMoKTtcbiAgfVxuXG4gIGFmdGVyKGNhbGxiYWNrKSB7XG4gICAgaWYgKHRoaXMuc2l6ZSgpID09PSAwKSB7XG4gICAgICBjYWxsYmFjaygpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnB1c2hQZW5kaW5nT3AoY2FsbGJhY2spO1xuICAgIH1cbiAgfVxuXG4gIGFkZFRyYW5zaXRpb24odGltZSwgb25TdGFydCwgb25Eb25lKSB7XG4gICAgb25TdGFydCgpO1xuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnRyYW5zaXRpb25zLmRlbGV0ZSh0aW1lcik7XG4gICAgICBvbkRvbmUoKTtcbiAgICAgIHRoaXMuZmx1c2hQZW5kaW5nT3BzKCk7XG4gICAgfSwgdGltZSk7XG4gICAgdGhpcy50cmFuc2l0aW9ucy5hZGQodGltZXIpO1xuICB9XG5cbiAgYWRkQXN5bmNUcmFuc2l0aW9uKHByb21pc2UpIHtcbiAgICB0aGlzLnByb21pc2VzLmFkZChwcm9taXNlKTtcbiAgICBwcm9taXNlLnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5wcm9taXNlcy5kZWxldGUocHJvbWlzZSk7XG4gICAgICB0aGlzLmZsdXNoUGVuZGluZ09wcygpO1xuICAgIH0pO1xuICB9XG5cbiAgcHVzaFBlbmRpbmdPcChvcCkge1xuICAgIHRoaXMucGVuZGluZ09wcy5wdXNoKG9wKTtcbiAgfVxuXG4gIHNpemUoKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNpdGlvbnMuc2l6ZSArIHRoaXMucHJvbWlzZXMuc2l6ZTtcbiAgfVxuXG4gIGZsdXNoUGVuZGluZ09wcygpIHtcbiAgICBpZiAodGhpcy5zaXplKCkgPiAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG9wID0gdGhpcy5wZW5kaW5nT3BzLnNoaWZ0KCk7XG4gICAgaWYgKG9wKSB7XG4gICAgICBvcCgpO1xuICAgICAgdGhpcy5mbHVzaFBlbmRpbmdPcHMoKTtcbiAgICB9XG4gIH1cbn1cbiIsICIvKlxuPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblBob2VuaXggTGl2ZVZpZXcgSmF2YVNjcmlwdCBDbGllbnRcbj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblNlZSB0aGUgaGV4ZG9jcyBhdCBgaHR0cHM6Ly9oZXhkb2NzLnBtL3Bob2VuaXhfbGl2ZV92aWV3YCBmb3IgZG9jdW1lbnRhdGlvbi5cbiovXG5cbmltcG9ydCBPcmlnaW5hbExpdmVTb2NrZXQsIHsgaXNVc2VkSW5wdXQgfSBmcm9tIFwiLi9saXZlX3NvY2tldFwiO1xuaW1wb3J0IERPTSBmcm9tIFwiLi9kb21cIjtcbmltcG9ydCB7IFZpZXdIb29rIH0gZnJvbSBcIi4vdmlld19ob29rXCI7XG5pbXBvcnQgVmlldyBmcm9tIFwiLi92aWV3XCI7XG5cbmltcG9ydCB0eXBlIHsgTGl2ZVNvY2tldEpTQ29tbWFuZHMgfSBmcm9tIFwiLi9qc19jb21tYW5kc1wiO1xuaW1wb3J0IHR5cGUgeyBIb29rLCBIb29rc09wdGlvbnMgfSBmcm9tIFwiLi92aWV3X2hvb2tcIjtcbmltcG9ydCB0eXBlIHsgU29ja2V0IGFzIFBob2VuaXhTb2NrZXQgfSBmcm9tIFwicGhvZW5peFwiO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIHRoZSBMaXZlU29ja2V0IGluc3RhbmNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExpdmVTb2NrZXRPcHRpb25zIHtcbiAgLyoqXG4gICAqIERlZmF1bHRzIGZvciBwaHgtZGVib3VuY2UgYW5kIHBoeC10aHJvdHRsZS5cbiAgICovXG4gIGRlZmF1bHRzPzoge1xuICAgIC8qKiBUaGUgbWlsbGlzZWNvbmQgcGh4LWRlYm91bmNlIHRpbWUuIERlZmF1bHRzIDMwMCAqL1xuICAgIGRlYm91bmNlPzogbnVtYmVyO1xuICAgIC8qKiBUaGUgbWlsbGlzZWNvbmQgcGh4LXRocm90dGxlIHRpbWUuIERlZmF1bHRzIDMwMCAqL1xuICAgIHRocm90dGxlPzogbnVtYmVyO1xuICB9O1xuICAvKipcbiAgICogQW4gb2JqZWN0IG9yIGZ1bmN0aW9uIGZvciBwYXNzaW5nIGNvbm5lY3QgcGFyYW1zLlxuICAgKiBUaGUgZnVuY3Rpb24gcmVjZWl2ZXMgdGhlIGVsZW1lbnQgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gTGl2ZVZpZXcuIEZvciBleGFtcGxlOlxuICAgKlxuICAgKiAgICAgKGVsKSA9PiB7dmlldzogZWwuZ2V0QXR0cmlidXRlKFwiZGF0YS1teS12aWV3LW5hbWVcIiwgdG9rZW46IHdpbmRvdy5teVRva2VufVxuICAgKlxuICAgKi9cbiAgcGFyYW1zPzpcbiAgICB8ICgoZWw6IEhUTUxFbGVtZW50KSA9PiB7IFtrZXk6IHN0cmluZ106IGFueSB9KVxuICAgIHwgeyBba2V5OiBzdHJpbmddOiBhbnkgfTtcbiAgLyoqXG4gICAqIFRoZSBvcHRpb25hbCBwcmVmaXggdG8gdXNlIGZvciBhbGwgcGh4IERPTSBhbm5vdGF0aW9ucy5cbiAgICpcbiAgICogRGVmYXVsdHMgdG8gXCJwaHgtXCIuXG4gICAqL1xuICBiaW5kaW5nUHJlZml4Pzogc3RyaW5nO1xuICAvKipcbiAgICogQ2FsbGJhY2tzIGZvciBMaXZlVmlldyBob29rcy5cbiAgICpcbiAgICogU2VlIFtDbGllbnQgaG9va3MgdmlhIGBwaHgtaG9va2BdKGh0dHBzOi8vaGV4ZG9jcy5wbS9waG9lbml4X2xpdmVfdmlldy9qcy1pbnRlcm9wLmh0bWwjY2xpZW50LWhvb2tzLXZpYS1waHgtaG9vaykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAqL1xuICBob29rcz86IEhvb2tzT3B0aW9ucztcbiAgLyoqIENhbGxiYWNrcyBmb3IgTGl2ZVZpZXcgdXBsb2FkZXJzLiAqL1xuICB1cGxvYWRlcnM/OiB7IFtrZXk6IHN0cmluZ106IGFueSB9OyAvLyBUT0RPOiBkZWZpbmUgbW9yZSBzcGVjaWZpY2FsbHlcbiAgLyoqIERlbGF5IGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgYXBwbHlpbmcgbG9hZGluZyBzdGF0ZXMuICovXG4gIGxvYWRlclRpbWVvdXQ/OiBudW1iZXI7XG4gIC8qKiBEZWxheSBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIGV4ZWN1dGluZyBwaHgtZGlzY29ubmVjdGVkIGNvbW1hbmRzLiAqL1xuICBkaXNjb25uZWN0ZWRUaW1lb3V0PzogbnVtYmVyO1xuICAvKiogTWF4aW11bSByZWxvYWRzIGJlZm9yZSBlbnRlcmluZyBmYWlsc2FmZSBtb2RlLiAqL1xuICBtYXhSZWxvYWRzPzogbnVtYmVyO1xuICAvKiogTWluaW11bSB0aW1lIGJldHdlZW4gbm9ybWFsIHJlbG9hZCBhdHRlbXB0cy4gKi9cbiAgcmVsb2FkSml0dGVyTWluPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSB0aW1lIGJldHdlZW4gbm9ybWFsIHJlbG9hZCBhdHRlbXB0cy4gKi9cbiAgcmVsb2FkSml0dGVyTWF4PzogbnVtYmVyO1xuICAvKiogVGltZSBiZXR3ZWVuIHJlbG9hZCBhdHRlbXB0cyBpbiBmYWlsc2FmZSBtb2RlLiAqL1xuICBmYWlsc2FmZUppdHRlcj86IG51bWJlcjtcbiAgLyoqXG4gICAqIEZ1bmN0aW9uIHRvIGxvZyBkZWJ1ZyBpbmZvcm1hdGlvbi4gRm9yIGV4YW1wbGU6XG4gICAqXG4gICAqICAgICAodmlldywga2luZCwgbXNnLCBvYmopID0+IGNvbnNvbGUubG9nKGAke3ZpZXcuaWR9ICR7a2luZH06ICR7bXNnfSAtIGAsIG9iailcbiAgICovXG4gIHZpZXdMb2dnZXI/OiAodmlldzogVmlldywga2luZDogc3RyaW5nLCBtc2c6IHN0cmluZywgb2JqOiBhbnkpID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBPYmplY3QgbWFwcGluZyBldmVudCBuYW1lcyB0byBmdW5jdGlvbnMgZm9yIHBvcHVsYXRpbmcgZXZlbnQgbWV0YWRhdGEuXG4gICAqXG4gICAqICAgICBtZXRhZGF0YToge1xuICAgKiAgICAgICBjbGljazogKGUsIGVsKSA9PiB7XG4gICAqICAgICAgICAgcmV0dXJuIHtcbiAgICogICAgICAgICAgIGN0cmxLZXk6IGUuY3RybEtleSxcbiAgICogICAgICAgICAgIG1ldGFLZXk6IGUubWV0YUtleSxcbiAgICogICAgICAgICAgIGRldGFpbDogZS5kZXRhaWwgfHwgMSxcbiAgICogICAgICAgICB9XG4gICAqICAgICAgIH0sXG4gICAqICAgICAgIGtleWRvd246IChlLCBlbCkgPT4ge1xuICAgKiAgICAgICAgIHJldHVybiB7XG4gICAqICAgICAgICAgICBrZXk6IGUua2V5LFxuICAgKiAgICAgICAgICAgY3RybEtleTogZS5jdHJsS2V5LFxuICAgKiAgICAgICAgICAgbWV0YUtleTogZS5tZXRhS2V5LFxuICAgKiAgICAgICAgICAgc2hpZnRLZXk6IGUuc2hpZnRLZXlcbiAgICogICAgICAgICB9XG4gICAqICAgICAgIH1cbiAgICogICAgIH1cbiAgICpcbiAgICovXG4gIG1ldGFkYXRhPzogeyBbZXZlbnROYW1lOiBzdHJpbmddOiAoZTogRXZlbnQsIGVsOiBIVE1MRWxlbWVudCkgPT4gb2JqZWN0IH07XG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCBTdG9yYWdlIGNvbXBhdGlibGUgb2JqZWN0XG4gICAqIFVzZWZ1bCB3aGVuIExpdmVWaWV3IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBzZXNzaW9uU3RvcmFnZWAuIEZvciBleGFtcGxlLCBUaGlzIGNvdWxkXG4gICAqIGhhcHBlbiBpZiBhIHNpdGUgbG9hZHMgYSBjcm9zcy1kb21haW4gTGl2ZVZpZXcgaW4gYW4gaWZyYW1lLlxuICAgKlxuICAgKiBFeGFtcGxlIHVzYWdlOlxuICAgKlxuICAgKiAgICAgY2xhc3MgSW5NZW1vcnlTdG9yYWdlIHtcbiAgICogICAgICAgY29uc3RydWN0b3IoKSB7IHRoaXMuc3RvcmFnZSA9IHt9IH1cbiAgICogICAgICAgZ2V0SXRlbShrZXlOYW1lKSB7IHJldHVybiB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gfHwgbnVsbCB9XG4gICAqICAgICAgIHJlbW92ZUl0ZW0oa2V5TmFtZSkgeyBkZWxldGUgdGhpcy5zdG9yYWdlW2tleU5hbWVdIH1cbiAgICogICAgICAgc2V0SXRlbShrZXlOYW1lLCBrZXlWYWx1ZSkgeyB0aGlzLnN0b3JhZ2Vba2V5TmFtZV0gPSBrZXlWYWx1ZSB9XG4gICAqICAgICB9XG4gICAqL1xuICBzZXNzaW9uU3RvcmFnZT86IFN0b3JhZ2U7XG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCBTdG9yYWdlIGNvbXBhdGlibGUgb2JqZWN0XG4gICAqIFVzZWZ1bCB3aGVuIExpdmVWaWV3IHdvbid0IGhhdmUgYWNjZXNzIHRvIGBsb2NhbFN0b3JhZ2VgLlxuICAgKlxuICAgKiBTZWUgYHNlc3Npb25TdG9yYWdlYCBmb3IgYW4gZXhhbXBsZS5cbiAgICovXG4gIGxvY2FsU3RvcmFnZT86IFN0b3JhZ2U7XG4gIC8qKlxuICAgKiBJZiBzZXQgdG8gYHRydWVgLCBgcGh4LWNoYW5nZWAgZXZlbnRzIHdpbGwgYmUgYmxvY2tlZCAod2lsbCBub3QgZmlyZSlcbiAgICogd2hpbGUgdGhlIHVzZXIgaXMgY29tcG9zaW5nIGlucHV0IHVzaW5nIGFuIElNRSAoSW5wdXQgTWV0aG9kIEVkaXRvcikuXG4gICAqIFRoaXMgaXMgZGV0ZXJtaW5lZCBieSB0aGUgYGUuaXNDb21wb3NpbmdgIHByb3BlcnR5IG9uIGtleWJvYXJkIGV2ZW50cyxcbiAgICogd2hpY2ggaXMgYHRydWVgIHdoZW4gdGhlIHVzZXIgaXMgaW4gdGhlIHByb2Nlc3Mgb2YgZW50ZXJpbmcgY29tcG9zZWQgY2hhcmFjdGVycyAoZm9yIGV4YW1wbGUsXG4gICAqIHdoZW4gdHlwaW5nIEphcGFuZXNlIG9yIENoaW5lc2UgdXNpbmcgcm9tYWppIG9yIHBpbnlpbiBpbnB1dCBtZXRob2RzKS5cbiAgICogQnkgZGVmYXVsdCwgYHBoeC1jaGFuZ2VgIHdpbGwgbm90IGJlIGJsb2NrZWQgZHVyaW5nIGEgY29tcG9zaXRpb24gc2Vzc2lvbixcbiAgICogYnV0IG5vdGUgdGhhdCB0aGVyZSB3ZXJlIGlzc3VlcyByZXBvcnRlZCBpbiBvbGRlciB2ZXJzaW9ucyBvZiBTYWZhcmksXG4gICAqIHdoZXJlIGEgTGl2ZVZpZXcgcGF0Y2ggdG8gdGhlIGlucHV0IGNhdXNlZCB1bmV4cGVjdGVkIGJlaGF2aW9yLlxuICAgKlxuICAgKiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlXG4gICAqIC0gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0tleWJvYXJkRXZlbnQvaXNDb21wb3NpbmdcbiAgICogLSBodHRwczovL2dpdGh1Yi5jb20vcGhvZW5peGZyYW1ld29yay9waG9lbml4X2xpdmVfdmlldy9pc3N1ZXMvMzMyMlxuICAgKlxuICAgKiBEZWZhdWx0cyB0byBgZmFsc2VgLlxuICAgKi9cbiAgYmxvY2tQaHhDaGFuZ2VXaGlsZUNvbXBvc2luZz86IGJvb2xlYW47XG4gIC8qKiBET00gY2FsbGJhY2tzLiAqL1xuICBkb20/OiB7XG4gICAgLyoqXG4gICAgICogQW4gb3B0aW9uYWwgZnVuY3Rpb24gdG8gbW9kaWZ5IHRoZSBiZWhhdmlvciBvZiBxdWVyeWluZyBlbGVtZW50cyBpbiBKUyBjb21tYW5kcy5cbiAgICAgKiBAcGFyYW0gc291cmNlRWwgLSBUaGUgc291cmNlIGVsZW1lbnQsIGUuZy4gdGhlIGJ1dHRvbiB0aGF0IHdhcyBjbGlja2VkLlxuICAgICAqIEBwYXJhbSBxdWVyeSAtIFRoZSBxdWVyeSB2YWx1ZS5cbiAgICAgKiBAcGFyYW0gZGVmYXVsdFF1ZXJ5IC0gQSBkZWZhdWx0IHF1ZXJ5IGZ1bmN0aW9uIHRoYXQgY2FuIGJlIHVzZWQgaWYgbm8gY3VzdG9tIHF1ZXJ5IHNob3VsZCBiZSBhcHBsaWVkLlxuICAgICAqIEByZXR1cm5zIEEgbGlzdCBvZiBET00gZWxlbWVudHMuXG4gICAgICovXG4gICAganNRdWVyeVNlbGVjdG9yQWxsPzogKFxuICAgICAgc291cmNlRWw6IEhUTUxFbGVtZW50LFxuICAgICAgcXVlcnk6IHN0cmluZyxcbiAgICAgIGRlZmF1bHRRdWVyeTogKCkgPT4gRWxlbWVudFtdLFxuICAgICkgPT4gRWxlbWVudFtdO1xuICAgIC8qKlxuICAgICAqIENhbGxlZCBpbW1lZGlhdGVseSBiZWZvcmUgYSBET00gcGF0Y2ggaXMgYXBwbGllZC5cbiAgICAgKi9cbiAgICBvblBhdGNoU3RhcnQ/OiAoY29udGFpbmVyOiBIVE1MRWxlbWVudCkgPT4gdm9pZDtcbiAgICAvKipcbiAgICAgKiBDYWxsZWQgaW1tZWRpYXRlbHkgYWZ0ZXIgYSBET00gcGF0Y2ggaXMgYXBwbGllZC5cbiAgICAgKi9cbiAgICBvblBhdGNoRW5kPzogKGNvbnRhaW5lcjogSFRNTEVsZW1lbnQpID0+IHZvaWQ7XG4gICAgLyoqXG4gICAgICogQ2FsbGVkIHdoZW4gYSBuZXcgRE9NIG5vZGUgaXMgYWRkZWQuXG4gICAgICovXG4gICAgb25Ob2RlQWRkZWQ/OiAobm9kZTogTm9kZSkgPT4gdm9pZDtcbiAgICAvKipcbiAgICAgKiBDYWxsZWQgYmVmb3JlIGFuIGVsZW1lbnQgaXMgdXBkYXRlZC5cbiAgICAgKi9cbiAgICBvbkJlZm9yZUVsVXBkYXRlZD86IChmcm9tRWw6IEVsZW1lbnQsIHRvRWw6IEVsZW1lbnQpID0+IHZvaWQ7XG4gIH07XG4gIC8qKiBBbGxvdyBwYXNzdGhyb3VnaCBvZiBvdGhlciBvcHRpb25zIHRvIHRoZSBQaG9lbml4IFNvY2tldCBjb25zdHJ1Y3Rvci4gKi9cbiAgW2tleTogc3RyaW5nXTogYW55O1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBkZXNjcmliaW5nIHRoZSBwdWJsaWMgQVBJIG9mIGEgTGl2ZVNvY2tldCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMaXZlU29ja2V0SW5zdGFuY2VJbnRlcmZhY2Uge1xuICAvKipcbiAgICogUmV0dXJucyB0aGUgdmVyc2lvbiBvZiB0aGUgTGl2ZVZpZXcgY2xpZW50LlxuICAgKi9cbiAgdmVyc2lvbigpOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgcHJvZmlsaW5nIGlzIGVuYWJsZWQuIFNlZSBgZW5hYmxlUHJvZmlsaW5nYCBhbmQgYGRpc2FibGVQcm9maWxpbmdgLlxuICAgKi9cbiAgaXNQcm9maWxlRW5hYmxlZCgpOiBib29sZWFuO1xuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGRlYnVnZ2luZyBpcyBlbmFibGVkLiBTZWUgYGVuYWJsZURlYnVnYCBhbmQgYGRpc2FibGVEZWJ1Z2AuXG4gICAqL1xuICBpc0RlYnVnRW5hYmxlZCgpOiBib29sZWFuO1xuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGRlYnVnZ2luZyBpcyBkaXNhYmxlZC4gU2VlIGBlbmFibGVEZWJ1Z2AgYW5kIGBkaXNhYmxlRGVidWdgLlxuICAgKi9cbiAgaXNEZWJ1Z0Rpc2FibGVkKCk6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBFbmFibGVzIGRlYnVnZ2luZy5cbiAgICpcbiAgICogV2hlbiBkZWJ1Z2dpbmcgaXMgZW5hYmxlZCwgdGhlIExpdmVWaWV3IGNsaWVudCB3aWxsIGxvZyBkZWJ1ZyBpbmZvcm1hdGlvbiB0byB0aGUgY29uc29sZS5cbiAgICogU2VlIFtEZWJ1Z2dpbmcgY2xpZW50IGV2ZW50c10oaHR0cHM6Ly9oZXhkb2NzLnBtL3Bob2VuaXhfbGl2ZV92aWV3L2pzLWludGVyb3AuaHRtbCNkZWJ1Z2dpbmctY2xpZW50LWV2ZW50cykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAqL1xuICBlbmFibGVEZWJ1ZygpOiB2b2lkO1xuICAvKipcbiAgICogRW5hYmxlcyBwcm9maWxpbmcuXG4gICAqXG4gICAqIFdoZW4gcHJvZmlsaW5nIGlzIGVuYWJsZWQsIHRoZSBMaXZlVmlldyBjbGllbnQgd2lsbCBsb2cgcHJvZmlsaW5nIGluZm9ybWF0aW9uIHRvIHRoZSBjb25zb2xlLlxuICAgKi9cbiAgZW5hYmxlUHJvZmlsaW5nKCk6IHZvaWQ7XG4gIC8qKlxuICAgKiBEaXNhYmxlcyBkZWJ1Z2dpbmcuXG4gICAqL1xuICBkaXNhYmxlRGVidWcoKTogdm9pZDtcbiAgLyoqXG4gICAqIERpc2FibGVzIHByb2ZpbGluZy5cbiAgICovXG4gIGRpc2FibGVQcm9maWxpbmcoKTogdm9pZDtcbiAgLyoqXG4gICAqIEVuYWJsZXMgbGF0ZW5jeSBzaW11bGF0aW9uLlxuICAgKlxuICAgKiBXaGVuIGxhdGVuY3kgc2ltdWxhdGlvbiBpcyBlbmFibGVkLCB0aGUgTGl2ZVZpZXcgY2xpZW50IHdpbGwgYWRkIGEgZGVsYXkgdG8gcmVxdWVzdHMgYW5kIHJlc3BvbnNlcyBmcm9tIHRoZSBzZXJ2ZXIuXG4gICAqIFNlZSBbU2ltdWxhdGluZyBMYXRlbmN5XShodHRwczovL2hleGRvY3MucG0vcGhvZW5peF9saXZlX3ZpZXcvanMtaW50ZXJvcC5odG1sI3NpbXVsYXRpbmctbGF0ZW5jeSkgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAqL1xuICBlbmFibGVMYXRlbmN5U2ltKHVwcGVyQm91bmRNczogbnVtYmVyKTogdm9pZDtcbiAgLyoqXG4gICAqIERpc2FibGVzIGxhdGVuY3kgc2ltdWxhdGlvbi5cbiAgICovXG4gIGRpc2FibGVMYXRlbmN5U2ltKCk6IHZvaWQ7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IGxhdGVuY3kgc2ltdWxhdGlvbiB1cHBlciBib3VuZC5cbiAgICovXG4gIGdldExhdGVuY3lTaW0oKTogbnVtYmVyIHwgbnVsbDtcbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIFBob2VuaXggU29ja2V0IGluc3RhbmNlLlxuICAgKi9cbiAgZ2V0U29ja2V0KCk6IFBob2VuaXhTb2NrZXQ7XG4gIC8qKlxuICAgKiBDb25uZWN0cyB0byB0aGUgTGl2ZVZpZXcgc2VydmVyLlxuICAgKi9cbiAgY29ubmVjdCgpOiB2b2lkO1xuICAvKipcbiAgICogRGlzY29ubmVjdHMgZnJvbSB0aGUgTGl2ZVZpZXcgc2VydmVyLlxuICAgKi9cbiAgZGlzY29ubmVjdChjYWxsYmFjaz86ICgpID0+IHZvaWQpOiB2b2lkO1xuICAvKipcbiAgICogQ2FuIGJlIHVzZWQgdG8gcmVwbGFjZSB0aGUgdHJhbnNwb3J0IHVzZWQgYnkgdGhlIHVuZGVybHlpbmcgUGhvZW5peCBTb2NrZXQuXG4gICAqL1xuICByZXBsYWNlVHJhbnNwb3J0KHRyYW5zcG9ydDogYW55KTogdm9pZDtcbiAgLyoqXG4gICAqIEV4ZWN1dGVzIGFuIGVuY29kZWQgSlMgY29tbWFuZCwgdGFyZ2V0aW5nIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgKlxuICAgKiBTZWUgW2BQaG9lbml4LkxpdmVWaWV3LkpTYF0oaHR0cHM6Ly9oZXhkb2NzLnBtL3Bob2VuaXhfbGl2ZV92aWV3L1Bob2VuaXguTGl2ZVZpZXcuSlMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAqL1xuICBleGVjSlMoZWw6IEhUTUxFbGVtZW50LCBlbmNvZGVkSlM6IHN0cmluZywgZXZlbnRUeXBlPzogc3RyaW5nIHwgbnVsbCk6IHZvaWQ7XG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIG9iamVjdCB3aXRoIG1ldGhvZHMgdG8gbWFuaXBsdWF0ZSB0aGUgRE9NIGFuZCBleGVjdXRlIEphdmFTY3JpcHQuXG4gICAqIFRoZSBhcHBsaWVkIGNoYW5nZXMgaW50ZWdyYXRlIHdpdGggc2VydmVyIERPTSBwYXRjaGluZy5cbiAgICpcbiAgICogU2VlIFtKYXZhU2NyaXB0IGludGVyb3BlcmFiaWxpdHldKGh0dHBzOi8vaGV4ZG9jcy5wbS9waG9lbml4X2xpdmVfdmlldy9qcy1pbnRlcm9wLmh0bWwpIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICAgKi9cbiAganMoKTogTGl2ZVNvY2tldEpTQ29tbWFuZHM7XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIGRlc2NyaWJpbmcgdGhlIExpdmVTb2NrZXQgY29uc3RydWN0b3IuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGl2ZVNvY2tldENvbnN0cnVjdG9yIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgTGl2ZVNvY2tldCBpbnN0YW5jZS5cbiAgICpcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gVGhlIHN0cmluZyBXZWJTb2NrZXQgZW5kcG9pbnQsIGllLCBgXCJ3c3M6Ly9leGFtcGxlLmNvbS9saXZlXCJgLFxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFwiL2xpdmVcImAgKGluaGVyaXRlZCBob3N0ICYgcHJvdG9jb2wpXG4gICAqIEBwYXJhbSBzb2NrZXQgLSB0aGUgcmVxdWlyZWQgUGhvZW5peCBTb2NrZXQgY2xhc3MgaW1wb3J0ZWQgZnJvbSBcInBob2VuaXhcIi4gRm9yIGV4YW1wbGU6XG4gICAqXG4gICAqICAgICBpbXBvcnQge1NvY2tldH0gZnJvbSBcInBob2VuaXhcIlxuICAgKiAgICAgaW1wb3J0IHtMaXZlU29ja2V0fSBmcm9tIFwicGhvZW5peF9saXZlX3ZpZXdcIlxuICAgKiAgICAgbGV0IGxpdmVTb2NrZXQgPSBuZXcgTGl2ZVNvY2tldChcIi9saXZlXCIsIFNvY2tldCwgey4uLn0pXG4gICAqXG4gICAqIEBwYXJhbSBvcHRzIC0gT3B0aW9uYWwgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIG5ldyAoXG4gICAgZW5kcG9pbnQ6IHN0cmluZyxcbiAgICBzb2NrZXQ6IHR5cGVvZiBQaG9lbml4U29ja2V0LFxuICAgIG9wdHM/OiBMaXZlU29ja2V0T3B0aW9ucyxcbiAgKTogTGl2ZVNvY2tldEluc3RhbmNlSW50ZXJmYWNlO1xufVxuXG4vLyBiZWNhdXNlIExpdmVTb2NrZXQgaXMgaW4gSlMgKGZvciBub3cpLCB3ZSBjYXN0IGl0IHRvIG91ciBkZWZpbmVkIFR5cGVTY3JpcHQgY29uc3RydWN0b3IuXG5jb25zdCBMaXZlU29ja2V0ID0gT3JpZ2luYWxMaXZlU29ja2V0IGFzIHVua25vd24gYXMgTGl2ZVNvY2tldENvbnN0cnVjdG9yO1xuXG4vKiogQ3JlYXRlcyBhIGhvb2sgaW5zdGFuY2UgZm9yIHRoZSBnaXZlbiBlbGVtZW50IGFuZCBjYWxsYmFja3MuXG4gKlxuICogQHBhcmFtIGVsIC0gVGhlIGVsZW1lbnQgdG8gYXNzb2NpYXRlIHdpdGggdGhlIGhvb2suXG4gKiBAcGFyYW0gY2FsbGJhY2tzIC0gVGhlIGxpc3Qgb2YgaG9vayBjYWxsYmFja3MsIHN1Y2ggYXMgbW91bnRlZCxcbiAqICAgdXBkYXRlZCwgZGVzdHJveWVkLCBldGMuXG4gKlxuICogKk5vdGUqOiBgY3JlYXRlSG9va2AgbXVzdCBiZSBjYWxsZWQgZnJvbSB0aGUgYGNvbm5lY3RlZENhbGxiYWNrYCBsaWZlY3ljbGVcbiAqIHdoaWNoIGlzIHRyaWdnZXJlZCBhZnRlciB0aGUgZWxlbWVudCBoYXMgYmVlbiBhZGRlZCB0byB0aGUgRE9NLiBJZiB5b3UgdHJ5XG4gKiB0byBjYWxsIGBjcmVhdGVIb29rYCBmcm9tIHRoZSBjb25zdHJ1Y3RvciwgYW4gZXJyb3Igd2lsbCBiZSBsb2dnZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBjbGFzcyBNeUNvbXBvbmVudCBleHRlbmRzIEhUTUxFbGVtZW50IHtcbiAqICAgY29ubmVjdGVkQ2FsbGJhY2soKXtcbiAqICAgICBsZXQgb25MaXZlVmlld01vdW50ZWQgPSAoKSA9PiB0aGlzLmhvb2sucHVzaEV2ZW50KC4uLikpXG4gKiAgICAgdGhpcy5ob29rID0gY3JlYXRlSG9vayh0aGlzLCB7bW91bnRlZDogb25MaXZlVmlld01vdW50ZWR9KVxuICogICB9XG4gKiB9XG4gKlxuICogQHJldHVybnMgUmV0dXJucyB0aGUgSG9vayBpbnN0YW5jZSBmb3IgdGhlIGN1c3RvbSBlbGVtZW50LlxuICovXG5mdW5jdGlvbiBjcmVhdGVIb29rKGVsOiBIVE1MRWxlbWVudCwgY2FsbGJhY2tzOiBIb29rKTogVmlld0hvb2sge1xuICBsZXQgZXhpc3RpbmdIb29rID0gRE9NLmdldEN1c3RvbUVsSG9vayhlbCk7XG4gIGlmIChleGlzdGluZ0hvb2spIHtcbiAgICByZXR1cm4gZXhpc3RpbmdIb29rO1xuICB9XG5cbiAgbGV0IGhvb2sgPSBuZXcgVmlld0hvb2soVmlldy5jbG9zZXN0VmlldyhlbCksIGVsLCBjYWxsYmFja3MpO1xuICBET00ucHV0Q3VzdG9tRWxIb29rKGVsLCBob29rKTtcbiAgcmV0dXJuIGhvb2s7XG59XG5cbmV4cG9ydCB7IExpdmVTb2NrZXQsIGlzVXNlZElucHV0LCBjcmVhdGVIb29rLCBWaWV3SG9vaywgSG9vaywgSG9va3NPcHRpb25zIH07XG4iLCAiZXhwb3J0IGNvbnN0IGhvb2tzID0ge307XG5leHBvcnQgZGVmYXVsdCB7fTsiLCAiLy8gSWYgeW91IHdhbnQgdG8gdXNlIFBob2VuaXggY2hhbm5lbHMsIHJ1biBgbWl4IGhlbHAgcGh4Lmdlbi5jaGFubmVsYFxuLy8gdG8gZ2V0IHN0YXJ0ZWQgYW5kIHRoZW4gdW5jb21tZW50IHRoZSBsaW5lIGJlbG93LlxuLy8gaW1wb3J0IFwiLi91c2VyX3NvY2tldC5qc1wiXG5cbi8vIFlvdSBjYW4gaW5jbHVkZSBkZXBlbmRlbmNpZXMgaW4gdHdvIHdheXMuXG4vL1xuLy8gVGhlIHNpbXBsZXN0IG9wdGlvbiBpcyB0byBwdXQgdGhlbSBpbiBhc3NldHMvdmVuZG9yIGFuZFxuLy8gaW1wb3J0IHRoZW0gdXNpbmcgcmVsYXRpdmUgcGF0aHM6XG4vL1xuLy8gICAgIGltcG9ydCBcIi4uL3ZlbmRvci9zb21lLXBhY2thZ2UuanNcIlxuLy9cbi8vIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gYG5wbSBpbnN0YWxsIHNvbWUtcGFja2FnZSAtLXByZWZpeCBhc3NldHNgIGFuZCBpbXBvcnRcbi8vIHRoZW0gdXNpbmcgYSBwYXRoIHN0YXJ0aW5nIHdpdGggdGhlIHBhY2thZ2UgbmFtZTpcbi8vXG4vLyAgICAgaW1wb3J0IFwic29tZS1wYWNrYWdlXCJcbi8vXG4vLyBJZiB5b3UgaGF2ZSBkZXBlbmRlbmNpZXMgdGhhdCB0cnkgdG8gaW1wb3J0IENTUywgZXNidWlsZCB3aWxsIGdlbmVyYXRlIGEgc2VwYXJhdGUgYGFwcC5jc3NgIGZpbGUuXG4vLyBUbyBsb2FkIGl0LCBzaW1wbHkgYWRkIGEgc2Vjb25kIGA8bGluaz5gIHRvIHlvdXIgYHJvb3QuaHRtbC5oZWV4YCBmaWxlLlxuXG4vLyBJbmNsdWRlIHBob2VuaXhfaHRtbCB0byBoYW5kbGUgbWV0aG9kPVBVVC9ERUxFVEUgaW4gZm9ybXMgYW5kIGJ1dHRvbnMuXG5pbXBvcnQgXCJwaG9lbml4X2h0bWxcIlxuLy8gRXN0YWJsaXNoIFBob2VuaXggU29ja2V0IGFuZCBMaXZlVmlldyBjb25maWd1cmF0aW9uLlxuaW1wb3J0IHtTb2NrZXR9IGZyb20gXCJwaG9lbml4XCJcbmltcG9ydCB7TGl2ZVNvY2tldH0gZnJvbSBcInBob2VuaXhfbGl2ZV92aWV3XCJcbmltcG9ydCB7aG9va3MgYXMgY29sb2NhdGVkSG9va3N9IGZyb20gXCJwaG9lbml4LWNvbG9jYXRlZC9teWFwcFwiXG5pbXBvcnQgdG9wYmFyIGZyb20gXCIuLi92ZW5kb3IvdG9wYmFyXCJcblxuY29uc3QgY3NyZlRva2VuID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIm1ldGFbbmFtZT0nY3NyZi10b2tlbiddXCIpLmdldEF0dHJpYnV0ZShcImNvbnRlbnRcIilcbmNvbnN0IGxpdmVTb2NrZXQgPSBuZXcgTGl2ZVNvY2tldChcIi9saXZlXCIsIFNvY2tldCwge1xuICBsb25nUG9sbEZhbGxiYWNrTXM6IDI1MDAsXG4gIHBhcmFtczoge19jc3JmX3Rva2VuOiBjc3JmVG9rZW59LFxuICBob29rczogey4uLmNvbG9jYXRlZEhvb2tzfSxcbn0pXG5cbi8vIFNob3cgcHJvZ3Jlc3MgYmFyIG9uIGxpdmUgbmF2aWdhdGlvbiBhbmQgZm9ybSBzdWJtaXRzXG50b3BiYXIuY29uZmlnKHtiYXJDb2xvcnM6IHswOiBcIiMyOWRcIn0sIHNoYWRvd0NvbG9yOiBcInJnYmEoMCwgMCwgMCwgLjMpXCJ9KVxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJwaHg6cGFnZS1sb2FkaW5nLXN0YXJ0XCIsIF9pbmZvID0+IHRvcGJhci5zaG93KDMwMCkpXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBoeDpwYWdlLWxvYWRpbmctc3RvcFwiLCBfaW5mbyA9PiB0b3BiYXIuaGlkZSgpKVxuXG4vLyBjb25uZWN0IGlmIHRoZXJlIGFyZSBhbnkgTGl2ZVZpZXdzIG9uIHRoZSBwYWdlXG5saXZlU29ja2V0LmNvbm5lY3QoKVxuXG4vLyBleHBvc2UgbGl2ZVNvY2tldCBvbiB3aW5kb3cgZm9yIHdlYiBjb25zb2xlIGRlYnVnIGxvZ3MgYW5kIGxhdGVuY3kgc2ltdWxhdGlvbjpcbi8vID4+IGxpdmVTb2NrZXQuZW5hYmxlRGVidWcoKVxuLy8gPj4gbGl2ZVNvY2tldC5lbmFibGVMYXRlbmN5U2ltKDEwMDApICAvLyBlbmFibGVkIGZvciBkdXJhdGlvbiBvZiBicm93c2VyIHNlc3Npb25cbi8vID4+IGxpdmVTb2NrZXQuZGlzYWJsZUxhdGVuY3lTaW0oKVxud2luZG93LmxpdmVTb2NrZXQgPSBsaXZlU29ja2V0XG5cbi8vIFRoZSBsaW5lcyBiZWxvdyBlbmFibGUgcXVhbGl0eSBvZiBsaWZlIHBob2VuaXhfbGl2ZV9yZWxvYWRcbi8vIGRldmVsb3BtZW50IGZlYXR1cmVzOlxuLy9cbi8vICAgICAxLiBzdHJlYW0gc2VydmVyIGxvZ3MgdG8gdGhlIGJyb3dzZXIgY29uc29sZVxuLy8gICAgIDIuIGNsaWNrIG9uIGVsZW1lbnRzIHRvIGp1bXAgdG8gdGhlaXIgZGVmaW5pdGlvbnMgaW4geW91ciBjb2RlIGVkaXRvclxuLy9cbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJkZXZlbG9wbWVudFwiKSB7XG4gIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGh4OmxpdmVfcmVsb2FkOmF0dGFjaGVkXCIsICh7ZGV0YWlsOiByZWxvYWRlcn0pID0+IHtcbiAgICAvLyBFbmFibGUgc2VydmVyIGxvZyBzdHJlYW1pbmcgdG8gY2xpZW50LlxuICAgIC8vIERpc2FibGUgd2l0aCByZWxvYWRlci5kaXNhYmxlU2VydmVyTG9ncygpXG4gICAgcmVsb2FkZXIuZW5hYmxlU2VydmVyTG9ncygpXG5cbiAgICAvLyBPcGVuIGNvbmZpZ3VyZWQgUExVR19FRElUT1IgYXQgZmlsZTpsaW5lIG9mIHRoZSBjbGlja2VkIGVsZW1lbnQncyBIRUV4IGNvbXBvbmVudFxuICAgIC8vXG4gICAgLy8gICAqIGNsaWNrIHdpdGggXCJjXCIga2V5IHByZXNzZWQgdG8gb3BlbiBhdCBjYWxsZXIgbG9jYXRpb25cbiAgICAvLyAgICogY2xpY2sgd2l0aCBcImRcIiBrZXkgcHJlc3NlZCB0byBvcGVuIGF0IGZ1bmN0aW9uIGNvbXBvbmVudCBkZWZpbml0aW9uIGxvY2F0aW9uXG4gICAgbGV0IGtleURvd25cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImtleWRvd25cIiwgZSA9PiBrZXlEb3duID0gZS5rZXkpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCBlID0+IGtleURvd24gPSBudWxsKVxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgZSA9PiB7XG4gICAgICBpZihrZXlEb3duID09PSBcImNcIil7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgICAgICBlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpXG4gICAgICAgIHJlbG9hZGVyLm9wZW5FZGl0b3JBdENhbGxlcihlLnRhcmdldClcbiAgICAgIH0gZWxzZSBpZihrZXlEb3duID09PSBcImRcIil7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgICAgICBlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpXG4gICAgICAgIHJlbG9hZGVyLm9wZW5FZGl0b3JBdERlZihlLnRhcmdldClcbiAgICAgIH1cbiAgICB9LCB0cnVlKVxuXG4gICAgd2luZG93LmxpdmVSZWxvYWRlciA9IHJlbG9hZGVyXG4gIH0pXG59XG5cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBTUEsT0FBQyxTQUFVQSxTQUFRQyxXQUFVO0FBQzNCO0FBRUEsWUFBSSxRQUNGLGlCQUNBLFNBQ0Esa0JBQWtCLE1BQ2xCLGNBQWMsTUFDZCxlQUFlLE1BQ2YsV0FBVyxTQUFVLE1BQU0sTUFBTSxTQUFTO0FBQ3hDLGNBQUksS0FBSyxpQkFBa0IsTUFBSyxpQkFBaUIsTUFBTSxTQUFTLEtBQUs7QUFBQSxtQkFDNUQsS0FBSyxZQUFhLE1BQUssWUFBWSxPQUFPLE1BQU0sT0FBTztBQUFBLGNBQzNELE1B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akIsWUFBRSx5QkFBeUI7QUFDM0IsbUJBQVMsbUJBQW1CLEVBQUUsTUFBTTtBQUFBLFFBQ3RDLFdBQVUsWUFBWSxLQUFJO0FBQ3hCLFlBQUUsZUFBZTtBQUNqQixZQUFFLHlCQUF5QjtBQUMzQixtQkFBUyxnQkFBZ0IsRUFBRSxNQUFNO0FBQUEsUUFDbkM7QUFBQSxNQUNGLEdBQUcsSUFBSTtBQUVQLGFBQU8sZUFBZTtBQUFBLElBQ3hCLENBQUM7QUFBQSxFQUNIOyIsCiAgIm5hbWVzIjogWyJ3aW5kb3ciLCAiZG9jdW1lbnQiLCAidG9wYmFyIiwgIkN1c3RvbUV2ZW50IiwgImNsb3N1cmUiLCAibGl2ZVNvY2tldCIsICJjbG9zdXJlIiwgImRvYyIsICJpc0VtcHR5IiwgImZpbGUiLCAibW9ycGhBdHRycyIsICJtb3JwaGRvbSIsICJjaGlsZHJlbk9ubHkiLCAidGFyZ2V0Q29udGFpbmVyIiwgImNsb25lIiwgImVsIiwgImlucHV0c1VudXNlZCIsICJvbmx5SGlkZGVuSW5wdXRzIiwgImhvb2tzIiwgImxvY2siLCAibG9hZGluZyIsICJlbnRyeSIsICJpbnB1dCIsICJjbG9zdXJlIiwgIkxpdmVTb2NrZXQiLCAidG9wYmFyIl0KfQo= diff --git a/priv/static/favicon.ico b/priv/static/favicon.ico new file mode 100644 index 0000000..7f372bf Binary files /dev/null and b/priv/static/favicon.ico differ diff --git a/priv/static/images/logo.svg b/priv/static/images/logo.svg new file mode 100644 index 0000000..9f26bab --- /dev/null +++ b/priv/static/images/logo.svg @@ -0,0 +1,6 @@ + diff --git a/priv/static/robots.txt b/priv/static/robots.txt new file mode 100644 index 0000000..26e06b5 --- /dev/null +++ b/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/src/main/resources/react-email/.nvmrc b/react-email/.nvmrc similarity index 100% rename from src/main/resources/react-email/.nvmrc rename to react-email/.nvmrc diff --git a/src/main/resources/react-email/emails/email-verification.tsx b/react-email/emails/email-verification.tsx similarity index 100% rename from src/main/resources/react-email/emails/email-verification.tsx rename to react-email/emails/email-verification.tsx diff --git a/src/main/resources/react-email/emails/password-reset.tsx b/react-email/emails/password-reset.tsx similarity index 100% rename from src/main/resources/react-email/emails/password-reset.tsx rename to react-email/emails/password-reset.tsx diff --git a/src/main/resources/react-email/package-lock.json b/react-email/package-lock.json similarity index 100% rename from src/main/resources/react-email/package-lock.json rename to react-email/package-lock.json diff --git a/src/main/resources/react-email/package.json b/react-email/package.json similarity index 100% rename from src/main/resources/react-email/package.json rename to react-email/package.json diff --git a/src/main/resources/react-email/readme.md b/react-email/readme.md similarity index 100% rename from src/main/resources/react-email/readme.md rename to react-email/readme.md diff --git a/src/main/java/com/pricetra/email_server/EmailServerApplication.java b/src/main/java/com/pricetra/email_server/EmailServerApplication.java deleted file mode 100644 index 6c791ad..0000000 --- a/src/main/java/com/pricetra/email_server/EmailServerApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.pricetra.email_server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class EmailServerApplication { - - public static void main(String[] args) { - SpringApplication.run(EmailServerApplication.class, args); - } - -} diff --git a/src/main/java/com/pricetra/email_server/OpenApiConfiguration.java b/src/main/java/com/pricetra/email_server/OpenApiConfiguration.java deleted file mode 100644 index a4f50d8..0000000 --- a/src/main/java/com/pricetra/email_server/OpenApiConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.pricetra.email_server; - -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class OpenApiConfiguration { - - @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI() - .info(new Info() - .title("Pricetra Email API Service") - .version("1.0") - .description("API documentation for the Pricetra Email API Service")); - } -} diff --git a/src/main/java/com/pricetra/email_server/SecurityConfiguration.java b/src/main/java/com/pricetra/email_server/SecurityConfiguration.java deleted file mode 100644 index e903860..0000000 --- a/src/main/java/com/pricetra/email_server/SecurityConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.pricetra.email_server; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import java.util.ArrayList; -import java.util.List; - -@Configuration -public class SecurityConfiguration { - @Bean - CorsConfigurationSource corsConfigurationSource() { - if (!System.getenv("ENV").equals("production")) return null; - - CorsConfiguration configuration = new CorsConfiguration(); - - configuration.setAllowedOrigins(List.of("https://pricetra.com")); - configuration.setAllowedMethods(List.of("GET","POST")); - configuration.setAllowedHeaders(List.of("Authorization","Content-Type")); - - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**",configuration); - return source; - } -} diff --git a/src/main/java/com/pricetra/email_server/controllers/BaseController.java b/src/main/java/com/pricetra/email_server/controllers/BaseController.java deleted file mode 100644 index d2fdf0b..0000000 --- a/src/main/java/com/pricetra/email_server/controllers/BaseController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.pricetra.email_server.controllers; - -import com.pricetra.email_server.dto.EmailVerificationRequest; -import com.sendgrid.Method; -import com.sendgrid.Request; -import com.sendgrid.Response; -import com.sendgrid.SendGrid; -import com.sendgrid.helpers.mail.Mail; -import com.sendgrid.helpers.mail.objects.Content; -import com.sendgrid.helpers.mail.objects.Email; -import org.springframework.core.io.ClassPathResource; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -public class BaseController { - protected final SendGrid sg = new SendGrid(System.getenv("SENDGRID_API_KEY")); - protected final String noReplyEmail = "no-reply@pricetra.com"; - - public Mail newHtmlMailer(String fromEmail, String recipientEmail, String subject, String html) { - Email from = new Email(fromEmail, "Pricetra"); - Email to = new Email(recipientEmail); - Content content = new Content("text/html", html); - return new Mail(from, subject, to, content); - } - - public Response sendEmail(Mail mail) throws IOException { - Request request = new Request(); - request.setMethod(Method.POST); - request.setEndpoint("mail/send"); - request.setBody(mail.build()); - return sg.api(request); - } - - public String getTemplateAsString(String templateFileName) throws IOException { - Charset charset = StandardCharsets.UTF_8; - return new ClassPathResource("email-templates/" + templateFileName) - .getContentAsString(charset); - } -} diff --git a/src/main/java/com/pricetra/email_server/controllers/EmailVerificationController.java b/src/main/java/com/pricetra/email_server/controllers/EmailVerificationController.java deleted file mode 100644 index 568aefa..0000000 --- a/src/main/java/com/pricetra/email_server/controllers/EmailVerificationController.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pricetra.email_server.controllers; - -import com.pricetra.email_server.dto.EmailVerificationRequest; -import com.pricetra.email_server.response.EmailVerificationResponse; -import com.pricetra.email_server.response.EmailResponse; -import com.sendgrid.helpers.mail.Mail; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import com.sendgrid.*; - -import java.io.IOException; - -@RestController -public class EmailVerificationController extends BaseController { - @PostMapping("/email-verification") - public EmailResponse sendEmailVerificationCode(@RequestBody EmailVerificationRequest params) throws IOException { - String html = getTemplateAsString("email-verification.html") - .replace("{{code}}", params.code) - .replace("{{name}}", params.name); - Mail mail = this.newHtmlMailer(noReplyEmail, params.recipientEmail, "Email Verification Code", html); - - Response emailResponse = sendEmail(mail); - EmailVerificationResponse res = new EmailVerificationResponse(); - res.content = html; - res.status = Integer.toString(emailResponse.getStatusCode()); - res.code = params.code; - res.name = params.name; - res.subject = mail.subject; - res.recipientEmail = params.recipientEmail; - return res; - } -} diff --git a/src/main/java/com/pricetra/email_server/controllers/PasswordResetController.java b/src/main/java/com/pricetra/email_server/controllers/PasswordResetController.java deleted file mode 100644 index efc78fe..0000000 --- a/src/main/java/com/pricetra/email_server/controllers/PasswordResetController.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pricetra.email_server.controllers; - -import com.pricetra.email_server.dto.PasswordResetRequest; -import com.pricetra.email_server.response.PasswordResetResponse; -import com.sendgrid.Response; -import com.sendgrid.helpers.mail.Mail; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; - -@RestController -public class PasswordResetController extends BaseController { - @PostMapping("password-reset") - public PasswordResetResponse sendPasswordResetCode(@RequestBody PasswordResetRequest params) throws IOException { - String html = getTemplateAsString("password-reset.html") - .replace("{{fullName}}", params.fullName) - .replace("{{avatarUrl}}", params.avatarUrl) - .replace("{{code}}", params.code); - Mail mail = this.newHtmlMailer(noReplyEmail, params.recipientEmail, "Password Reset Code", html); - Response emailResponse = this.sendEmail(mail); - PasswordResetResponse res = new PasswordResetResponse(); - res.content = html; - res.status = Integer.toString(emailResponse.getStatusCode()); - res.code = params.code; - res.fullName = params.fullName; - res.avatarUrl = params.avatarUrl; - res.subject = mail.subject; - res.recipientEmail = params.recipientEmail; - return res; - } -} diff --git a/src/main/java/com/pricetra/email_server/dto/EmailRequest.java b/src/main/java/com/pricetra/email_server/dto/EmailRequest.java deleted file mode 100644 index f7424aa..0000000 --- a/src/main/java/com/pricetra/email_server/dto/EmailRequest.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.pricetra.email_server.dto; - -public class EmailRequest { - public String recipientEmail = ""; -} diff --git a/src/main/java/com/pricetra/email_server/dto/EmailVerificationRequest.java b/src/main/java/com/pricetra/email_server/dto/EmailVerificationRequest.java deleted file mode 100644 index 86679a9..0000000 --- a/src/main/java/com/pricetra/email_server/dto/EmailVerificationRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.pricetra.email_server.dto; - -public class EmailVerificationRequest extends EmailRequest { - public String code; - public String name; -} diff --git a/src/main/java/com/pricetra/email_server/dto/PasswordResetRequest.java b/src/main/java/com/pricetra/email_server/dto/PasswordResetRequest.java deleted file mode 100644 index 161fc4b..0000000 --- a/src/main/java/com/pricetra/email_server/dto/PasswordResetRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pricetra.email_server.dto; - -public class PasswordResetRequest extends EmailRequest { - public String code; - public String fullName; - public String avatarUrl; -} diff --git a/src/main/java/com/pricetra/email_server/middlewares/AuthenticationMiddleware.java b/src/main/java/com/pricetra/email_server/middlewares/AuthenticationMiddleware.java deleted file mode 100644 index e4905ba..0000000 --- a/src/main/java/com/pricetra/email_server/middlewares/AuthenticationMiddleware.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.pricetra.email_server.middlewares; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.DecodedJWT; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; - -@Component -public class AuthenticationMiddleware extends OncePerRequestFilter { - private final String JWT_KEY = System.getenv("JWT_KEY"); - private final Algorithm algorithm = Algorithm.HMAC256(JWT_KEY); - - private DecodedJWT verifyJwt(String token) { - JWTVerifier verifier = JWT.require(algorithm) - // specify any specific claim validations - .withIssuer("pricetra") - // reusable verifier instance - .build(); - return verifier.verify(token); - } - - @Override - protected void doFilterInternal(@NonNull HttpServletRequest request, - @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) throws ServletException, IOException { - if (System.getenv("ENV").equals("development")) { - filterChain.doFilter(request, response); - return; - } - - final String authHeader = request.getHeader("Authorization"); - if (authHeader == null) throw new ServletException("unauthorized"); - - String[] parsedAuthHeader = authHeader.split(" "); - - if (parsedAuthHeader.length != 2 || !parsedAuthHeader[0].equals("Bearer")) { - throw new ServletException("unauthorized"); - } - - String token = parsedAuthHeader[1]; - this.verifyJwt(token); - filterChain.doFilter(request, response); - } -} diff --git a/src/main/java/com/pricetra/email_server/response/EmailResponse.java b/src/main/java/com/pricetra/email_server/response/EmailResponse.java deleted file mode 100644 index 769eb67..0000000 --- a/src/main/java/com/pricetra/email_server/response/EmailResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.pricetra.email_server.response; - -public class EmailResponse { - public String status; - public String content; - public String recipientEmail; - public String subject; -} diff --git a/src/main/java/com/pricetra/email_server/response/EmailVerificationResponse.java b/src/main/java/com/pricetra/email_server/response/EmailVerificationResponse.java deleted file mode 100644 index 17649dc..0000000 --- a/src/main/java/com/pricetra/email_server/response/EmailVerificationResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.pricetra.email_server.response; - -import java.io.Serializable; - -public class EmailVerificationResponse extends EmailResponse implements Serializable { - public String code; - public String name; -} diff --git a/src/main/java/com/pricetra/email_server/response/PasswordResetResponse.java b/src/main/java/com/pricetra/email_server/response/PasswordResetResponse.java deleted file mode 100644 index 12b37ec..0000000 --- a/src/main/java/com/pricetra/email_server/response/PasswordResetResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.pricetra.email_server.response; - -import java.io.Serializable; - -public class PasswordResetResponse extends EmailResponse implements Serializable { - public String code; - public String fullName; - public String avatarUrl; -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 9aff253..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=email_server -server.port=3001 diff --git a/src/test/java/com/pricetra/email_server/EmailServerApplicationTests.java b/src/test/java/com/pricetra/email_server/EmailServerApplicationTests.java deleted file mode 100644 index 48ce4b8..0000000 --- a/src/test/java/com/pricetra/email_server/EmailServerApplicationTests.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.pricetra.email_server; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class EmailServerApplicationTests { - - @Test - void contextLoads() { - assert(true); - } - -} diff --git a/test/myapp_web/controllers/error_html_test.exs b/test/myapp_web/controllers/error_html_test.exs new file mode 100644 index 0000000..729b8ab --- /dev/null +++ b/test/myapp_web/controllers/error_html_test.exs @@ -0,0 +1,14 @@ +defmodule MyappWeb.ErrorHTMLTest do + use MyappWeb.ConnCase, async: true + + # Bring render_to_string/4 for testing custom views + import Phoenix.Template, only: [render_to_string: 4] + + test "renders 404.html" do + assert render_to_string(MyappWeb.ErrorHTML, "404", "html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(MyappWeb.ErrorHTML, "500", "html", []) == "Internal Server Error" + end +end diff --git a/test/myapp_web/controllers/error_json_test.exs b/test/myapp_web/controllers/error_json_test.exs new file mode 100644 index 0000000..57425af --- /dev/null +++ b/test/myapp_web/controllers/error_json_test.exs @@ -0,0 +1,12 @@ +defmodule MyappWeb.ErrorJSONTest do + use MyappWeb.ConnCase, async: true + + test "renders 404" do + assert MyappWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}} + end + + test "renders 500" do + assert MyappWeb.ErrorJSON.render("500.json", %{}) == + %{errors: %{detail: "Internal Server Error"}} + end +end diff --git a/test/myapp_web/controllers/page_controller_test.exs b/test/myapp_web/controllers/page_controller_test.exs new file mode 100644 index 0000000..6c58cf2 --- /dev/null +++ b/test/myapp_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule MyappWeb.PageControllerTest do + use MyappWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, ~p"/") + assert html_response(conn, 200) =~ "Peace of mind from prototype to production" + end +end diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex new file mode 100644 index 0000000..2d492da --- /dev/null +++ b/test/support/conn_case.ex @@ -0,0 +1,38 @@ +defmodule MyappWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use MyappWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # The default endpoint for testing + @endpoint MyappWeb.Endpoint + + use MyappWeb, :verified_routes + + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import MyappWeb.ConnCase + end + end + + setup tags do + Myapp.DataCase.setup_sandbox(tags) + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/test/support/data_case.ex b/test/support/data_case.ex new file mode 100644 index 0000000..0e45454 --- /dev/null +++ b/test/support/data_case.ex @@ -0,0 +1,58 @@ +defmodule Myapp.DataCase do + @moduledoc """ + This module defines the setup for tests requiring + access to the application's data layer. + + You may define functions here to be used as helpers in + your tests. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use Myapp.DataCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + alias Myapp.Repo + + import Ecto + import Ecto.Changeset + import Ecto.Query + import Myapp.DataCase + end + end + + setup tags do + Myapp.DataCase.setup_sandbox(tags) + :ok + end + + @doc """ + Sets up the sandbox based on the test tags. + """ + def setup_sandbox(tags) do + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Myapp.Repo, shared: not tags[:async]) + on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) + end + + @doc """ + A helper that transforms changeset errors into a map of messages. + + assert {:error, changeset} = Accounts.create_user(%{password: "short"}) + assert "password is too short" in errors_on(changeset).password + assert %{password: ["password is too short"]} = errors_on(changeset) + + """ + def errors_on(changeset) do + Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> + Regex.replace(~r"%{(\w+)}", message, fn _, key -> + opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() + end) + end) + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..25f1b33 --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1,2 @@ +ExUnit.start() +Ecto.Adapters.SQL.Sandbox.mode(Myapp.Repo, :manual)