From 426c8cd1aca983bec22a64b227e463eae12ae4f4 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 19:34:01 -0500 Subject: [PATCH 01/37] [IF] add twine file name and content for database storage --- src/chigame/games/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index 09b0af253..b763b4cac 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -33,6 +33,8 @@ class Game(models.Model): # interactive fiction - twine file twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) + twine_file_name = models.CharField(max_length=255, null=True, blank=True) + twine_file_content = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( null=True, blank=True From 957393d7d1e5c2a921716cf46709dedd4ac75179 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 19:56:39 -0500 Subject: [PATCH 02/37] [Interactive fiction] to get twine from the database for viewing --- src/chigame/games/views.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index d2963f2be..0add4a05e 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -15,7 +15,7 @@ from django.core.paginator import Paginator from django.db.models import Avg, Case, Count, ExpressionWrapper, F, FloatField, Q, Value, When from django.db.models.functions import Lower -from django.http import HttpResponseForbidden, HttpResponseRedirect, JsonResponse +from django.http import HttpResponse, Http404, HttpResponseForbidden, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse, reverse_lazy from django.utils import timezone @@ -183,6 +183,17 @@ def get_context_data(self, **kwargs): context["is_create"] = False return context +# ===========For storing twine in database ============== + +def serve_twine_from_db(request, pk): + game = get_object_or_404(Game, pk=pk) + if not game.twine_file_content: + raise Http404("No Twine file stored in database.") + return HttpResponse( + game.twine_file_content, + content_type="text/html", + headers={"Content-Disposition": f'inline; filename="{game.twine_file_name}"'}, + ) # =============== BGG Searching ================= # The following functions involve using the BoardGameGeek API to search for games. From ecb9e8e5500b381206de05a04b84ddcb4aef900a Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 19:57:28 -0500 Subject: [PATCH 03/37] [Interactive fiction] make sure the serve_twine_from_db view is accessible from a link --- src/chigame/games/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chigame/games/urls.py b/src/chigame/games/urls.py index a01fa25b1..49c56867b 100644 --- a/src/chigame/games/urls.py +++ b/src/chigame/games/urls.py @@ -37,6 +37,7 @@ path("interactive-fiction/", views.InteractiveFictionView.as_view(), name="interactive-fiction"), path("/upload/", UploadFileView.as_view(), name="upload-file"), path("if-game//", InteractiveFictionView.as_view(), name="interactive-fiction-detail"), + path("twine-db//", views.serve_twine_from_db, name="twine-db"), # tournaments path("tournaments/", views.TournamentListView.as_view(), name="tournament-list"), path("tournaments//", views.TournamentDetailView.as_view(), name="tournament-detail"), From a081cd6de0a07ebc47f483b0b2aaf2019b55253f Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 20:01:24 -0500 Subject: [PATCH 04/37] [Interactive Fiction] Add play button if the twine game is from the database --- src/templates/games/game_detail.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/templates/games/game_detail.html b/src/templates/games/game_detail.html index 96b262d8d..3a45e4d5d 100644 --- a/src/templates/games/game_detail.html +++ b/src/templates/games/game_detail.html @@ -107,6 +107,13 @@

Play Twine Game

target="_blank" class="btn btn-success">Open Game in New Tab {% endif %} + + {% if game.twine_file_content %} +

Play Twine Game from Database

+ Open Game in New Tab + {% endif %}

Players

{% if game.min_players == game.max_players %} From dd04cd09f123f8784ec1bbba3620b87ff3c1a149 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 20:07:32 -0500 Subject: [PATCH 05/37] [Interactive Fiction] Make sure twine file is binary field not file field --- src/chigame/games/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index b763b4cac..fa7802119 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -32,9 +32,10 @@ class Game(models.Model): max_players = models.PositiveIntegerField() # interactive fiction - twine file - twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) + # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) + #want twine file to be binary to store in the actual database twine_file_name = models.CharField(max_length=255, null=True, blank=True) - twine_file_content = models.BinaryField(null=True, blank=True) + twine_file = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( null=True, blank=True From fb374becd4bc10810b8bf463a29f8ee65a7cac27 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 21:45:47 -0500 Subject: [PATCH 06/37] [Interactive Fiction] update form handling in game create view --- src/chigame/games/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 0add4a05e..c9e869c56 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -155,6 +155,8 @@ def form_valid(self, form): # ✅ Manually assign uploaded file if self.request.FILES.get("twine_file"): self.object.twine_file = self.request.FILES["twine_file"] + #read raw bytes + self.object.twine_file = uploaded_file.read() self.object.save() return redirect(self.get_success_url()) From 668be7a02ff462904d92713a52f912ceb8e6b750 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 22:06:56 -0500 Subject: [PATCH 07/37] [Interactive Fiction] Fix error as the file is a binary field now --- src/chigame/games/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index c9e869c56..784eb6bff 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -105,7 +105,7 @@ def get_context_data(self, **kwargs): context["avg_rating"] = self.object.reviews.filter(is_public=True).aggregate(Avg("rating"))["rating__avg"] # FOR IF/twine GAMES - context["is_twine_game"] = self.object.twine_file.name.endswith(".html") if self.object.twine_file else False + context["is_twine_game"] = self.object.twine_file is not None context["recommended_games"] = get_recommended_games( game=self.object, user=self.request.user if self.request.user.is_authenticated else None, From 2ce0f255bf5a986e65adf0c4563eb92eb00fe4cb Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 22:11:08 -0500 Subject: [PATCH 08/37] [Interactive Fiction] Update game_form.html with Twine upload --- src/templates/games/game_form.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/templates/games/game_form.html b/src/templates/games/game_form.html index 6d3414bfd..a09c71c89 100644 --- a/src/templates/games/game_form.html +++ b/src/templates/games/game_form.html @@ -28,6 +28,12 @@


{% endfor %} + + + + +

+ From b7ad807eefd7b72c3666ceed101e23097b1f3ac7 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 22:26:32 -0500 Subject: [PATCH 09/37] [Interactive Fiction] Fix the name error by not using the uploaded file --- src/chigame/games/views.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 784eb6bff..7862d99d4 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -152,11 +152,12 @@ def get_context_data(self, **kwargs): # Ensure the uploaded Twine .html file is saved to the Game model def form_valid(self, form): self.object = form.save(commit=False) - # ✅ Manually assign uploaded file - if self.request.FILES.get("twine_file"): - self.object.twine_file = self.request.FILES["twine_file"] - #read raw bytes - self.object.twine_file = uploaded_file.read() + # save both the file and its contents + uploaded_file = self.request.FILES.get("twine_file") + if uploaded_file: + self.object.twine_file = uploaded_file + self.object.twine_file_content = uploaded_file.read() + self.object.save() return redirect(self.get_success_url()) From 6a3c94dc88d4d925dddaf31fbd79fdee0d23785f Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 22:54:48 -0500 Subject: [PATCH 10/37] [Interactive fiction] fix byte reading in form_valid --- src/chigame/games/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 7862d99d4..0ddbe5719 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -155,8 +155,11 @@ def form_valid(self, form): # save both the file and its contents uploaded_file = self.request.FILES.get("twine_file") if uploaded_file: - self.object.twine_file = uploaded_file - self.object.twine_file_content = uploaded_file.read() + file_contents = uploaded_file.read() + uploaded_file.seek(0) + + self.object.twine_file_content = file_contents #binary field expects bytes + self.object.twine_file = uploaded_file #file field expects a file object self.object.save() return redirect(self.get_success_url()) From 4e532c2ee2fe4072b6e18acac7d57c38844bc483 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:00:43 -0500 Subject: [PATCH 11/37] [Interactive fiction] fix byte reading error in form_valid --- src/chigame/games/views.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 0ddbe5719..a924d26cb 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -157,9 +157,11 @@ def form_valid(self, form): if uploaded_file: file_contents = uploaded_file.read() uploaded_file.seek(0) - - self.object.twine_file_content = file_contents #binary field expects bytes - self.object.twine_file = uploaded_file #file field expects a file object + + #assign the file to file field first + self.object.twine_file = uploaded_file + #explicity assign the bytes explicitly to binary field to avoid error + self.object.twine_file_content = bytes(file_contents) self.object.save() return redirect(self.get_success_url()) From 925a565296343d5ab3bb3fa25ec9e7850033ff8a Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:04:31 -0500 Subject: [PATCH 12/37] [Interactive Fiction] Changing order for file handling in form_valid --- src/chigame/games/views.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index a924d26cb..5054fc1c7 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -155,13 +155,14 @@ def form_valid(self, form): # save both the file and its contents uploaded_file = self.request.FILES.get("twine_file") if uploaded_file: + #read the file contents as bytes file_contents = uploaded_file.read() - uploaded_file.seek(0) - - #assign the file to file field first + #rewind for FileField + uploaded_file.seek(0) + #store in file field self.object.twine_file = uploaded_file - #explicity assign the bytes explicitly to binary field to avoid error - self.object.twine_file_content = bytes(file_contents) + # store the raw bytes in BinaryField + self.object.twine_file_content = file_contents self.object.save() return redirect(self.get_success_url()) From 87c13757cd8baf24d14d6b6d239358b592bb86b2 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:15:53 -0500 Subject: [PATCH 13/37] [IF] rename variable --- src/chigame/games/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index fa7802119..f16500acd 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -35,7 +35,7 @@ class Game(models.Model): # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) #want twine file to be binary to store in the actual database twine_file_name = models.CharField(max_length=255, null=True, blank=True) - twine_file = models.BinaryField(null=True, blank=True) + twine_file_content = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( null=True, blank=True From 8e8399c538a6ce9b7757773d5cf7cc26df2fd75d Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:19:27 -0500 Subject: [PATCH 14/37] [IF] fix char versus binary field reading --- src/chigame/games/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 5054fc1c7..f4fa63b3b 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -554,7 +554,7 @@ class InteractiveFictionView(TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - latest_game = Game.objects.filter(twine_file__isnull=False).order_by("-id").first() + latest_game = Game.objects.filter(twine_file_content__isnull=False).order_by("-id").first() if not latest_game: # fallback dummy game to prevent pk=None From 2c70f219fd35ba4ffe27ce0015db43f06f4036fa Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:21:38 -0500 Subject: [PATCH 15/37] [IF] update variable name --- src/chigame/games/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index f4fa63b3b..c3054fcc6 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -568,7 +568,7 @@ def get_context_data(self, **kwargs): context["game"] = latest_game - if latest_game.twine_file: + if latest_game.twine_file_content: context["uploaded_file_url"] = latest_game.twine_file.url return context From a7722c69863a3e77a95db7868c582d259cea18b1 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:25:17 -0500 Subject: [PATCH 16/37] [IF] fix variable name inconsistency for twine_file --- src/chigame/games/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index c3054fcc6..33d5d8ea0 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -196,10 +196,10 @@ def get_context_data(self, **kwargs): def serve_twine_from_db(request, pk): game = get_object_or_404(Game, pk=pk) - if not game.twine_file_content: + if not game.twine_file: raise Http404("No Twine file stored in database.") return HttpResponse( - game.twine_file_content, + game.twine_file, content_type="text/html", headers={"Content-Disposition": f'inline; filename="{game.twine_file_name}"'}, ) @@ -554,7 +554,7 @@ class InteractiveFictionView(TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - latest_game = Game.objects.filter(twine_file_content__isnull=False).order_by("-id").first() + latest_game = Game.objects.filter(twine_file__isnull=False).order_by("-id").first() if not latest_game: # fallback dummy game to prevent pk=None @@ -568,7 +568,7 @@ def get_context_data(self, **kwargs): context["game"] = latest_game - if latest_game.twine_file_content: + if latest_game.twine_file: context["uploaded_file_url"] = latest_game.twine_file.url return context From c51f9558b333107d60944428cd2c3bbdd02be648 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:25:41 -0500 Subject: [PATCH 17/37] [IF] revert variable name to avoid naming inconsistency --- src/chigame/games/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index f16500acd..fa7802119 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -35,7 +35,7 @@ class Game(models.Model): # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) #want twine file to be binary to store in the actual database twine_file_name = models.CharField(max_length=255, null=True, blank=True) - twine_file_content = models.BinaryField(null=True, blank=True) + twine_file = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( null=True, blank=True From 819e992ae64a8385c876b1213ab9bf07ac2b862b Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:36:12 -0500 Subject: [PATCH 18/37] [IF] fix file handling based on update game model --- src/chigame/games/views.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 33d5d8ea0..11420e18c 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -155,14 +155,9 @@ def form_valid(self, form): # save both the file and its contents uploaded_file = self.request.FILES.get("twine_file") if uploaded_file: - #read the file contents as bytes - file_contents = uploaded_file.read() - #rewind for FileField + self.object.twine_file_name = uploaded_file.name + self.object.twine_file = uploaded_file.read() uploaded_file.seek(0) - #store in file field - self.object.twine_file = uploaded_file - # store the raw bytes in BinaryField - self.object.twine_file_content = file_contents self.object.save() return redirect(self.get_success_url()) From 931a5660a085bddf74b72f714702ee2368fe30f0 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:39:43 -0500 Subject: [PATCH 19/37] [Interactive fiction] update variable name based on model change --- src/chigame/games/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index 11420e18c..f9983e150 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -163,7 +163,7 @@ def form_valid(self, form): return redirect(self.get_success_url()) def get_success_url(self): - if self.object.twine_file and self.object.twine_file.name.endswith(".html"): + if self.object.twine_file_name and self.object.twine_file_name.endswith(".html"): return reverse("interactive-fiction-detail", kwargs={"pk": self.object.pk}) return reverse("game-detail", kwargs={"pk": self.object.pk}) From 7910929a678b597bb4f5467954a034a611cf4a4e Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:42:05 -0500 Subject: [PATCH 20/37] [IF] fix string error from changing file field to binary field in models.. --- src/chigame/games/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index f9983e150..5a23956b6 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -564,7 +564,7 @@ def get_context_data(self, **kwargs): context["game"] = latest_game if latest_game.twine_file: - context["uploaded_file_url"] = latest_game.twine_file.url + context["has_uploaded_twine"] = bool(latest_game.twine_file) return context From 4722e3885496b9a2acade8995c5bf6c71accde64 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Tue, 20 May 2025 23:44:10 -0500 Subject: [PATCH 21/37] [Interactive fiction] clean up twine file handling --- src/templates/games/game_detail.html | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/templates/games/game_detail.html b/src/templates/games/game_detail.html index 3a45e4d5d..f0a4c28de 100644 --- a/src/templates/games/game_detail.html +++ b/src/templates/games/game_detail.html @@ -101,15 +101,8 @@

Description

{% endif %}

{{ game.description|linebreaksbr }}

- {% if is_twine_game %} + {% if game.twine_file %}

Play Twine Game

- Open Game in New Tab - {% endif %} - - {% if game.twine_file_content %} -

Play Twine Game from Database

Open Game in New Tab From 7acb8115a7772e9496d23eb906d13338e0174f72 Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Wed, 21 May 2025 00:05:48 -0500 Subject: [PATCH 22/37] [IF] force migration check by removing, will add this back --- src/chigame/games/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index fa7802119..0e615a8d5 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -34,7 +34,7 @@ class Game(models.Model): # interactive fiction - twine file # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) #want twine file to be binary to store in the actual database - twine_file_name = models.CharField(max_length=255, null=True, blank=True) + #twine_file_name = models.CharField(max_length=255, null=True, blank=True) twine_file = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( From a332b75dee3333fa35f9e917977b16497b2aac5a Mon Sep 17 00:00:00 2001 From: zaynacheema <146792920+zaynacheema@users.noreply.github.com> Date: Wed, 21 May 2025 00:06:38 -0500 Subject: [PATCH 23/37] [IF] add it back --- src/chigame/games/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index 0e615a8d5..fa7802119 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -34,7 +34,7 @@ class Game(models.Model): # interactive fiction - twine file # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) #want twine file to be binary to store in the actual database - #twine_file_name = models.CharField(max_length=255, null=True, blank=True) + twine_file_name = models.CharField(max_length=255, null=True, blank=True) twine_file = models.BinaryField(null=True, blank=True) suggested_age = models.PositiveSmallIntegerField( From 8ec00ad570a360b4f3951779c9f93c89a1e1993b Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Wed, 21 May 2025 00:07:36 -0500 Subject: [PATCH 24/37] Fix migrations --- ...3_alter_livechatmessagereaction_content.py | 17 +++ ...twine_file_content_game_twine_file_name.py | 23 +++ ...wine_file_content_alter_game_twine_file.py | 22 +++ ...name_twine_file_game_twine_file_content.py | 18 +++ ...name_twine_file_content_game_twine_file.py | 18 +++ .../0043_remove_game_twine_file_name.py | 17 +++ .../migrations/0044_game_twine_file_name.py | 18 +++ .../leaderboards/migrations/0001_initial.py | 142 ++++++++++++++++++ .../leaderboards/migrations/__init__.py | 0 9 files changed, 275 insertions(+) create mode 100644 src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py create mode 100644 src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py create mode 100644 src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py create mode 100644 src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py create mode 100644 src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py create mode 100644 src/chigame/games/migrations/0043_remove_game_twine_file_name.py create mode 100644 src/chigame/games/migrations/0044_game_twine_file_name.py create mode 100644 src/chigame/leaderboards/migrations/0001_initial.py create mode 100644 src/chigame/leaderboards/migrations/__init__.py diff --git a/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py b/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py new file mode 100644 index 000000000..7eacde4db --- /dev/null +++ b/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.20 on 2025-05-20 21:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("chat", "0002_livechatmessagereaction"), + ] + + operations = [ + migrations.AlterField( + model_name="livechatmessagereaction", + name="content", + field=models.CharField(help_text="Up to 10 emoji characters", max_length=10), + ), + ] diff --git a/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py b/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py new file mode 100644 index 000000000..ca0c88ab8 --- /dev/null +++ b/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.7 on 2025-05-21 00:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0038_merge_20250519_0011"), + ] + + operations = [ + migrations.AddField( + model_name="game", + name="twine_file_content", + field=models.BinaryField(blank=True, null=True), + ), + migrations.AddField( + model_name="game", + name="twine_file_name", + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py b/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py new file mode 100644 index 000000000..dd19d4434 --- /dev/null +++ b/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.7 on 2025-05-21 01:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0039_game_twine_file_content_game_twine_file_name"), + ] + + operations = [ + migrations.RemoveField( + model_name="game", + name="twine_file_content", + ), + migrations.AlterField( + model_name="game", + name="twine_file", + field=models.BinaryField(blank=True, null=True), + ), + ] diff --git a/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py b/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py new file mode 100644 index 000000000..78fa198db --- /dev/null +++ b/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.20 on 2025-05-21 04:17 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0040_remove_game_twine_file_content_alter_game_twine_file"), + ] + + operations = [ + migrations.RenameField( + model_name="game", + old_name="twine_file", + new_name="twine_file_content", + ), + ] diff --git a/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py b/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py new file mode 100644 index 000000000..9b57f0107 --- /dev/null +++ b/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.20 on 2025-05-21 04:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0041_rename_twine_file_game_twine_file_content"), + ] + + operations = [ + migrations.RenameField( + model_name="game", + old_name="twine_file_content", + new_name="twine_file", + ), + ] diff --git a/src/chigame/games/migrations/0043_remove_game_twine_file_name.py b/src/chigame/games/migrations/0043_remove_game_twine_file_name.py new file mode 100644 index 000000000..96a42524e --- /dev/null +++ b/src/chigame/games/migrations/0043_remove_game_twine_file_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.20 on 2025-05-21 05:05 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0042_rename_twine_file_content_game_twine_file"), + ] + + operations = [ + migrations.RemoveField( + model_name="game", + name="twine_file_name", + ), + ] diff --git a/src/chigame/games/migrations/0044_game_twine_file_name.py b/src/chigame/games/migrations/0044_game_twine_file_name.py new file mode 100644 index 000000000..bbfd007e7 --- /dev/null +++ b/src/chigame/games/migrations/0044_game_twine_file_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.20 on 2025-05-21 05:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0043_remove_game_twine_file_name"), + ] + + operations = [ + migrations.AddField( + model_name="game", + name="twine_file_name", + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/src/chigame/leaderboards/migrations/0001_initial.py b/src/chigame/leaderboards/migrations/0001_initial.py new file mode 100644 index 000000000..a1d78d0c8 --- /dev/null +++ b/src/chigame/leaderboards/migrations/0001_initial.py @@ -0,0 +1,142 @@ +# Generated by Django 5.1.7 on 2025-05-21 01:03 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("games", "0039_game_twine_file_content_game_twine_file_name"), + ("users", "0013_merge_20250519_0011"), + ] + + operations = [ + migrations.CreateModel( + name="Region", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("continent", models.CharField(max_length=100)), + ("country", models.CharField(max_length=100)), + ("region", models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name="Leaderboard", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ( + "game", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="leaderboards", to="games.game" + ), + ), + ], + ), + migrations.CreateModel( + name="LeaderboardEntry", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("rank", models.IntegerField()), + ( + "leaderboard", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="entries", + to="leaderboards.leaderboard", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="leaderboard_entries", + to="users.userprofile", + ), + ), + ], + ), + migrations.CreateModel( + name="Metric", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("unit", models.CharField(max_length=50)), + ("description", models.TextField(blank=True)), + ( + "game", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="metrics", to="games.game" + ), + ), + ], + ), + migrations.CreateModel( + name="MetricScore", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("score", models.IntegerField()), + ( + "leaderboard_entry", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="metric_scores", + to="leaderboards.leaderboardentry", + ), + ), + ( + "match", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="metric_scores", to="games.match" + ), + ), + ( + "metric", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="metric_scores", + to="leaderboards.metric", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="metric_scores", + to="users.userprofile", + ), + ), + ], + ), + migrations.CreateModel( + name="LeaderboardPrivacySetting", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("complete_opt_out", models.BooleanField(default=False)), + ("display_as_anonymous", models.BooleanField(default=False)), + ( + "game", + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="games.game" + ), + ), + ( + "leaderboard", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="leaderboards.leaderboard", + ), + ), + ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="users.userprofile")), + ], + options={ + "unique_together": {("user", "game", "leaderboard")}, + }, + ), + ] diff --git a/src/chigame/leaderboards/migrations/__init__.py b/src/chigame/leaderboards/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb From c7d42be4e4175ba3ec16ea3e54436793042d6c12 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Wed, 21 May 2025 14:34:53 -0500 Subject: [PATCH 25/37] [IF] merge migrations --- .../games/migrations/0045_merge_20250521_1434.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/chigame/games/migrations/0045_merge_20250521_1434.py diff --git a/src/chigame/games/migrations/0045_merge_20250521_1434.py b/src/chigame/games/migrations/0045_merge_20250521_1434.py new file mode 100644 index 000000000..41b1a0c41 --- /dev/null +++ b/src/chigame/games/migrations/0045_merge_20250521_1434.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.20 on 2025-05-21 19:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0040_merge_20250521_1413"), + ("games", "0044_game_twine_file_name"), + ] + + operations = [] From 493eecf67d1ff513f438222140a6d097e9a4b72c Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Wed, 21 May 2025 14:38:28 -0500 Subject: [PATCH 26/37] ran pre commit fixes --- src/chigame/games/models.py | 2 +- src/chigame/games/views.py | 9 ++++++--- src/templates/games/game_form.html | 7 +++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/chigame/games/models.py b/src/chigame/games/models.py index 5ddccfed9..4e7f251df 100644 --- a/src/chigame/games/models.py +++ b/src/chigame/games/models.py @@ -33,7 +33,7 @@ class Game(models.Model): # interactive fiction - twine file # twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True) - #want twine file to be binary to store in the actual database + # want twine file to be binary to store in the actual database twine_file_name = models.CharField(max_length=255, null=True, blank=True) twine_file = models.BinaryField(null=True, blank=True) diff --git a/src/chigame/games/views.py b/src/chigame/games/views.py index fc4defdf8..44df9cd96 100644 --- a/src/chigame/games/views.py +++ b/src/chigame/games/views.py @@ -15,7 +15,7 @@ from django.core.paginator import Paginator from django.db.models import Avg, Case, Count, ExpressionWrapper, F, FloatField, Q, Value, When from django.db.models.functions import Lower -from django.http import HttpResponse, Http404, HttpResponseForbidden, HttpResponseRedirect, JsonResponse +from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse, reverse_lazy from django.utils import timezone @@ -158,7 +158,7 @@ def form_valid(self, form): self.object.twine_file_name = uploaded_file.name self.object.twine_file = uploaded_file.read() uploaded_file.seek(0) - + self.object.save() return redirect(self.get_success_url()) @@ -187,7 +187,9 @@ def get_context_data(self, **kwargs): context["is_create"] = False return context -# ===========For storing twine in database ============== + +# ===========For storing twine in database ============== + def serve_twine_from_db(request, pk): game = get_object_or_404(Game, pk=pk) @@ -199,6 +201,7 @@ def serve_twine_from_db(request, pk): headers={"Content-Disposition": f'inline; filename="{game.twine_file_name}"'}, ) + # =============== BGG Searching ================= # The following functions involve using the BoardGameGeek API to search for games. # API documentation: https://boardgamegeek.com/wiki/page/BGG_XML_API2 diff --git a/src/templates/games/game_form.html b/src/templates/games/game_form.html index a09c71c89..813e9c701 100644 --- a/src/templates/games/game_form.html +++ b/src/templates/games/game_form.html @@ -28,12 +28,11 @@


{% endfor %} - - -

- + +
+
From 7ab64d4058432a03beac968d89c5c1f0b247ad9d Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Wed, 21 May 2025 16:11:42 -0500 Subject: [PATCH 27/37] [IF] Fix migration --- .../migrations/0046_auto_20250521_1607.py | 26 +++++++++++++++++++ src/chigame/games/migrations/twine_b64.txt | 1 + twine_b64.txt | 0 3 files changed, 27 insertions(+) create mode 100644 src/chigame/games/migrations/0046_auto_20250521_1607.py create mode 100644 src/chigame/games/migrations/twine_b64.txt create mode 100644 twine_b64.txt diff --git a/src/chigame/games/migrations/0046_auto_20250521_1607.py b/src/chigame/games/migrations/0046_auto_20250521_1607.py new file mode 100644 index 000000000..0b1aaec7c --- /dev/null +++ b/src/chigame/games/migrations/0046_auto_20250521_1607.py @@ -0,0 +1,26 @@ +import base64 +from django.db import migrations + +def insert_twine_game(apps, schema_editor): + Game = apps.get_model("games", "Game") + + with open("src/chigame/games/migrations/twine_b64.txt", "rb") as f: + html_bytes = base64.b64decode(f.read()) + + Game.objects.create( + name="Midterm Project", + description="Uploaded via migration", + twine_file=html_bytes, + min_players=1, + max_players=1 + ) + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0045_merge_20250521_1434"), + ] + + operations = [ + migrations.RunPython(insert_twine_game, atomic=False), + ] diff --git a/src/chigame/games/migrations/twine_b64.txt b/src/chigame/games/migrations/twine_b64.txt new file mode 100644 index 000000000..085c2aa90 --- /dev/null +++ b/src/chigame/games/migrations/twine_b64.txt @@ -0,0 +1 @@ +PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KPG1ldGEgY2hhcnNldD0idXRmLTgiPgo8bWV0YSBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSIgbmFtZT0idmlld3BvcnQiPgo8dGl0bGU+TWlkdGVybSBQcm9qZWN0PC90aXRsZT4KPHN0eWxlIHRpdGxlPSJUd2luZSBDU1MiPkBrZXlmcmFtZXMgYXBwZWFyezAle29wYWNpdHk6MH10b3tvcGFjaXR5OjF9fUBrZXlmcmFtZXMgZmFkZS1pbi1vdXR7MCUsdG97b3BhY2l0eTowfTUwJXtvcGFjaXR5OjF9fUBrZXlmcmFtZXMgcnVtYmxlezI1JXt0b3A6LTAuMWVtfTc1JXt0b3A6LjFlbX0wJSx0b3t0b3A6MHB4fX1Aa2V5ZnJhbWVzIHNodWRkZXJ7MjUle2xlZnQ6LjFlbX03NSV7bGVmdDotMC4xZW19MCUsdG97bGVmdDowcHh9fUBrZXlmcmFtZXMgYnVveXsyNSV7dG9wOi4yNWVtfTc1JXt0b3A6LTAuMjVlbX0wJSx0b3t0b3A6MHB4fX1Aa2V5ZnJhbWVzIHN3YXl7MjUle2xlZnQ6LjI1ZW19NzUle2xlZnQ6LTAuMjVlbX0wJSx0b3tsZWZ0OjBweH19QGtleWZyYW1lcyBwdWxzZXswJXt0cmFuc2Zvcm06c2NhbGUoMCwgMCl9MjAle3RyYW5zZm9ybTpzY2FsZSgxLjIsIDEuMil9NDAle3RyYW5zZm9ybTpzY2FsZSgwLjksIDAuOSl9NjAle3RyYW5zZm9ybTpzY2FsZSgxLjA1LCAxLjA1KX04MCV7dHJhbnNmb3JtOnNjYWxlKDAuOTI1LCAwLjkyNSl9dG97dHJhbnNmb3JtOnNjYWxlKDEsIDEpfX1Aa2V5ZnJhbWVzIHpvb20taW57MCV7dHJhbnNmb3JtOnNjYWxlKDAsIDApfXRve3RyYW5zZm9ybTpzY2FsZSgxLCAxKX19QGtleWZyYW1lcyBzaHVkZGVyLWluezAlLHRve3RyYW5zZm9ybTp0cmFuc2xhdGVYKDBlbSl9NSUsMjUlLDQ1JXt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtMWVtKX0xNSUsMzUlLDU1JXt0cmFuc2Zvcm06dHJhbnNsYXRlWCgxZW0pfTY1JXt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtMC42ZW0pfTc1JXt0cmFuc2Zvcm06dHJhbnNsYXRlWCgwLjZlbSl9ODUle3RyYW5zZm9ybTp0cmFuc2xhdGVYKC0wLjJlbSl9OTUle3RyYW5zZm9ybTp0cmFuc2xhdGVYKDAuMmVtKX19QGtleWZyYW1lcyBydW1ibGUtaW57MCUsdG97dHJhbnNmb3JtOnRyYW5zbGF0ZVkoMGVtKX01JSwyNSUsNDUle3RyYW5zZm9ybTp0cmFuc2xhdGVZKC0xZW0pfTE1JSwzNSUsNTUle3RyYW5zZm9ybTp0cmFuc2xhdGVZKDFlbSl9NjUle3RyYW5zZm9ybTp0cmFuc2xhdGVZKC0wLjZlbSl9NzUle3RyYW5zZm9ybTp0cmFuc2xhdGVZKDAuNmVtKX04NSV7dHJhbnNmb3JtOnRyYW5zbGF0ZVkoLTAuMmVtKX05NSV7dHJhbnNmb3JtOnRyYW5zbGF0ZVkoMC4yZW0pfX1Aa2V5ZnJhbWVzIGZpZGdldHswJSw4LjElLDgyLjElLDMxLjElLDM4LjElLDQ0LjElLDQwLjElLDQ3LjElLDc0LjElLDE2LjElLDI3LjElLDcyLjElLDI0LjElLDk1LjElLDYuMSUsMzYuMSUsMjAuMSUsNC4xJSw5MS4xJSwxNC4xJSw4Ny4xJSx0b3tsZWZ0OjBweDt0b3A6MHB4fTglLDgyJSwzMSUsMzglLDQ0JXtsZWZ0Oi0xcHh9NDAlLDQ3JSw3NCUsMTYlLDI3JXtsZWZ0OjFweH03MiUsMjQlLDk1JSw2JSwzNiV7dG9wOi0xcHh9MjAlLDQlLDkxJSwxNCUsODcle3RvcDoxcHh9fUBrZXlmcmFtZXMgc2xpZGUtcmlnaHR7MCV7dHJhbnNmb3JtOnRyYW5zbGF0ZVgoLTEwMHZ3KX19QGtleWZyYW1lcyBzbGlkZS1sZWZ0ezAle3RyYW5zZm9ybTp0cmFuc2xhdGVYKDEwMHZ3KX19QGtleWZyYW1lcyBzbGlkZS11cHswJXt0cmFuc2Zvcm06dHJhbnNsYXRlWSgxMDB2aCl9fUBrZXlmcmFtZXMgc2xpZGUtZG93bnswJXt0cmFuc2Zvcm06dHJhbnNsYXRlWSgtMTAwdmgpfX1Aa2V5ZnJhbWVzIGZhZGUtcmlnaHR7MCV7b3BhY2l0eTowO3RyYW5zZm9ybTp0cmFuc2xhdGVYKC0xZW0pfXRve29wYWNpdHk6MX19QGtleWZyYW1lcyBmYWRlLWxlZnR7MCV7b3BhY2l0eTowO3RyYW5zZm9ybTp0cmFuc2xhdGVYKDFlbSl9dG97b3BhY2l0eToxfX1Aa2V5ZnJhbWVzIGZhZGUtdXB7MCV7b3BhY2l0eTowO3RyYW5zZm9ybTp0cmFuc2xhdGVZKDFlbSl9dG97b3BhY2l0eToxfX1Aa2V5ZnJhbWVzIGZhZGUtZG93bnswJXtvcGFjaXR5OjA7dHJhbnNmb3JtOnRyYW5zbGF0ZVkoLTFlbSl9dG97b3BhY2l0eToxfX1Aa2V5ZnJhbWVzIGZsaWNrZXJ7MCUsMjklLDMxJSw2MyUsNjUlLDc3JSw3OSUsODYlLDg4JSw5MSUsOTMle29wYWNpdHk6MH0zMCV7b3BhY2l0eTouMn02NCV7b3BhY2l0eTouNH03OCV7b3BhY2l0eTouNn04NyV7b3BhY2l0eTouOH05MiUsdG97b3BhY2l0eToxfX1Aa2V5ZnJhbWVzIGJsdXJ7MCV7ZmlsdGVyOmJsdXIoMnJlbSk7b3BhY2l0eTowfTI1JXtvcGFjaXR5OjF9dG97ZmlsdGVyOmJsdXIoMHJlbSk7b3BhY2l0eToxfX0uZG9tLWRlYnVnLW1vZGUgdHctc3RvcnksLmRvbS1kZWJ1Zy1tb2RlIHR3LXBhc3NhZ2UsLmRvbS1kZWJ1Zy1tb2RlIHR3LXNpZGViYXIsLmRvbS1kZWJ1Zy1tb2RlIHR3LWluY2x1ZGUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWhvb2ssLmRvbS1kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb24sLmRvbS1kZWJ1Zy1tb2RlIHR3LWxpbmssLmRvbS1kZWJ1Zy1tb2RlIHR3LWRpYWxvZywuZG9tLWRlYnVnLW1vZGUgdHctY29sdW1ucywuZG9tLWRlYnVnLW1vZGUgdHctY29sdW1uLC5kb20tZGVidWctbW9kZSB0dy1hbGlnbntvdXRsaW5lOjFweCBzb2xpZCAjZjVhM2RhO21pbi1oZWlnaHQ6MzJweDtkaXNwbGF5OmJsb2NrICFpbXBvcnRhbnR9LmRvbS1kZWJ1Zy1tb2RlIHR3LXN0b3J5OjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LXBhc3NhZ2U6OmJlZm9yZSwuZG9tLWRlYnVnLW1vZGUgdHctc2lkZWJhcjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1pbmNsdWRlOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWhvb2s6OmJlZm9yZSwuZG9tLWRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1saW5rOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWRpYWxvZzo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1jb2x1bW5zOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWNvbHVtbjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1hbGlnbjo6YmVmb3Jle3Bvc2l0aW9uOmFic29sdXRlO3RvcDowO2xlZnQ6MDtoZWlnaHQ6MTZweDtiYWNrZ3JvdW5kLWNvbG9yOiNmNWEzZGE7Y29sb3I6IzAwMDtmb250LXNpemU6MTZweDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC1mYW1pbHk6bW9ub3NwYWNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrO2xpbmUtaGVpZ2h0OjEwMCU7d2hpdGUtc3BhY2U6cHJlO3otaW5kZXg6OTk5OTk3fS5kb20tZGVidWctbW9kZSB0dy1zdG9yeTpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctcGFzc2FnZTpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctc2lkZWJhcjpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctaW5jbHVkZTpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctaG9vazpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbjpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctbGluazpob3ZlciwuZG9tLWRlYnVnLW1vZGUgdHctZGlhbG9nOmhvdmVyLC5kb20tZGVidWctbW9kZSB0dy1jb2x1bW5zOmhvdmVyLC5kb20tZGVidWctbW9kZSB0dy1jb2x1bW46aG92ZXIsLmRvbS1kZWJ1Zy1tb2RlIHR3LWFsaWduOmhvdmVye291dGxpbmU6MXB4IHNvbGlkICNmYzl9LmRvbS1kZWJ1Zy1tb2RlIHR3LXN0b3J5OmhvdmVyOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LXBhc3NhZ2U6aG92ZXI6OmJlZm9yZSwuZG9tLWRlYnVnLW1vZGUgdHctc2lkZWJhcjpob3Zlcjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1pbmNsdWRlOmhvdmVyOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWhvb2s6aG92ZXI6OmJlZm9yZSwuZG9tLWRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbjpob3Zlcjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1saW5rOmhvdmVyOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWRpYWxvZzpob3Zlcjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1jb2x1bW5zOmhvdmVyOjpiZWZvcmUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWNvbHVtbjpob3Zlcjo6YmVmb3JlLC5kb20tZGVidWctbW9kZSB0dy1hbGlnbjpob3Zlcjo6YmVmb3Jle2JhY2tncm91bmQtY29sb3I6I2ZjOTt0cmFuc2l0aW9uOmJhY2tncm91bmQtY29sb3IgMXN9LmRvbS1kZWJ1Zy1tb2RlIHR3LXBhc3NhZ2UsLmRvbS1kZWJ1Zy1tb2RlIHR3LWluY2x1ZGUsLmRvbS1kZWJ1Zy1tb2RlIHR3LWhvb2ssLmRvbS1kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb24sLmRvbS1kZWJ1Zy1tb2RlIHR3LWxpbmssLmRvbS1kZWJ1Zy1tb2RlIHR3LWRpYWxvZywuZG9tLWRlYnVnLW1vZGUgdHctY29sdW1ucywuZG9tLWRlYnVnLW1vZGUgdHctY29sdW1uLC5kb20tZGVidWctbW9kZSB0dy1hbGlnbntwYWRkaW5nOjFlbTttYXJnaW46MH0uZG9tLWRlYnVnLW1vZGUgdHctc3Rvcnk6OmJlZm9yZXtjb250ZW50Oic8dHctc3RvcnkgdGFncz0iJyBhdHRyKHRhZ3MpICciPid9LmRvbS1kZWJ1Zy1tb2RlIHR3LXBhc3NhZ2U6OmJlZm9yZXt0b3A6LTE2cHg7Y29udGVudDonPHR3LXBhc3NhZ2UgdGFncz0iJyBhdHRyKHRhZ3MpICciPid9LmRvbS1kZWJ1Zy1tb2RlIHR3LXNpZGViYXI6OmJlZm9yZXt0b3A6LTE2cHg7Y29udGVudDoiPHR3LXNpZGViYXI+In0uZG9tLWRlYnVnLW1vZGUgdHctaG9vazo6YmVmb3Jle2NvbnRlbnQ6Jzx0dy1ob29rIG5hbWU9IicgYXR0cihuYW1lKSAnIj4nfS5kb20tZGVidWctbW9kZSB0dy1leHByZXNzaW9uOjpiZWZvcmV7Y29udGVudDonPHR3LWV4cHJlc3Npb24gbmFtZT0iJyBhdHRyKG5hbWUpICciPid9LmRvbS1kZWJ1Zy1tb2RlIHR3LWxpbms6OmJlZm9yZXtjb250ZW50Oic8dHctbGluayBuYW1lPSInIGF0dHIobmFtZSkgJyI+J30uZG9tLWRlYnVnLW1vZGUgdHctZGlhbG9nOjpiZWZvcmV7Y29udGVudDoiPHR3LWRpYWxvZz4ifS5kb20tZGVidWctbW9kZSB0dy1jb2x1bW5zOjpiZWZvcmV7Y29udGVudDoiPHR3LWNvbHVtbnM+In0uZG9tLWRlYnVnLW1vZGUgdHctY29sdW1uOjpiZWZvcmV7Y29udGVudDoiPHR3LWNvbHVtbj4ifS5kb20tZGVidWctbW9kZSB0dy1hbGlnbjo6YmVmb3Jle2NvbnRlbnQ6Ijx0dy1hbGlnbj4ifS5kb20tZGVidWctbW9kZSB0dy1pbmNsdWRlOjpiZWZvcmV7Y29udGVudDonPHR3LWluY2x1ZGUgdHlwZT0iJyBhdHRyKHR5cGUpICciIG5hbWU9IicgYXR0cihuYW1lKSAnIj4nfXR3LW9wZW4tYnV0dG9uW2dvdG9de2Rpc3BsYXk6bm9uZX0uZGVidWctbW9kZSB0dy1vcGVuLWJ1dHRvbltyZXBsYXldLC5kZWJ1Zy1tb2RlIHR3LW9wZW4tYnV0dG9uW2dvdG9de2Rpc3BsYXk6aW5saW5lfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb257ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3R5cGU9dmFyaWFibGVdOjphZnRlcntmb250LXNpemU6LjhyZW07cGFkZGluZy1sZWZ0Oi4ycmVtO3BhZGRpbmctcmlnaHQ6LjJyZW07dmVydGljYWwtYWxpZ246dG9wO2NvbnRlbnQ6IiQiIGF0dHIobmFtZSl9LmRlYnVnLW1vZGUgdHctZXhwcmVzc2lvblt0eXBlPXRlbXBWYXJpYWJsZV06OmFmdGVye2ZvbnQtc2l6ZTouOHJlbTtwYWRkaW5nLWxlZnQ6LjJyZW07cGFkZGluZy1yaWdodDouMnJlbTt2ZXJ0aWNhbC1hbGlnbjp0b3A7Y29udGVudDoiXyIgYXR0cihuYW1lKX0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3JldHVybj1ib29sZWFuXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMTc5LDE3OSwxNzksLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWFycmF5XXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjU1LDEwMiwxMDIsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWRhdGFzZXRde2JhY2tncm91bmQtY29sb3I6cmdiYSgyNTUsMTI4LDAsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPW51bWJlcl17YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDI1NSwxNzksMTAyLC4yKX0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3JldHVybj1kYXRhbWFwXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjU1LDI1NSwxMDIsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWNoYW5nZXJde2JhY2tncm91bmQtY29sb3I6cmdiYSgxNzksMjU1LDEwMiwuMil9LmRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbltyZXR1cm49bGFtYmRhXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMTAyLDI1NSwxMDIsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWhvb2tuYW1lXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMTAyLDI1NSwyMDQsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPXN0cmluZ117YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDEwMiwyNTUsMjU1LC4yKX0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3JldHVybj1kYXRhdHlwZV17YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDEwMiwxNTMsMjU1LC4yKX0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3JldHVybj1ncmFkaWVudF0sLmRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbltyZXR1cm49Y29sb3VyXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjA0LDEwMiwyNTUsLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWluc3RhbnRdLC5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPW1hY3JvXXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjQwLDExNywxOTksLjIpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bcmV0dXJuPWNvbW1hbmRde2JhY2tncm91bmQtY29sb3I6cmdiYSgxNTMsMTUzLDI1NSwuMil9LmRlYnVnLW1vZGUgdHctZXhwcmVzc2lvbi5mYWxzZXtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjU1LDAsMCwuMikgIWltcG9ydGFudH0uZGVidWctbW9kZSB0dy1leHByZXNzaW9uW3R5cGU9bWFjcm9dOjpiZWZvcmV7Y29udGVudDoiKCIgYXR0cihuYW1lKSAiOikiO3BhZGRpbmc6MCAuNXJlbTtmb250LXNpemU6MXJlbTt2ZXJ0aWNhbC1hbGlnbjptaWRkbGU7bGluZS1oZWlnaHQ6bm9ybWFsO2JhY2tncm91bmQtY29sb3I6aW5oZXJpdDtib3JkZXI6MXB4IHNvbGlkIHJnYmEoMjU1LDI1NSwyNTUsLjUpfS5kZWJ1Zy1tb2RlIHR3LWV4cHJlc3Npb25bdGl0bGVdOm5vdChbdGl0bGU9IiJdKXtjdXJzb3I6aGVscH0uZGVidWctbW9kZSB0dy1ob29re2JhY2tncm91bmQtY29sb3I6cmdiYSgwLDg1LDI1NSwuMSkgIWltcG9ydGFudH0uZGVidWctbW9kZSB0dy1ob29rOjpiZWZvcmV7Zm9udC1zaXplOi44cmVtO3BhZGRpbmctbGVmdDouMnJlbTtwYWRkaW5nLXJpZ2h0Oi4ycmVtO3ZlcnRpY2FsLWFsaWduOnRvcDtjb250ZW50OiJbIn0uZGVidWctbW9kZSB0dy1ob29rOjphZnRlcntmb250LXNpemU6LjhyZW07cGFkZGluZy1sZWZ0Oi4ycmVtO3BhZGRpbmctcmlnaHQ6LjJyZW07dmVydGljYWwtYWxpZ246dG9wO2NvbnRlbnQ6Il0ifS5kZWJ1Zy1tb2RlIHR3LWhvb2tbbmFtZV06OmFmdGVye2ZvbnQtc2l6ZTouOHJlbTtwYWRkaW5nLWxlZnQ6LjJyZW07cGFkZGluZy1yaWdodDouMnJlbTt2ZXJ0aWNhbC1hbGlnbjp0b3A7Y29udGVudDoiXTwiIGF0dHIobmFtZSkgInwifS5kZWJ1Zy1tb2RlIHR3LXBzZXVkby1ob29re2JhY2tncm91bmQtY29sb3I6cmdiYSgyNTUsMTcwLDAsLjEpICFpbXBvcnRhbnR9LmRlYnVnLW1vZGUgdHctY29sbGFwc2VkOjpiZWZvcmV7Zm9udC1zaXplOi44cmVtO3BhZGRpbmctbGVmdDouMnJlbTtwYWRkaW5nLXJpZ2h0Oi4ycmVtO3ZlcnRpY2FsLWFsaWduOnRvcDtjb250ZW50OiJ7In0uZGVidWctbW9kZSB0dy1jb2xsYXBzZWQ6OmFmdGVye2ZvbnQtc2l6ZTouOHJlbTtwYWRkaW5nLWxlZnQ6LjJyZW07cGFkZGluZy1yaWdodDouMnJlbTt2ZXJ0aWNhbC1hbGlnbjp0b3A7Y29udGVudDoifSJ9LmRlYnVnLW1vZGUgdHctdmVyYmF0aW06OmJlZm9yZSwuZGVidWctbW9kZSB0dy12ZXJiYXRpbTo6YWZ0ZXJ7Zm9udC1zaXplOi44cmVtO3BhZGRpbmctbGVmdDouMnJlbTtwYWRkaW5nLXJpZ2h0Oi4ycmVtO3ZlcnRpY2FsLWFsaWduOnRvcDtjb250ZW50OiJgIn0uZGVidWctbW9kZSB0dy1hbGlnbltzdHlsZSo9InRleHQtYWxpZ246IGNlbnRlciJde2JhY2tncm91bmQ6bGluZWFyLWdyYWRpZW50KHRvIHJpZ2h0LCBoc2xhKDE0LCAxMDAlLCA4NyUsIDApIDAlLCBoc2xhKDE0LCAxMDAlLCA4NyUsIDAuMjUpIDUwJSwgaHNsYSgxNCwgMTAwJSwgODclLCAwKSAxMDAlKX0uZGVidWctbW9kZSB0dy1hbGlnbltzdHlsZSo9InRleHQtYWxpZ246IGxlZnQiXXtiYWNrZ3JvdW5kOmxpbmVhci1ncmFkaWVudCh0byByaWdodCwgaHNsYSgxNCwgMTAwJSwgODclLCAwLjI1KSAwJSwgaHNsYSgxNCwgMTAwJSwgODclLCAwKSAxMDAlKX0uZGVidWctbW9kZSB0dy1hbGlnbltzdHlsZSo9InRleHQtYWxpZ246IHJpZ2h0Il17YmFja2dyb3VuZDpsaW5lYXItZ3JhZGllbnQodG8gcmlnaHQsIGhzbGEoMTQsIDEwMCUsIDg3JSwgMCkgMCUsIGhzbGEoMTQsIDEwMCUsIDg3JSwgMC4yNSkgMTAwJSl9LmRlYnVnLW1vZGUgdHctY29sdW1ue2JhY2tncm91bmQtY29sb3I6cmdiYSgxODksMjI4LDI1NSwuMil9LmRlYnVnLW1vZGUgdHctZW5jaGFudG1lbnR7YW5pbWF0aW9uOmVuY2hhbnRtZW50IC41cyBpbmZpbml0ZTtib3JkZXI6MXB4IHNvbGlkfS5kZWJ1Zy1tb2RlIHR3LWxpbms6OmFmdGVyLC5kZWJ1Zy1tb2RlIHR3LWJyb2tlbi1saW5rOjphZnRlcntmb250LXNpemU6LjhyZW07cGFkZGluZy1sZWZ0Oi4ycmVtO3BhZGRpbmctcmlnaHQ6LjJyZW07dmVydGljYWwtYWxpZ246dG9wO2NvbnRlbnQ6YXR0cihwYXNzYWdlLW5hbWUpfS5kZWJ1Zy1tb2RlIHR3LWluY2x1ZGV7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDIwNCwxMjgsNTEsLjEpfS5kZWJ1Zy1tb2RlIHR3LWluY2x1ZGU6OmJlZm9yZXtmb250LXNpemU6LjhyZW07cGFkZGluZy1sZWZ0Oi4ycmVtO3BhZGRpbmctcmlnaHQ6LjJyZW07dmVydGljYWwtYWxpZ246dG9wO2NvbnRlbnQ6YXR0cih0eXBlKSAnICInIGF0dHIobmFtZSkgJyInfS5kZWJ1Zy1kaWFsb2dzIHR3LWJhY2tkcm9wOm5vdCguZXZhbC1yZXBsYXkpOm5vdCguaGFybG93ZS1jcmFzaCl7cG9pbnRlci1ldmVudHM6bm9uZTtvcGFjaXR5Oi4xfXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtY29kZSx0dy1ldmFsLXJlcGxheSB0dy1ldmFsLWV4cGxhbmF0aW9ue21heC1oZWlnaHQ6MjB2aDtvdmVyZmxvdzphdXRvO21hcmdpbjoxMHB4IGF1dG99dHctZXZhbC1yZXBsYXkgdHctZXZhbC1jb2Rle2Rpc3BsYXk6YmxvY2s7Zm9udC1mYW1pbHk6bW9ub3NwYWNlO3BhZGRpbmctYm90dG9tOjFleDtib3JkZXItYm90dG9tOjJweCBzb2xpZCBncmF5fXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtZXhwbGFuYXRpb257ZGlzcGxheTpibG9jazt0ZXh0LWFsaWduOmNlbnRlcn10dy1ldmFsLXJlcGxheSB0dy1ldmFsLWV4cGxhbmF0aW9uPmNvZGV7d2hpdGUtc3BhY2U6cHJlLXdyYXB9dHctZXZhbC1yZXBsYXkgdHctZXZhbC1leHBsYW5hdGlvbj5jb2RlLmZyb20tYmxvY2t7d2lkdGg6NDAlO2Rpc3BsYXk6aW5saW5lLWJsb2NrO3RleHQtYWxpZ246bGVmdDttYXgtaGVpZ2h0OjRlbTtvdmVyZmxvdy13cmFwOmFueXdoZXJlO292ZXJmbG93LXk6c2Nyb2xsfXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtZXhwbGFuYXRpb24+Y29kZS5mcm9tLWJsb2Nrfi50by1kZXNje3dpZHRoOmNhbGMoNDAlIC0gMmVtKTttYXJnaW4tbGVmdDoyZW07ZGlzcGxheTppbmxpbmUtYmxvY2t9dHctZXZhbC1yZXBsYXkgdHctZXZhbC1leHBsYW5hdGlvbj5jb2RlLmZyb20tYmxvY2src3Bhbjo6YWZ0ZXJ7Y29udGVudDoiLi4uIn10dy1ldmFsLXJlcGxheSB0dy1ldmFsLWV4cGxhbmF0aW9uPmNvZGUuZnJvbS1pbmxpbmV7dGV4dC1hbGlnbjpyaWdodH10dy1ldmFsLXJlcGxheSB0dy1ldmFsLWV4cGxhbmF0aW9uPjpudGgtY2hpbGQoMil7d2hpdGUtc3BhY2U6cHJlfXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtZXhwbGFuYXRpb24+LnRvLWRlc2N7dGV4dC1hbGlnbjpsZWZ0fXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtZXhwbGFuYXRpb24+dGFibGV7d2lkdGg6MTAwJTttYXJnaW4tdG9wOjFlbX10dy1ldmFsLXJlcGxheSB0dy1ldmFsLWV4cGxhbmF0aW9uPnRhYmxlIHRke3doaXRlLXNwYWNlOnByZS13cmFwICFpbXBvcnRhbnQ7d29yZC13cmFwOmFueXdoZXJlfXR3LWV2YWwtcmVwbGF5IHR3LWV2YWwtcmVhc29ue3RleHQtYWxpZ246Y2VudGVyO2ZvbnQtc2l6ZTo4MCU7Zm9udC1zdHlsZTppdGFsaWM7ZGlzcGxheTpibG9ja310dy1ldmFsLXJlcGxheSB0dy1ldmFsLWl0e3RleHQtYWxpZ246Y2VudGVyO2ZvbnQtc2l6ZTo4MCU7ZGlzcGxheTpibG9ja310dy1ldmFsLXJlcGxheSB0dy1kaWFsb2ctbGlua3N7ZGlzcGxheTotbXMtZmxleGJveDtkaXNwbGF5OmZsZXg7LW1zLWZsZXgtcGFjazpkaXN0cmlidXRlO2p1c3RpZnktY29udGVudDpzcGFjZS1hcm91bmR9QGtleWZyYW1lcyBlbmNoYW50bWVudHswJSx0b3tib3JkZXItY29sb3I6I2ZmYjM2Nn01MCV7Ym9yZGVyLWNvbG9yOiM2ZmN9fXR3LWRlYnVnZ2Vye3Bvc2l0aW9uOmZpeGVkO2JveC1zaXppbmc6Ym9yZGVyLWJveDtib3R0b206MDtyaWdodDowO3otaW5kZXg6OTk5OTk5O21pbi13aWR0aDoxNGVtO21pbi1oZWlnaHQ6MWVtO3BhZGRpbmc6MGVtIC41ZW0gLjVlbSAxZW07Zm9udC1zaXplOjEuMjVlbTtmb250LWZhbWlseTpzYW5zLXNlcmlmO2NvbG9yOiMyNjI2MjY7YmFja2dyb3VuZC1jb2xvcjojZmZmO2JvcmRlci1sZWZ0OnNvbGlkICMyNjI2MjYgMnB4O2JvcmRlci10b3A6c29saWQgIzI2MjYyNiAycHg7Ym9yZGVyLXRvcC1sZWZ0LXJhZGl1czouNWVtO29wYWNpdHk6MX10dy1kZWJ1Z2dlci5mYWRlLXBhbmVsOm5vdCg6aG92ZXIpe29wYWNpdHk6LjMzfXR3LWRlYnVnZ2VyLnRoZW1lLWRhcmt7Y29sb3I6I2Q5ZDlkOTtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9dHctZGVidWdnZXIudGhlbWUtZGFya3tib3JkZXItY29sb3I6I2Q5ZDlkOSByZ2JhKDAsMCwwLDApIHJnYmEoMCwwLDAsMCkgI2Q5ZDlkOX10dy1kZWJ1Z2dlciBzZWxlY3R7bWFyZ2luLXJpZ2h0OjFlbTt3aWR0aDoxMmVtfXR3LWRlYnVnZ2VyIGJ1dHRvbix0dy1kZWJ1Z2dlciB0dy1saW5re2JvcmRlci1yYWRpdXM6M3B4O2JvcmRlcjpzb2xpZCAjOTk5IDFweDttYXJnaW46YXV0byA0cHg7Y29sb3I6IzI2MjYyNjtiYWNrZ3JvdW5kLWNvbG9yOiNmZmY7Y3Vyc29yOnBvaW50ZXJ9dHctZGVidWdnZXIgYnV0dG9uLmVuYWJsZWQsdHctZGVidWdnZXIgdHctbGluay5lbmFibGVke2NvbG9yOiMwMDA7YmFja2dyb3VuZC1jb2xvcjojZDlkOWQ5O2JveC1zaGFkb3c6aW5zZXQgIzk5OSAzcHggNXB4IC41ZW19dHctZGVidWdnZXIudGhlbWUtZGFyayBidXR0b24sdHctZGVidWdnZXIudGhlbWUtZGFyayB0dy1saW5re2NvbG9yOiNkOWQ5ZDk7YmFja2dyb3VuZC1jb2xvcjojMDAwO2JvcmRlci1jb2xvcjojNjY2fXR3LWRlYnVnZ2VyLnRoZW1lLWRhcmsgYnV0dG9uLmVuYWJsZWQsdHctZGVidWdnZXIudGhlbWUtZGFyayB0dy1saW5rLmVuYWJsZWR7Y29sb3I6I2U2ZTZlNjtiYWNrZ3JvdW5kLWNvbG9yOiM0MjQyNDI7Ym94LXNoYWRvdzppbnNldCAjNjY2IDNweCA1cHggLjVlbX10dy1kZWJ1Z2dlciBidXR0b257Zm9udC1zaXplOjFlbTtvdmVyZmxvdy14OmhpZGRlbjt0ZXh0LW92ZXJmbG93OmVsbGlwc2lzO3doaXRlLXNwYWNlOnByZX10dy1kZWJ1Z2dlciB0dy1saW5re2ZvbnQtc2l6ZToxLjI1ZW07Ym9yZGVyLXJhZGl1czoxNnB4O2JvcmRlci1zdHlsZTpzb2xpZDtib3JkZXItd2lkdGg6MnB4O3RleHQtYWxpZ246Y2VudGVyO3BhZGRpbmc6MHB4IDhweDtkaXNwbGF5OmJsb2NrfXR3LWRlYnVnZ2VyIHR3LWxpbms6aG92ZXJ7Ym9yZGVyLWNvbG9yOiMyNjI2MjY7Y29sb3I6IzI2MjYyNn10dy1kZWJ1Z2dlci50aGVtZS1kYXJrIHR3LWxpbms6aG92ZXJ7Ym9yZGVyLWNvbG9yOiNkOWQ5ZDk7Y29sb3I6I2Q5ZDlkOX10dy1kZWJ1Z2dlciB0dy1kaWFsb2d7YmFja2dyb3VuZC1jb2xvcjojZmZmO2NvbG9yOiMwMDA7Zm9udC1zaXplOjEuMjVlbX10dy1kZWJ1Z2dlci50aGVtZS1kYXJrIHR3LWRpYWxvZ3tiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2U2ZTZlNn10dy1kZWJ1Z2dlciAucGFuZWx7ZGlzcGxheTotbXMtZmxleGJveDtkaXNwbGF5OmZsZXg7LW1zLWZsZXgtZGlyZWN0aW9uOmNvbHVtbjtmbGV4LWRpcmVjdGlvbjpjb2x1bW47cG9zaXRpb246YWJzb2x1dGU7Ym90dG9tOjEwMCU7bGVmdDotMnB4O3JpZ2h0OjA7cGFkZGluZzoxZW07b3ZlcmZsb3cteTpzY3JvbGw7b3ZlcmZsb3cteDpoaWRkZW47Ym9yZGVyOmluaGVyaXQ7Ym94LXNpemluZzpjb250ZW50LWJveDtiYWNrZ3JvdW5kLWNvbG9yOiNmZmY7Ym9yZGVyLWJvdHRvbTpzb2xpZCAjOTk5IDJweDtib3JkZXItdG9wLWxlZnQtcmFkaXVzOi41ZW07Ym9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czouNWVtO2ZvbnQtc2l6ZTouOGVtfXR3LWRlYnVnZ2VyIC5wYW5lbDplbXB0eSx0dy1kZWJ1Z2dlciAucGFuZWxbaGlkZGVuXXtkaXNwbGF5Om5vbmV9dHctZGVidWdnZXIudGhlbWUtZGFyayAucGFuZWx7YmFja2dyb3VuZC1jb2xvcjojMDAwO2JvcmRlci1ib3R0b20tY29sb3I6IzY2Nn10dy1kZWJ1Z2dlciAucGFuZWwtc291cmNlIC5wYW5lbC1yb3ctYnV0dG9uc3t3aWR0aDoycmVtfXR3LWRlYnVnZ2VyIC5wYW5lbC1zb3VyY2UgLnNvdXJjZS10YWdze3dpZHRoOjIwJTtmb250LXN0eWxlOml0YWxpY310dy1kZWJ1Z2dlciAucGFuZWwtcm93LXNvdXJjZSB0ZHtmb250LWZhbWlseTptb25vc3BhY2U7Zm9udC1zaXplOjFyZW07d2hpdGUtc3BhY2U6cHJlLXdyYXA7b3ZlcmZsb3ctd3JhcDphbnl3aGVyZTttYXgtaGVpZ2h0OjhyZW07cGFkZGluZzoxcmVtfXR3LWRlYnVnZ2VyIC5wYW5lbC1yb3dze3dpZHRoOjEwMCU7b3ZlcmZsb3cteDpzY3JvbGx9dHctZGVidWdnZXIgLnBhbmVsLXJvd3M+KntkaXNwbGF5OnRhYmxlLXJvd310dy1kZWJ1Z2dlciAucGFuZWwtcm93cz5kaXY6bnRoLW9mLXR5cGUoMm4pe2JhY2tncm91bmQtY29sb3I6I2U2ZTZlNn10dy1kZWJ1Z2dlciAucGFuZWwtdG9vbHMgLnBhbmVsLXJvd3M+Kix0dy1kZWJ1Z2dlciAucGFuZWwtb3B0aW9ucyAucGFuZWwtcm93cz4qe21hcmdpbi10b3A6LjRyZW07ZGlzcGxheTpibG9ja310dy1kZWJ1Z2dlci50aGVtZS1kYXJrIC5wYW5lbC1yb3dzPmRpdjpudGgtb2YtdHlwZSgybil7YmFja2dyb3VuZC1jb2xvcjojMjEyMTIxfXR3LWRlYnVnZ2VyIC5wYW5lbC1yb3ctYnV0dG9uc3t0ZXh0LWFsaWduOnJpZ2h0fXR3LWRlYnVnZ2VyIC5wYW5lbC12YXJpYWJsZXMgLnBhbmVsLXJvd3M6ZW1wdHk6OmJlZm9yZXtjb250ZW50OiJ+IE5vIHZhcmlhYmxlcyB+Ijtmb250LXN0eWxlOml0YWxpYztjb2xvcjojNTc1NzU3O3RleHQtYWxpZ246Y2VudGVyfXR3LWRlYnVnZ2VyIC5wYW5lbC1lbmNoYW50bWVudHMgLnBhbmVsLXJvd3M6ZW1wdHk6OmJlZm9yZXtjb250ZW50OiJ+IE5vIGVuY2hhbnRtZW50cyB+Ijtmb250LXN0eWxlOml0YWxpYztjb2xvcjojNTc1NzU3O3RleHQtYWxpZ246Y2VudGVyfXR3LWRlYnVnZ2VyIC5wYW5lbC1lcnJvcnMgLnBhbmVsLXJvd3M6ZW1wdHk6OmJlZm9yZXtjb250ZW50OiJ+IE5vIGVycm9ycy4uLiBmb3Igbm93LiB+Ijtmb250LXN0eWxlOml0YWxpYztjb2xvcjojNTc1NzU3O3RleHQtYWxpZ246Y2VudGVyfXR3LWRlYnVnZ2VyIC5wYW5lbC1lcnJvcnMgLnBhbmVsLXJvd3M6ZW1wdHkrLnBhbmVsLWVycm9ycy1ib3R0b217ZGlzcGxheTpub25lfXR3LWRlYnVnZ2VyLnRoZW1lLWRhcmsgLnBhbmVsLXZhcmlhYmxlcyAucGFuZWwtcm93czplbXB0eTo6YmVmb3JlLHR3LWRlYnVnZ2VyLnRoZW1lLWRhcmsgLnBhbmVsLWVuY2hhbnRtZW50cyAucGFuZWwtcm93czplbXB0eTo6YmVmb3JlLHR3LWRlYnVnZ2VyLnRoZW1lLWRhcmsgLnBhbmVsLWVycm9ycyAucGFuZWwtcm93czplbXB0eTo6YmVmb3Jle2NvbG9yOiNhOGE4YTh9dHctZGVidWdnZXIgLnBhbmVsLXJvd3M6ZW1wdHkrLnBhbmVsLXZhcmlhYmxlcy1ib3R0b217ZGlzcGxheTpub25lfXR3LWRlYnVnZ2VyIHRoW2RhdGEtY29sXXt0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO2N1cnNvcjpwb2ludGVyfXR3LWRlYnVnZ2VyIHRoW2RhdGEtY29sXVtkYXRhLW9yZGVyPWFzY106OmFmdGVye2NvbnRlbnQ6IuKGkyJ9dHctZGVidWdnZXIgdGhbZGF0YS1jb2xdW2RhdGEtb3JkZXI9ZGVzY106OmFmdGVye2NvbnRlbnQ6IuKGkSJ9dHctZGVidWdnZXIgLnBhbmVsLXN0b3J5bGV0czpub3QoLnBhbmVsLWV4Y2x1c2l2ZSkgLnN0b3J5bGV0LWV4Y2x1c2l2ZSx0dy1kZWJ1Z2dlciAucGFuZWwtc3RvcnlsZXRzOm5vdCgucGFuZWwtdXJnZW50KSAuc3RvcnlsZXQtdXJnZW50e2Rpc3BsYXk6bm9uZX10dy1kZWJ1Z2dlciAuc3RvcnlsZXQtZXhjbHVzaXZlLHR3LWRlYnVnZ2VyIC5zdG9yeWxldC11cmdlbnQsdHctZGVidWdnZXIgLnN0b3J5bGV0LW9wZW57dGV4dC1hbGlnbjpjZW50ZXJ9dHctZGVidWdnZXIgLnBhbmVsLXZhcmlhYmxlcy1ib3R0b217cGFkZGluZy10b3A6NXB4fXR3LWRlYnVnZ2VyIC5lbmNoYW50bWVudC1yb3d7bWluLWhlaWdodDoxLjVlbX10dy1kZWJ1Z2dlciAudmFyaWFibGUtcGF0aHtvcGFjaXR5Oi40fXR3LWRlYnVnZ2VyIC50ZW1wb3JhcnktdmFyaWFibGUtc2NvcGUsdHctZGVidWdnZXIgLmVuY2hhbnRtZW50LWxvY2Fse2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7Zm9udC13ZWlnaHQ6bm9ybWFsO29wYWNpdHk6Ljg7Zm9udC1zaXplOi43NWVtfXR3LWRlYnVnZ2VyIC50ZW1wb3JhcnktdmFyaWFibGUtc2NvcGU6bm90KDplbXB0eSk6OmJlZm9yZSx0dy1kZWJ1Z2dlciAuZW5jaGFudG1lbnQtbG9jYWw6bm90KDplbXB0eSk6OmJlZm9yZXtjb250ZW50OiIgaW4gIn10dy1kZWJ1Z2dlciAudmFyaWFibGUtbmFtZSx0dy1kZWJ1Z2dlciAuZW5jaGFudG1lbnQtbmFtZXtmb250LWZhbWlseTptb25vc3BhY2U7Zm9udC13ZWlnaHQ6Ym9sZH10dy1kZWJ1Z2dlciAudmFyaWFibGUtdHlwZXtjb2xvcjojNTc1NzU3O2ZvbnQtd2VpZ2h0Om5vcm1hbDt0ZXh0LW92ZXJmbG93OmVsbGlwc2lzO292ZXJmbG93OmhpZGRlbjttYXgtd2lkdGg6MTBlbX10dy1kZWJ1Z2dlci50aGVtZS1kYXJrIC52YXJpYWJsZS10eXBle2NvbG9yOiNhOGE4YTh9dHctZGVidWdnZXIgLmVycm9yLXJvd3tkaXNwbGF5OnRhYmxlLXJvdztiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjMwLDEwMSwyMDQsLjMpfXR3LWRlYnVnZ2VyIC5lcnJvci1yb3c6bnRoLW9mLXR5cGUoMm4pe2JhY2tncm91bmQtY29sb3I6cmdiYSgyMzcsMTQ1LDIxOSwuMyl9dHctZGVidWdnZXIgLmVycm9yLXJvdz4qe2Rpc3BsYXk6dGFibGUtY2VsbDtwYWRkaW5nOi4yNWVtIC41ZW19dHctZGVidWdnZXIgLmVycm9yLXJvdyAuZXJyb3ItbWVzc2FnZVt0aXRsZV06bm90KFt0aXRsZT0iIl0pe2N1cnNvcjpoZWxwfXR3LWRlYnVnZ2VyIC5lcnJvci1yb3cgLmVycm9yLXBhc3NhZ2V7Y29sb3I6IzU3NTc1N310dy1kZWJ1Z2dlci50aGVtZS1kYXJrIC5lcnJvci1yb3cgLmVycm9yLXBhc3NhZ2V7Y29sb3I6I2E4YThhOH10dy1kZWJ1Z2dlciAuc3RvcnlsZXQtcm93e2JhY2tncm91bmQtY29sb3I6cmdiYSgxOTMsMjQwLDIyNSwuMyl9dHctZGVidWdnZXIgLnN0b3J5bGV0LXJvdzpudGgtY2hpbGQoMm4pe2JhY2tncm91bmQtY29sb3I6cmdiYSgxNTIsMjMxLDIwNCwuMyl9dHctZGVidWdnZXIgLnN0b3J5bGV0LXJvdy5zdG9yeWxldC1jbG9zZWR7Zm9udC1zdHlsZTppdGFsaWM7YmFja2dyb3VuZC1jb2xvcjojZmZmfXR3LWRlYnVnZ2VyIC5zdG9yeWxldC1yb3cuc3RvcnlsZXQtY2xvc2VkOm50aC1jaGlsZCgybil7YmFja2dyb3VuZC1jb2xvcjojZTZlNmU2fXR3LWRlYnVnZ2VyIC5zdG9yeWxldC1yb3cuc3RvcnlsZXQtY2xvc2VkPjpub3QoLnN0b3J5bGV0LWxhbWJkYSl7b3BhY2l0eTouNn0uc3RvcnlsZXQtZXJyb3IgdHctZGVidWdnZXIgLnN0b3J5bGV0LXJvd3tiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjMwLDEwMSwyMDQsLjMpfS5zdG9yeWxldC1lcnJvciB0dy1kZWJ1Z2dlciAuc3RvcnlsZXQtcm93Om50aC1jaGlsZCgybil7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDIzNywxNDUsMjE5LC4zKX10dy1kZWJ1Z2dlciAuc3RvcnlsZXQtcm93IC5zdG9yeWxldC1uYW1lLHR3LWRlYnVnZ2VyIC5zdG9yeWxldC1yb3cgLnN0b3J5bGV0LXZhbHVle2Rpc3BsYXk6aW5saW5lLWJsb2NrO3dpZHRoOjUwJX10dy1kZWJ1Z2dlciAuc3RvcnlsZXQtcm93IC5zdG9yeWxldC1sYW1iZGF7Zm9udC1mYW1pbHk6bW9ub3NwYWNlO2ZvbnQtc2l6ZToxcmVtO3doaXRlLXNwYWNlOnByZS13cmFwO292ZXJmbG93LXdyYXA6YW55d2hlcmV9dHctZGVidWdnZXIudGhlbWUtZGFyayAuc3RvcnlsZXQtcm93LnN0b3J5bGV0LWNsb3NlZHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9dHctZGVidWdnZXIudGhlbWUtZGFyayAuc3RvcnlsZXQtcm93LnN0b3J5bGV0LWNsb3NlZDpudGgtY2hpbGQoMm4pe2JhY2tncm91bmQtY29sb3I6IzIxMjEyMX10dy1kZWJ1Z2dlciAudGFic3twYWRkaW5nLWJvdHRvbTouNWVtfXR3LWRlYnVnZ2VyIC50YWJ7Ym9yZGVyLXJhZGl1czowcHggMHB4IC41ZW0gLjVlbTtib3JkZXItdG9wOm5vbmU7dG9wOi0ycHh9dHctZGVidWdnZXIgLnJlc2l6ZXItaHtwb3NpdGlvbjphYnNvbHV0ZTtoZWlnaHQ6MTRlbTtib3JkZXItbGVmdDoycHggc29saWQgIzk5OTtib3JkZXItcmlnaHQ6MnB4IHNvbGlkICM5OTk7dG9wOjEwcHg7bGVmdDo0cHg7d2lkdGg6OHB4O2N1cnNvcjpldy1yZXNpemV9dHctZGVidWdnZXIudGhlbWUtZGFyayAucmVzaXplci1oe2JvcmRlci1jb2xvcjpyZ2JhKDAsMCwwLDApICM2NjZ9dHctZGVidWdnZXIgLnJlc2l6ZXItdntwb3NpdGlvbjphYnNvbHV0ZTtoZWlnaHQ6OHB4O2JvcmRlci10b3A6MnB4IHNvbGlkICM5OTk7Ym9yZGVyLWJvdHRvbToycHggc29saWQgIzk5OTttYXJnaW4tYm90dG9tOjRweDt0b3A6NHB4O2xlZnQ6MTBweDt3aWR0aDo5NSU7Y3Vyc29yOm5zLXJlc2l6ZTtib3gtc2l6aW5nOmJvcmRlci1ib3h9dHctZGVidWdnZXIudGhlbWUtZGFyayAucmVzaXplci12e2JvcmRlci1jb2xvcjojNjY2IHJnYmEoMCwwLDAsMCl9dHctZGVidWdnZXIgbWFya3tjb2xvcjppbmhlcml0O2JhY2tncm91bmQtY29sb3I6cmdiYSgxMDEsMjMwLDIzMCwuMykgIWltcG9ydGFudH10dy1kaWFsb2d7ei1pbmRleDo5OTk5OTc7Ym9yZGVyOiNmZmYgc29saWQgMnB4O3BhZGRpbmc6MmVtO2NvbG9yOiNmZmY7YmFja2dyb3VuZC1jb2xvcjojMDAwO2Rpc3BsYXk6YmxvY2t9QG1lZGlhKG1pbi13aWR0aDogNTc2cHgpe3R3LWRpYWxvZ3ttYXgtd2lkdGg6NTB2d319dHctZGlhbG9nIGlucHV0W3R5cGU9dGV4dF17Zm9udC1zaXplOmluaGVyaXQ7d2lkdGg6MTAwJTtib3JkZXI6c29saWQgI2ZmZiAhaW1wb3J0YW50fXR3LWRpYWxvZy1saW5rc3t0ZXh0LWFsaWduOnJpZ2h0O2Rpc3BsYXk6LW1zLWZsZXhib3g7ZGlzcGxheTpmbGV4Oy1tcy1mbGV4LXBhY2s6ZW5kO2p1c3RpZnktY29udGVudDpmbGV4LWVuZH10dy1iYWNrZHJvcHt6LWluZGV4Ojk5OTk5Njtwb3NpdGlvbjpmaXhlZDt0b3A6MDtsZWZ0OjA7cmlnaHQ6MDtib3R0b206MDtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwwLDAsLjgpO2Rpc3BsYXk6LW1zLWZsZXhib3g7ZGlzcGxheTpmbGV4Oy1tcy1mbGV4LWFsaWduOmNlbnRlcjthbGlnbi1pdGVtczpjZW50ZXI7LW1zLWZsZXgtcGFjazpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcn10dy1iYWNrZHJvcH50dy1iYWNrZHJvcHtkaXNwbGF5Om5vbmV9dHctbGluaywuZW5jaGFudG1lbnQtbGlua3tjdXJzb3I6cG9pbnRlcjtjb2xvcjojNDE2OWUxO2ZvbnQtd2VpZ2h0OmJvbGQ7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dHJhbnNpdGlvbjpjb2xvciAuMnMgZWFzZS1pbi1vdXR9dHctcGFzc2FnZSBbc3R5bGVePWNvbG9yXSB0dy1saW5rOm5vdCg6aG92ZXIpLHR3LXBhc3NhZ2UgW3N0eWxlKj0iIGNvbG9yIl0gdHctbGluazpub3QoOmhvdmVyKSx0dy1wYXNzYWdlIFtzdHlsZV49Y29sb3JdW2hvdmVyPXRydWVdIHR3LWxpbms6aG92ZXIsdHctcGFzc2FnZSBbc3R5bGUqPSIgY29sb3IiXVtob3Zlcj10cnVlXSB0dy1saW5rOmhvdmVyLHR3LXBhc3NhZ2UgW3N0eWxlXj1jb2xvcl0gLmVuY2hhbnRtZW50LWxpbms6bm90KDpob3ZlciksdHctcGFzc2FnZSBbc3R5bGUqPSIgY29sb3IiXSAuZW5jaGFudG1lbnQtbGluazpub3QoOmhvdmVyKSx0dy1wYXNzYWdlIFtzdHlsZV49Y29sb3JdW2hvdmVyPXRydWVdIC5lbmNoYW50bWVudC1saW5rOmhvdmVyLHR3LXBhc3NhZ2UgW3N0eWxlKj0iIGNvbG9yIl1baG92ZXI9dHJ1ZV0gLmVuY2hhbnRtZW50LWxpbms6aG92ZXJ7Y29sb3I6aW5oZXJpdH10dy1saW5rOmhvdmVyLC5lbmNoYW50bWVudC1saW5rOmhvdmVye2NvbG9yOiMwMGJmZmZ9dHctbGluazphY3RpdmUsLmVuY2hhbnRtZW50LWxpbms6YWN0aXZle2NvbG9yOiNkZDRiMzl9LnZpc2l0ZWR7Y29sb3I6IzY5NDFlMX10dy1wYXNzYWdlIFtzdHlsZV49Y29sb3JdIC52aXNpdGVkOm5vdCg6aG92ZXIpLHR3LXBhc3NhZ2UgW3N0eWxlKj0iIGNvbG9yIl0gLnZpc2l0ZWQ6bm90KDpob3ZlciksdHctcGFzc2FnZSBbc3R5bGVePWNvbG9yXVtob3Zlcj10cnVlXSAudmlzaXRlZDpob3Zlcix0dy1wYXNzYWdlIFtzdHlsZSo9IiBjb2xvciJdW2hvdmVyPXRydWVdIC52aXNpdGVkOmhvdmVye2NvbG9yOmluaGVyaXR9LnZpc2l0ZWQ6aG92ZXJ7Y29sb3I6I2UzZX10dy1icm9rZW4tbGlua3tjb2xvcjojOTMzO2JvcmRlci1ib3R0b206MnB4IHNvbGlkICM5MzM7Y3Vyc29yOm5vdC1hbGxvd2VkfXR3LXBhc3NhZ2UgW3N0eWxlXj1jb2xvcl0gdHctYnJva2VuLWxpbms6bm90KDpob3ZlciksdHctcGFzc2FnZSBbc3R5bGUqPSIgY29sb3IiXSB0dy1icm9rZW4tbGluazpub3QoOmhvdmVyKSx0dy1wYXNzYWdlIFtzdHlsZV49Y29sb3JdW2hvdmVyPXRydWVdIHR3LWJyb2tlbi1saW5rOmhvdmVyLHR3LXBhc3NhZ2UgW3N0eWxlKj0iIGNvbG9yIl1baG92ZXI9dHJ1ZV0gdHctYnJva2VuLWxpbms6aG92ZXJ7Y29sb3I6aW5oZXJpdH10dy1saW5rLmVuY2hhbnRtZW50LW1vdXNlb3ZlciwubGluay5lbmNoYW50bWVudC1tb3VzZW92ZXIsdHctZXhwcmVzc2lvbi5lbmNoYW50bWVudC1tb3VzZW92ZXI+dHctbGlua3tjb2xvcjppbmhlcml0O2ZvbnQtd2VpZ2h0OmluaGVyaXQ7dHJhbnNpdGlvbjpub25lO2N1cnNvcjppbmhlcml0O2JvcmRlci1ib3R0b206MnB4IGRhc2hlZCAjOTk5fXR3LWxpbmsuZW5jaGFudG1lbnQtbW91c2VvdmVyOmhvdmVyLHR3LWxpbmsuZW5jaGFudG1lbnQtbW91c2VvdmVyOmFjdGl2ZSwubGluay5lbmNoYW50bWVudC1tb3VzZW92ZXI6aG92ZXIsLmxpbmsuZW5jaGFudG1lbnQtbW91c2VvdmVyOmFjdGl2ZSx0dy1leHByZXNzaW9uLmVuY2hhbnRtZW50LW1vdXNlb3Zlcj50dy1saW5rOmhvdmVyLHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtbW91c2VvdmVyPnR3LWxpbms6YWN0aXZle2NvbG9yOmluaGVyaXR9dHctbGluay5lbmNoYW50bWVudC1tb3VzZW92ZXIuZW5jaGFudG1lbnQtYnV0dG9uLC5saW5rLmVuY2hhbnRtZW50LW1vdXNlb3Zlci5lbmNoYW50bWVudC1idXR0b24sdHctZXhwcmVzc2lvbi5lbmNoYW50bWVudC1tb3VzZW92ZXI+dHctbGluay5lbmNoYW50bWVudC1idXR0b257Ym9yZGVyLXN0eWxlOmRhc2hlZH10dy1saW5rLmVuY2hhbnRtZW50LW1vdXNlb3V0LC5saW5rLmVuY2hhbnRtZW50LW1vdXNlb3V0LHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtbW91c2VvdXQ+dHctbGlua3tjb2xvcjppbmhlcml0O2ZvbnQtd2VpZ2h0OmluaGVyaXQ7dHJhbnNpdGlvbjpub25lO2N1cnNvcjppbmhlcml0O2JvcmRlcjpyZ2JhKDY0LDE0OSwxOTEsLjYpIDFweCBzb2xpZDtib3JkZXItcmFkaXVzOi4yZW19dHctbGluay5lbmNoYW50bWVudC1tb3VzZW91dDpob3Zlcix0dy1saW5rLmVuY2hhbnRtZW50LW1vdXNlb3V0OmFjdGl2ZSwubGluay5lbmNoYW50bWVudC1tb3VzZW91dDpob3ZlciwubGluay5lbmNoYW50bWVudC1tb3VzZW91dDphY3RpdmUsdHctZXhwcmVzc2lvbi5lbmNoYW50bWVudC1tb3VzZW91dD50dy1saW5rOmhvdmVyLHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtbW91c2VvdXQ+dHctbGluazphY3RpdmV7Y29sb3I6aW5oZXJpdH10dy1saW5rLmVuY2hhbnRtZW50LW1vdXNlb3V0OmhvdmVyLC5saW5rLmVuY2hhbnRtZW50LW1vdXNlb3V0OmhvdmVyLHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtbW91c2VvdXQ+dHctbGluazpob3ZlcntiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMTc1LDE5NywyMDcsLjc1KTtib3JkZXI6cmdiYSgwLDAsMCwwKSAxcHggc29saWR9dHctbGluay5lbmNoYW50bWVudC1kYmxjbGljaywubGluay5lbmNoYW50bWVudC1kYmxjbGljayx0dy1leHByZXNzaW9uLmVuY2hhbnRtZW50LWRibGNsaWNrPnR3LWxpbmt7Y29sb3I6aW5oZXJpdDtmb250LXdlaWdodDppbmhlcml0O3RyYW5zaXRpb246bm9uZTtjdXJzb3I6aW5oZXJpdDtjdXJzb3I6cG9pbnRlcjtib3JkZXI6MnB4IHNvbGlkICM5OTk7Ym9yZGVyLXJhZGl1czowfXR3LWxpbmsuZW5jaGFudG1lbnQtZGJsY2xpY2s6aG92ZXIsdHctbGluay5lbmNoYW50bWVudC1kYmxjbGljazphY3RpdmUsLmxpbmsuZW5jaGFudG1lbnQtZGJsY2xpY2s6aG92ZXIsLmxpbmsuZW5jaGFudG1lbnQtZGJsY2xpY2s6YWN0aXZlLHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtZGJsY2xpY2s+dHctbGluazpob3Zlcix0dy1leHByZXNzaW9uLmVuY2hhbnRtZW50LWRibGNsaWNrPnR3LWxpbms6YWN0aXZle2NvbG9yOmluaGVyaXR9dHctbGluay5lbmNoYW50bWVudC1kYmxjbGljazphY3RpdmUsLmxpbmsuZW5jaGFudG1lbnQtZGJsY2xpY2s6YWN0aXZlLHR3LWV4cHJlc3Npb24uZW5jaGFudG1lbnQtZGJsY2xpY2s+dHctbGluazphY3RpdmV7YmFja2dyb3VuZC1jb2xvcjojOTk5fXR3LWxpbmsuZW5jaGFudG1lbnQtYnV0dG9uLC5saW5rLmVuY2hhbnRtZW50LWJ1dHRvbiwuZW5jaGFudG1lbnQtYnV0dG9uOm5vdCgubGluaykgdHctbGluaywuZW5jaGFudG1lbnQtYnV0dG9uOm5vdCgubGluaykgLmxpbmt7Ym9yZGVyLXJhZGl1czoxNnB4O2JvcmRlci1zdHlsZTpzb2xpZDtib3JkZXItd2lkdGg6MnB4O3RleHQtYWxpZ246Y2VudGVyO3BhZGRpbmc6MHB4IDhweDtkaXNwbGF5OmJsb2NrfS5lbmNoYW50bWVudC1idXR0b257ZGlzcGxheTpibG9ja30uZW5jaGFudG1lbnQtY2xpY2tibG9ja3tjdXJzb3I6cG9pbnRlcjt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO2Rpc3BsYXk6YmxvY2t9LmVuY2hhbnRtZW50LWNsaWNrYmxvY2s+Om5vdCh0dy1lbmNoYW50bWVudCk6OmFmdGVye2NvbnRlbnQ6IiI7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTt0b3A6MDtsZWZ0OjA7ZGlzcGxheTpibG9jaztib3gtc2l6aW5nOmJvcmRlci1ib3g7cG9zaXRpb246YWJzb2x1dGU7cG9pbnRlci1ldmVudHM6bm9uZTtjb2xvcjpyZ2JhKDY1LDEwNSwyMjUsLjUpO3RyYW5zaXRpb246Y29sb3IgLjJzIGVhc2UtaW4tb3V0fS5lbmNoYW50bWVudC1jbGlja2Jsb2NrPjpub3QodHctZW5jaGFudG1lbnQpOmhvdmVyOjphZnRlcntjb2xvcjpyZ2JhKDAsMTkxLDI1NSwuNSl9LmVuY2hhbnRtZW50LWNsaWNrYmxvY2s+Om5vdCh0dy1lbmNoYW50bWVudCk6YWN0aXZlOjphZnRlcntjb2xvcjpyZ2JhKDIyMiw3OCw1OSwuNSl9LmVuY2hhbnRtZW50LWNsaWNrYmxvY2s+Om5vdCh0dy1lbmNoYW50bWVudCk6OmFmdGVye2JveC1zaGFkb3c6aW5zZXQgMCAwIDAgLjV2bWF4fS5lbmNoYW50bWVudC1jbGlja2Jsb2NrPnR3LXBhc3NhZ2U6OmFmdGVyLC5lbmNoYW50bWVudC1jbGlja2Jsb2NrPnR3LXNpZGViYXI6OmFmdGVye2JveC1zaGFkb3c6MCAwIDAgLjV2bWF4fS5lbmNoYW50bWVudC1tb3VzZW92ZXJibG9jaz46bm90KHR3LWVuY2hhbnRtZW50KTo6YWZ0ZXJ7Y29udGVudDoiIjt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO3RvcDowO2xlZnQ6MDtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtwb3NpdGlvbjphYnNvbHV0ZTtwb2ludGVyLWV2ZW50czpub25lO2JvcmRlcjoycHggZGFzaGVkICM5OTl9LmVuY2hhbnRtZW50LW1vdXNlb3V0YmxvY2s+Om5vdCh0dy1lbmNoYW50bWVudCk6OmFmdGVye2NvbnRlbnQ6IiI7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTt0b3A6MDtsZWZ0OjA7ZGlzcGxheTpibG9jaztib3gtc2l6aW5nOmJvcmRlci1ib3g7cG9zaXRpb246YWJzb2x1dGU7cG9pbnRlci1ldmVudHM6bm9uZTtib3JkZXI6cmdiYSg2NCwxNDksMTkxLC42KSAycHggc29saWR9LmVuY2hhbnRtZW50LW1vdXNlb3V0YmxvY2s6aG92ZXI+Om5vdCh0dy1lbmNoYW50bWVudCk6OmFmdGVye2NvbnRlbnQ6IiI7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTt0b3A6MDtsZWZ0OjA7ZGlzcGxheTpibG9jaztib3gtc2l6aW5nOmJvcmRlci1ib3g7cG9zaXRpb246YWJzb2x1dGU7cG9pbnRlci1ldmVudHM6bm9uZTtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMTc1LDE5NywyMDcsLjc1KTtib3JkZXI6cmdiYSgwLDAsMCwwKSAycHggc29saWQ7Ym9yZGVyLXJhZGl1czouMmVtfS5lbmNoYW50bWVudC1kYmxjbGlja2Jsb2NrPjpub3QodHctZW5jaGFudG1lbnQpOjphZnRlcntjb250ZW50OiIiO3dpZHRoOjEwMCU7aGVpZ2h0OjEwMCU7dG9wOjA7bGVmdDowO2Rpc3BsYXk6YmxvY2s7Ym94LXNpemluZzpib3JkZXItYm94O3Bvc2l0aW9uOmFic29sdXRlO3BvaW50ZXItZXZlbnRzOm5vbmU7Y3Vyc29yOnBvaW50ZXI7Ym9yZGVyOjJweCBzb2xpZCAjOTk5fXR3LWRpYWxvZy1saW5rc3twYWRkaW5nLXRvcDoxLjVlbX10dy1kaWFsb2ctbGlua3MgdHctbGlua3tib3JkZXItcmFkaXVzOjE2cHg7Ym9yZGVyLXN0eWxlOnNvbGlkO2JvcmRlci13aWR0aDoycHg7dGV4dC1hbGlnbjpjZW50ZXI7cGFkZGluZzowcHggOHB4O2Rpc3BsYXk6YmxvY2s7ZGlzcGxheTppbmxpbmUtYmxvY2t9aHRtbHttYXJnaW46MDtoZWlnaHQ6MTAwJTtvdmVyZmxvdy14OmhpZGRlbn0qLDpiZWZvcmUsOmFmdGVye3Bvc2l0aW9uOnJlbGF0aXZlO2JveC1zaXppbmc6aW5oZXJpdH1ib2R5e21hcmdpbjowO2hlaWdodDoxMDAlfXR3LXN0b3J5ZGF0YXtkaXNwbGF5Om5vbmV9dHctc3Rvcnl7ZGlzcGxheTotbXMtZmxleGJveDtkaXNwbGF5OmZsZXg7LW1zLWZsZXgtZGlyZWN0aW9uOmNvbHVtbjtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Zm9udDoxMDAlIEdlb3JnaWEsc2VyaWY7Ym94LXNpemluZzpib3JkZXItYm94O3dpZHRoOjEwMCU7bWluLWhlaWdodDoxMDAlO2ZvbnQtc2l6ZToxLjVlbTtsaW5lLWhlaWdodDoxLjVlbTtwYWRkaW5nOjUlIDUlO292ZXJmbG93OmhpZGRlbjtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn10dy1zdG9yeSBbc3R5bGUqPWNvbnRlbnQtYm94XSAqe2JveC1zaXppbmc6Ym9yZGVyLWJveH1AbWVkaWEobWluLXdpZHRoOiA1NzZweCl7dHctc3Rvcnl7cGFkZGluZzo1JSAyMCV9fXR3LXN0b3J5IHR3LWNvbnNlY3V0aXZlLWJye2Rpc3BsYXk6YmxvY2s7aGVpZ2h0OjEuNmV4O3Zpc2liaWxpdHk6aGlkZGVufXR3LXN0b3J5IHNlbGVjdHtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwwLDAsMCk7Zm9udDppbmhlcml0O2JvcmRlci1zdHlsZTpzb2xpZDtwYWRkaW5nOjJweH10dy1zdG9yeSBzZWxlY3Q6bm90KFtkaXNhYmxlZF0pe2NvbG9yOmluaGVyaXR9dHctc3RvcnkgdGV4dGFyZWF7cmVzaXplOm5vbmU7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsMCwwLDApO2ZvbnQ6aW5oZXJpdDtjb2xvcjppbmhlcml0O2JvcmRlci1zdHlsZTpub25lO3BhZGRpbmc6MnB4fXR3LXN0b3J5IGlucHV0W3R5cGU9dGV4dF17YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsMCwwLDApO2ZvbnQ6aW5oZXJpdDtjb2xvcjppbmhlcml0O2JvcmRlci1zdHlsZTpub25lfXR3LXN0b3J5IGlucHV0W3R5cGU9Y2hlY2tib3hde3RyYW5zZm9ybTpzY2FsZSgxLjUpO21hcmdpbjowIC41ZW0gLjVlbSAuNWVtO3ZlcnRpY2FsLWFsaWduOm1pZGRsZX10dy1zdG9yeSB0dy1ub3NjcmlwdHthbmltYXRpb246YXBwZWFyIC44c310dy1wYXNzYWdle2Rpc3BsYXk6YmxvY2t9dHctc2lkZWJhcnt0ZXh0LWFsaWduOmNlbnRlcjtkaXNwbGF5Oi1tcy1mbGV4Ym94O2Rpc3BsYXk6ZmxleDstbXMtZmxleC1wYWNrOmp1c3RpZnk7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW59QG1lZGlhKG1pbi13aWR0aDogNTc2cHgpe3R3LXNpZGViYXJ7bGVmdDotNWVtO3dpZHRoOjNlbTtwb3NpdGlvbjphYnNvbHV0ZTstbXMtZmxleC1kaXJlY3Rpb246Y29sdW1uO2ZsZXgtZGlyZWN0aW9uOmNvbHVtbn10dy1lbmNoYW50bWVudFtzdHlsZSo9d2lkdGhdPnR3LXNpZGViYXJ7d2lkdGg6aW5oZXJpdH19dHctaWNvbntkaXNwbGF5OmlubGluZS1ibG9jazttYXJnaW46LjVlbSAwO2ZvbnQtc2l6ZTo2NnB4O2ZvbnQtZmFtaWx5OiJWZXJkYW5hIixzYW5zLXNlcmlmfXR3LWljb25bYWx0XXtvcGFjaXR5Oi4yO2N1cnNvcjpwb2ludGVyfXR3LWljb25bYWx0XTpob3ZlcntvcGFjaXR5Oi40fXR3LWljb25bZGF0YS1sYWJlbF06OmFmdGVye2ZvbnQtd2VpZ2h0OmJvbGQ7Y29udGVudDphdHRyKGRhdGEtbGFiZWwpO2ZvbnQtc2l6ZToyMHB4O2JvdHRvbTotMjBweDtsZWZ0Oi01MCU7d2hpdGUtc3BhY2U6bm93cmFwfXR3LW1ldGVye2Rpc3BsYXk6YmxvY2t9dHctaG9vazplbXB0eSx0dy1leHByZXNzaW9uOmVtcHR5e2Rpc3BsYXk6bm9uZX10dy1lcnJvcntkaXNwbGF5OmlubGluZS1ibG9jaztib3JkZXItcmFkaXVzOi4yZW07cGFkZGluZzouMmVtO2ZvbnQtc2l6ZToxcmVtO2N1cnNvcjpoZWxwO3doaXRlLXNwYWNlOnByZS13cmFwfXR3LWVycm9yLmVycm9ye2JhY2tncm91bmQtY29sb3I6cmdiYSgyMjMsNTgsMTkwLC42KTtjb2xvcjojZmZmfXR3LWVycm9yLndhcm5pbmd7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDIyMywxNDAsNTgsLjYpO2NvbG9yOiNmZmY7ZGlzcGxheTpub25lfS5kZWJ1Zy1tb2RlIHR3LWVycm9yLndhcm5pbmd7ZGlzcGxheTppbmxpbmV9dHctZXJyb3ItZXhwbGFuYXRpb257ZGlzcGxheTpibG9jaztmb250LXNpemU6LjhyZW07bGluZS1oZWlnaHQ6MXJlbX10dy1vcGVuLWJ1dHRvbix0dy1mb2xkZG93bntjdXJzb3I6cG9pbnRlcjtsaW5lLWhlaWdodDowZW07Ym9yZGVyLXJhZGl1czo0cHg7Ym9yZGVyOjFweCBzb2xpZCByZ2JhKDI1NSwyNTUsMjU1LC41KTtmb250LXNpemU6LjhyZW07bWFyZ2luOjAgLjJyZW07cGFkZGluZzozcHg7d2hpdGUtc3BhY2U6cHJlfXR3LWZvbGRkb3duOjphZnRlcntjb250ZW50OiLilrYifXR3LWZvbGRkb3duLm9wZW46OmFmdGVye2NvbnRlbnQ6IuKWvCJ9dHctb3Blbi1idXR0b25bcmVwbGF5XXtkaXNwbGF5Om5vbmV9dHctZXJyb3IgdHctb3Blbi1idXR0b24sdHctZXZhbC1yZXBsYXkgdHctb3Blbi1idXR0b257ZGlzcGxheTppbmxpbmUgIWltcG9ydGFudH10dy1vcGVuLWJ1dHRvbjo6YWZ0ZXJ7Y29udGVudDphdHRyKGxhYmVsKX10dy1ub3RpZmllcntib3JkZXItcmFkaXVzOi4yZW07cGFkZGluZzouMmVtO2ZvbnQtc2l6ZToxcmVtO2JhY2tncm91bmQtY29sb3I6cmdiYSgyMjMsMTgyLDU4LC40KTtkaXNwbGF5Om5vbmV9LmRlYnVnLW1vZGUgdHctbm90aWZpZXJ7ZGlzcGxheTppbmxpbmV9dHctbm90aWZpZXI6OmJlZm9yZXtjb250ZW50OmF0dHIobWVzc2FnZSl9dHctY29sb3Vye2JvcmRlcjoxcHggc29saWQgIzAwMDtkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDoxZW07aGVpZ2h0OjFlbX10dy1lbmNoYW50bWVudDplbXB0eXtkaXNwbGF5Om5vbmV9aDF7Zm9udC1zaXplOjNlbX1oMntmb250LXNpemU6Mi4yNWVtfWgze2ZvbnQtc2l6ZToxLjc1ZW19aDEsaDIsaDMsaDQsaDUsaDZ7bGluZS1oZWlnaHQ6MWVtO21hcmdpbjouM2VtIDAgLjZlbSAwfXByZXtmb250LXNpemU6MXJlbTtsaW5lLWhlaWdodDppbml0aWFsfXNtYWxse2ZvbnQtc2l6ZTo3MCV9Ymlne2ZvbnQtc2l6ZToxMjAlfW1hcmt7Y29sb3I6cmdiYSgwLDAsMCwuNik7YmFja2dyb3VuZC1jb2xvcjojZmY5fWluc3tjb2xvcjpyZ2JhKDAsMCwwLC42KTtiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjU1LDI0MiwyMDQsLjUpO2JvcmRlci1yYWRpdXM6LjVlbTtib3gtc2hhZG93OjBlbSAwZW0gLjJlbSAjZmZlNjk5O3RleHQtZGVjb3JhdGlvbjpub25lfWNlbnRlcnt0ZXh0LWFsaWduOmNlbnRlcjttYXJnaW46MCBhdXRvO3dpZHRoOjYwJX1ibGlua3t0ZXh0LWRlY29yYXRpb246bm9uZTthbmltYXRpb246ZmFkZS1pbi1vdXQgMXMgc3RlcHMoMSwgZW5kKSBpbmZpbml0ZSBhbHRlcm5hdGV9dHctYWxpZ257ZGlzcGxheTpibG9ja310dy1jb2x1bW5ze2Rpc3BsYXk6LW1zLWZsZXhib3g7ZGlzcGxheTpmbGV4Oy1tcy1mbGV4LWRpcmVjdGlvbjpyb3c7ZmxleC1kaXJlY3Rpb246cm93Oy1tcy1mbGV4LXBhY2s6anVzdGlmeTtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2Vlbn0udHJhbnNpdGlvbi1pbnthbmltYXRpb246YXBwZWFyIDBtcyBzdGVwLXN0YXJ0fS50cmFuc2l0aW9uLW91dHthbmltYXRpb246YXBwZWFyIDBtcyBzdGVwLWVuZH1bZGF0YS10OG5ePWRpc3NvbHZlXS50cmFuc2l0aW9uLWluLFtkYXRhLXQ4bj1mYWRlXS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjphcHBlYXIgLjhzfVtkYXRhLXQ4bl49ZGlzc29sdmVdLnRyYW5zaXRpb24tb3V0LFtkYXRhLXQ4bj1mYWRlXS50cmFuc2l0aW9uLW91dHthbmltYXRpb246YXBwZWFyIC44cyByZXZlcnNlfVtkYXRhLXQ4bl49c2h1ZGRlcl0udHJhbnNpdGlvbi1pbntkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50O2FuaW1hdGlvbjpzaHVkZGVyLWluIC44c31bZGF0YS10OG5ePXNodWRkZXJdLnRyYW5zaXRpb24tb3V0e2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnQ7YW5pbWF0aW9uOnNodWRkZXItaW4gLjhzIHJldmVyc2V9W2RhdGEtdDhuXj1ydW1ibGVdLnRyYW5zaXRpb24taW57ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudDthbmltYXRpb246cnVtYmxlLWluIC44c31bZGF0YS10OG5ePXJ1bWJsZV0udHJhbnNpdGlvbi1vdXR7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudDthbmltYXRpb246cnVtYmxlLWluIC44cyByZXZlcnNlfVtkYXRhLXQ4bl49cHVsc2VdLnRyYW5zaXRpb24taW57YW5pbWF0aW9uOnB1bHNlIC44cztkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49cHVsc2VdLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjpwdWxzZSAuOHMgcmV2ZXJzZTtkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49em9vbV0udHJhbnNpdGlvbi1pbnthbmltYXRpb246em9vbS1pbiAuOHM7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePXpvb21dLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjp6b29tLWluIC44cyByZXZlcnNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1ibHVyXS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjpibHVyIC44cztkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49Ymx1cl0udHJhbnNpdGlvbi1vdXR7YW5pbWF0aW9uOmJsdXIgLjhzIHJldmVyc2U7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePXNsaWRlbGVmdF0udHJhbnNpdGlvbi1pbnthbmltYXRpb246c2xpZGUtbGVmdCAuOHM7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePXNsaWRlbGVmdF0udHJhbnNpdGlvbi1vdXR7YW5pbWF0aW9uOnNsaWRlLXJpZ2h0IC44cyByZXZlcnNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1zbGlkZXJpZ2h0XS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjpzbGlkZS1yaWdodCAuOHM7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePXNsaWRlcmlnaHRdLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjpzbGlkZS1sZWZ0IC44cyByZXZlcnNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1zbGlkZXVwXS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjpzbGlkZS11cCAuOHM7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePXNsaWRldXBdLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjpzbGlkZS1kb3duIC44cyByZXZlcnNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1zbGlkZWRvd25dLnRyYW5zaXRpb24taW57YW5pbWF0aW9uOnNsaWRlLWRvd24gLjhzO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1zbGlkZWRvd25dLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjpzbGlkZS11cCAuOHMgcmV2ZXJzZTtkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49ZmFkZWxlZnRdLnRyYW5zaXRpb24taW57YW5pbWF0aW9uOmZhZGUtbGVmdCAuOHM7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePWZhZGVsZWZ0XS50cmFuc2l0aW9uLW91dHthbmltYXRpb246ZmFkZS1yaWdodCAuOHMgcmV2ZXJzZTtkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49ZmFkZXJpZ2h0XS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjpmYWRlLXJpZ2h0IC44cztkaXNwbGF5OmlubGluZS1ibG9jayAhaW1wb3J0YW50fVtkYXRhLXQ4bl49ZmFkZXJpZ2h0XS50cmFuc2l0aW9uLW91dHthbmltYXRpb246ZmFkZS1sZWZ0IC44cyByZXZlcnNlO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1mYWRldXBdLnRyYW5zaXRpb24taW57YW5pbWF0aW9uOmZhZGUtdXAgLjhzO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1mYWRldXBdLnRyYW5zaXRpb24tb3V0e2FuaW1hdGlvbjpmYWRlLWRvd24gLjhzIHJldmVyc2U7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePWZhZGVkb3duXS50cmFuc2l0aW9uLWlue2FuaW1hdGlvbjpmYWRlLWRvd24gLjhzO2Rpc3BsYXk6aW5saW5lLWJsb2NrICFpbXBvcnRhbnR9W2RhdGEtdDhuXj1mYWRlZG93bl0udHJhbnNpdGlvbi1vdXR7YW5pbWF0aW9uOmZhZGUtdXAgLjhzIHJldmVyc2U7ZGlzcGxheTppbmxpbmUtYmxvY2sgIWltcG9ydGFudH1bZGF0YS10OG5ePWZsaWNrZXJdLnRyYW5zaXRpb24taW57YW5pbWF0aW9uOmZsaWNrZXIgLjhzfVtkYXRhLXQ4bl49ZmxpY2tlcl0udHJhbnNpdGlvbi1vdXR7YW5pbWF0aW9uOmZsaWNrZXIgLjhzIHJldmVyc2V9Cjwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+Cjx0dy1zdG9yeT48bm9zY3JpcHQ+PHR3LW5vc2NyaXB0PkphdmFTY3JpcHQgbmVlZHMgdG8gYmUgZW5hYmxlZCB0byBwbGF5IE1pZHRlcm0gUHJvamVjdC48L3R3LW5vc2NyaXB0Pjwvbm9zY3JpcHQ+PC90dy1zdG9yeT4KPHR3LXN0b3J5ZGF0YSBuYW1lPSJNaWR0ZXJtIFByb2plY3QiIHN0YXJ0bm9kZT0iMSIgY3JlYXRvcj0iVHdpbmUiIGNyZWF0b3ItdmVyc2lvbj0iMi4xMC4wIiBmb3JtYXQ9Ikhhcmxvd2UiIGZvcm1hdC12ZXJzaW9uPSIzLjMuOSIgaWZpZD0iQTJCQTBFMTUtQUZDNi00ODJFLUIxNTEtNkRBN0IyN0QzQzkyIiBvcHRpb25zPSIiIHRhZ3M9IiIgem9vbT0iMSIgaGlkZGVuPjxzdHlsZSByb2xlPSJzdHlsZXNoZWV0IiBpZD0idHdpbmUtdXNlci1zdHlsZXNoZWV0IiB0eXBlPSJ0ZXh0L3R3aW5lLWNzcyI+PC9zdHlsZT48c2NyaXB0IHJvbGU9InNjcmlwdCIgaWQ9InR3aW5lLXVzZXItc2NyaXB0IiB0eXBlPSJ0ZXh0L3R3aW5lLWphdmFzY3JpcHQiPjwvc2NyaXB0Pjx0dy1wYXNzYWdlZGF0YSBwaWQ9IjEiIG5hbWU9Ik5ldyBKZXJzZXkiIHRhZ3M9IiIgcG9zaXRpb249IjcwMCwzMDAiIHNpemU9IjEwMCwxMDAiPllvdSYjMzk7dmUgcmVhY2hlZCBOZXcgSmVyc2V5ISBFeGNlcHRpb25hbC4gQSBncmVhdCBzdGF0ZS4gWW91IHdhbnQgdG8gbWFrZSBpdCB0byB0aGUgcmVzdXBwbHkgcG9pbnQgaW4gTWFzc2FjaHVldHRzLCBob3dldmVyLiBZb3UgY29udGludWUgeW91ciBwYXRoIHRyYXZlcnNpbmcgdGhlIGZvcmVzdCB3aGVuIHlvdSBlbmNvdW50ZXI6CgoKKiBbW0EgbXVzaHJvb21dXQoKKiBbW1NvbWUgbW9zcyBvbiBhIHRyZWUgdHJ1bmtdXQoKKiBbW0EgY2hpbGRdXTwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMiIgbmFtZT0iQSBtdXNocm9vbSIgdGFncz0iIiBwb3NpdGlvbj0iNzAwLDQyNSIgc2l6ZT0iMTAwLDEwMCI+SXQmIzM5O3MgcXVpdGUgY3V0ZSEgSXQmIzM5O3MgcmVkLi4uIHdpdGggd2hpdGUgZG90cy4uLiBMb29rcyBsaWtlIHRoZSBvbmVzIHlvdSBzZWUgaW4gTWFyaW8hIERvIHlvdToKCiogW1tFYXQgdGhlIG11c2hyb29tXV0KKiBMZWF2ZSBpdCBhbG9uZSBhbmQgW1tjb250aW51ZSBvbiB5b3VyIGpvdXJuZXldXTwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMyIgbmFtZT0iU29tZSBtb3NzIG9uIGEgdHJlZSB0cnVuayIgdGFncz0iIiBwb3NpdGlvbj0iODUwLDQwMCIgc2l6ZT0iMTAwLDEwMCI+WW91IGNyb3VjaCBkb3duIHRvIG9ic2VydmUgdGhlIG1vc3Mgb24gdGhlIHRyZWUgdHJ1bmsuIEl0IGxvb2tzIGxpa2UgYSBsaXR0bGUgZWNvc3lzdGVtLCBhIG1pbmktZm9yZXN0LiBJdCYjMzk7cyBxdWl0ZSBwcmV0dHkuIFlvdSBzaXQgdGhlcmUgZm9yIGFib3V0IDUgbWludXRlcywgZmVlbGluZyBhIGJpdCBoYXBwaWVyIGFuZCBbW2NvbnRpbnVlIG9uIHlvdXIgam91cm5leV1dLjwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iNCIgbmFtZT0iQSBjaGlsZCIgdGFncz0iIiBwb3NpdGlvbj0iNTI1LDQ1MCIgc2l6ZT0iMTAwLDEwMCI+VGhlcmUgaXMgYSBjaGlsZCBjcm91Y2hpbmcuIFlvdSBtb3ZlIHRvd2FyZHMgdGhlIGNoaWxkLiBJdCBhcHBhcmVudGx5IGlzIG5vdCBhIGNoaWxkLiBJdCYjMzk7cyBhIGJhYnkgYmVhci4gSXQgc2VlbXMgeW91IHdlcmUgaGFsbHVjaW5hdGluZy4gWW91IGhlYXIgbWFtYSBiZWFyIGJlaGluZCB5b3UuIFlvdSBhcmUgY29va2VkLgoKCiYjMzk7JiMzOTtZb3UgYXJlIGRlYWQuJiMzOTsmIzM5OzwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iNSIgbmFtZT0iRWF0IHRoZSBtdXNocm9vbSIgdGFncz0iIiBwb3NpdGlvbj0iNjI1LDY1MCIgc2l6ZT0iMTAwLDEwMCI+WW91IHBsdWNrIHRoZSBtdXNocm9vbSwgYnJlYWtpbmcgaXRzIHN0ZW0sIHBsb3BwaW5nIGl0IGludG8geW91ciBtb3V0aC4gWXVtISBJdCB0YXN0ZXMgc3dlZXQsIGVhcnRoeSwgdW5saWtlIGFueXRoaW5nIHlvdSYjMzk7dmUgaGFkIGJlZm9yZSEgSXQmIzM5O3MgcXVpdGUgYW1hemluZyByZWFsbHksIGEgbmljZSBzb2Z0IHRleHR1cmUgYXMgd2VsbOKAlCB5b3UgZmVlbCBpbmNsaW5lZCB0byBmaW5kIG1vcmUuIFlvdSBhbHNvIGZlZWwgcmVmcmVzaGVkIHRvIGNvbnRpbnVlIGJhY2twYWNraW5nLi4uCgoKQnV0IHRoZW4geW91IHN0YXJ0IGNob2tpbmcuCgpJdCB0dXJucyBvdXQgaXQgd2FzIC8vRXZpbC8vIG11c2hyb29tIQoKCiYjMzk7JiMzOTtZb3UgYXJlIGRlYWQuJiMzOTsmIzM5OzwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iNiIgbmFtZT0iY29udGludWUgb24geW91ciBqb3VybmV5IiB0YWdzPSIiIHBvc2l0aW9uPSI5NTAsNjc1IiBzaXplPSIxMDAsMTAwIj5Zb3UgY29udGludWUgeW91ciBoaWtpbmcsIG1ha2luZyBncmVhdCBwcm9nZXNzISBBIHdlZWsgcGFzc2VzIG9mIHRyYXZlcnNpbmcgZ3JlZW5lcnksIHNhdW50ZXJpbmcgdGhyb3VnaCBmb3Jlc3RzLCBoaWtpbmcgdGhyb3VnaCB0aGUgbW91bnRhaW5zLiBUaGVuLCB5b3UgZW5jb3VudGVyIGEgd2VpcmQgYWlyLiBZb3UgYXJlIGluIFdlc3Rlcm4gTWFzc2FjaHVzZXR0cy4gT25seSBob3Jyb3JzIGNhbiBhd2FpdC4KCllvdSBjb250aW51ZSB5b3VyIGJhY2twYWNraW5nLCByZWFsaXppbmcgaXQgaXMgdGltZSB0byByZXN0b2NrLiBBY2NvcmlkaW5nIHRvIHlvdXIgcHJlcGFyYXRpb25zIGFuZCBtYXAsIHRoZSBuZWFyZXN0IHJlc3RvY2sgcG9pbnQgaXMgaW4gR3JlYXQgQmFycmluZ3Rvbi4gWW91IGZvbGxvdyB0aGUgcGF0aCBzaWducyBhbmQgbWFrZSB5b3VyIHdheSB0byB0aGUgdG93bi4gT25jZSB5b3UgcmVhY2ggdGhlIHRvd24geW91IHNlZSB0aGF0IHRoZXJlIGFyZSB0d28gcGxhY2VzIG9mIGludGVyZXN0OgoKKiBBIFtbUHJpY2UgQ2hvcHBlcl1dIHN1cGVybWFya2V0IHRvIHlvdXIgbm9ydGguCiogQSBbW0RvbGxhciBUcmVlXV0gdG8geW91ciBzb3V0aC48L3R3LXBhc3NhZ2VkYXRhPjx0dy1wYXNzYWdlZGF0YSBwaWQ9IjciIG5hbWU9IlByaWNlIENob3BwZXIiIHRhZ3M9IiIgcG9zaXRpb249IjgwMCw4MjUiIHNpemU9IjEwMCwxMDAiPllvdSBlbnRlciB0aGUgUHJpY2UgQ2hvcHBlciwgc2VlaW5nIHRoZSByYW5nZSBvZiBmb29kLgoKJnF1b3Q7SGVoZSZxdW90OyBZb3UgaGVhciBiZWhpbmQgeW91LiBZb3UgdHVybiBhcm91bmQgYW5kIHNlZSBhIG1hbiBpbiBhIGJpZyBjYXQgY29zdHVtZS4KCiZxdW90O1doYXQgd291bGQgeW91IGxpa2UgdG9kYXk/JnF1b3Q7IFRoZSBjYXQtbWFuIGFza3MuCgoqIFtbJnF1b3Q7U29tZSBlbmVyZ3kgZHJpbmtzIGFuZCBzbmFja3MmcXVvdDtdXQoqICZxdW90O1VtLCBub3RoaW5nLCB3cm9uZyBzdG9yZSZxdW90OyBhbmQgW1tMZWF2ZV1dPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSI4IiBuYW1lPSJEb2xsYXIgVHJlZSIgdGFncz0iIiBwb3NpdGlvbj0iMTA1MCw4MjUiIHNpemU9IjEwMCwxMDAiPllvdSBlbnRlciB0aGUgZG9sbGFyIHRyZWUsIHBpY2tpbmcgdXAgc29tZSBzdXBwbGllcyBhbmQgZm9vZCB0aGV5IHByZXBhcmUgZm9yIHRoZSBoaWtlcnMsIHNpbmNlIHRoaXMgdG93biBpcyBhIHBvcHVsYXIgcmVzdGluZyBzcG90IGZvciBBcHBhbGFjaGlhbiBiYWNrcGFja2Vycy4gWW91IGNoZWNrb3V0IHRoZW4gbWFrZSB5b3VyIHdheSBiYWNrIHRvIHRoZSB0cmFpbCwgaGlraW5nIGJhY2sgdXAgdGhlIFtbbW91bnRhaW5dXS48L3R3LXBhc3NhZ2VkYXRhPjx0dy1wYXNzYWdlZGF0YSBwaWQ9IjkiIG5hbWU9IiZxdW90O1NvbWUgZW5lcmd5IGRyaW5rcyBhbmQgc25hY2tzJnF1b3Q7IiB0YWdzPSIiIHBvc2l0aW9uPSI2MjUsOTUwIiBzaXplPSIxMDAsMTAwIj4mcXVvdDtFbmVyZ3kgZHJpbmtzIGFuZCBzbmFja3MgeW91IHNheT8mcXVvdDsgVGhlIGNhdC1tYW4gYXNrcy4gJnF1b3Q7WW91IG11c3QgYmUgb25lIG9mIG91ciBiYWNrcGFja2VycyBvbiB0aGUgQXBwYWxhY2hpYW4gdHJhaWwhIEJveSBvaCBib3kgZG8gSSBoYXZlIGEgcHJlc2VudCBmb3IgeW91JnF1b3Q7IAoKWW91IGFyZSBzY2FyZWQuCgpUaGUgY2F0LW1hbiBsZWFkcyB5b3UgdG8gdGhlIGJhY2sgb2YgdGhlIHN0b3JlLiBTdWRkZW5seSBldmVyeXRoaW5nIGdvZXMgZGFyay4KCllvdSB3YWtlIHVwIGluIG11ZCwgaW4gb25lIG9mIHRoZSBtYXJzaGVzIG9mIFdlc3QgTWFzcy4gWW91IGhlYXIgYSB2b2ljZTogJnF1b3Q7SGVoZSwgdGhhbmsgeW91IGZvciB5b3VyIHBhdHJvbmFnZSZxdW90OwoKQSBjcm9jb2RpbGUgZW1lcmdlcyBiZWZvcmUgeW91IGNhbiB0dXJuIGFyb3VuZCBhbmQgY3Vyc2Ugb3V0IHRoZSBjYXQtbWFuLCBhbmQgLy9DSE9NUCEvLy4KCiYjMzk7JiMzOTtZb3UgYXJlIGRlYWQuJiMzOTsmIzM5OzwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMTAiIG5hbWU9IkxlYXZlIiB0YWdzPSIiIHBvc2l0aW9uPSI5MjUsOTI1IiBzaXplPSIxMDAsMTAwIj5Zb3UgbGVhdmUgYW5kIGdvIHRvIHRoZSBbW0RvbGxhciBUcmVlXV0uPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIxMSIgbmFtZT0ibW91bnRhaW4iIHRhZ3M9IiIgcG9zaXRpb249IjEwNTAsOTUwIiBzaXplPSIxMDAsMTAwIj5Zb3UgY29udGludWUgaGlraW5nIGZvciBtaWxlcywgZmluZGluZyBhIG5pY2Ugc3BvdCBhdCBhIHN1bW1pdCB3aXRoIGEgdmlldyBvZiBhIHZhbGxleSBiZWxvdy4gSXQgc2VlbXMgeW91JiMzOTt2ZSByZWFjaGVkIE1vdW50IEdyZXlsb2NrIQoKSXQmIzM5O3MgcXVpdGUgcHJldHR5ISBZb3UgdGhpbmsgdG8geW91cnNlbGYsIHNpbmNlIHlvdSBkbyBhIGxvdCBvZiB0aGF0LiAKClNvb24geW91IHdpbGwgYmUgb3V0IG9mIFdlc3Rlcm4gTWFzcyBhbmQgaW50byB0aGUgc2FmZXIgdGVycml0b3JpZXMgb2YgVmVybW9udC4gCgpJdCByZWFjaGVzIG5pZ2h0IGFnYWluLCBhbmQgeW91IHdhdGNoIHRoZSBzdW5zZXQgYXMgeW91IHNldCB1cCBjYW1wIHRvIHNsZWVwLiBUaGUgcHJvY2VzcyBmZWVscyBsaWtlIG11c2NsZSBtZW1vcnkgYXQgdGhpcyBwb2ludC4gWW91IGFyZSBsYXlpbmcgZG93biBpbiB0aGUgb3BlbiBhaXIgYmVmb3JlIHRyZWF0aW5nIHRvIHlvdXIgdGVudCwgYXMgdGhlIHNreSBpcyBjbGVhciBhbmQgdGhlIGFsbCB0aGUgc3RhcnMgYXJlIHZpc2libGUsIGFsb25nc2lkZSBhIG5pY2UsIG5ldyBtb29uLgoKCllvdSBoZWFyIHNvbWUgc2tpcm1pc2hpbmcgYmVoaW5kIHlvdS4gSXQmIzM5O3MgYSBsaWwgW1tnb2F0XV0uPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIxMiIgbmFtZT0iZ29hdCIgdGFncz0iIiBwb3NpdGlvbj0iMTEyNSwxMDc1IiBzaXplPSIxMDAsMTAwIj5JdHMgY29tcGxldGVseSB3aGl0ZSB3aXRoIHNtYWxsIGhvcm5zIGFuZCB5ZWxsb3cgZXllcywgcGVlcmluZyBpbnRvIHlvdXIgc291bC4gLy9JdCYjMzk7cyBraW5kYSBjdXRlLy8uICZxdW90O1lvdSYjMzk7cmUga2luZGEgY3V0ZSwmcXVvdDsgeW91IGhlYXIgdGhlIGdvYXQgc2F5IHRvIHlvdSwgZXZlbiB0aG91Z2ggaXQgZGlkbiYjMzk7dCBtb3ZlIGl0cyBtb3V0aC4gCgomcXVvdDtIdWg/JnF1b3Q7IFlvdSBzYXkuIAoKJnF1b3Q7SHVoIHdoYXQmcXVvdDsgTGlsIEdvYXQgc2F5cy4KCiogW1smcXVvdDtIb3cgYXJlIHlvdSB0YWxraW5nPyZxdW90O11dCgoqIFtbT2ggbm8sIEkmIzM5O3ZlIGxvc3QgbXkgZGFtbiBtaW5kXV08L3R3LXBhc3NhZ2VkYXRhPjx0dy1wYXNzYWdlZGF0YSBwaWQ9IjEzIiBuYW1lPSImcXVvdDtIb3cgYXJlIHlvdSB0YWxraW5nPyZxdW90OyIgdGFncz0iIiBwb3NpdGlvbj0iMTEyNSwxMjAwIiBzaXplPSIxMDAsMTAwIj5UaGUgZ29hdCBqdXN0IGxvb2tzIGF0IHlvdS4gSXQgdHVybnMgYXJvdW5kIGFuZCB3YWxrcyBhd2F5LiAvL0FoLi4uLy8gWW91IHRoaW5rIHRvIHlvdXJzZWxmLiAvL0kmIzM5O20gYSBmdWNraW5nIGx1bmF0aWMuLy8KCiogWW91IHRyeSB0byBzbGVlcCBhbmQgdHJ5IHRvIHJlZ2FpbiBbW3lvdXIgc2FuaXR5Ll1dCgoqIFlvdSBnZXQgdXAsIHRvIFtbZXhwbG9yZV1dIHNvbWUgbW9yZSBzaW5jZSB5b3UmIzM5O3JlIGZlZWxpbmcgYW50c3kuPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIxNCIgbmFtZT0ieW91ciBzYW5pdHkuIiB0YWdzPSIiIHBvc2l0aW9uPSIxMjUwLDEzMjUiIHNpemU9IjEwMCwxMDAiPkl0JiMzOTtzIGhhcmQgYmVpbmcgYWxvbmUgb3V0IGhlcmUuIEFuZCBpdHMgYmVlbiBtYW55IG1vbnRocy4gWW91IG1pc3MgeW91ciBNb20uIFlvdSBjYW4gc21lbGwgaXQgbm93LCBoZXIgY29va2luZywgeW91IHBsYXlpbmcgdmlkZW8gZ2FtZXMgaW4geW91ciByb29tIGFzIHRoZSBzY2VudCB3YWZ0cyBpbiBhbmQgeW91ciBtb3RoZXIgY2FsbHMgeW91IGZvciBkaW5uZXIuIFlvdSBhY3QgcmVsdWN0YW50IHRvIGdldCBvZmYgeW91ciBnYW1lLCBidXQgYXMgeW91IHNldCBkb3duIHlvdXIgaGVhZHBob25lcyBhbmQgc3RlcCBpbnRvIHRoZSBraXRjaGVuLCB5b3VyIGh1bmdlciBvdmVydGFrZXMgeW91LiBZb3UgZWF0IHlvdXIgbW9tJiMzOTtzIGNvb2tpbmcsIGFuZCBpdHMgaG90LiBJdHMgbmljZS4KCllvdSBmYWxsIFtbYXNsZWVwXV0sIGEgc29mdCBzbWlsZSBvbiB5b3VyIGZhY2UsIGRyb29saW5nLgoKCjwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMTUiIG5hbWU9IiZxdW90O1NhZmV0eSBhdCBsYXN0ISZxdW90OyIgdGFncz0iIiBwb3NpdGlvbj0iMTIyNSwxNjAwIiBzaXplPSIxMDAsMTAwIj5Zb3UgaGlrZSB0aHJvdWdoIHRoZSBHcmVlbiBNb3VudGFpbnMsIHRoZSB2aWV3IGJlYXV0aWZ1bCwgc2VyZW5lLCBhbmQgcmVsZXZhbnQuIEl0JiMzOTtzIG5pY2UgdG8gYmUgaW4gYSByZWFsIHBsYWNlLCBubyB3ZWlyZCBzd2FtcHMgaW4gc2lnaHQuCgoKWW91IHN1Y2Nlc3NmdWxseSBhdm9pZCB0aGUgc3RlZXAgc2xvcGVzLCB0aGUgbXVkLCBhbmQgd2hhdGV2ZXIgY29tZXMgeW91ciB3YXkuIFlvdSBmaW5hbGx5IHJlYWNoIFtbUm9sc3RvbiBSZXN0Ll1dPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIxNiIgbmFtZT0iUm9sc3RvbiBSZXN0LiIgdGFncz0iIiBwb3NpdGlvbj0iMTIwMCwxNzUwIiBzaXplPSIxMDAsMTAwIj5Zb3UgcmVwbGVuaXNoIHlvdXIgZm9vZCwgd2F0ZXIsIHN1cHBsaWVzLCBhbmQgY2hpbGwgb3V0IGEgYml0LiBJdCYjMzk7cyBiZWVuIDQgbW9udGhzIHNpbmNlIHlvdSBzdGFydGVkIHlvdXIgYWR2ZW50dXJlLCBhbmQgaXQmIzM5O3MgZ29uZSBwcmV0dHkgc21vb3RobHksIHlvdSYjMzk7ZCBzYXkuIAoKWW91JiMzOTt2ZSBnb3Qgb25seSBvbmUgbW9yZSBtb250aCB0byBnbywgaXRzIHRoZSBmaW5hbCBzdHJldGNoITwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMTciIG5hbWU9ImV4cGxvcmUiIHRhZ3M9IiIgcG9zaXRpb249IjEwNzUsMTMyNSIgc2l6ZT0iMTAwLDEwMCI+WW91IHdhbmRlciBhcm91bmQgb24gTW91bnQgR3JleWxvY2ssIGxvb2tpbmcgYmVsb3cgYXQgdGhlIEJlcmtzaGlyZXMsIGEgd2VpcmQgcGxhY2UgcmVhbGx5LiBZb3UgY29udGludWUgc2F1bnRlcmluZyBhdCB5b3VyIGhpZ2hlciBlbGV2YXRpb24sIGhvcGluZyB0aGUgd2FsayB3aWxsIGNsZWFyIHlvdXIgbWluZCwgYXMgaWYgeW91IGhhZG4mIzM5O3QgaGFkIGVub3VnaCB3YWxraW5nL2hpa2luZyBhbHJlYWR5LgoKVGhlcmUmIzM5O3Mgc29tZSBmYWxsIGZvbGlhZ2UgY29taW5nIGluIG9uIGEgdHJlZSB5b3UgcGFzcyBieS4gWW91IGZpbmQgYSBzdHJlYW0uCgpZb3Ugd2F0Y2ggdGhlIGZsb3dpbmcgd2F0ZXIgb2YgdGhlIHN0cmVhbSwgaXRzIGNvbnRpbnVvdXMsIGNvbnNpc3RlbnQgbW92ZW1lbnQgaXMgY2FsbWluZy4gCgoqIFtbWW91IGNvbnRpbnVlIHdhdGNoaW5nIHRoZSBzdHJlYW0gZm9yIGEgYml0XV0KCiogW1tZb3UgbW92ZSB0byBsb29rIGF0IHNvbWV0aGluZyBuZXddXTwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMTgiIG5hbWU9IllvdSBjb250aW51ZSB3YXRjaGluZyB0aGUgc3RyZWFtIGZvciBhIGJpdCIgdGFncz0iIiBwb3NpdGlvbj0iMTA3NSwxNDUwIiBzaXplPSIxMDAsMTAwIj5UaGUgd2F0ZXIgc3BhcmtsZXMgdW5kZXIgdGhlIG1vb25saWdodCwgYW5kIHNpbmNlIHRoZSBza3kgaXMgY2xlYXIsIGV2ZXJ5dGhpbmcgaXMgbmljZSwgYmx1ZSBhbmQgYnJpZ2h0LiBZb3Ugc2l0IGFyb3VuZCBvbiBhIHJvY2sgZm9yIGEgZmV3IG1pbnV0ZXMsIHRoZSBjYWxtIGJyaW5naW5nIHlvdSByZWxheGF0aW9uLCBhbmQgeW91IGJlY29tZSBtb3JlIHNsZWVweS4gCgpZb3UgaGVhZCBiYWNrIGFuZCBzZXR0bGUgZG93biBpbiB5b3VyIHRlbnQsIGFuZCBmYWxsIFtbYXNsZWVwXV0uPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIxOSIgbmFtZT0iWW91IG1vdmUgdG8gbG9vayBhdCBzb21ldGhpbmcgbmV3IiB0YWdzPSIiIHBvc2l0aW9uPSI5NTAsMTM3NSIgc2l6ZT0iMTAwLDEwMCI+WW91IGNvbnRpbnVlIHdhbGtpbmcsIGZvbGxvd2luZyB0aGUgc3RyZWFtLgoKWW91IHNlZSBhIG1vdW5kIG9mIG1vc3MuCgovL1dvdywgdGhhdCBsb29rcyBzbyBzb2Z0IGFuZCBmbHVmZnkhLy8KCltbSnVtcCBvbnRvIHRoZSBtb3VuZCBvZiBtb3NzXV08L3R3LXBhc3NhZ2VkYXRhPjx0dy1wYXNzYWdlZGF0YSBwaWQ9IjIwIiBuYW1lPSJhc2xlZXAiIHRhZ3M9IiIgcG9zaXRpb249IjEyNTAsMTQ3NSIgc2l6ZT0iMTAwLDEwMCI+WW91IHdha2UgdXAsIGFuZCBjb250aW51ZSBoaWtpbmcsIGZlZWxpbmcgcmVqdXZlbmF0ZWQuIFlvdXIgam91cm5leSBnb2VzIHNtb290aGx5LgoKCkEgY291cGxlIHdlZWtzIHBhc3MgYXMgeW91IGhpa2UgdGhyb3VnaCBNYXNzYWNodXNldHRzLCBhbmQgcGFzcyB0aGUgVmVybW9udCBib3JkZXIuCgpbWyZxdW90O1NhZmV0eSBhdCBsYXN0ISZxdW90O11dIFlvdSBzYXkuLi4gdG8geW91cnNlbGYuPC90dy1wYXNzYWdlZGF0YT48dHctcGFzc2FnZWRhdGEgcGlkPSIyMSIgbmFtZT0iSnVtcCBvbnRvIHRoZSBtb3VuZCBvZiBtb3NzIiB0YWdzPSIiIHBvc2l0aW9uPSI4NTAsMTUwMCIgc2l6ZT0iMTAwLDEwMCI+WW91IGp1bXAgb250byB0aGUgbW9zcywgZXhwZWN0aW5nIGEgcGx1c2ggbGFuZGluZyBvbiB0aGUgZmx1ZmZ5LCBuaWNlIG1vc3MuCgoKSXQgd2FzIG5vdCBuaWNlIG1vc3MuCgpJdCB3YXMgLy9FdmlsLy8gbW9zcy4KCgovL0V2aWwvLyBtb3NzIGNvbnN1bWVzIHlvdSBhbmQgeW91IHNpbmsgaW50byB0aGUgZ3JvdW5kLgoKCiYjMzk7JiMzOTtZb3UgYXJlIGRlYWQuJiMzOTsmIzM5OzwvdHctcGFzc2FnZWRhdGE+PHR3LXBhc3NhZ2VkYXRhIHBpZD0iMjIiIG5hbWU9Ik9oIG5vLCBJJiMzOTt2ZSBsb3N0IG15IGRhbW4gbWluZCIgdGFncz0iIiBwb3NpdGlvbj0iOTc1LDEyMDAiIHNpemU9IjEwMCwxMDAiPiZxdW90O1llcywgeW91IGhhdmUmcXVvdDsgTGlsIEdvYXQgc2F5cy4gJnF1b3Q7SXQmIzM5O3Mgb2theSB0aG91Z2gsIEkmIzM5O20gaGVyZSBmb3IgeW91LiZxdW90OwoKWW91IHN0YXJ0IHRvIGNyeS4gVGhpcyBpcyB3aHkgeW91IGhhdGUgV2VzdGVybiBNYXNzYWNodXNldHRzLiAKCiZxdW90O0V4Y3VzZSBtZT8mcXVvdDsgTGlsIEdvYXQgc2hhcnBseSBpbnF1aXJlcy4KCiZxdW90O1doYXQ/JnF1b3Q7CgomcXVvdDtZb3UgaGF0ZSBXZXN0ZXJuIE1hc3NhY2h1c2V0dHM/JnF1b3Q7CgomcXVvdDtJIGRpZG4mIzM5O3Qgc2F5IHRoYXQmcXVvdDsKCiZxdW90O1lvdSB0aG91Z2h0IGl0LiZxdW90OwoKJnF1b3Q7V2VsbC4uLiB5ZWFoLiBCb3N0b24gaXMgd2hlcmUgaXRzIGF0LiBXZXN0ZXJuIE1hc3MsIGl0JiMzOTtzIG5vdCByZWFsbHkgcmVsZXZhbnQuIEl0cyBmYWtlLiBMaWtlIHlvdSwgeW91JiMzOTtyZSBub3QgcmVhbCwgeW91JiMzOTtyZSBqdXN0IGluIG15IGhlYWQuJnF1b3Q7CgomcXVvdDtPaCBJJiMzOTttIHZlcnkgcmVhbC4gQW5kIHlvdSBhcmUgc2l0dGluZyBpbiBteSBmYXZvcml0ZSBtb3VudGFpbiBzcG90LCB3aGVyZSBJIGNhbiBkZWZ5IGdyYXZpdHkgYW5kIGFzc2VydCBteSBkb21pbmFuY2Ugb3ZlciB0aGUgRWFydGgmIzM5O3MgZm9yY2VzLiZxdW90OwoKJnF1b3Q7VW0sIHNvcnJ5PyZxdW90OwoKJnF1b3Q7SGVlZCBtZSwgYW5kIGFjY2VwdCB0aGUgY29uc2VxdWVuY2VzIG9mIHlvdXIgYWN0aW9ucyZxdW90OwpMaWwgR29hdCBydW5zIGF0IHlvdSwgYW5kIHRocm93cyB5b3Ugb2ZmIHRoZSBtb3VudGFpbi4gCgogJiMzOTsmIzM5O1lvdSBhcmUgZGVhZC4mIzM5OyYjMzk7PC90dy1wYXNzYWdlZGF0YT48L3R3LXN0b3J5ZGF0YT4KPHNjcmlwdCB0aXRsZT0iVHdpbmUgZW5naW5lIGNvZGUiIGRhdGEtbWFpbj0iaGFybG93ZSI+KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiOwp2YXIgcmVxdWlyZSxkZWZpbmU7IWZ1bmN0aW9uKCl7dmFyIGU9e30scj17fTtyZXF1aXJlPWZ1bmN0aW9uKGkpe3ZhciBuPWVbaV07cmV0dXJuIG4mJihyW2ldPW5bMV0uYXBwbHkodm9pZCAwLG5bMF0ubWFwKHJlcXVpcmUpKSxlW2ldPXZvaWQgMCkscltpXX0sKGRlZmluZT1mdW5jdGlvbihyLGksbil7aWYoImZ1bmN0aW9uIj09dHlwZW9mIHIpcmV0dXJuIHIoKTtlW3JdPVtpLG5dfSkuYW1kPSEwfSgpOy8qIQogKiBodHRwczovL2dpdGh1Yi5jb20vcGF1bG1pbGxyL2VzNi1zaGltCiAqIEBsaWNlbnNlIGVzNi1zaGltIENvcHlyaWdodCAyMDEzLTIwMTYgYnkgUGF1bCBNaWxsZXIgKGh0dHA6Ly9wYXVsbWlsbHIuY29tKQogKiAgIGFuZCBjb250cmlidXRvcnMsICBNSVQgTGljZW5zZQogKiBlczYtc2hpbTogdjAuMzUuNAogKiBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3BhdWxtaWxsci9lczYtc2hpbS9ibG9iLzAuMzUuMy9MSUNFTlNFCiAqIERldGFpbHMgYW5kIGRvY3VtZW50YXRpb246CiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9wYXVsbWlsbHIvZXM2LXNoaW0vCiAqLwooZnVuY3Rpb24oZSx0KXtpZih0eXBlb2YgZGVmaW5lPT09ImZ1bmN0aW9uIiYmZGVmaW5lLmFtZCl7ZGVmaW5lKHQpfWVsc2UgaWYodHlwZW9mIGV4cG9ydHM9PT0ib2JqZWN0Iil7bW9kdWxlLmV4cG9ydHM9dCgpfWVsc2V7ZS5yZXR1cm5FeHBvcnRzPXQoKX19KSh0aGlzLGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO3ZhciBlPUZ1bmN0aW9uLmNhbGwuYmluZChGdW5jdGlvbi5hcHBseSk7dmFyIHQ9RnVuY3Rpb24uY2FsbC5iaW5kKEZ1bmN0aW9uLmNhbGwpO3ZhciByPUFycmF5LmlzQXJyYXk7dmFyIG49T2JqZWN0LmtleXM7dmFyIG89ZnVuY3Rpb24gbm90VGh1bmtlcih0KXtyZXR1cm4gZnVuY3Rpb24gbm90VGh1bmsoKXtyZXR1cm4hZSh0LHRoaXMsYXJndW1lbnRzKX19O3ZhciBpPWZ1bmN0aW9uKGUpe3RyeXtlKCk7cmV0dXJuIGZhbHNlfWNhdGNoKHQpe3JldHVybiB0cnVlfX07dmFyIGE9ZnVuY3Rpb24gdmFsdWVPckZhbHNlSWZUaHJvd3MoZSl7dHJ5e3JldHVybiBlKCl9Y2F0Y2godCl7cmV0dXJuIGZhbHNlfX07dmFyIHU9byhpKTt2YXIgZj1mdW5jdGlvbigpe3JldHVybiFpKGZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh7fSwieCIse2dldDpmdW5jdGlvbigpe319KX0pfTt2YXIgcz0hIU9iamVjdC5kZWZpbmVQcm9wZXJ0eSYmZigpO3ZhciBjPWZ1bmN0aW9uIGZvbygpe30ubmFtZT09PSJmb28iO3ZhciBsPUZ1bmN0aW9uLmNhbGwuYmluZChBcnJheS5wcm90b3R5cGUuZm9yRWFjaCk7dmFyIHA9RnVuY3Rpb24uY2FsbC5iaW5kKEFycmF5LnByb3RvdHlwZS5yZWR1Y2UpO3ZhciB2PUZ1bmN0aW9uLmNhbGwuYmluZChBcnJheS5wcm90b3R5cGUuZmlsdGVyKTt2YXIgeT1GdW5jdGlvbi5jYWxsLmJpbmQoQXJyYXkucHJvdG90eXBlLnNvbWUpO3ZhciBoPWZ1bmN0aW9uKGUsdCxyLG4pe2lmKCFuJiZ0IGluIGUpe3JldHVybn1pZihzKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHtjb25maWd1cmFibGU6dHJ1ZSxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsdmFsdWU6cn0pfWVsc2V7ZVt0XT1yfX07dmFyIGI9ZnVuY3Rpb24oZSx0LHIpe2wobih0KSxmdW5jdGlvbihuKXt2YXIgbz10W25dO2goZSxuLG8sISFyKX0pfTt2YXIgZz1GdW5jdGlvbi5jYWxsLmJpbmQoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZyk7dmFyIGQ9dHlwZW9mL2FiYy89PT0iZnVuY3Rpb24iP2Z1bmN0aW9uIElzQ2FsbGFibGVTbG93KGUpe3JldHVybiB0eXBlb2YgZT09PSJmdW5jdGlvbiImJmcoZSk9PT0iW29iamVjdCBGdW5jdGlvbl0ifTpmdW5jdGlvbiBJc0NhbGxhYmxlRmFzdChlKXtyZXR1cm4gdHlwZW9mIGU9PT0iZnVuY3Rpb24ifTt2YXIgbT17Z2V0dGVyOmZ1bmN0aW9uKGUsdCxyKXtpZighcyl7dGhyb3cgbmV3IFR5cGVFcnJvcigiZ2V0dGVycyByZXF1aXJlIHRydWUgRVM1IHN1cHBvcnQiKX1PYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHtjb25maWd1cmFibGU6dHJ1ZSxlbnVtZXJhYmxlOmZhbHNlLGdldDpyfSl9LHByb3h5OmZ1bmN0aW9uKGUsdCxyKXtpZighcyl7dGhyb3cgbmV3IFR5cGVFcnJvcigiZ2V0dGVycyByZXF1aXJlIHRydWUgRVM1IHN1cHBvcnQiKX12YXIgbj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGUsdCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHIsdCx7Y29uZmlndXJhYmxlOm4uY29uZmlndXJhYmxlLGVudW1lcmFibGU6bi5lbnVtZXJhYmxlLGdldDpmdW5jdGlvbiBnZXRLZXkoKXtyZXR1cm4gZVt0XX0sc2V0OmZ1bmN0aW9uIHNldEtleShyKXtlW3RdPXJ9fSl9LHJlZGVmaW5lOmZ1bmN0aW9uKGUsdCxyKXtpZihzKXt2YXIgbj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGUsdCk7bi52YWx1ZT1yO09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHQsbil9ZWxzZXtlW3RdPXJ9fSxkZWZpbmVCeURlc2NyaXB0b3I6ZnVuY3Rpb24oZSx0LHIpe2lmKHMpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHQscil9ZWxzZSBpZigidmFsdWUiaW4gcil7ZVt0XT1yLnZhbHVlfX0scHJlc2VydmVUb1N0cmluZzpmdW5jdGlvbihlLHQpe2lmKHQmJmQodC50b1N0cmluZykpe2goZSwidG9TdHJpbmciLHQudG9TdHJpbmcuYmluZCh0KSx0cnVlKX19fTt2YXIgTz1PYmplY3QuY3JlYXRlfHxmdW5jdGlvbihlLHQpe3ZhciByPWZ1bmN0aW9uIFByb3RvdHlwZSgpe307ci5wcm90b3R5cGU9ZTt2YXIgbz1uZXcgcjtpZih0eXBlb2YgdCE9PSJ1bmRlZmluZWQiKXtuKHQpLmZvckVhY2goZnVuY3Rpb24oZSl7bS5kZWZpbmVCeURlc2NyaXB0b3IobyxlLHRbZV0pfSl9cmV0dXJuIG99O3ZhciB3PWZ1bmN0aW9uKGUsdCl7aWYoIU9iamVjdC5zZXRQcm90b3R5cGVPZil7cmV0dXJuIGZhbHNlfXJldHVybiBhKGZ1bmN0aW9uKCl7dmFyIHI9ZnVuY3Rpb24gU3ViY2xhc3ModCl7dmFyIHI9bmV3IGUodCk7T2JqZWN0LnNldFByb3RvdHlwZU9mKHIsU3ViY2xhc3MucHJvdG90eXBlKTtyZXR1cm4gcn07T2JqZWN0LnNldFByb3RvdHlwZU9mKHIsZSk7ci5wcm90b3R5cGU9TyhlLnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOnJ9fSk7cmV0dXJuIHQocil9KX07dmFyIGo9ZnVuY3Rpb24oKXtpZih0eXBlb2Ygc2VsZiE9PSJ1bmRlZmluZWQiKXtyZXR1cm4gc2VsZn1pZih0eXBlb2Ygd2luZG93IT09InVuZGVmaW5lZCIpe3JldHVybiB3aW5kb3d9aWYodHlwZW9mIGdsb2JhbCE9PSJ1bmRlZmluZWQiKXtyZXR1cm4gZ2xvYmFsfXRocm93IG5ldyBFcnJvcigidW5hYmxlIHRvIGxvY2F0ZSBnbG9iYWwgb2JqZWN0Iil9O3ZhciBTPWooKTt2YXIgVD1TLmlzRmluaXRlO3ZhciBJPUZ1bmN0aW9uLmNhbGwuYmluZChTdHJpbmcucHJvdG90eXBlLmluZGV4T2YpO3ZhciBFPUZ1bmN0aW9uLmFwcGx5LmJpbmQoQXJyYXkucHJvdG90eXBlLmluZGV4T2YpO3ZhciBQPUZ1bmN0aW9uLmNhbGwuYmluZChBcnJheS5wcm90b3R5cGUuY29uY2F0KTt2YXIgQz1GdW5jdGlvbi5jYWxsLmJpbmQoU3RyaW5nLnByb3RvdHlwZS5zbGljZSk7dmFyIE09RnVuY3Rpb24uY2FsbC5iaW5kKEFycmF5LnByb3RvdHlwZS5wdXNoKTt2YXIgeD1GdW5jdGlvbi5hcHBseS5iaW5kKEFycmF5LnByb3RvdHlwZS5wdXNoKTt2YXIgTj1GdW5jdGlvbi5jYWxsLmJpbmQoQXJyYXkucHJvdG90eXBlLmpvaW4pO3ZhciBBPUZ1bmN0aW9uLmNhbGwuYmluZChBcnJheS5wcm90b3R5cGUuc2hpZnQpO3ZhciBfPU1hdGgubWF4O3ZhciBSPU1hdGgubWluO3ZhciBrPU1hdGguZmxvb3I7dmFyIEw9TWF0aC5hYnM7dmFyIEY9TWF0aC5leHA7dmFyIEQ9TWF0aC5sb2c7dmFyIHo9TWF0aC5zcXJ0O3ZhciBxPUZ1bmN0aW9uLmNhbGwuYmluZChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5KTt2YXIgVzt2YXIgRz1mdW5jdGlvbigpe307dmFyIEg9Uy5NYXA7dmFyIFY9SCYmSC5wcm90b3R5cGVbImRlbGV0ZSJdO3ZhciBCPUgmJkgucHJvdG90eXBlLmdldDt2YXIgVT1IJiZILnByb3RvdHlwZS5oYXM7dmFyICQ9SCYmSC5wcm90b3R5cGUuc2V0O3ZhciBKPVMuU3ltYm9sfHx7fTt2YXIgWD1KLnNwZWNpZXN8fCJAQHNwZWNpZXMiO3ZhciBLPU51bWJlci5pc05hTnx8ZnVuY3Rpb24gaXNOYU4oZSl7cmV0dXJuIGUhPT1lfTt2YXIgWj1OdW1iZXIuaXNGaW5pdGV8fGZ1bmN0aW9uIGlzRmluaXRlKGUpe3JldHVybiB0eXBlb2YgZT09PSJudW1iZXIiJiZUKGUpfTt2YXIgWT1kKE1hdGguc2lnbik/TWF0aC5zaWduOmZ1bmN0aW9uIHNpZ24oZSl7dmFyIHQ9TnVtYmVyKGUpO2lmKHQ9PT0wKXtyZXR1cm4gdH1pZihLKHQpKXtyZXR1cm4gdH1yZXR1cm4gdDwwPy0xOjF9O3ZhciBRPWZ1bmN0aW9uIGxvZzFwKGUpe3ZhciB0PU51bWJlcihlKTtpZih0PC0xfHxLKHQpKXtyZXR1cm4gTmFOfWlmKHQ9PT0wfHx0PT09SW5maW5pdHkpe3JldHVybiB0fWlmKHQ9PT0tMSl7cmV0dXJuLUluZmluaXR5fXJldHVybiAxK3QtMT09PTA/dDp0KihEKDErdCkvKDErdC0xKSl9O3ZhciBlZT1mdW5jdGlvbiBpc0FyZ3VtZW50cyhlKXtyZXR1cm4gZyhlKT09PSJbb2JqZWN0IEFyZ3VtZW50c10ifTt2YXIgdGU9ZnVuY3Rpb24gaXNBcmd1bWVudHMoZSl7cmV0dXJuIGUhPT1udWxsJiZ0eXBlb2YgZT09PSJvYmplY3QiJiZ0eXBlb2YgZS5sZW5ndGg9PT0ibnVtYmVyIiYmZS5sZW5ndGg+PTAmJmcoZSkhPT0iW29iamVjdCBBcnJheV0iJiZnKGUuY2FsbGVlKT09PSJbb2JqZWN0IEZ1bmN0aW9uXSJ9O3ZhciByZT1lZShhcmd1bWVudHMpP2VlOnRlO3ZhciBuZT17cHJpbWl0aXZlOmZ1bmN0aW9uKGUpe3JldHVybiBlPT09bnVsbHx8dHlwZW9mIGUhPT0iZnVuY3Rpb24iJiZ0eXBlb2YgZSE9PSJvYmplY3QifSxzdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuIGcoZSk9PT0iW29iamVjdCBTdHJpbmddIn0scmVnZXg6ZnVuY3Rpb24oZSl7cmV0dXJuIGcoZSk9PT0iW29iamVjdCBSZWdFeHBdIn0sc3ltYm9sOmZ1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgUy5TeW1ib2w9PT0iZnVuY3Rpb24iJiZ0eXBlb2YgZT09PSJzeW1ib2wifX07dmFyIG9lPWZ1bmN0aW9uIG92ZXJyaWRlTmF0aXZlKGUsdCxyKXt2YXIgbj1lW3RdO2goZSx0LHIsdHJ1ZSk7bS5wcmVzZXJ2ZVRvU3RyaW5nKGVbdF0sbil9O3ZhciBpZT10eXBlb2YgSj09PSJmdW5jdGlvbiImJnR5cGVvZiBKWyJmb3IiXT09PSJmdW5jdGlvbiImJm5lLnN5bWJvbChKKCkpO3ZhciBhZT1uZS5zeW1ib2woSi5pdGVyYXRvcik/Si5pdGVyYXRvcjoiX2VzNi1zaGltIGl0ZXJhdG9yXyI7aWYoUy5TZXQmJnR5cGVvZihuZXcgUy5TZXQpWyJAQGl0ZXJhdG9yIl09PT0iZnVuY3Rpb24iKXthZT0iQEBpdGVyYXRvciJ9aWYoIVMuUmVmbGVjdCl7aChTLCJSZWZsZWN0Iix7fSx0cnVlKX12YXIgdWU9Uy5SZWZsZWN0O3ZhciBmZT1TdHJpbmc7dmFyIHNlPXR5cGVvZiBkb2N1bWVudD09PSJ1bmRlZmluZWQifHwhZG9jdW1lbnQ/bnVsbDpkb2N1bWVudC5hbGw7dmFyIGNlPXNlPT1udWxsP2Z1bmN0aW9uIGlzTnVsbE9yVW5kZWZpbmVkKGUpe3JldHVybiBlPT1udWxsfTpmdW5jdGlvbiBpc051bGxPclVuZGVmaW5lZEFuZE5vdERvY3VtZW50QWxsKGUpe3JldHVybiBlPT1udWxsJiZlIT09c2V9O3ZhciBsZT17Q2FsbDpmdW5jdGlvbiBDYWxsKHQscil7dmFyIG49YXJndW1lbnRzLmxlbmd0aD4yP2FyZ3VtZW50c1syXTpbXTtpZighbGUuSXNDYWxsYWJsZSh0KSl7dGhyb3cgbmV3IFR5cGVFcnJvcih0KyIgaXMgbm90IGEgZnVuY3Rpb24iKX1yZXR1cm4gZSh0LHIsbil9LFJlcXVpcmVPYmplY3RDb2VyY2libGU6ZnVuY3Rpb24oZSx0KXtpZihjZShlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcih0fHwiQ2Fubm90IGNhbGwgbWV0aG9kIG9uICIrZSl9cmV0dXJuIGV9LFR5cGVJc09iamVjdDpmdW5jdGlvbihlKXtpZihlPT09dm9pZCAwfHxlPT09bnVsbHx8ZT09PXRydWV8fGU9PT1mYWxzZSl7cmV0dXJuIGZhbHNlfXJldHVybiB0eXBlb2YgZT09PSJmdW5jdGlvbiJ8fHR5cGVvZiBlPT09Im9iamVjdCJ8fGU9PT1zZX0sVG9PYmplY3Q6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0KGxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUoZSx0KSl9LElzQ2FsbGFibGU6ZCxJc0NvbnN0cnVjdG9yOmZ1bmN0aW9uKGUpe3JldHVybiBsZS5Jc0NhbGxhYmxlKGUpfSxUb0ludDMyOmZ1bmN0aW9uKGUpe3JldHVybiBsZS5Ub051bWJlcihlKT4+MH0sVG9VaW50MzI6ZnVuY3Rpb24oZSl7cmV0dXJuIGxlLlRvTnVtYmVyKGUpPj4+MH0sVG9OdW1iZXI6ZnVuY3Rpb24oZSl7aWYoaWUmJmcoZSk9PT0iW29iamVjdCBTeW1ib2xdIil7dGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNvbnZlcnQgYSBTeW1ib2wgdmFsdWUgdG8gYSBudW1iZXIiKX1yZXR1cm4rZX0sVG9JbnRlZ2VyOmZ1bmN0aW9uKGUpe3ZhciB0PWxlLlRvTnVtYmVyKGUpO2lmKEsodCkpe3JldHVybiAwfWlmKHQ9PT0wfHwhWih0KSl7cmV0dXJuIHR9cmV0dXJuKHQ+MD8xOi0xKSprKEwodCkpfSxUb0xlbmd0aDpmdW5jdGlvbihlKXt2YXIgdD1sZS5Ub0ludGVnZXIoZSk7aWYodDw9MCl7cmV0dXJuIDB9aWYodD5OdW1iZXIuTUFYX1NBRkVfSU5URUdFUil7cmV0dXJuIE51bWJlci5NQVhfU0FGRV9JTlRFR0VSfXJldHVybiB0fSxTYW1lVmFsdWU6ZnVuY3Rpb24oZSx0KXtpZihlPT09dCl7aWYoZT09PTApe3JldHVybiAxL2U9PT0xL3R9cmV0dXJuIHRydWV9cmV0dXJuIEsoZSkmJksodCl9LFNhbWVWYWx1ZVplcm86ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT09PXR8fEsoZSkmJksodCl9LEdldEl0ZXJhdG9yOmZ1bmN0aW9uKGUpe2lmKHJlKGUpKXtyZXR1cm4gbmV3IFcoZSwidmFsdWUiKX12YXIgdD1sZS5HZXRNZXRob2QoZSxhZSk7aWYoIWxlLklzQ2FsbGFibGUodCkpe3Rocm93IG5ldyBUeXBlRXJyb3IoInZhbHVlIGlzIG5vdCBhbiBpdGVyYWJsZSIpfXZhciByPWxlLkNhbGwodCxlKTtpZighbGUuVHlwZUlzT2JqZWN0KHIpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJiYWQgaXRlcmF0b3IiKX1yZXR1cm4gcn0sR2V0TWV0aG9kOmZ1bmN0aW9uKGUsdCl7dmFyIHI9bGUuVG9PYmplY3QoZSlbdF07aWYoY2Uocikpe3JldHVybiB2b2lkIDB9aWYoIWxlLklzQ2FsbGFibGUocikpe3Rocm93IG5ldyBUeXBlRXJyb3IoIk1ldGhvZCBub3QgY2FsbGFibGU6ICIrdCl9cmV0dXJuIHJ9LEl0ZXJhdG9yQ29tcGxldGU6ZnVuY3Rpb24oZSl7cmV0dXJuISFlLmRvbmV9LEl0ZXJhdG9yQ2xvc2U6ZnVuY3Rpb24oZSx0KXt2YXIgcj1sZS5HZXRNZXRob2QoZSwicmV0dXJuIik7aWYocj09PXZvaWQgMCl7cmV0dXJufXZhciBuLG87dHJ5e249bGUuQ2FsbChyLGUpfWNhdGNoKGkpe289aX1pZih0KXtyZXR1cm59aWYobyl7dGhyb3cgb31pZighbGUuVHlwZUlzT2JqZWN0KG4pKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJJdGVyYXRvcidzIHJldHVybiBtZXRob2QgcmV0dXJuZWQgYSBub24tb2JqZWN0LiIpfX0sSXRlcmF0b3JOZXh0OmZ1bmN0aW9uKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MT9lLm5leHQoYXJndW1lbnRzWzFdKTplLm5leHQoKTtpZighbGUuVHlwZUlzT2JqZWN0KHQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJiYWQgaXRlcmF0b3IiKX1yZXR1cm4gdH0sSXRlcmF0b3JTdGVwOmZ1bmN0aW9uKGUpe3ZhciB0PWxlLkl0ZXJhdG9yTmV4dChlKTt2YXIgcj1sZS5JdGVyYXRvckNvbXBsZXRlKHQpO3JldHVybiByP2ZhbHNlOnR9LENvbnN0cnVjdDpmdW5jdGlvbihlLHQscixuKXt2YXIgbz10eXBlb2Ygcj09PSJ1bmRlZmluZWQiP2U6cjtpZighbiYmdWUuY29uc3RydWN0KXtyZXR1cm4gdWUuY29uc3RydWN0KGUsdCxvKX12YXIgaT1vLnByb3RvdHlwZTtpZighbGUuVHlwZUlzT2JqZWN0KGkpKXtpPU9iamVjdC5wcm90b3R5cGV9dmFyIGE9TyhpKTt2YXIgdT1sZS5DYWxsKGUsYSx0KTtyZXR1cm4gbGUuVHlwZUlzT2JqZWN0KHUpP3U6YX0sU3BlY2llc0NvbnN0cnVjdG9yOmZ1bmN0aW9uKGUsdCl7dmFyIHI9ZS5jb25zdHJ1Y3RvcjtpZihyPT09dm9pZCAwKXtyZXR1cm4gdH1pZighbGUuVHlwZUlzT2JqZWN0KHIpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJCYWQgY29uc3RydWN0b3IiKX12YXIgbj1yW1hdO2lmKGNlKG4pKXtyZXR1cm4gdH1pZighbGUuSXNDb25zdHJ1Y3RvcihuKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQmFkIEBAc3BlY2llcyIpfXJldHVybiBufSxDcmVhdGVIVE1MOmZ1bmN0aW9uKGUsdCxyLG4pe3ZhciBvPWxlLlRvU3RyaW5nKGUpO3ZhciBpPSI8Iit0O2lmKHIhPT0iIil7dmFyIGE9bGUuVG9TdHJpbmcobik7dmFyIHU9YS5yZXBsYWNlKC8iL2csIiZxdW90OyIpO2krPSIgIityKyc9IicrdSsnIid9dmFyIGY9aSsiPiI7dmFyIHM9ZitvO3JldHVybiBzKyI8LyIrdCsiPiJ9LElzUmVnRXhwOmZ1bmN0aW9uIElzUmVnRXhwKGUpe2lmKCFsZS5UeXBlSXNPYmplY3QoZSkpe3JldHVybiBmYWxzZX12YXIgdD1lW0oubWF0Y2hdO2lmKHR5cGVvZiB0IT09InVuZGVmaW5lZCIpe3JldHVybiEhdH1yZXR1cm4gbmUucmVnZXgoZSl9LFRvU3RyaW5nOmZ1bmN0aW9uIFRvU3RyaW5nKGUpe2lmKGllJiZnKGUpPT09IltvYmplY3QgU3ltYm9sXSIpe3Rocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjb252ZXJ0IGEgU3ltYm9sIHZhbHVlIHRvIGEgbnVtYmVyIil9cmV0dXJuIGZlKGUpfX07aWYocyYmaWUpe3ZhciBwZT1mdW5jdGlvbiBkZWZpbmVXZWxsS25vd25TeW1ib2woZSl7aWYobmUuc3ltYm9sKEpbZV0pKXtyZXR1cm4gSltlXX12YXIgdD1KWyJmb3IiXSgiU3ltYm9sLiIrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KEosZSx7Y29uZmlndXJhYmxlOmZhbHNlLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6ZmFsc2UsdmFsdWU6dH0pO3JldHVybiB0fTtpZighbmUuc3ltYm9sKEouc2VhcmNoKSl7dmFyIHZlPXBlKCJzZWFyY2giKTt2YXIgeWU9U3RyaW5nLnByb3RvdHlwZS5zZWFyY2g7aChSZWdFeHAucHJvdG90eXBlLHZlLGZ1bmN0aW9uIHNlYXJjaChlKXtyZXR1cm4gbGUuQ2FsbCh5ZSxlLFt0aGlzXSl9KTt2YXIgaGU9ZnVuY3Rpb24gc2VhcmNoKGUpe3ZhciB0PWxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcyk7aWYoIWNlKGUpKXt2YXIgcj1sZS5HZXRNZXRob2QoZSx2ZSk7aWYodHlwZW9mIHIhPT0idW5kZWZpbmVkIil7cmV0dXJuIGxlLkNhbGwocixlLFt0XSl9fXJldHVybiBsZS5DYWxsKHllLHQsW2xlLlRvU3RyaW5nKGUpXSl9O29lKFN0cmluZy5wcm90b3R5cGUsInNlYXJjaCIsaGUpfWlmKCFuZS5zeW1ib2woSi5yZXBsYWNlKSl7dmFyIGJlPXBlKCJyZXBsYWNlIik7dmFyIGdlPVN0cmluZy5wcm90b3R5cGUucmVwbGFjZTtoKFJlZ0V4cC5wcm90b3R5cGUsYmUsZnVuY3Rpb24gcmVwbGFjZShlLHQpe3JldHVybiBsZS5DYWxsKGdlLGUsW3RoaXMsdF0pfSk7dmFyIGRlPWZ1bmN0aW9uIHJlcGxhY2UoZSx0KXt2YXIgcj1sZS5SZXF1aXJlT2JqZWN0Q29lcmNpYmxlKHRoaXMpO2lmKCFjZShlKSl7dmFyIG49bGUuR2V0TWV0aG9kKGUsYmUpO2lmKHR5cGVvZiBuIT09InVuZGVmaW5lZCIpe3JldHVybiBsZS5DYWxsKG4sZSxbcix0XSl9fXJldHVybiBsZS5DYWxsKGdlLHIsW2xlLlRvU3RyaW5nKGUpLHRdKX07b2UoU3RyaW5nLnByb3RvdHlwZSwicmVwbGFjZSIsZGUpfWlmKCFuZS5zeW1ib2woSi5zcGxpdCkpe3ZhciBtZT1wZSgic3BsaXQiKTt2YXIgT2U9U3RyaW5nLnByb3RvdHlwZS5zcGxpdDtoKFJlZ0V4cC5wcm90b3R5cGUsbWUsZnVuY3Rpb24gc3BsaXQoZSx0KXtyZXR1cm4gbGUuQ2FsbChPZSxlLFt0aGlzLHRdKX0pO3ZhciB3ZT1mdW5jdGlvbiBzcGxpdChlLHQpe3ZhciByPWxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcyk7aWYoIWNlKGUpKXt2YXIgbj1sZS5HZXRNZXRob2QoZSxtZSk7aWYodHlwZW9mIG4hPT0idW5kZWZpbmVkIil7cmV0dXJuIGxlLkNhbGwobixlLFtyLHRdKX19cmV0dXJuIGxlLkNhbGwoT2UscixbbGUuVG9TdHJpbmcoZSksdF0pfTtvZShTdHJpbmcucHJvdG90eXBlLCJzcGxpdCIsd2UpfXZhciBqZT1uZS5zeW1ib2woSi5tYXRjaCk7dmFyIFNlPWplJiZmdW5jdGlvbigpe3ZhciBlPXt9O2VbSi5tYXRjaF09ZnVuY3Rpb24oKXtyZXR1cm4gNDJ9O3JldHVybiJhIi5tYXRjaChlKSE9PTQyfSgpO2lmKCFqZXx8U2Upe3ZhciBUZT1wZSgibWF0Y2giKTt2YXIgSWU9U3RyaW5nLnByb3RvdHlwZS5tYXRjaDtoKFJlZ0V4cC5wcm90b3R5cGUsVGUsZnVuY3Rpb24gbWF0Y2goZSl7cmV0dXJuIGxlLkNhbGwoSWUsZSxbdGhpc10pfSk7dmFyIEVlPWZ1bmN0aW9uIG1hdGNoKGUpe3ZhciB0PWxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcyk7aWYoIWNlKGUpKXt2YXIgcj1sZS5HZXRNZXRob2QoZSxUZSk7aWYodHlwZW9mIHIhPT0idW5kZWZpbmVkIil7cmV0dXJuIGxlLkNhbGwocixlLFt0XSl9fXJldHVybiBsZS5DYWxsKEllLHQsW2xlLlRvU3RyaW5nKGUpXSl9O29lKFN0cmluZy5wcm90b3R5cGUsIm1hdGNoIixFZSl9fXZhciBQZT1mdW5jdGlvbiB3cmFwQ29uc3RydWN0b3IoZSx0LHIpe20ucHJlc2VydmVUb1N0cmluZyh0LGUpO2lmKE9iamVjdC5zZXRQcm90b3R5cGVPZil7T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCl9aWYocyl7bChPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhlKSxmdW5jdGlvbihuKXtpZihuIGluIEd8fHJbbl0pe3JldHVybn1tLnByb3h5KGUsbix0KX0pfWVsc2V7bChPYmplY3Qua2V5cyhlKSxmdW5jdGlvbihuKXtpZihuIGluIEd8fHJbbl0pe3JldHVybn10W25dPWVbbl19KX10LnByb3RvdHlwZT1lLnByb3RvdHlwZTttLnJlZGVmaW5lKGUucHJvdG90eXBlLCJjb25zdHJ1Y3RvciIsdCl9O3ZhciBDZT1mdW5jdGlvbigpe3JldHVybiB0aGlzfTt2YXIgTWU9ZnVuY3Rpb24oZSl7aWYocyYmIXEoZSxYKSl7bS5nZXR0ZXIoZSxYLENlKX19O3ZhciB4ZT1mdW5jdGlvbihlLHQpe3ZhciByPXR8fGZ1bmN0aW9uIGl0ZXJhdG9yKCl7cmV0dXJuIHRoaXN9O2goZSxhZSxyKTtpZighZVthZV0mJm5lLnN5bWJvbChhZSkpe2VbYWVdPXJ9fTt2YXIgTmU9ZnVuY3Rpb24gY3JlYXRlRGF0YVByb3BlcnR5KGUsdCxyKXtpZihzKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHtjb25maWd1cmFibGU6dHJ1ZSxlbnVtZXJhYmxlOnRydWUsd3JpdGFibGU6dHJ1ZSx2YWx1ZTpyfSl9ZWxzZXtlW3RdPXJ9fTt2YXIgQWU9ZnVuY3Rpb24gY3JlYXRlRGF0YVByb3BlcnR5T3JUaHJvdyhlLHQscil7TmUoZSx0LHIpO2lmKCFsZS5TYW1lVmFsdWUoZVt0XSxyKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigicHJvcGVydHkgaXMgbm9uY29uZmlndXJhYmxlIil9fTt2YXIgX2U9ZnVuY3Rpb24oZSx0LHIsbil7aWYoIWxlLlR5cGVJc09iamVjdChlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQ29uc3RydWN0b3IgcmVxdWlyZXMgYG5ld2A6ICIrdC5uYW1lKX12YXIgbz10LnByb3RvdHlwZTtpZighbGUuVHlwZUlzT2JqZWN0KG8pKXtvPXJ9dmFyIGk9TyhvKTtmb3IodmFyIGEgaW4gbil7aWYocShuLGEpKXt2YXIgdT1uW2FdO2goaSxhLHUsdHJ1ZSl9fXJldHVybiBpfTtpZihTdHJpbmcuZnJvbUNvZGVQb2ludCYmU3RyaW5nLmZyb21Db2RlUG9pbnQubGVuZ3RoIT09MSl7dmFyIFJlPVN0cmluZy5mcm9tQ29kZVBvaW50O29lKFN0cmluZywiZnJvbUNvZGVQb2ludCIsZnVuY3Rpb24gZnJvbUNvZGVQb2ludChlKXtyZXR1cm4gbGUuQ2FsbChSZSx0aGlzLGFyZ3VtZW50cyl9KX12YXIga2U9e2Zyb21Db2RlUG9pbnQ6ZnVuY3Rpb24gZnJvbUNvZGVQb2ludChlKXt2YXIgdD1bXTt2YXIgcjtmb3IodmFyIG49MCxvPWFyZ3VtZW50cy5sZW5ndGg7bjxvO24rKyl7cj1OdW1iZXIoYXJndW1lbnRzW25dKTtpZighbGUuU2FtZVZhbHVlKHIsbGUuVG9JbnRlZ2VyKHIpKXx8cjwwfHxyPjExMTQxMTEpe3Rocm93IG5ldyBSYW5nZUVycm9yKCJJbnZhbGlkIGNvZGUgcG9pbnQgIityKX1pZihyPDY1NTM2KXtNKHQsU3RyaW5nLmZyb21DaGFyQ29kZShyKSl9ZWxzZXtyLT02NTUzNjtNKHQsU3RyaW5nLmZyb21DaGFyQ29kZSgocj4+MTApKzU1Mjk2KSk7TSh0LFN0cmluZy5mcm9tQ2hhckNvZGUociUxMDI0KzU2MzIwKSl9fXJldHVybiBOKHQsIiIpfSxyYXc6ZnVuY3Rpb24gcmF3KGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGgtMTt2YXIgcj1sZS5Ub09iamVjdChlLCJiYWQgdGVtcGxhdGUiKTt2YXIgcmF3PWxlLlRvT2JqZWN0KHIucmF3LCJiYWQgcmF3IHZhbHVlIik7dmFyIG49cmF3Lmxlbmd0aDt2YXIgbz1sZS5Ub0xlbmd0aChuKTtpZihvPD0wKXtyZXR1cm4iIn12YXIgaT1bXTt2YXIgYT0wO3ZhciB1LGYscyxjO3doaWxlKGE8byl7dT1sZS5Ub1N0cmluZyhhKTtzPWxlLlRvU3RyaW5nKHJhd1t1XSk7TShpLHMpO2lmKGErMT49byl7YnJlYWt9Zj1hKzE8YXJndW1lbnRzLmxlbmd0aD9hcmd1bWVudHNbYSsxXToiIjtjPWxlLlRvU3RyaW5nKGYpO00oaSxjKTthKz0xfXJldHVybiBOKGksIiIpfX07aWYoU3RyaW5nLnJhdyYmU3RyaW5nLnJhdyh7cmF3OnswOiJ4IiwxOiJ5IixsZW5ndGg6Mn19KSE9PSJ4eSIpe29lKFN0cmluZywicmF3IixrZS5yYXcpfWIoU3RyaW5nLGtlKTt2YXIgTGU9ZnVuY3Rpb24gcmVwZWF0KGUsdCl7aWYodDwxKXtyZXR1cm4iIn1pZih0JTIpe3JldHVybiByZXBlYXQoZSx0LTEpK2V9dmFyIHI9cmVwZWF0KGUsdC8yKTtyZXR1cm4gcityfTt2YXIgRmU9SW5maW5pdHk7dmFyIERlPXtyZXBlYXQ6ZnVuY3Rpb24gcmVwZWF0KGUpe3ZhciB0PWxlLlRvU3RyaW5nKGxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcykpO3ZhciByPWxlLlRvSW50ZWdlcihlKTtpZihyPDB8fHI+PUZlKXt0aHJvdyBuZXcgUmFuZ2VFcnJvcigicmVwZWF0IGNvdW50IG11c3QgYmUgbGVzcyB0aGFuIGluZmluaXR5IGFuZCBub3Qgb3ZlcmZsb3cgbWF4aW11bSBzdHJpbmcgc2l6ZSIpfXJldHVybiBMZSh0LHIpfSxzdGFydHNXaXRoOmZ1bmN0aW9uIHN0YXJ0c1dpdGgoZSl7dmFyIHQ9bGUuVG9TdHJpbmcobGUuUmVxdWlyZU9iamVjdENvZXJjaWJsZSh0aGlzKSk7aWYobGUuSXNSZWdFeHAoZSkpe3Rocm93IG5ldyBUeXBlRXJyb3IoJ0Nhbm5vdCBjYWxsIG1ldGhvZCAic3RhcnRzV2l0aCIgd2l0aCBhIHJlZ2V4Jyl9dmFyIHI9bGUuVG9TdHJpbmcoZSk7dmFyIG47aWYoYXJndW1lbnRzLmxlbmd0aD4xKXtuPWFyZ3VtZW50c1sxXX12YXIgbz1fKGxlLlRvSW50ZWdlcihuKSwwKTtyZXR1cm4gQyh0LG8sbytyLmxlbmd0aCk9PT1yfSxlbmRzV2l0aDpmdW5jdGlvbiBlbmRzV2l0aChlKXt2YXIgdD1sZS5Ub1N0cmluZyhsZS5SZXF1aXJlT2JqZWN0Q29lcmNpYmxlKHRoaXMpKTtpZihsZS5Jc1JlZ0V4cChlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcignQ2Fubm90IGNhbGwgbWV0aG9kICJlbmRzV2l0aCIgd2l0aCBhIHJlZ2V4Jyl9dmFyIHI9bGUuVG9TdHJpbmcoZSk7dmFyIG49dC5sZW5ndGg7dmFyIG87aWYoYXJndW1lbnRzLmxlbmd0aD4xKXtvPWFyZ3VtZW50c1sxXX12YXIgaT10eXBlb2Ygbz09PSJ1bmRlZmluZWQiP246bGUuVG9JbnRlZ2VyKG8pO3ZhciBhPVIoXyhpLDApLG4pO3JldHVybiBDKHQsYS1yLmxlbmd0aCxhKT09PXJ9LGluY2x1ZGVzOmZ1bmN0aW9uIGluY2x1ZGVzKGUpe2lmKGxlLklzUmVnRXhwKGUpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCciaW5jbHVkZXMiIGRvZXMgbm90IGFjY2VwdCBhIFJlZ0V4cCcpfXZhciB0PWxlLlRvU3RyaW5nKGUpO3ZhciByO2lmKGFyZ3VtZW50cy5sZW5ndGg+MSl7cj1hcmd1bWVudHNbMV19cmV0dXJuIEkodGhpcyx0LHIpIT09LTF9LGNvZGVQb2ludEF0OmZ1bmN0aW9uIGNvZGVQb2ludEF0KGUpe3ZhciB0PWxlLlRvU3RyaW5nKGxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcykpO3ZhciByPWxlLlRvSW50ZWdlcihlKTt2YXIgbj10Lmxlbmd0aDtpZihyPj0wJiZyPG4pe3ZhciBvPXQuY2hhckNvZGVBdChyKTt2YXIgaT1yKzE9PT1uO2lmKG88NTUyOTZ8fG8+NTYzMTl8fGkpe3JldHVybiBvfXZhciBhPXQuY2hhckNvZGVBdChyKzEpO2lmKGE8NTYzMjB8fGE+NTczNDMpe3JldHVybiBvfXJldHVybihvLTU1Mjk2KSoxMDI0KyhhLTU2MzIwKSs2NTUzNn19fTtpZihTdHJpbmcucHJvdG90eXBlLmluY2x1ZGVzJiYiYSIuaW5jbHVkZXMoImEiLEluZmluaXR5KSE9PWZhbHNlKXtvZShTdHJpbmcucHJvdG90eXBlLCJpbmNsdWRlcyIsRGUuaW5jbHVkZXMpfWlmKFN0cmluZy5wcm90b3R5cGUuc3RhcnRzV2l0aCYmU3RyaW5nLnByb3RvdHlwZS5lbmRzV2l0aCl7dmFyIHplPWkoZnVuY3Rpb24oKXtyZXR1cm4iL2EvIi5zdGFydHNXaXRoKC9hLyl9KTt2YXIgcWU9YShmdW5jdGlvbigpe3JldHVybiJhYmMiLnN0YXJ0c1dpdGgoImEiLEluZmluaXR5KT09PWZhbHNlfSk7aWYoIXplfHwhcWUpe29lKFN0cmluZy5wcm90b3R5cGUsInN0YXJ0c1dpdGgiLERlLnN0YXJ0c1dpdGgpO29lKFN0cmluZy5wcm90b3R5cGUsImVuZHNXaXRoIixEZS5lbmRzV2l0aCl9fWlmKGllKXt2YXIgV2U9YShmdW5jdGlvbigpe3ZhciBlPS9hLztlW0oubWF0Y2hdPWZhbHNlO3JldHVybiIvYS8iLnN0YXJ0c1dpdGgoZSl9KTtpZighV2Upe29lKFN0cmluZy5wcm90b3R5cGUsInN0YXJ0c1dpdGgiLERlLnN0YXJ0c1dpdGgpfXZhciBHZT1hKGZ1bmN0aW9uKCl7dmFyIGU9L2EvO2VbSi5tYXRjaF09ZmFsc2U7cmV0dXJuIi9hLyIuZW5kc1dpdGgoZSl9KTtpZighR2Upe29lKFN0cmluZy5wcm90b3R5cGUsImVuZHNXaXRoIixEZS5lbmRzV2l0aCl9dmFyIEhlPWEoZnVuY3Rpb24oKXt2YXIgZT0vYS87ZVtKLm1hdGNoXT1mYWxzZTtyZXR1cm4iL2EvIi5pbmNsdWRlcyhlKX0pO2lmKCFIZSl7b2UoU3RyaW5nLnByb3RvdHlwZSwiaW5jbHVkZXMiLERlLmluY2x1ZGVzKX19YihTdHJpbmcucHJvdG90eXBlLERlKTt2YXIgVmU9WyJcdFxuXHgwQlxmXHIgXHhhMFx1MTY4MFx1MTgwZVx1MjAwMFx1MjAwMVx1MjAwMlx1MjAwMyIsIlx1MjAwNFx1MjAwNVx1MjAwNlx1MjAwN1x1MjAwOFx1MjAwOVx1MjAwYVx1MjAyZlx1MjA1Zlx1MzAwMFx1MjAyOCIsIlx1MjAyOVx1ZmVmZiJdLmpvaW4oIiIpO3ZhciBCZT1uZXcgUmVnRXhwKCIoXlsiK1ZlKyJdKyl8KFsiK1ZlKyJdKyQpIiwiZyIpO3ZhciBVZT1mdW5jdGlvbiB0cmltKCl7cmV0dXJuIGxlLlRvU3RyaW5nKGxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcykpLnJlcGxhY2UoQmUsIiIpfTt2YXIgJGU9WyJceDg1IiwiXHUyMDBiIiwiXHVmZmZlIl0uam9pbigiIik7dmFyIEplPW5ldyBSZWdFeHAoIlsiKyRlKyJdIiwiZyIpO3ZhciBYZT0vXlstK10weFswLTlhLWZdKyQvaTt2YXIgS2U9JGUudHJpbSgpLmxlbmd0aCE9PSRlLmxlbmd0aDtoKFN0cmluZy5wcm90b3R5cGUsInRyaW0iLFVlLEtlKTt2YXIgWmU9ZnVuY3Rpb24oZSl7cmV0dXJue3ZhbHVlOmUsZG9uZTphcmd1bWVudHMubGVuZ3RoPT09MH19O3ZhciBZZT1mdW5jdGlvbihlKXtsZS5SZXF1aXJlT2JqZWN0Q29lcmNpYmxlKGUpO2godGhpcywiX3MiLGxlLlRvU3RyaW5nKGUpKTtoKHRoaXMsIl9pIiwwKX07WWUucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLl9zO3ZhciB0PXRoaXMuX2k7aWYodHlwZW9mIGU9PT0idW5kZWZpbmVkInx8dD49ZS5sZW5ndGgpe3RoaXMuX3M9dm9pZCAwO3JldHVybiBaZSgpfXZhciByPWUuY2hhckNvZGVBdCh0KTt2YXIgbixvO2lmKHI8NTUyOTZ8fHI+NTYzMTl8fHQrMT09PWUubGVuZ3RoKXtvPTF9ZWxzZXtuPWUuY2hhckNvZGVBdCh0KzEpO289bjw1NjMyMHx8bj41NzM0Mz8xOjJ9dGhpcy5faT10K287cmV0dXJuIFplKGUuc3Vic3RyKHQsbykpfTt4ZShZZS5wcm90b3R5cGUpO3hlKFN0cmluZy5wcm90b3R5cGUsZnVuY3Rpb24oKXtyZXR1cm4gbmV3IFllKHRoaXMpfSk7dmFyIFFlPXtmcm9tOmZ1bmN0aW9uIGZyb20oZSl7dmFyIHI9dGhpczt2YXIgbjtpZihhcmd1bWVudHMubGVuZ3RoPjEpe249YXJndW1lbnRzWzFdfXZhciBvLGk7aWYodHlwZW9mIG49PT0idW5kZWZpbmVkIil7bz1mYWxzZX1lbHNle2lmKCFsZS5Jc0NhbGxhYmxlKG4pKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJBcnJheS5mcm9tOiB3aGVuIHByb3ZpZGVkLCB0aGUgc2Vjb25kIGFyZ3VtZW50IG11c3QgYmUgYSBmdW5jdGlvbiIpfWlmKGFyZ3VtZW50cy5sZW5ndGg+Mil7aT1hcmd1bWVudHNbMl19bz10cnVlfXZhciBhPXR5cGVvZihyZShlKXx8bGUuR2V0TWV0aG9kKGUsYWUpKSE9PSJ1bmRlZmluZWQiO3ZhciB1LGYscztpZihhKXtmPWxlLklzQ29uc3RydWN0b3Iocik/T2JqZWN0KG5ldyByKTpbXTt2YXIgYz1sZS5HZXRJdGVyYXRvcihlKTt2YXIgbCxwO3M9MDt3aGlsZSh0cnVlKXtsPWxlLkl0ZXJhdG9yU3RlcChjKTtpZihsPT09ZmFsc2Upe2JyZWFrfXA9bC52YWx1ZTt0cnl7aWYobyl7cD10eXBlb2YgaT09PSJ1bmRlZmluZWQiP24ocCxzKTp0KG4saSxwLHMpfWZbc109cH1jYXRjaCh2KXtsZS5JdGVyYXRvckNsb3NlKGMsdHJ1ZSk7dGhyb3cgdn1zKz0xfXU9c31lbHNle3ZhciB5PWxlLlRvT2JqZWN0KGUpO3U9bGUuVG9MZW5ndGgoeS5sZW5ndGgpO2Y9bGUuSXNDb25zdHJ1Y3RvcihyKT9PYmplY3QobmV3IHIodSkpOm5ldyBBcnJheSh1KTt2YXIgaDtmb3Iocz0wO3M8dTsrK3Mpe2g9eVtzXTtpZihvKXtoPXR5cGVvZiBpPT09InVuZGVmaW5lZCI/bihoLHMpOnQobixpLGgscyl9QWUoZixzLGgpfX1mLmxlbmd0aD11O3JldHVybiBmfSxvZjpmdW5jdGlvbiBvZigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg7dmFyIHQ9dGhpczt2YXIgbj1yKHQpfHwhbGUuSXNDYWxsYWJsZSh0KT9uZXcgQXJyYXkoZSk6bGUuQ29uc3RydWN0KHQsW2VdKTtmb3IodmFyIG89MDtvPGU7KytvKXtBZShuLG8sYXJndW1lbnRzW29dKX1uLmxlbmd0aD1lO3JldHVybiBufX07YihBcnJheSxRZSk7TWUoQXJyYXkpO1c9ZnVuY3Rpb24oZSx0KXtoKHRoaXMsImkiLDApO2godGhpcywiYXJyYXkiLGUpO2godGhpcywia2luZCIsdCl9O2IoVy5wcm90b3R5cGUse25leHQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmk7dmFyIHQ9dGhpcy5hcnJheTtpZighKHRoaXMgaW5zdGFuY2VvZiBXKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiTm90IGFuIEFycmF5SXRlcmF0b3IiKX1pZih0eXBlb2YgdCE9PSJ1bmRlZmluZWQiKXt2YXIgcj1sZS5Ub0xlbmd0aCh0Lmxlbmd0aCk7aWYoZTxyKXt2YXIgbj10aGlzLmtpbmQ7dmFyIG87aWYobj09PSJrZXkiKXtvPWV9ZWxzZSBpZihuPT09InZhbHVlIil7bz10W2VdfWVsc2UgaWYobj09PSJlbnRyeSIpe289W2UsdFtlXV19dGhpcy5pPWUrMTtyZXR1cm4gWmUobyl9fXRoaXMuYXJyYXk9dm9pZCAwO3JldHVybiBaZSgpfX0pO3hlKFcucHJvdG90eXBlKTt2YXIgZXQ9QXJyYXkub2Y9PT1RZS5vZnx8ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbiBGb28oZSl7dGhpcy5sZW5ndGg9ZX07ZS5wcm90b3R5cGU9W107dmFyIHQ9QXJyYXkub2YuYXBwbHkoZSxbMSwyXSk7cmV0dXJuIHQgaW5zdGFuY2VvZiBlJiZ0Lmxlbmd0aD09PTJ9KCk7aWYoIWV0KXtvZShBcnJheSwib2YiLFFlLm9mKX12YXIgdHQ9e2NvcHlXaXRoaW46ZnVuY3Rpb24gY29weVdpdGhpbihlLHQpe3ZhciByPWxlLlRvT2JqZWN0KHRoaXMpO3ZhciBuPWxlLlRvTGVuZ3RoKHIubGVuZ3RoKTt2YXIgbz1sZS5Ub0ludGVnZXIoZSk7dmFyIGk9bGUuVG9JbnRlZ2VyKHQpO3ZhciBhPW88MD9fKG4rbywwKTpSKG8sbik7dmFyIHU9aTwwP18obitpLDApOlIoaSxuKTt2YXIgZjtpZihhcmd1bWVudHMubGVuZ3RoPjIpe2Y9YXJndW1lbnRzWzJdfXZhciBzPXR5cGVvZiBmPT09InVuZGVmaW5lZCI/bjpsZS5Ub0ludGVnZXIoZik7dmFyIGM9czwwP18obitzLDApOlIocyxuKTt2YXIgbD1SKGMtdSxuLWEpO3ZhciBwPTE7aWYodTxhJiZhPHUrbCl7cD0tMTt1Kz1sLTE7YSs9bC0xfXdoaWxlKGw+MCl7aWYodSBpbiByKXtyW2FdPXJbdV19ZWxzZXtkZWxldGUgclthXX11Kz1wO2ErPXA7bC09MX1yZXR1cm4gcn0sZmlsbDpmdW5jdGlvbiBmaWxsKGUpe3ZhciB0O2lmKGFyZ3VtZW50cy5sZW5ndGg+MSl7dD1hcmd1bWVudHNbMV19dmFyIHI7aWYoYXJndW1lbnRzLmxlbmd0aD4yKXtyPWFyZ3VtZW50c1syXX12YXIgbj1sZS5Ub09iamVjdCh0aGlzKTt2YXIgbz1sZS5Ub0xlbmd0aChuLmxlbmd0aCk7dD1sZS5Ub0ludGVnZXIodHlwZW9mIHQ9PT0idW5kZWZpbmVkIj8wOnQpO3I9bGUuVG9JbnRlZ2VyKHR5cGVvZiByPT09InVuZGVmaW5lZCI/bzpyKTt2YXIgaT10PDA/XyhvK3QsMCk6Uih0LG8pO3ZhciBhPXI8MD9vK3I6cjtmb3IodmFyIHU9aTt1PG8mJnU8YTsrK3Upe25bdV09ZX1yZXR1cm4gbn0sZmluZDpmdW5jdGlvbiBmaW5kKGUpe3ZhciByPWxlLlRvT2JqZWN0KHRoaXMpO3ZhciBuPWxlLlRvTGVuZ3RoKHIubGVuZ3RoKTtpZighbGUuSXNDYWxsYWJsZShlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQXJyYXkjZmluZDogcHJlZGljYXRlIG11c3QgYmUgYSBmdW5jdGlvbiIpfXZhciBvPWFyZ3VtZW50cy5sZW5ndGg+MT9hcmd1bWVudHNbMV06bnVsbDtmb3IodmFyIGk9MCxhO2k8bjtpKyspe2E9cltpXTtpZihvKXtpZih0KGUsbyxhLGkscikpe3JldHVybiBhfX1lbHNlIGlmKGUoYSxpLHIpKXtyZXR1cm4gYX19fSxmaW5kSW5kZXg6ZnVuY3Rpb24gZmluZEluZGV4KGUpe3ZhciByPWxlLlRvT2JqZWN0KHRoaXMpO3ZhciBuPWxlLlRvTGVuZ3RoKHIubGVuZ3RoKTtpZighbGUuSXNDYWxsYWJsZShlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQXJyYXkjZmluZEluZGV4OiBwcmVkaWNhdGUgbXVzdCBiZSBhIGZ1bmN0aW9uIil9dmFyIG89YXJndW1lbnRzLmxlbmd0aD4xP2FyZ3VtZW50c1sxXTpudWxsO2Zvcih2YXIgaT0wO2k8bjtpKyspe2lmKG8pe2lmKHQoZSxvLHJbaV0saSxyKSl7cmV0dXJuIGl9fWVsc2UgaWYoZShyW2ldLGkscikpe3JldHVybiBpfX1yZXR1cm4tMX0sa2V5czpmdW5jdGlvbiBrZXlzKCl7cmV0dXJuIG5ldyBXKHRoaXMsImtleSIpfSx2YWx1ZXM6ZnVuY3Rpb24gdmFsdWVzKCl7cmV0dXJuIG5ldyBXKHRoaXMsInZhbHVlIil9LGVudHJpZXM6ZnVuY3Rpb24gZW50cmllcygpe3JldHVybiBuZXcgVyh0aGlzLCJlbnRyeSIpfX07aWYoQXJyYXkucHJvdG90eXBlLmtleXMmJiFsZS5Jc0NhbGxhYmxlKFsxXS5rZXlzKCkubmV4dCkpe2RlbGV0ZSBBcnJheS5wcm90b3R5cGUua2V5c31pZihBcnJheS5wcm90b3R5cGUuZW50cmllcyYmIWxlLklzQ2FsbGFibGUoWzFdLmVudHJpZXMoKS5uZXh0KSl7ZGVsZXRlIEFycmF5LnByb3RvdHlwZS5lbnRyaWVzfWlmKEFycmF5LnByb3RvdHlwZS5rZXlzJiZBcnJheS5wcm90b3R5cGUuZW50cmllcyYmIUFycmF5LnByb3RvdHlwZS52YWx1ZXMmJkFycmF5LnByb3RvdHlwZVthZV0pe2IoQXJyYXkucHJvdG90eXBlLHt2YWx1ZXM6QXJyYXkucHJvdG90eXBlW2FlXX0pO2lmKG5lLnN5bWJvbChKLnVuc2NvcGFibGVzKSl7QXJyYXkucHJvdG90eXBlW0oudW5zY29wYWJsZXNdLnZhbHVlcz10cnVlfX1pZihjJiZBcnJheS5wcm90b3R5cGUudmFsdWVzJiZBcnJheS5wcm90b3R5cGUudmFsdWVzLm5hbWUhPT0idmFsdWVzIil7dmFyIHJ0PUFycmF5LnByb3RvdHlwZS52YWx1ZXM7b2UoQXJyYXkucHJvdG90eXBlLCJ2YWx1ZXMiLGZ1bmN0aW9uIHZhbHVlcygpe3JldHVybiBsZS5DYWxsKHJ0LHRoaXMsYXJndW1lbnRzKX0pO2goQXJyYXkucHJvdG90eXBlLGFlLEFycmF5LnByb3RvdHlwZS52YWx1ZXMsdHJ1ZSl9YihBcnJheS5wcm90b3R5cGUsdHQpO2lmKDEvW3RydWVdLmluZGV4T2YodHJ1ZSwtMCk8MCl7aChBcnJheS5wcm90b3R5cGUsImluZGV4T2YiLGZ1bmN0aW9uIGluZGV4T2YoZSl7dmFyIHQ9RSh0aGlzLGFyZ3VtZW50cyk7aWYodD09PTAmJjEvdDwwKXtyZXR1cm4gMH1yZXR1cm4gdH0sdHJ1ZSl9eGUoQXJyYXkucHJvdG90eXBlLGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmFsdWVzKCl9KTtpZihPYmplY3QuZ2V0UHJvdG90eXBlT2Ype3ZhciBudD1PYmplY3QuZ2V0UHJvdG90eXBlT2YoW10udmFsdWVzKCkpO2lmKG50KXt4ZShudCl9fXZhciBvdD1mdW5jdGlvbigpe3JldHVybiBhKGZ1bmN0aW9uKCl7cmV0dXJuIEFycmF5LmZyb20oe2xlbmd0aDotMX0pLmxlbmd0aD09PTB9KX0oKTt2YXIgaXQ9ZnVuY3Rpb24oKXt2YXIgZT1BcnJheS5mcm9tKFswXS5lbnRyaWVzKCkpO3JldHVybiBlLmxlbmd0aD09PTEmJnIoZVswXSkmJmVbMF1bMF09PT0wJiZlWzBdWzFdPT09MH0oKTtpZighb3R8fCFpdCl7b2UoQXJyYXksImZyb20iLFFlLmZyb20pfXZhciBhdD1mdW5jdGlvbigpe3JldHVybiBhKGZ1bmN0aW9uKCl7cmV0dXJuIEFycmF5LmZyb20oWzBdLHZvaWQgMCl9KX0oKTtpZighYXQpe3ZhciB1dD1BcnJheS5mcm9tO29lKEFycmF5LCJmcm9tIixmdW5jdGlvbiBmcm9tKGUpe2lmKGFyZ3VtZW50cy5sZW5ndGg+MSYmdHlwZW9mIGFyZ3VtZW50c1sxXSE9PSJ1bmRlZmluZWQiKXtyZXR1cm4gbGUuQ2FsbCh1dCx0aGlzLGFyZ3VtZW50cyl9cmV0dXJuIHQodXQsdGhpcyxlKX0pfXZhciBmdD0tKE1hdGgucG93KDIsMzIpLTEpO3ZhciBzdD1mdW5jdGlvbihlLHIpe3ZhciBuPXtsZW5ndGg6ZnR9O25bcj8obi5sZW5ndGg+Pj4wKS0xOjBdPXRydWU7cmV0dXJuIGEoZnVuY3Rpb24oKXt0KGUsbixmdW5jdGlvbigpe3Rocm93IG5ldyBSYW5nZUVycm9yKCJzaG91bGQgbm90IHJlYWNoIGhlcmUiKX0sW10pO3JldHVybiB0cnVlfSl9O2lmKCFzdChBcnJheS5wcm90b3R5cGUuZm9yRWFjaCkpe3ZhciBjdD1BcnJheS5wcm90b3R5cGUuZm9yRWFjaDtvZShBcnJheS5wcm90b3R5cGUsImZvckVhY2giLGZ1bmN0aW9uIGZvckVhY2goZSl7cmV0dXJuIGxlLkNhbGwoY3QsdGhpcy5sZW5ndGg+PTA/dGhpczpbXSxhcmd1bWVudHMpfSl9aWYoIXN0KEFycmF5LnByb3RvdHlwZS5tYXApKXt2YXIgbHQ9QXJyYXkucHJvdG90eXBlLm1hcDtvZShBcnJheS5wcm90b3R5cGUsIm1hcCIsZnVuY3Rpb24gbWFwKGUpe3JldHVybiBsZS5DYWxsKGx0LHRoaXMubGVuZ3RoPj0wP3RoaXM6W10sYXJndW1lbnRzKX0pfWlmKCFzdChBcnJheS5wcm90b3R5cGUuZmlsdGVyKSl7dmFyIHB0PUFycmF5LnByb3RvdHlwZS5maWx0ZXI7b2UoQXJyYXkucHJvdG90eXBlLCJmaWx0ZXIiLGZ1bmN0aW9uIGZpbHRlcihlKXtyZXR1cm4gbGUuQ2FsbChwdCx0aGlzLmxlbmd0aD49MD90aGlzOltdLGFyZ3VtZW50cyl9KX1pZighc3QoQXJyYXkucHJvdG90eXBlLnNvbWUpKXt2YXIgdnQ9QXJyYXkucHJvdG90eXBlLnNvbWU7b2UoQXJyYXkucHJvdG90eXBlLCJzb21lIixmdW5jdGlvbiBzb21lKGUpe3JldHVybiBsZS5DYWxsKHZ0LHRoaXMubGVuZ3RoPj0wP3RoaXM6W10sYXJndW1lbnRzKX0pfWlmKCFzdChBcnJheS5wcm90b3R5cGUuZXZlcnkpKXt2YXIgeXQ9QXJyYXkucHJvdG90eXBlLmV2ZXJ5O29lKEFycmF5LnByb3RvdHlwZSwiZXZlcnkiLGZ1bmN0aW9uIGV2ZXJ5KGUpe3JldHVybiBsZS5DYWxsKHl0LHRoaXMubGVuZ3RoPj0wP3RoaXM6W10sYXJndW1lbnRzKX0pfWlmKCFzdChBcnJheS5wcm90b3R5cGUucmVkdWNlKSl7dmFyIGh0PUFycmF5LnByb3RvdHlwZS5yZWR1Y2U7b2UoQXJyYXkucHJvdG90eXBlLCJyZWR1Y2UiLGZ1bmN0aW9uIHJlZHVjZShlKXtyZXR1cm4gbGUuQ2FsbChodCx0aGlzLmxlbmd0aD49MD90aGlzOltdLGFyZ3VtZW50cyl9KX1pZighc3QoQXJyYXkucHJvdG90eXBlLnJlZHVjZVJpZ2h0LHRydWUpKXt2YXIgYnQ9QXJyYXkucHJvdG90eXBlLnJlZHVjZVJpZ2h0O29lKEFycmF5LnByb3RvdHlwZSwicmVkdWNlUmlnaHQiLGZ1bmN0aW9uIHJlZHVjZVJpZ2h0KGUpe3JldHVybiBsZS5DYWxsKGJ0LHRoaXMubGVuZ3RoPj0wP3RoaXM6W10sYXJndW1lbnRzKX0pfXZhciBndD1OdW1iZXIoIjBvMTAiKSE9PTg7dmFyIGR0PU51bWJlcigiMGIxMCIpIT09Mjt2YXIgbXQ9eSgkZSxmdW5jdGlvbihlKXtyZXR1cm4gTnVtYmVyKGUrMCtlKT09PTB9KTtpZihndHx8ZHR8fG10KXt2YXIgT3Q9TnVtYmVyO3ZhciB3dD0vXjBiWzAxXSskL2k7dmFyIGp0PS9eMG9bMC03XSskL2k7dmFyIFN0PXd0LnRlc3QuYmluZCh3dCk7dmFyIFR0PWp0LnRlc3QuYmluZChqdCk7dmFyIEl0PWZ1bmN0aW9uKGUsdCl7dmFyIHI7aWYodHlwZW9mIGUudmFsdWVPZj09PSJmdW5jdGlvbiIpe3I9ZS52YWx1ZU9mKCk7aWYobmUucHJpbWl0aXZlKHIpKXtyZXR1cm4gcn19aWYodHlwZW9mIGUudG9TdHJpbmc9PT0iZnVuY3Rpb24iKXtyPWUudG9TdHJpbmcoKTtpZihuZS5wcmltaXRpdmUocikpe3JldHVybiByfX10aHJvdyBuZXcgVHlwZUVycm9yKCJObyBkZWZhdWx0IHZhbHVlIil9O3ZhciBFdD1KZS50ZXN0LmJpbmQoSmUpO3ZhciBQdD1YZS50ZXN0LmJpbmQoWGUpO3ZhciBDdD1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uIE51bWJlcih0KXt2YXIgcjtpZihhcmd1bWVudHMubGVuZ3RoPjApe3I9bmUucHJpbWl0aXZlKHQpP3Q6SXQodCwibnVtYmVyIil9ZWxzZXtyPTB9aWYodHlwZW9mIHI9PT0ic3RyaW5nIil7cj1sZS5DYWxsKFVlLHIpO2lmKFN0KHIpKXtyPXBhcnNlSW50KEMociwyKSwyKX1lbHNlIGlmKFR0KHIpKXtyPXBhcnNlSW50KEMociwyKSw4KX1lbHNlIGlmKEV0KHIpfHxQdChyKSl7cj1OYU59fXZhciBuPXRoaXM7dmFyIG89YShmdW5jdGlvbigpe090LnByb3RvdHlwZS52YWx1ZU9mLmNhbGwobik7cmV0dXJuIHRydWV9KTtpZihuIGluc3RhbmNlb2YgZSYmIW8pe3JldHVybiBuZXcgT3Qocil9cmV0dXJuIE90KHIpfTtyZXR1cm4gZX0oKTtQZShPdCxDdCx7fSk7YihDdCx7TmFOOk90Lk5hTixNQVhfVkFMVUU6T3QuTUFYX1ZBTFVFLE1JTl9WQUxVRTpPdC5NSU5fVkFMVUUsTkVHQVRJVkVfSU5GSU5JVFk6T3QuTkVHQVRJVkVfSU5GSU5JVFksUE9TSVRJVkVfSU5GSU5JVFk6T3QuUE9TSVRJVkVfSU5GSU5JVFl9KTtOdW1iZXI9Q3Q7bS5yZWRlZmluZShTLCJOdW1iZXIiLEN0KX12YXIgTXQ9TWF0aC5wb3coMiw1MyktMTtiKE51bWJlcix7TUFYX1NBRkVfSU5URUdFUjpNdCxNSU5fU0FGRV9JTlRFR0VSOi1NdCxFUFNJTE9OOjIuMjIwNDQ2MDQ5MjUwMzEzZS0xNixwYXJzZUludDpTLnBhcnNlSW50LHBhcnNlRmxvYXQ6Uy5wYXJzZUZsb2F0LGlzRmluaXRlOlosaXNJbnRlZ2VyOmZ1bmN0aW9uIGlzSW50ZWdlcihlKXtyZXR1cm4gWihlKSYmbGUuVG9JbnRlZ2VyKGUpPT09ZX0saXNTYWZlSW50ZWdlcjpmdW5jdGlvbiBpc1NhZmVJbnRlZ2VyKGUpe3JldHVybiBOdW1iZXIuaXNJbnRlZ2VyKGUpJiZMKGUpPD1OdW1iZXIuTUFYX1NBRkVfSU5URUdFUn0saXNOYU46S30pO2goTnVtYmVyLCJwYXJzZUludCIsUy5wYXJzZUludCxOdW1iZXIucGFyc2VJbnQhPT1TLnBhcnNlSW50KTtpZihbLDFdLmZpbmQoZnVuY3Rpb24oKXtyZXR1cm4gdHJ1ZX0pPT09MSl7b2UoQXJyYXkucHJvdG90eXBlLCJmaW5kIix0dC5maW5kKX1pZihbLDFdLmZpbmRJbmRleChmdW5jdGlvbigpe3JldHVybiB0cnVlfSkhPT0wKXtvZShBcnJheS5wcm90b3R5cGUsImZpbmRJbmRleCIsdHQuZmluZEluZGV4KX12YXIgeHQ9RnVuY3Rpb24uYmluZC5jYWxsKEZ1bmN0aW9uLmJpbmQsT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZSk7dmFyIE50PWZ1bmN0aW9uIGVuc3VyZUVudW1lcmFibGUoZSx0KXtpZihzJiZ4dChlLHQpKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHtlbnVtZXJhYmxlOmZhbHNlfSl9fTt2YXIgQXQ9ZnVuY3Rpb24gc2xpY2VBcmdzKCl7dmFyIGU9TnVtYmVyKHRoaXMpO3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg7dmFyIHI9dC1lO3ZhciBuPW5ldyBBcnJheShyPDA/MDpyKTtmb3IodmFyIG89ZTtvPHQ7KytvKXtuW28tZV09YXJndW1lbnRzW29dfXJldHVybiBufTt2YXIgX3Q9ZnVuY3Rpb24gYXNzaWduVG8oZSl7cmV0dXJuIGZ1bmN0aW9uIGFzc2lnblRvU291cmNlKHQscil7dFtyXT1lW3JdO3JldHVybiB0fX07dmFyIFJ0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9bihPYmplY3QodCkpO3ZhciBvO2lmKGxlLklzQ2FsbGFibGUoT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scykpe289dihPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKE9iamVjdCh0KSkseHQodCkpfXJldHVybiBwKFAocixvfHxbXSksX3QodCksZSl9O3ZhciBrdD17YXNzaWduOmZ1bmN0aW9uKGUsdCl7dmFyIHI9bGUuVG9PYmplY3QoZSwiQ2Fubm90IGNvbnZlcnQgdW5kZWZpbmVkIG9yIG51bGwgdG8gb2JqZWN0Iik7cmV0dXJuIHAobGUuQ2FsbChBdCwxLGFyZ3VtZW50cyksUnQscil9LGlzOmZ1bmN0aW9uIGlzKGUsdCl7cmV0dXJuIGxlLlNhbWVWYWx1ZShlLHQpfX07dmFyIEx0PU9iamVjdC5hc3NpZ24mJk9iamVjdC5wcmV2ZW50RXh0ZW5zaW9ucyYmZnVuY3Rpb24oKXt2YXIgZT1PYmplY3QucHJldmVudEV4dGVuc2lvbnMoezE6Mn0pO3RyeXtPYmplY3QuYXNzaWduKGUsInh5Iil9Y2F0Y2godCl7cmV0dXJuIGVbMV09PT0ieSJ9fSgpO2lmKEx0KXtvZShPYmplY3QsImFzc2lnbiIsa3QuYXNzaWduKX1iKE9iamVjdCxrdCk7aWYocyl7dmFyIEZ0PXtzZXRQcm90b3R5cGVPZjpmdW5jdGlvbihlKXt2YXIgcjt2YXIgbj1mdW5jdGlvbihlLHQpe2lmKCFsZS5UeXBlSXNPYmplY3QoZSkpe3Rocm93IG5ldyBUeXBlRXJyb3IoImNhbm5vdCBzZXQgcHJvdG90eXBlIG9uIGEgbm9uLW9iamVjdCIpfWlmKCEodD09PW51bGx8fGxlLlR5cGVJc09iamVjdCh0KSkpe3Rocm93IG5ldyBUeXBlRXJyb3IoImNhbiBvbmx5IHNldCBwcm90b3R5cGUgdG8gYW4gb2JqZWN0IG9yIG51bGwiK3QpfX07dmFyIG89ZnVuY3Rpb24oZSxvKXtuKGUsbyk7dChyLGUsbyk7cmV0dXJuIGV9O3RyeXtyPWUuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGUucHJvdG90eXBlLCJfX3Byb3RvX18iKS5zZXQ7dChyLHt9LG51bGwpfWNhdGNoKGkpe2lmKGUucHJvdG90eXBlIT09e30uX19wcm90b19fKXtyZXR1cm59cj1mdW5jdGlvbihlKXt0aGlzLl9fcHJvdG9fXz1lfTtvLnBvbHlmaWxsPW8obyh7fSxudWxsKSxlLnByb3RvdHlwZSlpbnN0YW5jZW9mIGV9cmV0dXJuIG99KE9iamVjdCl9O2IoT2JqZWN0LEZ0KX1pZihPYmplY3Quc2V0UHJvdG90eXBlT2YmJk9iamVjdC5nZXRQcm90b3R5cGVPZiYmT2JqZWN0LmdldFByb3RvdHlwZU9mKE9iamVjdC5zZXRQcm90b3R5cGVPZih7fSxudWxsKSkhPT1udWxsJiZPYmplY3QuZ2V0UHJvdG90eXBlT2YoT2JqZWN0LmNyZWF0ZShudWxsKSk9PT1udWxsKXsoZnVuY3Rpb24oKXt2YXIgZT1PYmplY3QuY3JlYXRlKG51bGwpO3ZhciB0PU9iamVjdC5nZXRQcm90b3R5cGVPZjt2YXIgcj1PYmplY3Quc2V0UHJvdG90eXBlT2Y7T2JqZWN0LmdldFByb3RvdHlwZU9mPWZ1bmN0aW9uKHIpe3ZhciBuPXQocik7cmV0dXJuIG49PT1lP251bGw6bn07T2JqZWN0LnNldFByb3RvdHlwZU9mPWZ1bmN0aW9uKHQsbil7dmFyIG89bj09PW51bGw/ZTpuO3JldHVybiByKHQsbyl9O09iamVjdC5zZXRQcm90b3R5cGVPZi5wb2x5ZmlsbD1mYWxzZX0pKCl9dmFyIER0PSFpKGZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5rZXlzKCJmb28iKX0pO2lmKCFEdCl7dmFyIHp0PU9iamVjdC5rZXlzO29lKE9iamVjdCwia2V5cyIsZnVuY3Rpb24ga2V5cyhlKXtyZXR1cm4genQobGUuVG9PYmplY3QoZSkpfSk7bj1PYmplY3Qua2V5c312YXIgcXQ9aShmdW5jdGlvbigpe3JldHVybiBPYmplY3Qua2V5cygvYS9nKX0pO2lmKHF0KXt2YXIgV3Q9T2JqZWN0LmtleXM7b2UoT2JqZWN0LCJrZXlzIixmdW5jdGlvbiBrZXlzKGUpe2lmKG5lLnJlZ2V4KGUpKXt2YXIgdD1bXTtmb3IodmFyIHIgaW4gZSl7aWYocShlLHIpKXtNKHQscil9fXJldHVybiB0fXJldHVybiBXdChlKX0pO249T2JqZWN0LmtleXN9aWYoT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMpe3ZhciBHdD0haShmdW5jdGlvbigpe3JldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcygiZm9vIil9KTtpZighR3Qpe3ZhciBIdD10eXBlb2Ygd2luZG93PT09Im9iamVjdCI/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMod2luZG93KTpbXTt2YXIgVnQ9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXM7b2UoT2JqZWN0LCJnZXRPd25Qcm9wZXJ0eU5hbWVzIixmdW5jdGlvbiBnZXRPd25Qcm9wZXJ0eU5hbWVzKGUpe3ZhciB0PWxlLlRvT2JqZWN0KGUpO2lmKGcodCk9PT0iW29iamVjdCBXaW5kb3ddIil7dHJ5e3JldHVybiBWdCh0KX1jYXRjaChyKXtyZXR1cm4gUChbXSxIdCl9fXJldHVybiBWdCh0KX0pfX1pZihPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKXt2YXIgQnQ9IWkoZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcigiZm9vIiwiYmFyIil9KTtpZighQnQpe3ZhciBVdD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yO29lKE9iamVjdCwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIixmdW5jdGlvbiBnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZSx0KXtyZXR1cm4gVXQobGUuVG9PYmplY3QoZSksdCl9KX19aWYoT2JqZWN0LnNlYWwpe3ZhciAkdD0haShmdW5jdGlvbigpe3JldHVybiBPYmplY3Quc2VhbCgiZm9vIil9KTtpZighJHQpe3ZhciBKdD1PYmplY3Quc2VhbDtvZShPYmplY3QsInNlYWwiLGZ1bmN0aW9uIHNlYWwoZSl7aWYoIWxlLlR5cGVJc09iamVjdChlKSl7cmV0dXJuIGV9cmV0dXJuIEp0KGUpfSl9fWlmKE9iamVjdC5pc1NlYWxlZCl7dmFyIFh0PSFpKGZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5pc1NlYWxlZCgiZm9vIil9KTtpZighWHQpe3ZhciBLdD1PYmplY3QuaXNTZWFsZWQ7b2UoT2JqZWN0LCJpc1NlYWxlZCIsZnVuY3Rpb24gaXNTZWFsZWQoZSl7aWYoIWxlLlR5cGVJc09iamVjdChlKSl7cmV0dXJuIHRydWV9cmV0dXJuIEt0KGUpfSl9fWlmKE9iamVjdC5mcmVlemUpe3ZhciBadD0haShmdW5jdGlvbigpe3JldHVybiBPYmplY3QuZnJlZXplKCJmb28iKX0pO2lmKCFadCl7dmFyIFl0PU9iamVjdC5mcmVlemU7b2UoT2JqZWN0LCJmcmVlemUiLGZ1bmN0aW9uIGZyZWV6ZShlKXtpZighbGUuVHlwZUlzT2JqZWN0KGUpKXtyZXR1cm4gZX1yZXR1cm4gWXQoZSl9KX19aWYoT2JqZWN0LmlzRnJvemVuKXt2YXIgUXQ9IWkoZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LmlzRnJvemVuKCJmb28iKX0pO2lmKCFRdCl7dmFyIGVyPU9iamVjdC5pc0Zyb3plbjtvZShPYmplY3QsImlzRnJvemVuIixmdW5jdGlvbiBpc0Zyb3plbihlKXtpZighbGUuVHlwZUlzT2JqZWN0KGUpKXtyZXR1cm4gdHJ1ZX1yZXR1cm4gZXIoZSl9KX19aWYoT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zKXt2YXIgdHI9IWkoZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zKCJmb28iKX0pO2lmKCF0cil7dmFyIHJyPU9iamVjdC5wcmV2ZW50RXh0ZW5zaW9ucztvZShPYmplY3QsInByZXZlbnRFeHRlbnNpb25zIixmdW5jdGlvbiBwcmV2ZW50RXh0ZW5zaW9ucyhlKXtpZighbGUuVHlwZUlzT2JqZWN0KGUpKXtyZXR1cm4gZX1yZXR1cm4gcnIoZSl9KX19aWYoT2JqZWN0LmlzRXh0ZW5zaWJsZSl7dmFyIG5yPSFpKGZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5pc0V4dGVuc2libGUoImZvbyIpfSk7aWYoIW5yKXt2YXIgb3I9T2JqZWN0LmlzRXh0ZW5zaWJsZTtvZShPYmplY3QsImlzRXh0ZW5zaWJsZSIsZnVuY3Rpb24gaXNFeHRlbnNpYmxlKGUpe2lmKCFsZS5UeXBlSXNPYmplY3QoZSkpe3JldHVybiBmYWxzZX1yZXR1cm4gb3IoZSl9KX19aWYoT2JqZWN0LmdldFByb3RvdHlwZU9mKXt2YXIgaXI9IWkoZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LmdldFByb3RvdHlwZU9mKCJmb28iKX0pO2lmKCFpcil7dmFyIGFyPU9iamVjdC5nZXRQcm90b3R5cGVPZjtvZShPYmplY3QsImdldFByb3RvdHlwZU9mIixmdW5jdGlvbiBnZXRQcm90b3R5cGVPZihlKXtyZXR1cm4gYXIobGUuVG9PYmplY3QoZSkpfSl9fXZhciB1cj1zJiZmdW5jdGlvbigpe3ZhciBlPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoUmVnRXhwLnByb3RvdHlwZSwiZmxhZ3MiKTtyZXR1cm4gZSYmbGUuSXNDYWxsYWJsZShlLmdldCl9KCk7aWYocyYmIXVyKXt2YXIgZnI9ZnVuY3Rpb24gZmxhZ3MoKXtpZighbGUuVHlwZUlzT2JqZWN0KHRoaXMpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJNZXRob2QgY2FsbGVkIG9uIGluY29tcGF0aWJsZSB0eXBlOiBtdXN0IGJlIGFuIG9iamVjdC4iKX12YXIgZT0iIjtpZih0aGlzLmdsb2JhbCl7ZSs9ImcifWlmKHRoaXMuaWdub3JlQ2FzZSl7ZSs9ImkifWlmKHRoaXMubXVsdGlsaW5lKXtlKz0ibSJ9aWYodGhpcy51bmljb2RlKXtlKz0idSJ9aWYodGhpcy5zdGlja3kpe2UrPSJ5In1yZXR1cm4gZX07bS5nZXR0ZXIoUmVnRXhwLnByb3RvdHlwZSwiZmxhZ3MiLGZyKX12YXIgc3I9cyYmYShmdW5jdGlvbigpe3JldHVybiBTdHJpbmcobmV3IFJlZ0V4cCgvYS9nLCJpIikpPT09Ii9hL2kifSk7dmFyIGNyPWllJiZzJiZmdW5jdGlvbigpe3ZhciBlPS8uLztlW0oubWF0Y2hdPWZhbHNlO3JldHVybiBSZWdFeHAoZSk9PT1lfSgpO3ZhciBscj1hKGZ1bmN0aW9uKCl7cmV0dXJuIFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh7c291cmNlOiJhYmMifSk9PT0iL2FiYy8ifSk7dmFyIHByPWxyJiZhKGZ1bmN0aW9uKCl7cmV0dXJuIFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh7c291cmNlOiJhIixmbGFnczoiYiJ9KT09PSIvYS9iIn0pO2lmKCFscnx8IXByKXt2YXIgdnI9UmVnRXhwLnByb3RvdHlwZS50b1N0cmluZztoKFJlZ0V4cC5wcm90b3R5cGUsInRvU3RyaW5nIixmdW5jdGlvbiB0b1N0cmluZygpe3ZhciBlPWxlLlJlcXVpcmVPYmplY3RDb2VyY2libGUodGhpcyk7aWYobmUucmVnZXgoZSkpe3JldHVybiB0KHZyLGUpfXZhciByPWZlKGUuc291cmNlKTt2YXIgbj1mZShlLmZsYWdzKTtyZXR1cm4iLyIrcisiLyIrbn0sdHJ1ZSk7bS5wcmVzZXJ2ZVRvU3RyaW5nKFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcsdnIpO1JlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcucHJvdG90eXBlPXZvaWQgMH1pZihzJiYoIXNyfHxjcikpe3ZhciB5cj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFJlZ0V4cC5wcm90b3R5cGUsImZsYWdzIikuZ2V0O3ZhciBocj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFJlZ0V4cC5wcm90b3R5cGUsInNvdXJjZSIpfHx7fTt2YXIgYnI9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zb3VyY2V9O3ZhciBncj1sZS5Jc0NhbGxhYmxlKGhyLmdldCk/aHIuZ2V0OmJyO3ZhciBkcj1SZWdFeHA7dmFyIG1yPWZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uIFJlZ0V4cChlLHQpe3ZhciByPWxlLklzUmVnRXhwKGUpO3ZhciBuPXRoaXMgaW5zdGFuY2VvZiBSZWdFeHA7aWYoIW4mJnImJnR5cGVvZiB0PT09InVuZGVmaW5lZCImJmUuY29uc3RydWN0b3I9PT1SZWdFeHApe3JldHVybiBlfXZhciBvPWU7dmFyIGk9dDtpZihuZS5yZWdleChlKSl7bz1sZS5DYWxsKGdyLGUpO2k9dHlwZW9mIHQ9PT0idW5kZWZpbmVkIj9sZS5DYWxsKHlyLGUpOnQ7cmV0dXJuIG5ldyBSZWdFeHAobyxpKX1lbHNlIGlmKHIpe289ZS5zb3VyY2U7aT10eXBlb2YgdD09PSJ1bmRlZmluZWQiP2UuZmxhZ3M6dH1yZXR1cm4gbmV3IGRyKGUsdCl9fSgpO1BlKGRyLG1yLHskaW5wdXQ6dHJ1ZX0pO1JlZ0V4cD1tcjttLnJlZGVmaW5lKFMsIlJlZ0V4cCIsbXIpfWlmKHMpe3ZhciBPcj17aW5wdXQ6IiRfIixsYXN0TWF0Y2g6IiQmIixsYXN0UGFyZW46IiQrIixsZWZ0Q29udGV4dDoiJGAiLHJpZ2h0Q29udGV4dDoiJCcifTtsKG4oT3IpLGZ1bmN0aW9uKGUpe2lmKGUgaW4gUmVnRXhwJiYhKE9yW2VdaW4gUmVnRXhwKSl7bS5nZXR0ZXIoUmVnRXhwLE9yW2VdLGZ1bmN0aW9uIGdldCgpe3JldHVybiBSZWdFeHBbZV19KX19KX1NZShSZWdFeHApO3ZhciB3cj0xL051bWJlci5FUFNJTE9OO3ZhciBqcj1mdW5jdGlvbiByb3VuZFRpZXNUb0V2ZW4oZSl7cmV0dXJuIGUrd3Itd3J9O3ZhciBTcj1NYXRoLnBvdygyLC0yMyk7dmFyIFRyPU1hdGgucG93KDIsMTI3KSooMi1Tcik7dmFyIElyPU1hdGgucG93KDIsLTEyNik7dmFyIEVyPU1hdGguRTt2YXIgUHI9TWF0aC5MT0cyRTt2YXIgQ3I9TWF0aC5MT0cxMEU7dmFyIE1yPU51bWJlci5wcm90b3R5cGUuY2x6O2RlbGV0ZSBOdW1iZXIucHJvdG90eXBlLmNsejt2YXIgeHI9e2Fjb3NoOmZ1bmN0aW9uIGFjb3NoKGUpe3ZhciB0PU51bWJlcihlKTtpZihLKHQpfHxlPDEpe3JldHVybiBOYU59aWYodD09PTEpe3JldHVybiAwfWlmKHQ9PT1JbmZpbml0eSl7cmV0dXJuIHR9dmFyIHI9MS8odCp0KTtpZih0PDIpe3JldHVybiBRKHQtMSt6KDEtcikqdCl9dmFyIG49dC8yO3JldHVybiBRKG4reigxLXIpKm4tMSkrMS9Qcn0sYXNpbmg6ZnVuY3Rpb24gYXNpbmgoZSl7dmFyIHQ9TnVtYmVyKGUpO2lmKHQ9PT0wfHwhVCh0KSl7cmV0dXJuIHR9dmFyIHI9TCh0KTt2YXIgbj1yKnI7dmFyIG89WSh0KTtpZihyPDEpe3JldHVybiBvKlEocituLyh6KG4rMSkrMSkpfXJldHVybiBvKihRKHIvMit6KDErMS9uKSpyLzItMSkrMS9Qcil9LGF0YW5oOmZ1bmN0aW9uIGF0YW5oKGUpe3ZhciB0PU51bWJlcihlKTtpZih0PT09MCl7cmV0dXJuIHR9aWYodD09PS0xKXtyZXR1cm4tSW5maW5pdHl9aWYodD09PTEpe3JldHVybiBJbmZpbml0eX1pZihLKHQpfHx0PC0xfHx0PjEpe3JldHVybiBOYU59dmFyIHI9TCh0KTtyZXR1cm4gWSh0KSpRKDIqci8oMS1yKSkvMn0sY2JydDpmdW5jdGlvbiBjYnJ0KGUpe3ZhciB0PU51bWJlcihlKTtpZih0PT09MCl7cmV0dXJuIHR9dmFyIHI9dDwwO3ZhciBuO2lmKHIpe3Q9LXR9aWYodD09PUluZmluaXR5KXtuPUluZmluaXR5fWVsc2V7bj1GKEQodCkvMyk7bj0odC8obipuKSsyKm4pLzN9cmV0dXJuIHI/LW46bn0sY2x6MzI6ZnVuY3Rpb24gY2x6MzIoZSl7dmFyIHQ9TnVtYmVyKGUpO3ZhciByPWxlLlRvVWludDMyKHQpO2lmKHI9PT0wKXtyZXR1cm4gMzJ9cmV0dXJuIE1yP2xlLkNhbGwoTXIscik6MzEtayhEKHIrLjUpKlByKX0sY29zaDpmdW5jdGlvbiBjb3NoKGUpe3ZhciB0PU51bWJlcihlKTtpZih0PT09MCl7cmV0dXJuIDF9aWYoSyh0KSl7cmV0dXJuIE5hTn1pZighVCh0KSl7cmV0dXJuIEluZmluaXR5fXZhciByPUYoTCh0KS0xKTtyZXR1cm4ocisxLyhyKkVyKkVyKSkqKEVyLzIpfSxleHBtMTpmdW5jdGlvbiBleHBtMShlKXt2YXIgdD1OdW1iZXIoZSk7aWYodD09PS1JbmZpbml0eSl7cmV0dXJuLTF9aWYoIVQodCl8fHQ9PT0wKXtyZXR1cm4gdH1pZihMKHQpPi41KXtyZXR1cm4gRih0KS0xfXZhciByPXQ7dmFyIG49MDt2YXIgbz0xO3doaWxlKG4rciE9PW4pe24rPXI7bys9MTtyKj10L299cmV0dXJuIG59LGh5cG90OmZ1bmN0aW9uIGh5cG90KGUsdCl7dmFyIHI9MDt2YXIgbj0wO2Zvcih2YXIgbz0wO288YXJndW1lbnRzLmxlbmd0aDsrK28pe3ZhciBpPUwoTnVtYmVyKGFyZ3VtZW50c1tvXSkpO2lmKG48aSl7cio9bi9pKihuL2kpO3IrPTE7bj1pfWVsc2V7cis9aT4wP2kvbiooaS9uKTppfX1yZXR1cm4gbj09PUluZmluaXR5P0luZmluaXR5Om4qeihyKX0sbG9nMjpmdW5jdGlvbiBsb2cyKGUpe3JldHVybiBEKGUpKlByfSxsb2cxMDpmdW5jdGlvbiBsb2cxMChlKXtyZXR1cm4gRChlKSpDcn0sbG9nMXA6USxzaWduOlksc2luaDpmdW5jdGlvbiBzaW5oKGUpe3ZhciB0PU51bWJlcihlKTtpZighVCh0KXx8dD09PTApe3JldHVybiB0fXZhciByPUwodCk7aWYocjwxKXt2YXIgbj1NYXRoLmV4cG0xKHIpO3JldHVybiBZKHQpKm4qKDErMS8obisxKSkvMn12YXIgbz1GKHItMSk7cmV0dXJuIFkodCkqKG8tMS8obypFcipFcikpKihFci8yKX0sdGFuaDpmdW5jdGlvbiB0YW5oKGUpe3ZhciB0PU51bWJlcihlKTtpZihLKHQpfHx0PT09MCl7cmV0dXJuIHR9aWYodD49MjApe3JldHVybiAxfWlmKHQ8PS0yMCl7cmV0dXJuLTF9cmV0dXJuKE1hdGguZXhwbTEodCktTWF0aC5leHBtMSgtdCkpLyhGKHQpK0YoLXQpKX0sdHJ1bmM6ZnVuY3Rpb24gdHJ1bmMoZSl7dmFyIHQ9TnVtYmVyKGUpO3JldHVybiB0PDA/LWsoLXQpOmsodCl9LGltdWw6ZnVuY3Rpb24gaW11bChlLHQpe3ZhciByPWxlLlRvVWludDMyKGUpO3ZhciBuPWxlLlRvVWludDMyKHQpO3ZhciBvPXI+Pj4xNiY2NTUzNTt2YXIgaT1yJjY1NTM1O3ZhciBhPW4+Pj4xNiY2NTUzNTt2YXIgdT1uJjY1NTM1O3JldHVybiBpKnUrKG8qdStpKmE8PDE2Pj4+MCl8MH0sZnJvdW5kOmZ1bmN0aW9uIGZyb3VuZChlKXt2YXIgdD1OdW1iZXIoZSk7aWYodD09PTB8fHQ9PT1JbmZpbml0eXx8dD09PS1JbmZpbml0eXx8Syh0KSl7cmV0dXJuIHR9dmFyIHI9WSh0KTt2YXIgbj1MKHQpO2lmKG48SXIpe3JldHVybiByKmpyKG4vSXIvU3IpKklyKlNyfXZhciBvPSgxK1NyL051bWJlci5FUFNJTE9OKSpuO3ZhciBpPW8tKG8tbik7aWYoaT5Ucnx8SyhpKSl7cmV0dXJuIHIqSW5maW5pdHl9cmV0dXJuIHIqaX19O3ZhciBOcj1mdW5jdGlvbiB3aXRoaW5VTFBEaXN0YW5jZShlLHQscil7cmV0dXJuIEwoMS1lL3QpL051bWJlci5FUFNJTE9OPChyfHw4KX07YihNYXRoLHhyKTtoKE1hdGgsInNpbmgiLHhyLnNpbmgsTWF0aC5zaW5oKDcxMCk9PT1JbmZpbml0eSk7aChNYXRoLCJjb3NoIix4ci5jb3NoLE1hdGguY29zaCg3MTApPT09SW5maW5pdHkpO2goTWF0aCwibG9nMXAiLHhyLmxvZzFwLE1hdGgubG9nMXAoLTFlLTE3KSE9PS0xZS0xNyk7aChNYXRoLCJhc2luaCIseHIuYXNpbmgsTWF0aC5hc2luaCgtMWU3KSE9PS1NYXRoLmFzaW5oKDFlNykpOwpoKE1hdGgsImFzaW5oIix4ci5hc2luaCxNYXRoLmFzaW5oKDFlMzAwKT09PUluZmluaXR5KTtoKE1hdGgsImF0YW5oIix4ci5hdGFuaCxNYXRoLmF0YW5oKDFlLTMwMCk9PT0wKTtoKE1hdGgsInRhbmgiLHhyLnRhbmgsTWF0aC50YW5oKC0yZS0xNykhPT0tMmUtMTcpO2goTWF0aCwiYWNvc2giLHhyLmFjb3NoLE1hdGguYWNvc2goTnVtYmVyLk1BWF9WQUxVRSk9PT1JbmZpbml0eSk7aChNYXRoLCJhY29zaCIseHIuYWNvc2gsIU5yKE1hdGguYWNvc2goMStOdW1iZXIuRVBTSUxPTiksTWF0aC5zcXJ0KDIqTnVtYmVyLkVQU0lMT04pKSk7aChNYXRoLCJjYnJ0Iix4ci5jYnJ0LCFOcihNYXRoLmNicnQoMWUtMzAwKSwxZS0xMDApKTtoKE1hdGgsInNpbmgiLHhyLnNpbmgsTWF0aC5zaW5oKC0yZS0xNykhPT0tMmUtMTcpO3ZhciBBcj1NYXRoLmV4cG0xKDEwKTtoKE1hdGgsImV4cG0xIix4ci5leHBtMSxBcj4yMjAyNS40NjU3OTQ4MDY3MTh8fEFyPDIyMDI1LjQ2NTc5NDgwNjcxOCk7aChNYXRoLCJoeXBvdCIseHIuaHlwb3QsTWF0aC5oeXBvdChJbmZpbml0eSxOYU4pIT09SW5maW5pdHkpO3ZhciBfcj1NYXRoLnJvdW5kO3ZhciBScj1NYXRoLnJvdW5kKC41LU51bWJlci5FUFNJTE9OLzQpPT09MCYmTWF0aC5yb3VuZCgtLjUrTnVtYmVyLkVQU0lMT04vMy45OSk9PT0xO3ZhciBrcj13cisxO3ZhciBMcj0yKndyLTE7dmFyIEZyPVtrcixMcl0uZXZlcnkoZnVuY3Rpb24oZSl7cmV0dXJuIE1hdGgucm91bmQoZSk9PT1lfSk7aChNYXRoLCJyb3VuZCIsZnVuY3Rpb24gcm91bmQoZSl7dmFyIHQ9ayhlKTt2YXIgcj10PT09LTE/LTA6dCsxO3JldHVybiBlLXQ8LjU/dDpyfSwhUnJ8fCFGcik7bS5wcmVzZXJ2ZVRvU3RyaW5nKE1hdGgucm91bmQsX3IpO3ZhciBEcj1NYXRoLmltdWw7aWYoTWF0aC5pbXVsKDQyOTQ5NjcyOTUsNSkhPT0tNSl7TWF0aC5pbXVsPXhyLmltdWw7bS5wcmVzZXJ2ZVRvU3RyaW5nKE1hdGguaW11bCxEcil9aWYoTWF0aC5pbXVsLmxlbmd0aCE9PTIpe29lKE1hdGgsImltdWwiLGZ1bmN0aW9uIGltdWwoZSx0KXtyZXR1cm4gbGUuQ2FsbChEcixNYXRoLGFyZ3VtZW50cyl9KX12YXIgenI9ZnVuY3Rpb24oKXt2YXIgZT1TLnNldFRpbWVvdXQ7aWYodHlwZW9mIGUhPT0iZnVuY3Rpb24iJiZ0eXBlb2YgZSE9PSJvYmplY3QiKXtyZXR1cm59bGUuSXNQcm9taXNlPWZ1bmN0aW9uKGUpe2lmKCFsZS5UeXBlSXNPYmplY3QoZSkpe3JldHVybiBmYWxzZX1pZih0eXBlb2YgZS5fcHJvbWlzZT09PSJ1bmRlZmluZWQiKXtyZXR1cm4gZmFsc2V9cmV0dXJuIHRydWV9O3ZhciByPWZ1bmN0aW9uKGUpe2lmKCFsZS5Jc0NvbnN0cnVjdG9yKGUpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJCYWQgcHJvbWlzZSBjb25zdHJ1Y3RvciIpfXZhciB0PXRoaXM7dmFyIHI9ZnVuY3Rpb24oZSxyKXtpZih0LnJlc29sdmUhPT12b2lkIDB8fHQucmVqZWN0IT09dm9pZCAwKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJCYWQgUHJvbWlzZSBpbXBsZW1lbnRhdGlvbiEiKX10LnJlc29sdmU9ZTt0LnJlamVjdD1yfTt0LnJlc29sdmU9dm9pZCAwO3QucmVqZWN0PXZvaWQgMDt0LnByb21pc2U9bmV3IGUocik7aWYoIShsZS5Jc0NhbGxhYmxlKHQucmVzb2x2ZSkmJmxlLklzQ2FsbGFibGUodC5yZWplY3QpKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQmFkIHByb21pc2UgY29uc3RydWN0b3IiKX19O3ZhciBuO2lmKHR5cGVvZiB3aW5kb3chPT0idW5kZWZpbmVkIiYmbGUuSXNDYWxsYWJsZSh3aW5kb3cucG9zdE1lc3NhZ2UpKXtuPWZ1bmN0aW9uKCl7dmFyIGU9W107dmFyIHQ9Inplcm8tdGltZW91dC1tZXNzYWdlIjt2YXIgcj1mdW5jdGlvbihyKXtNKGUscik7d2luZG93LnBvc3RNZXNzYWdlKHQsIioiKX07dmFyIG49ZnVuY3Rpb24ocil7aWYoci5zb3VyY2U9PT13aW5kb3cmJnIuZGF0YT09PXQpe3Iuc3RvcFByb3BhZ2F0aW9uKCk7aWYoZS5sZW5ndGg9PT0wKXtyZXR1cm59dmFyIG49QShlKTtuKCl9fTt3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsbix0cnVlKTtyZXR1cm4gcn19dmFyIG89ZnVuY3Rpb24oKXt2YXIgZT1TLlByb21pc2U7dmFyIHQ9ZSYmZS5yZXNvbHZlJiZlLnJlc29sdmUoKTtyZXR1cm4gdCYmZnVuY3Rpb24oZSl7cmV0dXJuIHQudGhlbihlKX19O3ZhciBpPWxlLklzQ2FsbGFibGUoUy5zZXRJbW1lZGlhdGUpP1Muc2V0SW1tZWRpYXRlOnR5cGVvZiBwcm9jZXNzPT09Im9iamVjdCImJnByb2Nlc3MubmV4dFRpY2s/cHJvY2Vzcy5uZXh0VGljazpvKCl8fChsZS5Jc0NhbGxhYmxlKG4pP24oKTpmdW5jdGlvbih0KXtlKHQsMCl9KTt2YXIgYT1mdW5jdGlvbihlKXtyZXR1cm4gZX07dmFyIHU9ZnVuY3Rpb24oZSl7dGhyb3cgZX07dmFyIGY9MDt2YXIgcz0xO3ZhciBjPTI7dmFyIGw9MDt2YXIgcD0xO3ZhciB2PTI7dmFyIHk9e307dmFyIGg9ZnVuY3Rpb24oZSx0LHIpe2koZnVuY3Rpb24oKXtnKGUsdCxyKX0pfTt2YXIgZz1mdW5jdGlvbihlLHQscil7dmFyIG4sbztpZih0PT09eSl7cmV0dXJuIGUocil9dHJ5e249ZShyKTtvPXQucmVzb2x2ZX1jYXRjaChpKXtuPWk7bz10LnJlamVjdH1vKG4pfTt2YXIgZD1mdW5jdGlvbihlLHQpe3ZhciByPWUuX3Byb21pc2U7dmFyIG49ci5yZWFjdGlvbkxlbmd0aDtpZihuPjApe2goci5mdWxmaWxsUmVhY3Rpb25IYW5kbGVyMCxyLnJlYWN0aW9uQ2FwYWJpbGl0eTAsdCk7ci5mdWxmaWxsUmVhY3Rpb25IYW5kbGVyMD12b2lkIDA7ci5yZWplY3RSZWFjdGlvbnMwPXZvaWQgMDtyLnJlYWN0aW9uQ2FwYWJpbGl0eTA9dm9pZCAwO2lmKG4+MSl7Zm9yKHZhciBvPTEsaT0wO288bjtvKyssaSs9Myl7aChyW2krbF0scltpK3ZdLHQpO2VbaStsXT12b2lkIDA7ZVtpK3BdPXZvaWQgMDtlW2krdl09dm9pZCAwfX19ci5yZXN1bHQ9dDtyLnN0YXRlPXM7ci5yZWFjdGlvbkxlbmd0aD0wfTt2YXIgbT1mdW5jdGlvbihlLHQpe3ZhciByPWUuX3Byb21pc2U7dmFyIG49ci5yZWFjdGlvbkxlbmd0aDtpZihuPjApe2goci5yZWplY3RSZWFjdGlvbkhhbmRsZXIwLHIucmVhY3Rpb25DYXBhYmlsaXR5MCx0KTtyLmZ1bGZpbGxSZWFjdGlvbkhhbmRsZXIwPXZvaWQgMDtyLnJlamVjdFJlYWN0aW9uczA9dm9pZCAwO3IucmVhY3Rpb25DYXBhYmlsaXR5MD12b2lkIDA7aWYobj4xKXtmb3IodmFyIG89MSxpPTA7bzxuO28rKyxpKz0zKXtoKHJbaStwXSxyW2krdl0sdCk7ZVtpK2xdPXZvaWQgMDtlW2krcF09dm9pZCAwO2VbaSt2XT12b2lkIDB9fX1yLnJlc3VsdD10O3Iuc3RhdGU9YztyLnJlYWN0aW9uTGVuZ3RoPTB9O3ZhciBPPWZ1bmN0aW9uKGUpe3ZhciB0PWZhbHNlO3ZhciByPWZ1bmN0aW9uKHIpe3ZhciBuO2lmKHQpe3JldHVybn10PXRydWU7aWYocj09PWUpe3JldHVybiBtKGUsbmV3IFR5cGVFcnJvcigiU2VsZiByZXNvbHV0aW9uIikpfWlmKCFsZS5UeXBlSXNPYmplY3Qocikpe3JldHVybiBkKGUscil9dHJ5e249ci50aGVufWNhdGNoKG8pe3JldHVybiBtKGUsbyl9aWYoIWxlLklzQ2FsbGFibGUobikpe3JldHVybiBkKGUscil9aShmdW5jdGlvbigpe2ooZSxyLG4pfSl9O3ZhciBuPWZ1bmN0aW9uKHIpe2lmKHQpe3JldHVybn10PXRydWU7cmV0dXJuIG0oZSxyKX07cmV0dXJue3Jlc29sdmU6cixyZWplY3Q6bn19O3ZhciB3PWZ1bmN0aW9uKGUscixuLG8pe2lmKGU9PT1JKXt0KGUscixuLG8seSl9ZWxzZXt0KGUscixuLG8pfX07dmFyIGo9ZnVuY3Rpb24oZSx0LHIpe3ZhciBuPU8oZSk7dmFyIG89bi5yZXNvbHZlO3ZhciBpPW4ucmVqZWN0O3RyeXt3KHIsdCxvLGkpfWNhdGNoKGEpe2koYSl9fTt2YXIgVCxJO3ZhciBFPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24gUHJvbWlzZSh0KXtpZighKHRoaXMgaW5zdGFuY2VvZiBlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcignQ29uc3RydWN0b3IgUHJvbWlzZSByZXF1aXJlcyAibmV3IicpfWlmKHRoaXMmJnRoaXMuX3Byb21pc2Upe3Rocm93IG5ldyBUeXBlRXJyb3IoIkJhZCBjb25zdHJ1Y3Rpb24iKX1pZighbGUuSXNDYWxsYWJsZSh0KSl7dGhyb3cgbmV3IFR5cGVFcnJvcigibm90IGEgdmFsaWQgcmVzb2x2ZXIiKX12YXIgcj1fZSh0aGlzLGUsVCx7X3Byb21pc2U6e3Jlc3VsdDp2b2lkIDAsc3RhdGU6ZixyZWFjdGlvbkxlbmd0aDowLGZ1bGZpbGxSZWFjdGlvbkhhbmRsZXIwOnZvaWQgMCxyZWplY3RSZWFjdGlvbkhhbmRsZXIwOnZvaWQgMCxyZWFjdGlvbkNhcGFiaWxpdHkwOnZvaWQgMH19KTt2YXIgbj1PKHIpO3ZhciBvPW4ucmVqZWN0O3RyeXt0KG4ucmVzb2x2ZSxvKX1jYXRjaChpKXtvKGkpfXJldHVybiByfTtyZXR1cm4gZX0oKTtUPUUucHJvdG90eXBlO3ZhciBQPWZ1bmN0aW9uKGUsdCxyLG4pe3ZhciBvPWZhbHNlO3JldHVybiBmdW5jdGlvbihpKXtpZihvKXtyZXR1cm59bz10cnVlO3RbZV09aTtpZigtLW4uY291bnQ9PT0wKXt2YXIgYT1yLnJlc29sdmU7YSh0KX19fTt2YXIgQz1mdW5jdGlvbihlLHQscil7dmFyIG49ZS5pdGVyYXRvcjt2YXIgbz1bXTt2YXIgaT17Y291bnQ6MX07dmFyIGEsdTt2YXIgZj0wO3doaWxlKHRydWUpe3RyeXthPWxlLkl0ZXJhdG9yU3RlcChuKTtpZihhPT09ZmFsc2Upe2UuZG9uZT10cnVlO2JyZWFrfXU9YS52YWx1ZX1jYXRjaChzKXtlLmRvbmU9dHJ1ZTt0aHJvdyBzfW9bZl09dm9pZCAwO3ZhciBjPXQucmVzb2x2ZSh1KTt2YXIgbD1QKGYsbyxyLGkpO2kuY291bnQrPTE7dyhjLnRoZW4sYyxsLHIucmVqZWN0KTtmKz0xfWlmKC0taS5jb3VudD09PTApe3ZhciBwPXIucmVzb2x2ZTtwKG8pfXJldHVybiByLnByb21pc2V9O3ZhciB4PWZ1bmN0aW9uKGUsdCxyKXt2YXIgbj1lLml0ZXJhdG9yO3ZhciBvLGksYTt3aGlsZSh0cnVlKXt0cnl7bz1sZS5JdGVyYXRvclN0ZXAobik7aWYobz09PWZhbHNlKXtlLmRvbmU9dHJ1ZTticmVha31pPW8udmFsdWV9Y2F0Y2godSl7ZS5kb25lPXRydWU7dGhyb3cgdX1hPXQucmVzb2x2ZShpKTt3KGEudGhlbixhLHIucmVzb2x2ZSxyLnJlamVjdCl9cmV0dXJuIHIucHJvbWlzZX07YihFLHthbGw6ZnVuY3Rpb24gYWxsKGUpe3ZhciB0PXRoaXM7aWYoIWxlLlR5cGVJc09iamVjdCh0KSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvbWlzZSBpcyBub3Qgb2JqZWN0Iil9dmFyIG49bmV3IHIodCk7dmFyIG8saTt0cnl7bz1sZS5HZXRJdGVyYXRvcihlKTtpPXtpdGVyYXRvcjpvLGRvbmU6ZmFsc2V9O3JldHVybiBDKGksdCxuKX1jYXRjaChhKXt2YXIgdT1hO2lmKGkmJiFpLmRvbmUpe3RyeXtsZS5JdGVyYXRvckNsb3NlKG8sdHJ1ZSl9Y2F0Y2goZil7dT1mfX12YXIgcz1uLnJlamVjdDtzKHUpO3JldHVybiBuLnByb21pc2V9fSxyYWNlOmZ1bmN0aW9uIHJhY2UoZSl7dmFyIHQ9dGhpcztpZighbGUuVHlwZUlzT2JqZWN0KHQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJQcm9taXNlIGlzIG5vdCBvYmplY3QiKX12YXIgbj1uZXcgcih0KTt2YXIgbyxpO3RyeXtvPWxlLkdldEl0ZXJhdG9yKGUpO2k9e2l0ZXJhdG9yOm8sZG9uZTpmYWxzZX07cmV0dXJuIHgoaSx0LG4pfWNhdGNoKGEpe3ZhciB1PWE7aWYoaSYmIWkuZG9uZSl7dHJ5e2xlLkl0ZXJhdG9yQ2xvc2Uobyx0cnVlKX1jYXRjaChmKXt1PWZ9fXZhciBzPW4ucmVqZWN0O3ModSk7cmV0dXJuIG4ucHJvbWlzZX19LHJlamVjdDpmdW5jdGlvbiByZWplY3QoZSl7dmFyIHQ9dGhpcztpZighbGUuVHlwZUlzT2JqZWN0KHQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJCYWQgcHJvbWlzZSBjb25zdHJ1Y3RvciIpfXZhciBuPW5ldyByKHQpO3ZhciBvPW4ucmVqZWN0O28oZSk7cmV0dXJuIG4ucHJvbWlzZX0scmVzb2x2ZTpmdW5jdGlvbiByZXNvbHZlKGUpe3ZhciB0PXRoaXM7aWYoIWxlLlR5cGVJc09iamVjdCh0KSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiQmFkIHByb21pc2UgY29uc3RydWN0b3IiKX1pZihsZS5Jc1Byb21pc2UoZSkpe3ZhciBuPWUuY29uc3RydWN0b3I7aWYobj09PXQpe3JldHVybiBlfX12YXIgbz1uZXcgcih0KTt2YXIgaT1vLnJlc29sdmU7aShlKTtyZXR1cm4gby5wcm9taXNlfX0pO2IoVCx7ImNhdGNoIjpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy50aGVuKG51bGwsZSl9LHRoZW46ZnVuY3Rpb24gdGhlbihlLHQpe3ZhciBuPXRoaXM7aWYoIWxlLklzUHJvbWlzZShuKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigibm90IGEgcHJvbWlzZSIpfXZhciBvPWxlLlNwZWNpZXNDb25zdHJ1Y3RvcihuLEUpO3ZhciBpO3ZhciBiPWFyZ3VtZW50cy5sZW5ndGg+MiYmYXJndW1lbnRzWzJdPT09eTtpZihiJiZvPT09RSl7aT15fWVsc2V7aT1uZXcgcihvKX12YXIgZz1sZS5Jc0NhbGxhYmxlKGUpP2U6YTt2YXIgZD1sZS5Jc0NhbGxhYmxlKHQpP3Q6dTt2YXIgbT1uLl9wcm9taXNlO3ZhciBPO2lmKG0uc3RhdGU9PT1mKXtpZihtLnJlYWN0aW9uTGVuZ3RoPT09MCl7bS5mdWxmaWxsUmVhY3Rpb25IYW5kbGVyMD1nO20ucmVqZWN0UmVhY3Rpb25IYW5kbGVyMD1kO20ucmVhY3Rpb25DYXBhYmlsaXR5MD1pfWVsc2V7dmFyIHc9MyoobS5yZWFjdGlvbkxlbmd0aC0xKTttW3crbF09ZzttW3crcF09ZDttW3crdl09aX1tLnJlYWN0aW9uTGVuZ3RoKz0xfWVsc2UgaWYobS5zdGF0ZT09PXMpe089bS5yZXN1bHQ7aChnLGksTyl9ZWxzZSBpZihtLnN0YXRlPT09Yyl7Tz1tLnJlc3VsdDtoKGQsaSxPKX1lbHNle3Rocm93IG5ldyBUeXBlRXJyb3IoInVuZXhwZWN0ZWQgUHJvbWlzZSBzdGF0ZSIpfXJldHVybiBpLnByb21pc2V9fSk7eT1uZXcgcihFKTtJPVQudGhlbjtyZXR1cm4gRX0oKTtpZihTLlByb21pc2Upe2RlbGV0ZSBTLlByb21pc2UuYWNjZXB0O2RlbGV0ZSBTLlByb21pc2UuZGVmZXI7ZGVsZXRlIFMuUHJvbWlzZS5wcm90b3R5cGUuY2hhaW59aWYodHlwZW9mIHpyPT09ImZ1bmN0aW9uIil7YihTLHtQcm9taXNlOnpyfSk7dmFyIHFyPXcoUy5Qcm9taXNlLGZ1bmN0aW9uKGUpe3JldHVybiBlLnJlc29sdmUoNDIpLnRoZW4oZnVuY3Rpb24oKXt9KWluc3RhbmNlb2YgZX0pO3ZhciBXcj0haShmdW5jdGlvbigpe3JldHVybiBTLlByb21pc2UucmVqZWN0KDQyKS50aGVuKG51bGwsNSkudGhlbihudWxsLEcpfSk7dmFyIEdyPWkoZnVuY3Rpb24oKXtyZXR1cm4gUy5Qcm9taXNlLmNhbGwoMyxHKX0pO3ZhciBIcj1mdW5jdGlvbihlKXt2YXIgdD1lLnJlc29sdmUoNSk7dC5jb25zdHJ1Y3Rvcj17fTt2YXIgcj1lLnJlc29sdmUodCk7dHJ5e3IudGhlbihudWxsLEcpLnRoZW4obnVsbCxHKX1jYXRjaChuKXtyZXR1cm4gdHJ1ZX1yZXR1cm4gdD09PXJ9KFMuUHJvbWlzZSk7dmFyIFZyPXMmJmZ1bmN0aW9uKCl7dmFyIGU9MDt2YXIgdD1PYmplY3QuZGVmaW5lUHJvcGVydHkoe30sInRoZW4iLHtnZXQ6ZnVuY3Rpb24oKXtlKz0xfX0pO1Byb21pc2UucmVzb2x2ZSh0KTtyZXR1cm4gZT09PTF9KCk7dmFyIEJyPWZ1bmN0aW9uIEJhZFJlc29sdmVyUHJvbWlzZShlKXt2YXIgdD1uZXcgUHJvbWlzZShlKTtlKDMsZnVuY3Rpb24oKXt9KTt0aGlzLnRoZW49dC50aGVuO3RoaXMuY29uc3RydWN0b3I9QmFkUmVzb2x2ZXJQcm9taXNlfTtCci5wcm90b3R5cGU9UHJvbWlzZS5wcm90b3R5cGU7QnIuYWxsPVByb21pc2UuYWxsO3ZhciBVcj1hKGZ1bmN0aW9uKCl7cmV0dXJuISFCci5hbGwoWzEsMl0pfSk7aWYoIXFyfHwhV3J8fCFHcnx8SHJ8fCFWcnx8VXIpe1Byb21pc2U9enI7b2UoUywiUHJvbWlzZSIsenIpfWlmKFByb21pc2UuYWxsLmxlbmd0aCE9PTEpe3ZhciAkcj1Qcm9taXNlLmFsbDtvZShQcm9taXNlLCJhbGwiLGZ1bmN0aW9uIGFsbChlKXtyZXR1cm4gbGUuQ2FsbCgkcix0aGlzLGFyZ3VtZW50cyl9KX1pZihQcm9taXNlLnJhY2UubGVuZ3RoIT09MSl7dmFyIEpyPVByb21pc2UucmFjZTtvZShQcm9taXNlLCJyYWNlIixmdW5jdGlvbiByYWNlKGUpe3JldHVybiBsZS5DYWxsKEpyLHRoaXMsYXJndW1lbnRzKX0pfWlmKFByb21pc2UucmVzb2x2ZS5sZW5ndGghPT0xKXt2YXIgWHI9UHJvbWlzZS5yZXNvbHZlO29lKFByb21pc2UsInJlc29sdmUiLGZ1bmN0aW9uIHJlc29sdmUoZSl7cmV0dXJuIGxlLkNhbGwoWHIsdGhpcyxhcmd1bWVudHMpfSl9aWYoUHJvbWlzZS5yZWplY3QubGVuZ3RoIT09MSl7dmFyIEtyPVByb21pc2UucmVqZWN0O29lKFByb21pc2UsInJlamVjdCIsZnVuY3Rpb24gcmVqZWN0KGUpe3JldHVybiBsZS5DYWxsKEtyLHRoaXMsYXJndW1lbnRzKX0pfU50KFByb21pc2UsImFsbCIpO050KFByb21pc2UsInJhY2UiKTtOdChQcm9taXNlLCJyZXNvbHZlIik7TnQoUHJvbWlzZSwicmVqZWN0Iik7TWUoUHJvbWlzZSl9dmFyIFpyPWZ1bmN0aW9uKGUpe3ZhciB0PW4ocChlLGZ1bmN0aW9uKGUsdCl7ZVt0XT10cnVlO3JldHVybiBlfSx7fSkpO3JldHVybiBlLmpvaW4oIjoiKT09PXQuam9pbigiOiIpfTt2YXIgWXI9WnIoWyJ6IiwiYSIsImJiIl0pO3ZhciBRcj1acihbInoiLDEsImEiLCIzIiwyXSk7aWYocyl7dmFyIGVuPWZ1bmN0aW9uIGZhc3RrZXkoZSx0KXtpZighdCYmIVlyKXtyZXR1cm4gbnVsbH1pZihjZShlKSl7cmV0dXJuIl4iK2xlLlRvU3RyaW5nKGUpfWVsc2UgaWYodHlwZW9mIGU9PT0ic3RyaW5nIil7cmV0dXJuIiQiK2V9ZWxzZSBpZih0eXBlb2YgZT09PSJudW1iZXIiKXtpZighUXIpe3JldHVybiJuIitlfXJldHVybiBlfWVsc2UgaWYodHlwZW9mIGU9PT0iYm9vbGVhbiIpe3JldHVybiJiIitlfXJldHVybiBudWxsfTt2YXIgdG49ZnVuY3Rpb24gZW1wdHlPYmplY3QoKXtyZXR1cm4gT2JqZWN0LmNyZWF0ZT9PYmplY3QuY3JlYXRlKG51bGwpOnt9fTt2YXIgcm49ZnVuY3Rpb24gYWRkSXRlcmFibGVUb01hcChlLG4sbyl7aWYocihvKXx8bmUuc3RyaW5nKG8pKXtsKG8sZnVuY3Rpb24oZSl7aWYoIWxlLlR5cGVJc09iamVjdChlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiSXRlcmF0b3IgdmFsdWUgIitlKyIgaXMgbm90IGFuIGVudHJ5IG9iamVjdCIpfW4uc2V0KGVbMF0sZVsxXSl9KX1lbHNlIGlmKG8gaW5zdGFuY2VvZiBlKXt0KGUucHJvdG90eXBlLmZvckVhY2gsbyxmdW5jdGlvbihlLHQpe24uc2V0KHQsZSl9KX1lbHNle3ZhciBpLGE7aWYoIWNlKG8pKXthPW4uc2V0O2lmKCFsZS5Jc0NhbGxhYmxlKGEpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJiYWQgbWFwIil9aT1sZS5HZXRJdGVyYXRvcihvKX1pZih0eXBlb2YgaSE9PSJ1bmRlZmluZWQiKXt3aGlsZSh0cnVlKXt2YXIgdT1sZS5JdGVyYXRvclN0ZXAoaSk7aWYodT09PWZhbHNlKXticmVha312YXIgZj11LnZhbHVlO3RyeXtpZighbGUuVHlwZUlzT2JqZWN0KGYpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJJdGVyYXRvciB2YWx1ZSAiK2YrIiBpcyBub3QgYW4gZW50cnkgb2JqZWN0Iil9dChhLG4sZlswXSxmWzFdKX1jYXRjaChzKXtsZS5JdGVyYXRvckNsb3NlKGksdHJ1ZSk7dGhyb3cgc319fX19O3ZhciBubj1mdW5jdGlvbiBhZGRJdGVyYWJsZVRvU2V0KGUsbixvKXtpZihyKG8pfHxuZS5zdHJpbmcobykpe2wobyxmdW5jdGlvbihlKXtuLmFkZChlKX0pfWVsc2UgaWYobyBpbnN0YW5jZW9mIGUpe3QoZS5wcm90b3R5cGUuZm9yRWFjaCxvLGZ1bmN0aW9uKGUpe24uYWRkKGUpfSl9ZWxzZXt2YXIgaSxhO2lmKCFjZShvKSl7YT1uLmFkZDtpZighbGUuSXNDYWxsYWJsZShhKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiYmFkIHNldCIpfWk9bGUuR2V0SXRlcmF0b3Iobyl9aWYodHlwZW9mIGkhPT0idW5kZWZpbmVkIil7d2hpbGUodHJ1ZSl7dmFyIHU9bGUuSXRlcmF0b3JTdGVwKGkpO2lmKHU9PT1mYWxzZSl7YnJlYWt9dmFyIGY9dS52YWx1ZTt0cnl7dChhLG4sZil9Y2F0Y2gocyl7bGUuSXRlcmF0b3JDbG9zZShpLHRydWUpO3Rocm93IHN9fX19fTt2YXIgb249e01hcDpmdW5jdGlvbigpe3ZhciBlPXt9O3ZhciByPWZ1bmN0aW9uIE1hcEVudHJ5KGUsdCl7dGhpcy5rZXk9ZTt0aGlzLnZhbHVlPXQ7dGhpcy5uZXh0PW51bGw7dGhpcy5wcmV2PW51bGx9O3IucHJvdG90eXBlLmlzUmVtb3ZlZD1mdW5jdGlvbiBpc1JlbW92ZWQoKXtyZXR1cm4gdGhpcy5rZXk9PT1lfTt2YXIgbj1mdW5jdGlvbiBpc01hcChlKXtyZXR1cm4hIWUuX2VzNm1hcH07dmFyIG89ZnVuY3Rpb24gcmVxdWlyZU1hcFNsb3QoZSx0KXtpZighbGUuVHlwZUlzT2JqZWN0KGUpfHwhbihlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiTWV0aG9kIE1hcC5wcm90b3R5cGUuIit0KyIgY2FsbGVkIG9uIGluY29tcGF0aWJsZSByZWNlaXZlciAiK2xlLlRvU3RyaW5nKGUpKX19O3ZhciBpPWZ1bmN0aW9uIE1hcEl0ZXJhdG9yKGUsdCl7byhlLCJbW01hcEl0ZXJhdG9yXV0iKTtoKHRoaXMsImhlYWQiLGUuX2hlYWQpO2godGhpcywiaSIsdGhpcy5oZWFkKTtoKHRoaXMsImtpbmQiLHQpfTtpLnByb3RvdHlwZT17aXNNYXBJdGVyYXRvcjp0cnVlLG5leHQ6ZnVuY3Rpb24gbmV4dCgpe2lmKCF0aGlzLmlzTWFwSXRlcmF0b3Ipe3Rocm93IG5ldyBUeXBlRXJyb3IoIk5vdCBhIE1hcEl0ZXJhdG9yIil9dmFyIGU9dGhpcy5pO3ZhciB0PXRoaXMua2luZDt2YXIgcj10aGlzLmhlYWQ7aWYodHlwZW9mIHRoaXMuaT09PSJ1bmRlZmluZWQiKXtyZXR1cm4gWmUoKX13aGlsZShlLmlzUmVtb3ZlZCgpJiZlIT09cil7ZT1lLnByZXZ9dmFyIG47d2hpbGUoZS5uZXh0IT09cil7ZT1lLm5leHQ7aWYoIWUuaXNSZW1vdmVkKCkpe2lmKHQ9PT0ia2V5Iil7bj1lLmtleX1lbHNlIGlmKHQ9PT0idmFsdWUiKXtuPWUudmFsdWV9ZWxzZXtuPVtlLmtleSxlLnZhbHVlXX10aGlzLmk9ZTtyZXR1cm4gWmUobil9fXRoaXMuaT12b2lkIDA7cmV0dXJuIFplKCl9fTt4ZShpLnByb3RvdHlwZSk7dmFyIGE7dmFyIHU9ZnVuY3Rpb24gTWFwKCl7aWYoISh0aGlzIGluc3RhbmNlb2YgTWFwKSl7dGhyb3cgbmV3IFR5cGVFcnJvcignQ29uc3RydWN0b3IgTWFwIHJlcXVpcmVzICJuZXciJyl9aWYodGhpcyYmdGhpcy5fZXM2bWFwKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJCYWQgY29uc3RydWN0aW9uIil9dmFyIGU9X2UodGhpcyxNYXAsYSx7X2VzNm1hcDp0cnVlLF9oZWFkOm51bGwsX21hcDpIP25ldyBIOm51bGwsX3NpemU6MCxfc3RvcmFnZTp0bigpfSk7dmFyIHQ9bmV3IHIobnVsbCxudWxsKTt0Lm5leHQ9dC5wcmV2PXQ7ZS5faGVhZD10O2lmKGFyZ3VtZW50cy5sZW5ndGg+MCl7cm4oTWFwLGUsYXJndW1lbnRzWzBdKX1yZXR1cm4gZX07YT11LnByb3RvdHlwZTttLmdldHRlcihhLCJzaXplIixmdW5jdGlvbigpe2lmKHR5cGVvZiB0aGlzLl9zaXplPT09InVuZGVmaW5lZCIpe3Rocm93IG5ldyBUeXBlRXJyb3IoInNpemUgbWV0aG9kIGNhbGxlZCBvbiBpbmNvbXBhdGlibGUgTWFwIil9cmV0dXJuIHRoaXMuX3NpemV9KTtiKGEse2dldDpmdW5jdGlvbiBnZXQoZSl7byh0aGlzLCJnZXQiKTt2YXIgdDt2YXIgcj1lbihlLHRydWUpO2lmKHIhPT1udWxsKXt0PXRoaXMuX3N0b3JhZ2Vbcl07aWYodCl7cmV0dXJuIHQudmFsdWV9cmV0dXJufWlmKHRoaXMuX21hcCl7dD1CLmNhbGwodGhpcy5fbWFwLGUpO2lmKHQpe3JldHVybiB0LnZhbHVlfXJldHVybn12YXIgbj10aGlzLl9oZWFkO3ZhciBpPW47d2hpbGUoKGk9aS5uZXh0KSE9PW4pe2lmKGxlLlNhbWVWYWx1ZVplcm8oaS5rZXksZSkpe3JldHVybiBpLnZhbHVlfX19LGhhczpmdW5jdGlvbiBoYXMoZSl7byh0aGlzLCJoYXMiKTt2YXIgdD1lbihlLHRydWUpO2lmKHQhPT1udWxsKXtyZXR1cm4gdHlwZW9mIHRoaXMuX3N0b3JhZ2VbdF0hPT0idW5kZWZpbmVkIn1pZih0aGlzLl9tYXApe3JldHVybiBVLmNhbGwodGhpcy5fbWFwLGUpfXZhciByPXRoaXMuX2hlYWQ7dmFyIG49cjt3aGlsZSgobj1uLm5leHQpIT09cil7aWYobGUuU2FtZVZhbHVlWmVybyhuLmtleSxlKSl7cmV0dXJuIHRydWV9fXJldHVybiBmYWxzZX0sc2V0OmZ1bmN0aW9uIHNldChlLHQpe28odGhpcywic2V0Iik7dmFyIG49dGhpcy5faGVhZDt2YXIgaT1uO3ZhciBhO3ZhciB1PWVuKGUsdHJ1ZSk7aWYodSE9PW51bGwpe2lmKHR5cGVvZiB0aGlzLl9zdG9yYWdlW3VdIT09InVuZGVmaW5lZCIpe3RoaXMuX3N0b3JhZ2VbdV0udmFsdWU9dDtyZXR1cm4gdGhpc31hPXRoaXMuX3N0b3JhZ2VbdV09bmV3IHIoZSx0KTtpPW4ucHJldn1lbHNlIGlmKHRoaXMuX21hcCl7aWYoVS5jYWxsKHRoaXMuX21hcCxlKSl7Qi5jYWxsKHRoaXMuX21hcCxlKS52YWx1ZT10fWVsc2V7YT1uZXcgcihlLHQpOyQuY2FsbCh0aGlzLl9tYXAsZSxhKTtpPW4ucHJldn19d2hpbGUoKGk9aS5uZXh0KSE9PW4pe2lmKGxlLlNhbWVWYWx1ZVplcm8oaS5rZXksZSkpe2kudmFsdWU9dDtyZXR1cm4gdGhpc319YT1hfHxuZXcgcihlLHQpO2lmKGxlLlNhbWVWYWx1ZSgtMCxlKSl7YS5rZXk9KzB9YS5uZXh0PXRoaXMuX2hlYWQ7YS5wcmV2PXRoaXMuX2hlYWQucHJldjthLnByZXYubmV4dD1hO2EubmV4dC5wcmV2PWE7dGhpcy5fc2l6ZSs9MTtyZXR1cm4gdGhpc30sImRlbGV0ZSI6ZnVuY3Rpb24odCl7byh0aGlzLCJkZWxldGUiKTt2YXIgcj10aGlzLl9oZWFkO3ZhciBuPXI7dmFyIGk9ZW4odCx0cnVlKTtpZihpIT09bnVsbCl7aWYodHlwZW9mIHRoaXMuX3N0b3JhZ2VbaV09PT0idW5kZWZpbmVkIil7cmV0dXJuIGZhbHNlfW49dGhpcy5fc3RvcmFnZVtpXS5wcmV2O2RlbGV0ZSB0aGlzLl9zdG9yYWdlW2ldfWVsc2UgaWYodGhpcy5fbWFwKXtpZighVS5jYWxsKHRoaXMuX21hcCx0KSl7cmV0dXJuIGZhbHNlfW49Qi5jYWxsKHRoaXMuX21hcCx0KS5wcmV2O1YuY2FsbCh0aGlzLl9tYXAsdCl9d2hpbGUoKG49bi5uZXh0KSE9PXIpe2lmKGxlLlNhbWVWYWx1ZVplcm8obi5rZXksdCkpe24ua2V5PWU7bi52YWx1ZT1lO24ucHJldi5uZXh0PW4ubmV4dDtuLm5leHQucHJldj1uLnByZXY7dGhpcy5fc2l6ZS09MTtyZXR1cm4gdHJ1ZX19cmV0dXJuIGZhbHNlfSxjbGVhcjpmdW5jdGlvbiBjbGVhcigpe28odGhpcywiY2xlYXIiKTt0aGlzLl9tYXA9SD9uZXcgSDpudWxsO3RoaXMuX3NpemU9MDt0aGlzLl9zdG9yYWdlPXRuKCk7dmFyIHQ9dGhpcy5faGVhZDt2YXIgcj10O3ZhciBuPXIubmV4dDt3aGlsZSgocj1uKSE9PXQpe3Iua2V5PWU7ci52YWx1ZT1lO249ci5uZXh0O3IubmV4dD1yLnByZXY9dH10Lm5leHQ9dC5wcmV2PXR9LGtleXM6ZnVuY3Rpb24ga2V5cygpe28odGhpcywia2V5cyIpO3JldHVybiBuZXcgaSh0aGlzLCJrZXkiKX0sdmFsdWVzOmZ1bmN0aW9uIHZhbHVlcygpe28odGhpcywidmFsdWVzIik7cmV0dXJuIG5ldyBpKHRoaXMsInZhbHVlIil9LGVudHJpZXM6ZnVuY3Rpb24gZW50cmllcygpe28odGhpcywiZW50cmllcyIpO3JldHVybiBuZXcgaSh0aGlzLCJrZXkrdmFsdWUiKX0sZm9yRWFjaDpmdW5jdGlvbiBmb3JFYWNoKGUpe28odGhpcywiZm9yRWFjaCIpO3ZhciByPWFyZ3VtZW50cy5sZW5ndGg+MT9hcmd1bWVudHNbMV06bnVsbDt2YXIgbj10aGlzLmVudHJpZXMoKTtmb3IodmFyIGk9bi5uZXh0KCk7IWkuZG9uZTtpPW4ubmV4dCgpKXtpZihyKXt0KGUscixpLnZhbHVlWzFdLGkudmFsdWVbMF0sdGhpcyl9ZWxzZXtlKGkudmFsdWVbMV0saS52YWx1ZVswXSx0aGlzKX19fX0pO3hlKGEsYS5lbnRyaWVzKTtyZXR1cm4gdX0oKSxTZXQ6ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbiBpc1NldChlKXtyZXR1cm4gZS5fZXM2c2V0JiZ0eXBlb2YgZS5fc3RvcmFnZSE9PSJ1bmRlZmluZWQifTt2YXIgcj1mdW5jdGlvbiByZXF1aXJlU2V0U2xvdCh0LHIpe2lmKCFsZS5UeXBlSXNPYmplY3QodCl8fCFlKHQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJTZXQucHJvdG90eXBlLiIrcisiIGNhbGxlZCBvbiBpbmNvbXBhdGlibGUgcmVjZWl2ZXIgIitsZS5Ub1N0cmluZyh0KSl9fTt2YXIgbzt2YXIgaT1mdW5jdGlvbiBTZXQoKXtpZighKHRoaXMgaW5zdGFuY2VvZiBTZXQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCdDb25zdHJ1Y3RvciBTZXQgcmVxdWlyZXMgIm5ldyInKX1pZih0aGlzJiZ0aGlzLl9lczZzZXQpe3Rocm93IG5ldyBUeXBlRXJyb3IoIkJhZCBjb25zdHJ1Y3Rpb24iKX12YXIgZT1fZSh0aGlzLFNldCxvLHtfZXM2c2V0OnRydWUsIltbU2V0RGF0YV1dIjpudWxsLF9zdG9yYWdlOnRuKCl9KTtpZighZS5fZXM2c2V0KXt0aHJvdyBuZXcgVHlwZUVycm9yKCJiYWQgc2V0Iil9aWYoYXJndW1lbnRzLmxlbmd0aD4wKXtubihTZXQsZSxhcmd1bWVudHNbMF0pfXJldHVybiBlfTtvPWkucHJvdG90eXBlO3ZhciBhPWZ1bmN0aW9uKGUpe3ZhciB0PWU7aWYodD09PSJebnVsbCIpe3JldHVybiBudWxsfWVsc2UgaWYodD09PSJedW5kZWZpbmVkIil7cmV0dXJuIHZvaWQgMH12YXIgcj10LmNoYXJBdCgwKTtpZihyPT09IiQiKXtyZXR1cm4gQyh0LDEpfWVsc2UgaWYocj09PSJuIil7cmV0dXJuK0ModCwxKX1lbHNlIGlmKHI9PT0iYiIpe3JldHVybiB0PT09ImJ0cnVlIn1yZXR1cm4rdH07dmFyIHU9ZnVuY3Rpb24gZW5zdXJlTWFwKGUpe2lmKCFlWyJbW1NldERhdGFdXSJdKXt2YXIgdD1uZXcgb24uTWFwO2VbIltbU2V0RGF0YV1dIl09dDtsKG4oZS5fc3RvcmFnZSksZnVuY3Rpb24oZSl7dmFyIHI9YShlKTt0LnNldChyLHIpfSk7ZVsiW1tTZXREYXRhXV0iXT10fWUuX3N0b3JhZ2U9bnVsbH07bS5nZXR0ZXIoaS5wcm90b3R5cGUsInNpemUiLGZ1bmN0aW9uKCl7cih0aGlzLCJzaXplIik7aWYodGhpcy5fc3RvcmFnZSl7cmV0dXJuIG4odGhpcy5fc3RvcmFnZSkubGVuZ3RofXUodGhpcyk7cmV0dXJuIHRoaXNbIltbU2V0RGF0YV1dIl0uc2l6ZX0pO2IoaS5wcm90b3R5cGUse2hhczpmdW5jdGlvbiBoYXMoZSl7cih0aGlzLCJoYXMiKTt2YXIgdDtpZih0aGlzLl9zdG9yYWdlJiYodD1lbihlKSkhPT1udWxsKXtyZXR1cm4hIXRoaXMuX3N0b3JhZ2VbdF19dSh0aGlzKTtyZXR1cm4gdGhpc1siW1tTZXREYXRhXV0iXS5oYXMoZSl9LGFkZDpmdW5jdGlvbiBhZGQoZSl7cih0aGlzLCJhZGQiKTt2YXIgdDtpZih0aGlzLl9zdG9yYWdlJiYodD1lbihlKSkhPT1udWxsKXt0aGlzLl9zdG9yYWdlW3RdPXRydWU7cmV0dXJuIHRoaXN9dSh0aGlzKTt0aGlzWyJbW1NldERhdGFdXSJdLnNldChlLGUpO3JldHVybiB0aGlzfSwiZGVsZXRlIjpmdW5jdGlvbihlKXtyKHRoaXMsImRlbGV0ZSIpO3ZhciB0O2lmKHRoaXMuX3N0b3JhZ2UmJih0PWVuKGUpKSE9PW51bGwpe3ZhciBuPXEodGhpcy5fc3RvcmFnZSx0KTtyZXR1cm4gZGVsZXRlIHRoaXMuX3N0b3JhZ2VbdF0mJm59dSh0aGlzKTtyZXR1cm4gdGhpc1siW1tTZXREYXRhXV0iXVsiZGVsZXRlIl0oZSl9LGNsZWFyOmZ1bmN0aW9uIGNsZWFyKCl7cih0aGlzLCJjbGVhciIpO2lmKHRoaXMuX3N0b3JhZ2Upe3RoaXMuX3N0b3JhZ2U9dG4oKX1pZih0aGlzWyJbW1NldERhdGFdXSJdKXt0aGlzWyJbW1NldERhdGFdXSJdLmNsZWFyKCl9fSx2YWx1ZXM6ZnVuY3Rpb24gdmFsdWVzKCl7cih0aGlzLCJ2YWx1ZXMiKTt1KHRoaXMpO3JldHVybiBuZXcgZih0aGlzWyJbW1NldERhdGFdXSJdLnZhbHVlcygpKX0sZW50cmllczpmdW5jdGlvbiBlbnRyaWVzKCl7cih0aGlzLCJlbnRyaWVzIik7dSh0aGlzKTtyZXR1cm4gbmV3IGYodGhpc1siW1tTZXREYXRhXV0iXS5lbnRyaWVzKCkpfSxmb3JFYWNoOmZ1bmN0aW9uIGZvckVhY2goZSl7cih0aGlzLCJmb3JFYWNoIik7dmFyIG49YXJndW1lbnRzLmxlbmd0aD4xP2FyZ3VtZW50c1sxXTpudWxsO3ZhciBvPXRoaXM7dShvKTt0aGlzWyJbW1NldERhdGFdXSJdLmZvckVhY2goZnVuY3Rpb24ocixpKXtpZihuKXt0KGUsbixpLGksbyl9ZWxzZXtlKGksaSxvKX19KX19KTtoKGkucHJvdG90eXBlLCJrZXlzIixpLnByb3RvdHlwZS52YWx1ZXMsdHJ1ZSk7eGUoaS5wcm90b3R5cGUsaS5wcm90b3R5cGUudmFsdWVzKTt2YXIgZj1mdW5jdGlvbiBTZXRJdGVyYXRvcihlKXtoKHRoaXMsIml0IixlKX07Zi5wcm90b3R5cGU9e2lzU2V0SXRlcmF0b3I6dHJ1ZSxuZXh0OmZ1bmN0aW9uIG5leHQoKXtpZighdGhpcy5pc1NldEl0ZXJhdG9yKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJOb3QgYSBTZXRJdGVyYXRvciIpfXJldHVybiB0aGlzLml0Lm5leHQoKX19O3hlKGYucHJvdG90eXBlKTtyZXR1cm4gaX0oKX07dmFyIGFuPVMuU2V0JiYhU2V0LnByb3RvdHlwZVsiZGVsZXRlIl0mJlNldC5wcm90b3R5cGUucmVtb3ZlJiZTZXQucHJvdG90eXBlLml0ZW1zJiZTZXQucHJvdG90eXBlLm1hcCYmQXJyYXkuaXNBcnJheSgobmV3IFNldCkua2V5cyk7aWYoYW4pe1MuU2V0PW9uLlNldH1pZihTLk1hcHx8Uy5TZXQpe3ZhciB1bj1hKGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBNYXAoW1sxLDJdXSkuZ2V0KDEpPT09Mn0pO2lmKCF1bil7Uy5NYXA9ZnVuY3Rpb24gTWFwKCl7aWYoISh0aGlzIGluc3RhbmNlb2YgTWFwKSl7dGhyb3cgbmV3IFR5cGVFcnJvcignQ29uc3RydWN0b3IgTWFwIHJlcXVpcmVzICJuZXciJyl9dmFyIGU9bmV3IEg7aWYoYXJndW1lbnRzLmxlbmd0aD4wKXtybihNYXAsZSxhcmd1bWVudHNbMF0pfWRlbGV0ZSBlLmNvbnN0cnVjdG9yO09iamVjdC5zZXRQcm90b3R5cGVPZihlLFMuTWFwLnByb3RvdHlwZSk7cmV0dXJuIGV9O1MuTWFwLnByb3RvdHlwZT1PKEgucHJvdG90eXBlKTtoKFMuTWFwLnByb3RvdHlwZSwiY29uc3RydWN0b3IiLFMuTWFwLHRydWUpO20ucHJlc2VydmVUb1N0cmluZyhTLk1hcCxIKX12YXIgZm49bmV3IE1hcDt2YXIgc249ZnVuY3Rpb24oKXt2YXIgZT1uZXcgTWFwKFtbMSwwXSxbMiwwXSxbMywwXSxbNCwwXV0pO2Uuc2V0KC0wLGUpO3JldHVybiBlLmdldCgwKT09PWUmJmUuZ2V0KC0wKT09PWUmJmUuaGFzKDApJiZlLmhhcygtMCl9KCk7dmFyIGNuPWZuLnNldCgxLDIpPT09Zm47aWYoIXNufHwhY24pe29lKE1hcC5wcm90b3R5cGUsInNldCIsZnVuY3Rpb24gc2V0KGUscil7dCgkLHRoaXMsZT09PTA/MDplLHIpO3JldHVybiB0aGlzfSl9aWYoIXNuKXtiKE1hcC5wcm90b3R5cGUse2dldDpmdW5jdGlvbiBnZXQoZSl7cmV0dXJuIHQoQix0aGlzLGU9PT0wPzA6ZSl9LGhhczpmdW5jdGlvbiBoYXMoZSl7cmV0dXJuIHQoVSx0aGlzLGU9PT0wPzA6ZSl9fSx0cnVlKTttLnByZXNlcnZlVG9TdHJpbmcoTWFwLnByb3RvdHlwZS5nZXQsQik7bS5wcmVzZXJ2ZVRvU3RyaW5nKE1hcC5wcm90b3R5cGUuaGFzLFUpfXZhciBsbj1uZXcgU2V0O3ZhciBwbj1TZXQucHJvdG90eXBlWyJkZWxldGUiXSYmU2V0LnByb3RvdHlwZS5hZGQmJlNldC5wcm90b3R5cGUuaGFzJiZmdW5jdGlvbihlKXtlWyJkZWxldGUiXSgwKTtlLmFkZCgtMCk7cmV0dXJuIWUuaGFzKDApfShsbik7dmFyIHZuPWxuLmFkZCgxKT09PWxuO2lmKCFwbnx8IXZuKXt2YXIgeW49U2V0LnByb3RvdHlwZS5hZGQ7U2V0LnByb3RvdHlwZS5hZGQ9ZnVuY3Rpb24gYWRkKGUpe3QoeW4sdGhpcyxlPT09MD8wOmUpO3JldHVybiB0aGlzfTttLnByZXNlcnZlVG9TdHJpbmcoU2V0LnByb3RvdHlwZS5hZGQseW4pfWlmKCFwbil7dmFyIGhuPVNldC5wcm90b3R5cGUuaGFzO1NldC5wcm90b3R5cGUuaGFzPWZ1bmN0aW9uIGhhcyhlKXtyZXR1cm4gdChobix0aGlzLGU9PT0wPzA6ZSl9O20ucHJlc2VydmVUb1N0cmluZyhTZXQucHJvdG90eXBlLmhhcyxobik7dmFyIGJuPVNldC5wcm90b3R5cGVbImRlbGV0ZSJdO1NldC5wcm90b3R5cGVbImRlbGV0ZSJdPWZ1bmN0aW9uIFNldERlbGV0ZShlKXtyZXR1cm4gdChibix0aGlzLGU9PT0wPzA6ZSl9O20ucHJlc2VydmVUb1N0cmluZyhTZXQucHJvdG90eXBlWyJkZWxldGUiXSxibil9dmFyIGduPXcoUy5NYXAsZnVuY3Rpb24oZSl7dmFyIHQ9bmV3IGUoW10pO3Quc2V0KDQyLDQyKTtyZXR1cm4gdCBpbnN0YW5jZW9mIGV9KTt2YXIgZG49T2JqZWN0LnNldFByb3RvdHlwZU9mJiYhZ247dmFyIG1uPWZ1bmN0aW9uKCl7dHJ5e3JldHVybiEoUy5NYXAoKWluc3RhbmNlb2YgUy5NYXApfWNhdGNoKGUpe3JldHVybiBlIGluc3RhbmNlb2YgVHlwZUVycm9yfX0oKTtpZihTLk1hcC5sZW5ndGghPT0wfHxkbnx8IW1uKXtTLk1hcD1mdW5jdGlvbiBNYXAoKXtpZighKHRoaXMgaW5zdGFuY2VvZiBNYXApKXt0aHJvdyBuZXcgVHlwZUVycm9yKCdDb25zdHJ1Y3RvciBNYXAgcmVxdWlyZXMgIm5ldyInKX12YXIgZT1uZXcgSDtpZihhcmd1bWVudHMubGVuZ3RoPjApe3JuKE1hcCxlLGFyZ3VtZW50c1swXSl9ZGVsZXRlIGUuY29uc3RydWN0b3I7T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsTWFwLnByb3RvdHlwZSk7cmV0dXJuIGV9O1MuTWFwLnByb3RvdHlwZT1ILnByb3RvdHlwZTtoKFMuTWFwLnByb3RvdHlwZSwiY29uc3RydWN0b3IiLFMuTWFwLHRydWUpO20ucHJlc2VydmVUb1N0cmluZyhTLk1hcCxIKX12YXIgT249dyhTLlNldCxmdW5jdGlvbihlKXt2YXIgdD1uZXcgZShbXSk7dC5hZGQoNDIsNDIpO3JldHVybiB0IGluc3RhbmNlb2YgZX0pO3ZhciB3bj1PYmplY3Quc2V0UHJvdG90eXBlT2YmJiFPbjt2YXIgam49ZnVuY3Rpb24oKXt0cnl7cmV0dXJuIShTLlNldCgpaW5zdGFuY2VvZiBTLlNldCl9Y2F0Y2goZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBUeXBlRXJyb3J9fSgpO2lmKFMuU2V0Lmxlbmd0aCE9PTB8fHdufHwham4pe3ZhciBTbj1TLlNldDtTLlNldD1mdW5jdGlvbiBTZXQoKXtpZighKHRoaXMgaW5zdGFuY2VvZiBTZXQpKXt0aHJvdyBuZXcgVHlwZUVycm9yKCdDb25zdHJ1Y3RvciBTZXQgcmVxdWlyZXMgIm5ldyInKX12YXIgZT1uZXcgU247aWYoYXJndW1lbnRzLmxlbmd0aD4wKXtubihTZXQsZSxhcmd1bWVudHNbMF0pfWRlbGV0ZSBlLmNvbnN0cnVjdG9yO09iamVjdC5zZXRQcm90b3R5cGVPZihlLFNldC5wcm90b3R5cGUpO3JldHVybiBlfTtTLlNldC5wcm90b3R5cGU9U24ucHJvdG90eXBlO2goUy5TZXQucHJvdG90eXBlLCJjb25zdHJ1Y3RvciIsUy5TZXQsdHJ1ZSk7bS5wcmVzZXJ2ZVRvU3RyaW5nKFMuU2V0LFNuKX12YXIgVG49bmV3IFMuTWFwO3ZhciBJbj0hYShmdW5jdGlvbigpe3JldHVybiBUbi5rZXlzKCkubmV4dCgpLmRvbmV9KTtpZih0eXBlb2YgUy5NYXAucHJvdG90eXBlLmNsZWFyIT09ImZ1bmN0aW9uInx8KG5ldyBTLlNldCkuc2l6ZSE9PTB8fFRuLnNpemUhPT0wfHx0eXBlb2YgUy5NYXAucHJvdG90eXBlLmtleXMhPT0iZnVuY3Rpb24ifHx0eXBlb2YgUy5TZXQucHJvdG90eXBlLmtleXMhPT0iZnVuY3Rpb24ifHx0eXBlb2YgUy5NYXAucHJvdG90eXBlLmZvckVhY2ghPT0iZnVuY3Rpb24ifHx0eXBlb2YgUy5TZXQucHJvdG90eXBlLmZvckVhY2ghPT0iZnVuY3Rpb24ifHx1KFMuTWFwKXx8dShTLlNldCl8fHR5cGVvZiBUbi5rZXlzKCkubmV4dCE9PSJmdW5jdGlvbiJ8fElufHwhZ24pe2IoUyx7TWFwOm9uLk1hcCxTZXQ6b24uU2V0fSx0cnVlKX1pZihTLlNldC5wcm90b3R5cGUua2V5cyE9PVMuU2V0LnByb3RvdHlwZS52YWx1ZXMpe2goUy5TZXQucHJvdG90eXBlLCJrZXlzIixTLlNldC5wcm90b3R5cGUudmFsdWVzLHRydWUpfXhlKE9iamVjdC5nZXRQcm90b3R5cGVPZigobmV3IFMuTWFwKS5rZXlzKCkpKTt4ZShPYmplY3QuZ2V0UHJvdG90eXBlT2YoKG5ldyBTLlNldCkua2V5cygpKSk7aWYoYyYmUy5TZXQucHJvdG90eXBlLmhhcy5uYW1lIT09ImhhcyIpe3ZhciBFbj1TLlNldC5wcm90b3R5cGUuaGFzO29lKFMuU2V0LnByb3RvdHlwZSwiaGFzIixmdW5jdGlvbiBoYXMoZSl7cmV0dXJuIHQoRW4sdGhpcyxlKX0pfX1iKFMsb24pO01lKFMuTWFwKTtNZShTLlNldCl9dmFyIFBuPWZ1bmN0aW9uIHRocm93VW5sZXNzVGFyZ2V0SXNPYmplY3QoZSl7aWYoIWxlLlR5cGVJc09iamVjdChlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iil9fTt2YXIgQ249e2FwcGx5OmZ1bmN0aW9uIGFwcGx5KCl7cmV0dXJuIGxlLkNhbGwobGUuQ2FsbCxudWxsLGFyZ3VtZW50cyl9LGNvbnN0cnVjdDpmdW5jdGlvbiBjb25zdHJ1Y3QoZSx0KXtpZighbGUuSXNDb25zdHJ1Y3RvcihlKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigiRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIGNvbnN0cnVjdG9yLiIpfXZhciByPWFyZ3VtZW50cy5sZW5ndGg+Mj9hcmd1bWVudHNbMl06ZTtpZighbGUuSXNDb25zdHJ1Y3RvcihyKSl7dGhyb3cgbmV3IFR5cGVFcnJvcigibmV3LnRhcmdldCBtdXN0IGJlIGEgY29uc3RydWN0b3IuIil9cmV0dXJuIGxlLkNvbnN0cnVjdChlLHQsciwiaW50ZXJuYWwiKX0sZGVsZXRlUHJvcGVydHk6ZnVuY3Rpb24gZGVsZXRlUHJvcGVydHkoZSx0KXtQbihlKTtpZihzKXt2YXIgcj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGUsdCk7aWYociYmIXIuY29uZmlndXJhYmxlKXtyZXR1cm4gZmFsc2V9fXJldHVybiBkZWxldGUgZVt0XX0saGFzOmZ1bmN0aW9uIGhhcyhlLHQpe1BuKGUpO3JldHVybiB0IGluIGV9fTtpZihPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyl7T2JqZWN0LmFzc2lnbihDbix7b3duS2V5czpmdW5jdGlvbiBvd25LZXlzKGUpe1BuKGUpO3ZhciB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGUpO2lmKGxlLklzQ2FsbGFibGUoT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scykpe3godCxPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGUpKX1yZXR1cm4gdH19KX12YXIgTW49ZnVuY3Rpb24gQ29udmVydEV4Y2VwdGlvblRvQm9vbGVhbihlKXtyZXR1cm4haShlKX07aWYoT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zKXtPYmplY3QuYXNzaWduKENuLHtpc0V4dGVuc2libGU6ZnVuY3Rpb24gaXNFeHRlbnNpYmxlKGUpe1BuKGUpO3JldHVybiBPYmplY3QuaXNFeHRlbnNpYmxlKGUpfSxwcmV2ZW50RXh0ZW5zaW9uczpmdW5jdGlvbiBwcmV2ZW50RXh0ZW5zaW9ucyhlKXtQbihlKTtyZXR1cm4gTW4oZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zKGUpfSl9fSl9aWYocyl7dmFyIHhuPWZ1bmN0aW9uIGdldChlLHQscil7dmFyIG49T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihlLHQpO2lmKCFuKXt2YXIgbz1PYmplY3QuZ2V0UHJvdG90eXBlT2YoZSk7aWYobz09PW51bGwpe3JldHVybiB2b2lkIDB9cmV0dXJuIHhuKG8sdCxyKX1pZigidmFsdWUiaW4gbil7cmV0dXJuIG4udmFsdWV9aWYobi5nZXQpe3JldHVybiBsZS5DYWxsKG4uZ2V0LHIpfXJldHVybiB2b2lkIDB9O3ZhciBObj1mdW5jdGlvbiBzZXQoZSxyLG4sbyl7dmFyIGk9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihlLHIpO2lmKCFpKXt2YXIgYT1PYmplY3QuZ2V0UHJvdG90eXBlT2YoZSk7aWYoYSE9PW51bGwpe3JldHVybiBObihhLHIsbixvKX1pPXt2YWx1ZTp2b2lkIDAsd3JpdGFibGU6dHJ1ZSxlbnVtZXJhYmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9fWlmKCJ2YWx1ZSJpbiBpKXtpZighaS53cml0YWJsZSl7cmV0dXJuIGZhbHNlfWlmKCFsZS5UeXBlSXNPYmplY3Qobykpe3JldHVybiBmYWxzZX12YXIgdT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKG8scik7aWYodSl7cmV0dXJuIHVlLmRlZmluZVByb3BlcnR5KG8scix7dmFsdWU6bn0pfXJldHVybiB1ZS5kZWZpbmVQcm9wZXJ0eShvLHIse3ZhbHVlOm4sd3JpdGFibGU6dHJ1ZSxlbnVtZXJhYmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9KX1pZihpLnNldCl7dChpLnNldCxvLG4pO3JldHVybiB0cnVlfXJldHVybiBmYWxzZX07T2JqZWN0LmFzc2lnbihDbix7ZGVmaW5lUHJvcGVydHk6ZnVuY3Rpb24gZGVmaW5lUHJvcGVydHkoZSx0LHIpe1BuKGUpO3JldHVybiBNbihmdW5jdGlvbigpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHIpfSl9LGdldE93blByb3BlcnR5RGVzY3JpcHRvcjpmdW5jdGlvbiBnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZSx0KXtQbihlKTtyZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihlLHQpfSxnZXQ6ZnVuY3Rpb24gZ2V0KGUsdCl7UG4oZSk7dmFyIHI9YXJndW1lbnRzLmxlbmd0aD4yP2FyZ3VtZW50c1syXTplO3JldHVybiB4bihlLHQscil9LHNldDpmdW5jdGlvbiBzZXQoZSx0LHIpe1BuKGUpO3ZhciBuPWFyZ3VtZW50cy5sZW5ndGg+Mz9hcmd1bWVudHNbM106ZTtyZXR1cm4gTm4oZSx0LHIsbil9fSl9aWYoT2JqZWN0LmdldFByb3RvdHlwZU9mKXt2YXIgQW49T2JqZWN0LmdldFByb3RvdHlwZU9mO0NuLmdldFByb3RvdHlwZU9mPWZ1bmN0aW9uIGdldFByb3RvdHlwZU9mKGUpe1BuKGUpO3JldHVybiBBbihlKX19aWYoT2JqZWN0LnNldFByb3RvdHlwZU9mJiZDbi5nZXRQcm90b3R5cGVPZil7dmFyIF9uPWZ1bmN0aW9uKGUsdCl7dmFyIHI9dDt3aGlsZShyKXtpZihlPT09cil7cmV0dXJuIHRydWV9cj1Dbi5nZXRQcm90b3R5cGVPZihyKX1yZXR1cm4gZmFsc2V9O09iamVjdC5hc3NpZ24oQ24se3NldFByb3RvdHlwZU9mOmZ1bmN0aW9uIHNldFByb3RvdHlwZU9mKGUsdCl7UG4oZSk7aWYodCE9PW51bGwmJiFsZS5UeXBlSXNPYmplY3QodCkpe3Rocm93IG5ldyBUeXBlRXJyb3IoInByb3RvIG11c3QgYmUgYW4gb2JqZWN0IG9yIG51bGwiKX1pZih0PT09dWUuZ2V0UHJvdG90eXBlT2YoZSkpe3JldHVybiB0cnVlfWlmKHVlLmlzRXh0ZW5zaWJsZSYmIXVlLmlzRXh0ZW5zaWJsZShlKSl7cmV0dXJuIGZhbHNlfWlmKF9uKGUsdCkpe3JldHVybiBmYWxzZX1PYmplY3Quc2V0UHJvdG90eXBlT2YoZSx0KTtyZXR1cm4gdHJ1ZX19KX12YXIgUm49ZnVuY3Rpb24oZSx0KXtpZighbGUuSXNDYWxsYWJsZShTLlJlZmxlY3RbZV0pKXtoKFMuUmVmbGVjdCxlLHQpfWVsc2V7dmFyIHI9YShmdW5jdGlvbigpe1MuUmVmbGVjdFtlXSgxKTtTLlJlZmxlY3RbZV0oTmFOKTtTLlJlZmxlY3RbZV0odHJ1ZSk7cmV0dXJuIHRydWV9KTtpZihyKXtvZShTLlJlZmxlY3QsZSx0KX19fTtPYmplY3Qua2V5cyhDbikuZm9yRWFjaChmdW5jdGlvbihlKXtSbihlLENuW2VdKX0pO3ZhciBrbj1TLlJlZmxlY3QuZ2V0UHJvdG90eXBlT2Y7aWYoYyYma24mJmtuLm5hbWUhPT0iZ2V0UHJvdG90eXBlT2YiKXtvZShTLlJlZmxlY3QsImdldFByb3RvdHlwZU9mIixmdW5jdGlvbiBnZXRQcm90b3R5cGVPZihlKXtyZXR1cm4gdChrbixTLlJlZmxlY3QsZSl9KX1pZihTLlJlZmxlY3Quc2V0UHJvdG90eXBlT2Ype2lmKGEoZnVuY3Rpb24oKXtTLlJlZmxlY3Quc2V0UHJvdG90eXBlT2YoMSx7fSk7cmV0dXJuIHRydWV9KSl7b2UoUy5SZWZsZWN0LCJzZXRQcm90b3R5cGVPZiIsQ24uc2V0UHJvdG90eXBlT2YpfX1pZihTLlJlZmxlY3QuZGVmaW5lUHJvcGVydHkpe2lmKCFhKGZ1bmN0aW9uKCl7dmFyIGU9IVMuUmVmbGVjdC5kZWZpbmVQcm9wZXJ0eSgxLCJ0ZXN0Iix7dmFsdWU6MX0pO3ZhciB0PXR5cGVvZiBPYmplY3QucHJldmVudEV4dGVuc2lvbnMhPT0iZnVuY3Rpb24ifHwhUy5SZWZsZWN0LmRlZmluZVByb3BlcnR5KE9iamVjdC5wcmV2ZW50RXh0ZW5zaW9ucyh7fSksInRlc3QiLHt9KTtyZXR1cm4gZSYmdH0pKXtvZShTLlJlZmxlY3QsImRlZmluZVByb3BlcnR5IixDbi5kZWZpbmVQcm9wZXJ0eSl9fWlmKFMuUmVmbGVjdC5jb25zdHJ1Y3Qpe2lmKCFhKGZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24gRigpe307cmV0dXJuIFMuUmVmbGVjdC5jb25zdHJ1Y3QoZnVuY3Rpb24oKXt9LFtdLGUpaW5zdGFuY2VvZiBlfSkpe29lKFMuUmVmbGVjdCwiY29uc3RydWN0IixDbi5jb25zdHJ1Y3QpfX1pZihTdHJpbmcobmV3IERhdGUoTmFOKSkhPT0iSW52YWxpZCBEYXRlIil7dmFyIExuPURhdGUucHJvdG90eXBlLnRvU3RyaW5nO3ZhciBGbj1mdW5jdGlvbiB0b1N0cmluZygpe3ZhciBlPSt0aGlzO2lmKGUhPT1lKXtyZXR1cm4iSW52YWxpZCBEYXRlIn1yZXR1cm4gbGUuQ2FsbChMbix0aGlzKX07b2UoRGF0ZS5wcm90b3R5cGUsInRvU3RyaW5nIixGbil9dmFyIERuPXthbmNob3I6ZnVuY3Rpb24gYW5jaG9yKGUpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImEiLCJuYW1lIixlKX0sYmlnOmZ1bmN0aW9uIGJpZygpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImJpZyIsIiIsIiIpfSxibGluazpmdW5jdGlvbiBibGluaygpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImJsaW5rIiwiIiwiIil9LGJvbGQ6ZnVuY3Rpb24gYm9sZCgpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImIiLCIiLCIiKX0sZml4ZWQ6ZnVuY3Rpb24gZml4ZWQoKXtyZXR1cm4gbGUuQ3JlYXRlSFRNTCh0aGlzLCJ0dCIsIiIsIiIpfSxmb250Y29sb3I6ZnVuY3Rpb24gZm9udGNvbG9yKGUpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImZvbnQiLCJjb2xvciIsZSl9LGZvbnRzaXplOmZ1bmN0aW9uIGZvbnRzaXplKGUpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsImZvbnQiLCJzaXplIixlKX0saXRhbGljczpmdW5jdGlvbiBpdGFsaWNzKCl7cmV0dXJuIGxlLkNyZWF0ZUhUTUwodGhpcywiaSIsIiIsIiIpfSxsaW5rOmZ1bmN0aW9uIGxpbmsoZSl7cmV0dXJuIGxlLkNyZWF0ZUhUTUwodGhpcywiYSIsImhyZWYiLGUpfSxzbWFsbDpmdW5jdGlvbiBzbWFsbCgpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsInNtYWxsIiwiIiwiIil9LHN0cmlrZTpmdW5jdGlvbiBzdHJpa2UoKXtyZXR1cm4gbGUuQ3JlYXRlSFRNTCh0aGlzLCJzdHJpa2UiLCIiLCIiKX0sc3ViOmZ1bmN0aW9uIHN1Yigpe3JldHVybiBsZS5DcmVhdGVIVE1MKHRoaXMsInN1YiIsIiIsIiIpfSxzdXA6ZnVuY3Rpb24gc3ViKCl7cmV0dXJuIGxlLkNyZWF0ZUhUTUwodGhpcywic3VwIiwiIiwiIil9fTtsKE9iamVjdC5rZXlzKERuKSxmdW5jdGlvbihlKXt2YXIgcj1TdHJpbmcucHJvdG90eXBlW2VdO3ZhciBuPWZhbHNlO2lmKGxlLklzQ2FsbGFibGUocikpe3ZhciBvPXQociwiIiwnICIgJyk7dmFyIGk9UChbXSxvLm1hdGNoKC8iL2cpKS5sZW5ndGg7bj1vIT09by50b0xvd2VyQ2FzZSgpfHxpPjJ9ZWxzZXtuPXRydWV9aWYobil7b2UoU3RyaW5nLnByb3RvdHlwZSxlLERuW2VdKX19KTt2YXIgem49ZnVuY3Rpb24oKXtpZighaWUpe3JldHVybiBmYWxzZX12YXIgZT10eXBlb2YgSlNPTj09PSJvYmplY3QiJiZ0eXBlb2YgSlNPTi5zdHJpbmdpZnk9PT0iZnVuY3Rpb24iP0pTT04uc3RyaW5naWZ5Om51bGw7aWYoIWUpe3JldHVybiBmYWxzZX1pZih0eXBlb2YgZShKKCkpIT09InVuZGVmaW5lZCIpe3JldHVybiB0cnVlfWlmKGUoW0ooKV0pIT09IltudWxsXSIpe3JldHVybiB0cnVlfXZhciB0PXthOkooKX07dFtKKCldPXRydWU7aWYoZSh0KSE9PSJ7fSIpe3JldHVybiB0cnVlfXJldHVybiBmYWxzZX0oKTt2YXIgcW49YShmdW5jdGlvbigpe2lmKCFpZSl7cmV0dXJuIHRydWV9cmV0dXJuIEpTT04uc3RyaW5naWZ5KE9iamVjdChKKCkpKT09PSJ7fSImJkpTT04uc3RyaW5naWZ5KFtPYmplY3QoSigpKV0pPT09Ilt7fV0ifSk7aWYoem58fCFxbil7dmFyIFduPUpTT04uc3RyaW5naWZ5O29lKEpTT04sInN0cmluZ2lmeSIsZnVuY3Rpb24gc3RyaW5naWZ5KGUpe2lmKHR5cGVvZiBlPT09InN5bWJvbCIpe3JldHVybn12YXIgbjtpZihhcmd1bWVudHMubGVuZ3RoPjEpe249YXJndW1lbnRzWzFdfXZhciBvPVtlXTtpZighcihuKSl7dmFyIGk9bGUuSXNDYWxsYWJsZShuKT9uOm51bGw7dmFyIGE9ZnVuY3Rpb24oZSxyKXt2YXIgbj1pP3QoaSx0aGlzLGUscik6cjtpZih0eXBlb2YgbiE9PSJzeW1ib2wiKXtpZihuZS5zeW1ib2wobikpe3JldHVybiBfdCh7fSkobil9cmV0dXJuIG59fTtvLnB1c2goYSl9ZWxzZXtvLnB1c2gobil9aWYoYXJndW1lbnRzLmxlbmd0aD4yKXtvLnB1c2goYXJndW1lbnRzWzJdKX1yZXR1cm4gV24uYXBwbHkodGhpcyxvKX0pfXJldHVybiBTfSk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPWVzNi1zaGltLm1hcAovKiEgalF1ZXJ5IHYzLjcuMSB8IChjKSBPcGVuSlMgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIHwganF1ZXJ5Lm9yZy9saWNlbnNlICovCiFmdW5jdGlvbihlLHQpeyJ1c2Ugc3RyaWN0Ijsib2JqZWN0Ij09dHlwZW9mIG1vZHVsZSYmIm9iamVjdCI9PXR5cGVvZiBtb2R1bGUuZXhwb3J0cz9tb2R1bGUuZXhwb3J0cz1lLmRvY3VtZW50P3QoZSwhMCk6ZnVuY3Rpb24oZSl7aWYoIWUuZG9jdW1lbnQpdGhyb3cgbmV3IEVycm9yKCJqUXVlcnkgcmVxdWlyZXMgYSB3aW5kb3cgd2l0aCBhIGRvY3VtZW50Iik7cmV0dXJuIHQoZSl9OnQoZSl9KCJ1bmRlZmluZWQiIT10eXBlb2Ygd2luZG93P3dpbmRvdzp0aGlzLGZ1bmN0aW9uKGllLGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgb2U9W10scj1PYmplY3QuZ2V0UHJvdG90eXBlT2YsYWU9b2Uuc2xpY2UsZz1vZS5mbGF0P2Z1bmN0aW9uKGUpe3JldHVybiBvZS5mbGF0LmNhbGwoZSl9OmZ1bmN0aW9uKGUpe3JldHVybiBvZS5jb25jYXQuYXBwbHkoW10sZSl9LHM9b2UucHVzaCxzZT1vZS5pbmRleE9mLG49e30saT1uLnRvU3RyaW5nLHVlPW4uaGFzT3duUHJvcGVydHksbz11ZS50b1N0cmluZyxhPW8uY2FsbChPYmplY3QpLGxlPXt9LHY9ZnVuY3Rpb24oZSl7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIGUmJiJudW1iZXIiIT10eXBlb2YgZS5ub2RlVHlwZSYmImZ1bmN0aW9uIiE9dHlwZW9mIGUuaXRlbX0seT1mdW5jdGlvbihlKXtyZXR1cm4gbnVsbCE9ZSYmZT09PWUud2luZG93fSxDPWllLmRvY3VtZW50LHU9e3R5cGU6ITAsc3JjOiEwLG5vbmNlOiEwLG5vTW9kdWxlOiEwfTtmdW5jdGlvbiBtKGUsdCxuKXt2YXIgcixpLG89KG49bnx8QykuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7aWYoby50ZXh0PWUsdClmb3IociBpbiB1KShpPXRbcl18fHQuZ2V0QXR0cmlidXRlJiZ0LmdldEF0dHJpYnV0ZShyKSkmJm8uc2V0QXR0cmlidXRlKHIsaSk7bi5oZWFkLmFwcGVuZENoaWxkKG8pLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQobyl9ZnVuY3Rpb24geChlKXtyZXR1cm4gbnVsbD09ZT9lKyIiOiJvYmplY3QiPT10eXBlb2YgZXx8ImZ1bmN0aW9uIj09dHlwZW9mIGU/bltpLmNhbGwoZSldfHwib2JqZWN0Ijp0eXBlb2YgZX12YXIgdD0iMy43LjEiLGw9L0hUTUwkL2ksY2U9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gbmV3IGNlLmZuLmluaXQoZSx0KX07ZnVuY3Rpb24gYyhlKXt2YXIgdD0hIWUmJiJsZW5ndGgiaW4gZSYmZS5sZW5ndGgsbj14KGUpO3JldHVybiF2KGUpJiYheShlKSYmKCJhcnJheSI9PT1ufHwwPT09dHx8Im51bWJlciI9PXR5cGVvZiB0JiYwPHQmJnQtMSBpbiBlKX1mdW5jdGlvbiBmZShlLHQpe3JldHVybiBlLm5vZGVOYW1lJiZlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT10LnRvTG93ZXJDYXNlKCl9Y2UuZm49Y2UucHJvdG90eXBlPXtqcXVlcnk6dCxjb25zdHJ1Y3RvcjpjZSxsZW5ndGg6MCx0b0FycmF5OmZ1bmN0aW9uKCl7cmV0dXJuIGFlLmNhbGwodGhpcyl9LGdldDpmdW5jdGlvbihlKXtyZXR1cm4gbnVsbD09ZT9hZS5jYWxsKHRoaXMpOmU8MD90aGlzW2UrdGhpcy5sZW5ndGhdOnRoaXNbZV19LHB1c2hTdGFjazpmdW5jdGlvbihlKXt2YXIgdD1jZS5tZXJnZSh0aGlzLmNvbnN0cnVjdG9yKCksZSk7cmV0dXJuIHQucHJldk9iamVjdD10aGlzLHR9LGVhY2g6ZnVuY3Rpb24oZSl7cmV0dXJuIGNlLmVhY2godGhpcyxlKX0sbWFwOmZ1bmN0aW9uKG4pe3JldHVybiB0aGlzLnB1c2hTdGFjayhjZS5tYXAodGhpcyxmdW5jdGlvbihlLHQpe3JldHVybiBuLmNhbGwoZSx0LGUpfSkpfSxzbGljZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnB1c2hTdGFjayhhZS5hcHBseSh0aGlzLGFyZ3VtZW50cykpfSxmaXJzdDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmVxKDApfSxsYXN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZXEoLTEpfSxldmVuOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucHVzaFN0YWNrKGNlLmdyZXAodGhpcyxmdW5jdGlvbihlLHQpe3JldHVybih0KzEpJTJ9KSl9LG9kZDpmdW5jdGlvbigpe3JldHVybiB0aGlzLnB1c2hTdGFjayhjZS5ncmVwKHRoaXMsZnVuY3Rpb24oZSx0KXtyZXR1cm4gdCUyfSkpfSxlcTpmdW5jdGlvbihlKXt2YXIgdD10aGlzLmxlbmd0aCxuPStlKyhlPDA/dDowKTtyZXR1cm4gdGhpcy5wdXNoU3RhY2soMDw9biYmbjx0P1t0aGlzW25dXTpbXSl9LGVuZDpmdW5jdGlvbigpe3JldHVybiB0aGlzLnByZXZPYmplY3R8fHRoaXMuY29uc3RydWN0b3IoKX0scHVzaDpzLHNvcnQ6b2Uuc29ydCxzcGxpY2U6b2Uuc3BsaWNlfSxjZS5leHRlbmQ9Y2UuZm4uZXh0ZW5kPWZ1bmN0aW9uKCl7dmFyIGUsdCxuLHIsaSxvLGE9YXJndW1lbnRzWzBdfHx7fSxzPTEsdT1hcmd1bWVudHMubGVuZ3RoLGw9ITE7Zm9yKCJib29sZWFuIj09dHlwZW9mIGEmJihsPWEsYT1hcmd1bWVudHNbc118fHt9LHMrKyksIm9iamVjdCI9PXR5cGVvZiBhfHx2KGEpfHwoYT17fSkscz09PXUmJihhPXRoaXMscy0tKTtzPHU7cysrKWlmKG51bGwhPShlPWFyZ3VtZW50c1tzXSkpZm9yKHQgaW4gZSlyPWVbdF0sIl9fcHJvdG9fXyIhPT10JiZhIT09ciYmKGwmJnImJihjZS5pc1BsYWluT2JqZWN0KHIpfHwoaT1BcnJheS5pc0FycmF5KHIpKSk/KG49YVt0XSxvPWkmJiFBcnJheS5pc0FycmF5KG4pP1tdOml8fGNlLmlzUGxhaW5PYmplY3Qobik/bjp7fSxpPSExLGFbdF09Y2UuZXh0ZW5kKGwsbyxyKSk6dm9pZCAwIT09ciYmKGFbdF09cikpO3JldHVybiBhfSxjZS5leHRlbmQoe2V4cGFuZG86ImpRdWVyeSIrKHQrTWF0aC5yYW5kb20oKSkucmVwbGFjZSgvXEQvZywiIiksaXNSZWFkeTohMCxlcnJvcjpmdW5jdGlvbihlKXt0aHJvdyBuZXcgRXJyb3IoZSl9LG5vb3A6ZnVuY3Rpb24oKXt9LGlzUGxhaW5PYmplY3Q6ZnVuY3Rpb24oZSl7dmFyIHQsbjtyZXR1cm4hKCFlfHwiW29iamVjdCBPYmplY3RdIiE9PWkuY2FsbChlKSkmJighKHQ9cihlKSl8fCJmdW5jdGlvbiI9PXR5cGVvZihuPXVlLmNhbGwodCwiY29uc3RydWN0b3IiKSYmdC5jb25zdHJ1Y3RvcikmJm8uY2FsbChuKT09PWEpfSxpc0VtcHR5T2JqZWN0OmZ1bmN0aW9uKGUpe3ZhciB0O2Zvcih0IGluIGUpcmV0dXJuITE7cmV0dXJuITB9LGdsb2JhbEV2YWw6ZnVuY3Rpb24oZSx0LG4pe20oZSx7bm9uY2U6dCYmdC5ub25jZX0sbil9LGVhY2g6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPTA7aWYoYyhlKSl7Zm9yKG49ZS5sZW5ndGg7cjxuO3IrKylpZighMT09PXQuY2FsbChlW3JdLHIsZVtyXSkpYnJlYWt9ZWxzZSBmb3IociBpbiBlKWlmKCExPT09dC5jYWxsKGVbcl0scixlW3JdKSlicmVhaztyZXR1cm4gZX0sdGV4dDpmdW5jdGlvbihlKXt2YXIgdCxuPSIiLHI9MCxpPWUubm9kZVR5cGU7aWYoIWkpd2hpbGUodD1lW3IrK10pbis9Y2UudGV4dCh0KTtyZXR1cm4gMT09PWl8fDExPT09aT9lLnRleHRDb250ZW50Ojk9PT1pP2UuZG9jdW1lbnRFbGVtZW50LnRleHRDb250ZW50OjM9PT1pfHw0PT09aT9lLm5vZGVWYWx1ZTpufSxtYWtlQXJyYXk6ZnVuY3Rpb24oZSx0KXt2YXIgbj10fHxbXTtyZXR1cm4gbnVsbCE9ZSYmKGMoT2JqZWN0KGUpKT9jZS5tZXJnZShuLCJzdHJpbmciPT10eXBlb2YgZT9bZV06ZSk6cy5jYWxsKG4sZSkpLG59LGluQXJyYXk6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBudWxsPT10Py0xOnNlLmNhbGwodCxlLG4pfSxpc1hNTERvYzpmdW5jdGlvbihlKXt2YXIgdD1lJiZlLm5hbWVzcGFjZVVSSSxuPWUmJihlLm93bmVyRG9jdW1lbnR8fGUpLmRvY3VtZW50RWxlbWVudDtyZXR1cm4hbC50ZXN0KHR8fG4mJm4ubm9kZU5hbWV8fCJIVE1MIil9LG1lcmdlOmZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPSt0Lmxlbmd0aCxyPTAsaT1lLmxlbmd0aDtyPG47cisrKWVbaSsrXT10W3JdO3JldHVybiBlLmxlbmd0aD1pLGV9LGdyZXA6ZnVuY3Rpb24oZSx0LG4pe2Zvcih2YXIgcj1bXSxpPTAsbz1lLmxlbmd0aCxhPSFuO2k8bztpKyspIXQoZVtpXSxpKSE9PWEmJnIucHVzaChlW2ldKTtyZXR1cm4gcn0sbWFwOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG89MCxhPVtdO2lmKGMoZSkpZm9yKHI9ZS5sZW5ndGg7bzxyO28rKyludWxsIT0oaT10KGVbb10sbyxuKSkmJmEucHVzaChpKTtlbHNlIGZvcihvIGluIGUpbnVsbCE9KGk9dChlW29dLG8sbikpJiZhLnB1c2goaSk7cmV0dXJuIGcoYSl9LGd1aWQ6MSxzdXBwb3J0OmxlfSksImZ1bmN0aW9uIj09dHlwZW9mIFN5bWJvbCYmKGNlLmZuW1N5bWJvbC5pdGVyYXRvcl09b2VbU3ltYm9sLml0ZXJhdG9yXSksY2UuZWFjaCgiQm9vbGVhbiBOdW1iZXIgU3RyaW5nIEZ1bmN0aW9uIEFycmF5IERhdGUgUmVnRXhwIE9iamVjdCBFcnJvciBTeW1ib2wiLnNwbGl0KCIgIiksZnVuY3Rpb24oZSx0KXtuWyJbb2JqZWN0ICIrdCsiXSJdPXQudG9Mb3dlckNhc2UoKX0pO3ZhciBwZT1vZS5wb3AsZGU9b2Uuc29ydCxoZT1vZS5zcGxpY2UsZ2U9IltcXHgyMFxcdFxcclxcblxcZl0iLHZlPW5ldyBSZWdFeHAoIl4iK2dlKyIrfCgoPzpefFteXFxcXF0pKD86XFxcXC4pKikiK2dlKyIrJCIsImciKTtjZS5jb250YWlucz1mdW5jdGlvbihlLHQpe3ZhciBuPXQmJnQucGFyZW50Tm9kZTtyZXR1cm4gZT09PW58fCEoIW58fDEhPT1uLm5vZGVUeXBlfHwhKGUuY29udGFpbnM/ZS5jb250YWlucyhuKTplLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uJiYxNiZlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKG4pKSl9O3ZhciBmPS8oW1wwLVx4MWZceDdmXXxeLT9cZCl8Xi0kfFteXHg4MC1cdUZGRkZcdy1dL2c7ZnVuY3Rpb24gcChlLHQpe3JldHVybiB0PyJcMCI9PT1lPyJcdWZmZmQiOmUuc2xpY2UoMCwtMSkrIlxcIitlLmNoYXJDb2RlQXQoZS5sZW5ndGgtMSkudG9TdHJpbmcoMTYpKyIgIjoiXFwiK2V9Y2UuZXNjYXBlU2VsZWN0b3I9ZnVuY3Rpb24oZSl7cmV0dXJuKGUrIiIpLnJlcGxhY2UoZixwKX07dmFyIHllPUMsbWU9czshZnVuY3Rpb24oKXt2YXIgZSxiLHcsbyxhLFQscixDLGQsaSxrPW1lLFM9Y2UuZXhwYW5kbyxFPTAsbj0wLHM9VygpLGM9VygpLHU9VygpLGg9VygpLGw9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT09PXQmJihhPSEwKSwwfSxmPSJjaGVja2VkfHNlbGVjdGVkfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58aXNtYXB8bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZCIsdD0iKD86XFxcXFtcXGRhLWZBLUZdezEsNn0iK2dlKyI/fFxcXFxbXlxcclxcblxcZl18W1xcdy1dfFteXDAtXFx4N2ZdKSsiLHA9IlxcWyIrZ2UrIiooIit0KyIpKD86IitnZSsiKihbKl4kfCF+XT89KSIrZ2UrIiooPzonKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcInwoIit0KyIpKXwpIitnZSsiKlxcXSIsZz0iOigiK3QrIikoPzpcXCgoKCcoKD86XFxcXC58W15cXFxcJ10pKiknfFwiKCg/OlxcXFwufFteXFxcXFwiXSkqKVwiKXwoKD86XFxcXC58W15cXFxcKClbXFxdXXwiK3ArIikqKXwuKilcXCl8KSIsdj1uZXcgUmVnRXhwKGdlKyIrIiwiZyIpLHk9bmV3IFJlZ0V4cCgiXiIrZ2UrIiosIitnZSsiKiIpLG09bmV3IFJlZ0V4cCgiXiIrZ2UrIiooWz4rfl18IitnZSsiKSIrZ2UrIioiKSx4PW5ldyBSZWdFeHAoZ2UrInw+Iiksaj1uZXcgUmVnRXhwKGcpLEE9bmV3IFJlZ0V4cCgiXiIrdCsiJCIpLEQ9e0lEOm5ldyBSZWdFeHAoIl4jKCIrdCsiKSIpLENMQVNTOm5ldyBSZWdFeHAoIl5cXC4oIit0KyIpIiksVEFHOm5ldyBSZWdFeHAoIl4oIit0KyJ8WypdKSIpLEFUVFI6bmV3IFJlZ0V4cCgiXiIrcCksUFNFVURPOm5ldyBSZWdFeHAoIl4iK2cpLENISUxEOm5ldyBSZWdFeHAoIl46KG9ubHl8Zmlyc3R8bGFzdHxudGh8bnRoLWxhc3QpLShjaGlsZHxvZi10eXBlKSg/OlxcKCIrZ2UrIiooZXZlbnxvZGR8KChbKy1dfCkoXFxkKilufCkiK2dlKyIqKD86KFsrLV18KSIrZ2UrIiooXFxkKyl8KSkiK2dlKyIqXFwpfCkiLCJpIiksYm9vbDpuZXcgUmVnRXhwKCJeKD86IitmKyIpJCIsImkiKSxuZWVkc0NvbnRleHQ6bmV3IFJlZ0V4cCgiXiIrZ2UrIipbPit+XXw6KGV2ZW58b2RkfGVxfGd0fGx0fG50aHxmaXJzdHxsYXN0KSg/OlxcKCIrZ2UrIiooKD86LVxcZCk/XFxkKikiK2dlKyIqXFwpfCkoPz1bXi1dfCQpIiwiaSIpfSxOPS9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2kscT0vXmhcZCQvaSxMPS9eKD86IyhbXHctXSspfChcdyspfFwuKFtcdy1dKykpJC8sSD0vWyt+XS8sTz1uZXcgUmVnRXhwKCJcXFxcW1xcZGEtZkEtRl17MSw2fSIrZ2UrIj98XFxcXChbXlxcclxcblxcZl0pIiwiZyIpLFA9ZnVuY3Rpb24oZSx0KXt2YXIgbj0iMHgiK2Uuc2xpY2UoMSktNjU1MzY7cmV0dXJuIHR8fChuPDA/U3RyaW5nLmZyb21DaGFyQ29kZShuKzY1NTM2KTpTdHJpbmcuZnJvbUNoYXJDb2RlKG4+PjEwfDU1Mjk2LDEwMjMmbnw1NjMyMCkpfSxNPWZ1bmN0aW9uKCl7VigpfSxSPUooZnVuY3Rpb24oZSl7cmV0dXJuITA9PT1lLmRpc2FibGVkJiZmZShlLCJmaWVsZHNldCIpfSx7ZGlyOiJwYXJlbnROb2RlIixuZXh0OiJsZWdlbmQifSk7dHJ5e2suYXBwbHkob2U9YWUuY2FsbCh5ZS5jaGlsZE5vZGVzKSx5ZS5jaGlsZE5vZGVzKSxvZVt5ZS5jaGlsZE5vZGVzLmxlbmd0aF0ubm9kZVR5cGV9Y2F0Y2goZSl7az17YXBwbHk6ZnVuY3Rpb24oZSx0KXttZS5hcHBseShlLGFlLmNhbGwodCkpfSxjYWxsOmZ1bmN0aW9uKGUpe21lLmFwcGx5KGUsYWUuY2FsbChhcmd1bWVudHMsMSkpfX19ZnVuY3Rpb24gSSh0LGUsbixyKXt2YXIgaSxvLGEscyx1LGwsYyxmPWUmJmUub3duZXJEb2N1bWVudCxwPWU/ZS5ub2RlVHlwZTo5O2lmKG49bnx8W10sInN0cmluZyIhPXR5cGVvZiB0fHwhdHx8MSE9PXAmJjkhPT1wJiYxMSE9PXApcmV0dXJuIG47aWYoIXImJihWKGUpLGU9ZXx8VCxDKSl7aWYoMTEhPT1wJiYodT1MLmV4ZWModCkpKWlmKGk9dVsxXSl7aWYoOT09PXApe2lmKCEoYT1lLmdldEVsZW1lbnRCeUlkKGkpKSlyZXR1cm4gbjtpZihhLmlkPT09aSlyZXR1cm4gay5jYWxsKG4sYSksbn1lbHNlIGlmKGYmJihhPWYuZ2V0RWxlbWVudEJ5SWQoaSkpJiZJLmNvbnRhaW5zKGUsYSkmJmEuaWQ9PT1pKXJldHVybiBrLmNhbGwobixhKSxufWVsc2V7aWYodVsyXSlyZXR1cm4gay5hcHBseShuLGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUodCkpLG47aWYoKGk9dVszXSkmJmUuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSlyZXR1cm4gay5hcHBseShuLGUuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShpKSksbn1pZighKGhbdCsiICJdfHxkJiZkLnRlc3QodCkpKXtpZihjPXQsZj1lLDE9PT1wJiYoeC50ZXN0KHQpfHxtLnRlc3QodCkpKXsoZj1ILnRlc3QodCkmJlUoZS5wYXJlbnROb2RlKXx8ZSk9PWUmJmxlLnNjb3BlfHwoKHM9ZS5nZXRBdHRyaWJ1dGUoImlkIikpP3M9Y2UuZXNjYXBlU2VsZWN0b3Iocyk6ZS5zZXRBdHRyaWJ1dGUoImlkIixzPVMpKSxvPShsPVkodCkpLmxlbmd0aDt3aGlsZShvLS0pbFtvXT0ocz8iIyIrczoiOnNjb3BlIikrIiAiK1EobFtvXSk7Yz1sLmpvaW4oIiwiKX10cnl7cmV0dXJuIGsuYXBwbHkobixmLnF1ZXJ5U2VsZWN0b3JBbGwoYykpLG59Y2F0Y2goZSl7aCh0LCEwKX1maW5hbGx5e3M9PT1TJiZlLnJlbW92ZUF0dHJpYnV0ZSgiaWQiKX19fXJldHVybiByZSh0LnJlcGxhY2UodmUsIiQxIiksZSxuLHIpfWZ1bmN0aW9uIFcoKXt2YXIgcj1bXTtyZXR1cm4gZnVuY3Rpb24gZSh0LG4pe3JldHVybiByLnB1c2godCsiICIpPmIuY2FjaGVMZW5ndGgmJmRlbGV0ZSBlW3Iuc2hpZnQoKV0sZVt0KyIgIl09bn19ZnVuY3Rpb24gRihlKXtyZXR1cm4gZVtTXT0hMCxlfWZ1bmN0aW9uICQoZSl7dmFyIHQ9VC5jcmVhdGVFbGVtZW50KCJmaWVsZHNldCIpO3RyeXtyZXR1cm4hIWUodCl9Y2F0Y2goZSl7cmV0dXJuITF9ZmluYWxseXt0LnBhcmVudE5vZGUmJnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0KSx0PW51bGx9fWZ1bmN0aW9uIEIodCl7cmV0dXJuIGZ1bmN0aW9uKGUpe3JldHVybiBmZShlLCJpbnB1dCIpJiZlLnR5cGU9PT10fX1mdW5jdGlvbiBfKHQpe3JldHVybiBmdW5jdGlvbihlKXtyZXR1cm4oZmUoZSwiaW5wdXQiKXx8ZmUoZSwiYnV0dG9uIikpJiZlLnR5cGU9PT10fX1mdW5jdGlvbiB6KHQpe3JldHVybiBmdW5jdGlvbihlKXtyZXR1cm4iZm9ybSJpbiBlP2UucGFyZW50Tm9kZSYmITE9PT1lLmRpc2FibGVkPyJsYWJlbCJpbiBlPyJsYWJlbCJpbiBlLnBhcmVudE5vZGU/ZS5wYXJlbnROb2RlLmRpc2FibGVkPT09dDplLmRpc2FibGVkPT09dDplLmlzRGlzYWJsZWQ9PT10fHxlLmlzRGlzYWJsZWQhPT0hdCYmUihlKT09PXQ6ZS5kaXNhYmxlZD09PXQ6ImxhYmVsImluIGUmJmUuZGlzYWJsZWQ9PT10fX1mdW5jdGlvbiBYKGEpe3JldHVybiBGKGZ1bmN0aW9uKG8pe3JldHVybiBvPStvLEYoZnVuY3Rpb24oZSx0KXt2YXIgbixyPWEoW10sZS5sZW5ndGgsbyksaT1yLmxlbmd0aDt3aGlsZShpLS0pZVtuPXJbaV1dJiYoZVtuXT0hKHRbbl09ZVtuXSkpfSl9KX1mdW5jdGlvbiBVKGUpe3JldHVybiBlJiYidW5kZWZpbmVkIiE9dHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWUmJmV9ZnVuY3Rpb24gVihlKXt2YXIgdCxuPWU/ZS5vd25lckRvY3VtZW50fHxlOnllO3JldHVybiBuIT1UJiY5PT09bi5ub2RlVHlwZSYmbi5kb2N1bWVudEVsZW1lbnQmJihyPShUPW4pLmRvY3VtZW50RWxlbWVudCxDPSFjZS5pc1hNTERvYyhUKSxpPXIubWF0Y2hlc3x8ci53ZWJraXRNYXRjaGVzU2VsZWN0b3J8fHIubXNNYXRjaGVzU2VsZWN0b3Isci5tc01hdGNoZXNTZWxlY3RvciYmeWUhPVQmJih0PVQuZGVmYXVsdFZpZXcpJiZ0LnRvcCE9PXQmJnQuYWRkRXZlbnRMaXN0ZW5lcigidW5sb2FkIixNKSxsZS5nZXRCeUlkPSQoZnVuY3Rpb24oZSl7cmV0dXJuIHIuYXBwZW5kQ2hpbGQoZSkuaWQ9Y2UuZXhwYW5kbywhVC5nZXRFbGVtZW50c0J5TmFtZXx8IVQuZ2V0RWxlbWVudHNCeU5hbWUoY2UuZXhwYW5kbykubGVuZ3RofSksbGUuZGlzY29ubmVjdGVkTWF0Y2g9JChmdW5jdGlvbihlKXtyZXR1cm4gaS5jYWxsKGUsIioiKX0pLGxlLnNjb3BlPSQoZnVuY3Rpb24oKXtyZXR1cm4gVC5xdWVyeVNlbGVjdG9yQWxsKCI6c2NvcGUiKX0pLGxlLmNzc0hhcz0kKGZ1bmN0aW9uKCl7dHJ5e3JldHVybiBULnF1ZXJ5U2VsZWN0b3IoIjpoYXMoKiw6anFmYWtlKSIpLCExfWNhdGNoKGUpe3JldHVybiEwfX0pLGxlLmdldEJ5SWQ/KGIuZmlsdGVyLklEPWZ1bmN0aW9uKGUpe3ZhciB0PWUucmVwbGFjZShPLFApO3JldHVybiBmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXRBdHRyaWJ1dGUoImlkIik9PT10fX0sYi5maW5kLklEPWZ1bmN0aW9uKGUsdCl7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiB0LmdldEVsZW1lbnRCeUlkJiZDKXt2YXIgbj10LmdldEVsZW1lbnRCeUlkKGUpO3JldHVybiBuP1tuXTpbXX19KTooYi5maWx0ZXIuSUQ9ZnVuY3Rpb24oZSl7dmFyIG49ZS5yZXBsYWNlKE8sUCk7cmV0dXJuIGZ1bmN0aW9uKGUpe3ZhciB0PSJ1bmRlZmluZWQiIT10eXBlb2YgZS5nZXRBdHRyaWJ1dGVOb2RlJiZlLmdldEF0dHJpYnV0ZU5vZGUoImlkIik7cmV0dXJuIHQmJnQudmFsdWU9PT1ufX0sYi5maW5kLklEPWZ1bmN0aW9uKGUsdCl7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiB0LmdldEVsZW1lbnRCeUlkJiZDKXt2YXIgbixyLGksbz10LmdldEVsZW1lbnRCeUlkKGUpO2lmKG8pe2lmKChuPW8uZ2V0QXR0cmlidXRlTm9kZSgiaWQiKSkmJm4udmFsdWU9PT1lKXJldHVybltvXTtpPXQuZ2V0RWxlbWVudHNCeU5hbWUoZSkscj0wO3doaWxlKG89aVtyKytdKWlmKChuPW8uZ2V0QXR0cmlidXRlTm9kZSgiaWQiKSkmJm4udmFsdWU9PT1lKXJldHVybltvXX1yZXR1cm5bXX19KSxiLmZpbmQuVEFHPWZ1bmN0aW9uKGUsdCl7cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiB0LmdldEVsZW1lbnRzQnlUYWdOYW1lP3QuZ2V0RWxlbWVudHNCeVRhZ05hbWUoZSk6dC5xdWVyeVNlbGVjdG9yQWxsKGUpfSxiLmZpbmQuQ0xBU1M9ZnVuY3Rpb24oZSx0KXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSYmQylyZXR1cm4gdC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKGUpfSxkPVtdLCQoZnVuY3Rpb24oZSl7dmFyIHQ7ci5hcHBlbmRDaGlsZChlKS5pbm5lckhUTUw9IjxhIGlkPSciK1MrIicgaHJlZj0nJyBkaXNhYmxlZD0nZGlzYWJsZWQnPjwvYT48c2VsZWN0IGlkPSciK1MrIi1cclxcJyBkaXNhYmxlZD0nZGlzYWJsZWQnPjxvcHRpb24gc2VsZWN0ZWQ9Jyc+PC9vcHRpb24+PC9zZWxlY3Q+IixlLnF1ZXJ5U2VsZWN0b3JBbGwoIltzZWxlY3RlZF0iKS5sZW5ndGh8fGQucHVzaCgiXFxbIitnZSsiKig/OnZhbHVlfCIrZisiKSIpLGUucXVlcnlTZWxlY3RvckFsbCgiW2lkfj0iK1MrIi1dIikubGVuZ3RofHxkLnB1c2goIn49IiksZS5xdWVyeVNlbGVjdG9yQWxsKCJhIyIrUysiKyoiKS5sZW5ndGh8fGQucHVzaCgiLiMuK1srfl0iKSxlLnF1ZXJ5U2VsZWN0b3JBbGwoIjpjaGVja2VkIikubGVuZ3RofHxkLnB1c2goIjpjaGVja2VkIiksKHQ9VC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpKS5zZXRBdHRyaWJ1dGUoInR5cGUiLCJoaWRkZW4iKSxlLmFwcGVuZENoaWxkKHQpLnNldEF0dHJpYnV0ZSgibmFtZSIsIkQiKSxyLmFwcGVuZENoaWxkKGUpLmRpc2FibGVkPSEwLDIhPT1lLnF1ZXJ5U2VsZWN0b3JBbGwoIjpkaXNhYmxlZCIpLmxlbmd0aCYmZC5wdXNoKCI6ZW5hYmxlZCIsIjpkaXNhYmxlZCIpLCh0PVQuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSkuc2V0QXR0cmlidXRlKCJuYW1lIiwiIiksZS5hcHBlbmRDaGlsZCh0KSxlLnF1ZXJ5U2VsZWN0b3JBbGwoIltuYW1lPScnXSIpLmxlbmd0aHx8ZC5wdXNoKCJcXFsiK2dlKyIqbmFtZSIrZ2UrIio9IitnZSsiKig/OicnfFwiXCIpIil9KSxsZS5jc3NIYXN8fGQucHVzaCgiOmhhcyIpLGQ9ZC5sZW5ndGgmJm5ldyBSZWdFeHAoZC5qb2luKCJ8IikpLGw9ZnVuY3Rpb24oZSx0KXtpZihlPT09dClyZXR1cm4gYT0hMCwwO3ZhciBuPSFlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uLSF0LmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uO3JldHVybiBufHwoMSYobj0oZS5vd25lckRvY3VtZW50fHxlKT09KHQub3duZXJEb2N1bWVudHx8dCk/ZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbih0KToxKXx8IWxlLnNvcnREZXRhY2hlZCYmdC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihlKT09PW4/ZT09PVR8fGUub3duZXJEb2N1bWVudD09eWUmJkkuY29udGFpbnMoeWUsZSk/LTE6dD09PVR8fHQub3duZXJEb2N1bWVudD09eWUmJkkuY29udGFpbnMoeWUsdCk/MTpvP3NlLmNhbGwobyxlKS1zZS5jYWxsKG8sdCk6MDo0Jm4/LTE6MSl9KSxUfWZvcihlIGluIEkubWF0Y2hlcz1mdW5jdGlvbihlLHQpe3JldHVybiBJKGUsbnVsbCxudWxsLHQpfSxJLm1hdGNoZXNTZWxlY3Rvcj1mdW5jdGlvbihlLHQpe2lmKFYoZSksQyYmIWhbdCsiICJdJiYoIWR8fCFkLnRlc3QodCkpKXRyeXt2YXIgbj1pLmNhbGwoZSx0KTtpZihufHxsZS5kaXNjb25uZWN0ZWRNYXRjaHx8ZS5kb2N1bWVudCYmMTEhPT1lLmRvY3VtZW50Lm5vZGVUeXBlKXJldHVybiBufWNhdGNoKGUpe2godCwhMCl9cmV0dXJuIDA8SSh0LFQsbnVsbCxbZV0pLmxlbmd0aH0sSS5jb250YWlucz1mdW5jdGlvbihlLHQpe3JldHVybihlLm93bmVyRG9jdW1lbnR8fGUpIT1UJiZWKGUpLGNlLmNvbnRhaW5zKGUsdCl9LEkuYXR0cj1mdW5jdGlvbihlLHQpeyhlLm93bmVyRG9jdW1lbnR8fGUpIT1UJiZWKGUpO3ZhciBuPWIuYXR0ckhhbmRsZVt0LnRvTG93ZXJDYXNlKCldLHI9biYmdWUuY2FsbChiLmF0dHJIYW5kbGUsdC50b0xvd2VyQ2FzZSgpKT9uKGUsdCwhQyk6dm9pZCAwO3JldHVybiB2b2lkIDAhPT1yP3I6ZS5nZXRBdHRyaWJ1dGUodCl9LEkuZXJyb3I9ZnVuY3Rpb24oZSl7dGhyb3cgbmV3IEVycm9yKCJTeW50YXggZXJyb3IsIHVucmVjb2duaXplZCBleHByZXNzaW9uOiAiK2UpfSxjZS51bmlxdWVTb3J0PWZ1bmN0aW9uKGUpe3ZhciB0LG49W10scj0wLGk9MDtpZihhPSFsZS5zb3J0U3RhYmxlLG89IWxlLnNvcnRTdGFibGUmJmFlLmNhbGwoZSwwKSxkZS5jYWxsKGUsbCksYSl7d2hpbGUodD1lW2krK10pdD09PWVbaV0mJihyPW4ucHVzaChpKSk7d2hpbGUoci0tKWhlLmNhbGwoZSxuW3JdLDEpfXJldHVybiBvPW51bGwsZX0sY2UuZm4udW5pcXVlU29ydD1mdW5jdGlvbigpe3JldHVybiB0aGlzLnB1c2hTdGFjayhjZS51bmlxdWVTb3J0KGFlLmFwcGx5KHRoaXMpKSl9LChiPWNlLmV4cHI9e2NhY2hlTGVuZ3RoOjUwLGNyZWF0ZVBzZXVkbzpGLG1hdGNoOkQsYXR0ckhhbmRsZTp7fSxmaW5kOnt9LHJlbGF0aXZlOnsiPiI6e2RpcjoicGFyZW50Tm9kZSIsZmlyc3Q6ITB9LCIgIjp7ZGlyOiJwYXJlbnROb2RlIn0sIisiOntkaXI6InByZXZpb3VzU2libGluZyIsZmlyc3Q6ITB9LCJ+Ijp7ZGlyOiJwcmV2aW91c1NpYmxpbmcifX0scHJlRmlsdGVyOntBVFRSOmZ1bmN0aW9uKGUpe3JldHVybiBlWzFdPWVbMV0ucmVwbGFjZShPLFApLGVbM109KGVbM118fGVbNF18fGVbNV18fCIiKS5yZXBsYWNlKE8sUCksIn49Ij09PWVbMl0mJihlWzNdPSIgIitlWzNdKyIgIiksZS5zbGljZSgwLDQpfSxDSElMRDpmdW5jdGlvbihlKXtyZXR1cm4gZVsxXT1lWzFdLnRvTG93ZXJDYXNlKCksIm50aCI9PT1lWzFdLnNsaWNlKDAsMyk/KGVbM118fEkuZXJyb3IoZVswXSksZVs0XT0rKGVbNF0/ZVs1XSsoZVs2XXx8MSk6MiooImV2ZW4iPT09ZVszXXx8Im9kZCI9PT1lWzNdKSksZVs1XT0rKGVbN10rZVs4XXx8Im9kZCI9PT1lWzNdKSk6ZVszXSYmSS5lcnJvcihlWzBdKSxlfSxQU0VVRE86ZnVuY3Rpb24oZSl7dmFyIHQsbj0hZVs2XSYmZVsyXTtyZXR1cm4gRC5DSElMRC50ZXN0KGVbMF0pP251bGw6KGVbM10/ZVsyXT1lWzRdfHxlWzVdfHwiIjpuJiZqLnRlc3QobikmJih0PVkobiwhMCkpJiYodD1uLmluZGV4T2YoIikiLG4ubGVuZ3RoLXQpLW4ubGVuZ3RoKSYmKGVbMF09ZVswXS5zbGljZSgwLHQpLGVbMl09bi5zbGljZSgwLHQpKSxlLnNsaWNlKDAsMykpfX0sZmlsdGVyOntUQUc6ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5yZXBsYWNlKE8sUCkudG9Mb3dlckNhc2UoKTtyZXR1cm4iKiI9PT1lP2Z1bmN0aW9uKCl7cmV0dXJuITB9OmZ1bmN0aW9uKGUpe3JldHVybiBmZShlLHQpfX0sQ0xBU1M6ZnVuY3Rpb24oZSl7dmFyIHQ9c1tlKyIgIl07cmV0dXJuIHR8fCh0PW5ldyBSZWdFeHAoIihefCIrZ2UrIikiK2UrIigiK2dlKyJ8JCkiKSkmJnMoZSxmdW5jdGlvbihlKXtyZXR1cm4gdC50ZXN0KCJzdHJpbmciPT10eXBlb2YgZS5jbGFzc05hbWUmJmUuY2xhc3NOYW1lfHwidW5kZWZpbmVkIiE9dHlwZW9mIGUuZ2V0QXR0cmlidXRlJiZlLmdldEF0dHJpYnV0ZSgiY2xhc3MiKXx8IiIpfSl9LEFUVFI6ZnVuY3Rpb24obixyLGkpe3JldHVybiBmdW5jdGlvbihlKXt2YXIgdD1JLmF0dHIoZSxuKTtyZXR1cm4gbnVsbD09dD8iIT0iPT09cjohcnx8KHQrPSIiLCI9Ij09PXI/dD09PWk6IiE9Ij09PXI/dCE9PWk6Il49Ij09PXI/aSYmMD09PXQuaW5kZXhPZihpKToiKj0iPT09cj9pJiYtMTx0LmluZGV4T2YoaSk6IiQ9Ij09PXI/aSYmdC5zbGljZSgtaS5sZW5ndGgpPT09aToifj0iPT09cj8tMTwoIiAiK3QucmVwbGFjZSh2LCIgIikrIiAiKS5pbmRleE9mKGkpOiJ8PSI9PT1yJiYodD09PWl8fHQuc2xpY2UoMCxpLmxlbmd0aCsxKT09PWkrIi0iKSl9fSxDSElMRDpmdW5jdGlvbihkLGUsdCxoLGcpe3ZhciB2PSJudGgiIT09ZC5zbGljZSgwLDMpLHk9Imxhc3QiIT09ZC5zbGljZSgtNCksbT0ib2YtdHlwZSI9PT1lO3JldHVybiAxPT09aCYmMD09PWc/ZnVuY3Rpb24oZSl7cmV0dXJuISFlLnBhcmVudE5vZGV9OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG8sYSxzLHU9diE9PXk/Im5leHRTaWJsaW5nIjoicHJldmlvdXNTaWJsaW5nIixsPWUucGFyZW50Tm9kZSxjPW0mJmUubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxmPSFuJiYhbSxwPSExO2lmKGwpe2lmKHYpe3doaWxlKHUpe289ZTt3aGlsZShvPW9bdV0paWYobT9mZShvLGMpOjE9PT1vLm5vZGVUeXBlKXJldHVybiExO3M9dT0ib25seSI9PT1kJiYhcyYmIm5leHRTaWJsaW5nIn1yZXR1cm4hMH1pZihzPVt5P2wuZmlyc3RDaGlsZDpsLmxhc3RDaGlsZF0seSYmZil7cD0oYT0ocj0oaT1sW1NdfHwobFtTXT17fSkpW2RdfHxbXSlbMF09PT1FJiZyWzFdKSYmclsyXSxvPWEmJmwuY2hpbGROb2Rlc1thXTt3aGlsZShvPSsrYSYmbyYmb1t1XXx8KHA9YT0wKXx8cy5wb3AoKSlpZigxPT09by5ub2RlVHlwZSYmKytwJiZvPT09ZSl7aVtkXT1bRSxhLHBdO2JyZWFrfX1lbHNlIGlmKGYmJihwPWE9KHI9KGk9ZVtTXXx8KGVbU109e30pKVtkXXx8W10pWzBdPT09RSYmclsxXSksITE9PT1wKXdoaWxlKG89KythJiZvJiZvW3VdfHwocD1hPTApfHxzLnBvcCgpKWlmKChtP2ZlKG8sYyk6MT09PW8ubm9kZVR5cGUpJiYrK3AmJihmJiYoKGk9b1tTXXx8KG9bU109e30pKVtkXT1bRSxwXSksbz09PWUpKWJyZWFrO3JldHVybihwLT1nKT09PWh8fHAlaD09MCYmMDw9cC9ofX19LFBTRVVETzpmdW5jdGlvbihlLG8pe3ZhciB0LGE9Yi5wc2V1ZG9zW2VdfHxiLnNldEZpbHRlcnNbZS50b0xvd2VyQ2FzZSgpXXx8SS5lcnJvcigidW5zdXBwb3J0ZWQgcHNldWRvOiAiK2UpO3JldHVybiBhW1NdP2Eobyk6MTxhLmxlbmd0aD8odD1bZSxlLCIiLG9dLGIuc2V0RmlsdGVycy5oYXNPd25Qcm9wZXJ0eShlLnRvTG93ZXJDYXNlKCkpP0YoZnVuY3Rpb24oZSx0KXt2YXIgbixyPWEoZSxvKSxpPXIubGVuZ3RoO3doaWxlKGktLSllW249c2UuY2FsbChlLHJbaV0pXT0hKHRbbl09cltpXSl9KTpmdW5jdGlvbihlKXtyZXR1cm4gYShlLDAsdCl9KTphfX0scHNldWRvczp7bm90OkYoZnVuY3Rpb24oZSl7dmFyIHI9W10saT1bXSxzPW5lKGUucmVwbGFjZSh2ZSwiJDEiKSk7cmV0dXJuIHNbU10/RihmdW5jdGlvbihlLHQsbixyKXt2YXIgaSxvPXMoZSxudWxsLHIsW10pLGE9ZS5sZW5ndGg7d2hpbGUoYS0tKShpPW9bYV0pJiYoZVthXT0hKHRbYV09aSkpfSk6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiByWzBdPWUscyhyLG51bGwsbixpKSxyWzBdPW51bGwsIWkucG9wKCl9fSksaGFzOkYoZnVuY3Rpb24odCl7cmV0dXJuIGZ1bmN0aW9uKGUpe3JldHVybiAwPEkodCxlKS5sZW5ndGh9fSksY29udGFpbnM6RihmdW5jdGlvbih0KXtyZXR1cm4gdD10LnJlcGxhY2UoTyxQKSxmdW5jdGlvbihlKXtyZXR1cm4tMTwoZS50ZXh0Q29udGVudHx8Y2UudGV4dChlKSkuaW5kZXhPZih0KX19KSxsYW5nOkYoZnVuY3Rpb24obil7cmV0dXJuIEEudGVzdChufHwiIil8fEkuZXJyb3IoInVuc3VwcG9ydGVkIGxhbmc6ICIrbiksbj1uLnJlcGxhY2UoTyxQKS50b0xvd2VyQ2FzZSgpLGZ1bmN0aW9uKGUpe3ZhciB0O2Rve2lmKHQ9Qz9lLmxhbmc6ZS5nZXRBdHRyaWJ1dGUoInhtbDpsYW5nIil8fGUuZ2V0QXR0cmlidXRlKCJsYW5nIikpcmV0dXJuKHQ9dC50b0xvd2VyQ2FzZSgpKT09PW58fDA9PT10LmluZGV4T2YobisiLSIpfXdoaWxlKChlPWUucGFyZW50Tm9kZSkmJjE9PT1lLm5vZGVUeXBlKTtyZXR1cm4hMX19KSx0YXJnZXQ6ZnVuY3Rpb24oZSl7dmFyIHQ9aWUubG9jYXRpb24mJmllLmxvY2F0aW9uLmhhc2g7cmV0dXJuIHQmJnQuc2xpY2UoMSk9PT1lLmlkfSxyb290OmZ1bmN0aW9uKGUpe3JldHVybiBlPT09cn0sZm9jdXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT1mdW5jdGlvbigpe3RyeXtyZXR1cm4gVC5hY3RpdmVFbGVtZW50fWNhdGNoKGUpe319KCkmJlQuaGFzRm9jdXMoKSYmISEoZS50eXBlfHxlLmhyZWZ8fH5lLnRhYkluZGV4KX0sZW5hYmxlZDp6KCExKSxkaXNhYmxlZDp6KCEwKSxjaGVja2VkOmZ1bmN0aW9uKGUpe3JldHVybiBmZShlLCJpbnB1dCIpJiYhIWUuY2hlY2tlZHx8ZmUoZSwib3B0aW9uIikmJiEhZS5zZWxlY3RlZH0sc2VsZWN0ZWQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUucGFyZW50Tm9kZSYmZS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXgsITA9PT1lLnNlbGVjdGVkfSxlbXB0eTpmdW5jdGlvbihlKXtmb3IoZT1lLmZpcnN0Q2hpbGQ7ZTtlPWUubmV4dFNpYmxpbmcpaWYoZS5ub2RlVHlwZTw2KXJldHVybiExO3JldHVybiEwfSxwYXJlbnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIWIucHNldWRvcy5lbXB0eShlKX0saGVhZGVyOmZ1bmN0aW9uKGUpe3JldHVybiBxLnRlc3QoZS5ub2RlTmFtZSl9LGlucHV0OmZ1bmN0aW9uKGUpe3JldHVybiBOLnRlc3QoZS5ub2RlTmFtZSl9LGJ1dHRvbjpmdW5jdGlvbihlKXtyZXR1cm4gZmUoZSwiaW5wdXQiKSYmImJ1dHRvbiI9PT1lLnR5cGV8fGZlKGUsImJ1dHRvbiIpfSx0ZXh0OmZ1bmN0aW9uKGUpe3ZhciB0O3JldHVybiBmZShlLCJpbnB1dCIpJiYidGV4dCI9PT1lLnR5cGUmJihudWxsPT0odD1lLmdldEF0dHJpYnV0ZSgidHlwZSIpKXx8InRleHQiPT09dC50b0xvd2VyQ2FzZSgpKX0sZmlyc3Q6WChmdW5jdGlvbigpe3JldHVyblswXX0pLGxhc3Q6WChmdW5jdGlvbihlLHQpe3JldHVyblt0LTFdfSksZXE6WChmdW5jdGlvbihlLHQsbil7cmV0dXJuW248MD9uK3Q6bl19KSxldmVuOlgoZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49MDtuPHQ7bis9MillLnB1c2gobik7cmV0dXJuIGV9KSxvZGQ6WChmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj0xO248dDtuKz0yKWUucHVzaChuKTtyZXR1cm4gZX0pLGx0OlgoZnVuY3Rpb24oZSx0LG4pe3ZhciByO2ZvcihyPW48MD9uK3Q6dDxuP3Q6bjswPD0tLXI7KWUucHVzaChyKTtyZXR1cm4gZX0pLGd0OlgoZnVuY3Rpb24oZSx0LG4pe2Zvcih2YXIgcj1uPDA/bit0Om47KytyPHQ7KWUucHVzaChyKTtyZXR1cm4gZX0pfX0pLnBzZXVkb3MubnRoPWIucHNldWRvcy5lcSx7cmFkaW86ITAsY2hlY2tib3g6ITAsZmlsZTohMCxwYXNzd29yZDohMCxpbWFnZTohMH0pYi5wc2V1ZG9zW2VdPUIoZSk7Zm9yKGUgaW57c3VibWl0OiEwLHJlc2V0OiEwfSliLnBzZXVkb3NbZV09XyhlKTtmdW5jdGlvbiBHKCl7fWZ1bmN0aW9uIFkoZSx0KXt2YXIgbixyLGksbyxhLHMsdSxsPWNbZSsiICJdO2lmKGwpcmV0dXJuIHQ/MDpsLnNsaWNlKDApO2E9ZSxzPVtdLHU9Yi5wcmVGaWx0ZXI7d2hpbGUoYSl7Zm9yKG8gaW4gbiYmIShyPXkuZXhlYyhhKSl8fChyJiYoYT1hLnNsaWNlKHJbMF0ubGVuZ3RoKXx8YSkscy5wdXNoKGk9W10pKSxuPSExLChyPW0uZXhlYyhhKSkmJihuPXIuc2hpZnQoKSxpLnB1c2goe3ZhbHVlOm4sdHlwZTpyWzBdLnJlcGxhY2UodmUsIiAiKX0pLGE9YS5zbGljZShuLmxlbmd0aCkpLGIuZmlsdGVyKSEocj1EW29dLmV4ZWMoYSkpfHx1W29dJiYhKHI9dVtvXShyKSl8fChuPXIuc2hpZnQoKSxpLnB1c2goe3ZhbHVlOm4sdHlwZTpvLG1hdGNoZXM6cn0pLGE9YS5zbGljZShuLmxlbmd0aCkpO2lmKCFuKWJyZWFrfXJldHVybiB0P2EubGVuZ3RoOmE/SS5lcnJvcihlKTpjKGUscykuc2xpY2UoMCl9ZnVuY3Rpb24gUShlKXtmb3IodmFyIHQ9MCxuPWUubGVuZ3RoLHI9IiI7dDxuO3QrKylyKz1lW3RdLnZhbHVlO3JldHVybiByfWZ1bmN0aW9uIEooYSxlLHQpe3ZhciBzPWUuZGlyLHU9ZS5uZXh0LGw9dXx8cyxjPXQmJiJwYXJlbnROb2RlIj09PWwsZj1uKys7cmV0dXJuIGUuZmlyc3Q/ZnVuY3Rpb24oZSx0LG4pe3doaWxlKGU9ZVtzXSlpZigxPT09ZS5ub2RlVHlwZXx8YylyZXR1cm4gYShlLHQsbik7cmV0dXJuITF9OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG89W0UsZl07aWYobil7d2hpbGUoZT1lW3NdKWlmKCgxPT09ZS5ub2RlVHlwZXx8YykmJmEoZSx0LG4pKXJldHVybiEwfWVsc2Ugd2hpbGUoZT1lW3NdKWlmKDE9PT1lLm5vZGVUeXBlfHxjKWlmKGk9ZVtTXXx8KGVbU109e30pLHUmJmZlKGUsdSkpZT1lW3NdfHxlO2Vsc2V7aWYoKHI9aVtsXSkmJnJbMF09PT1FJiZyWzFdPT09ZilyZXR1cm4gb1syXT1yWzJdO2lmKChpW2xdPW8pWzJdPWEoZSx0LG4pKXJldHVybiEwfXJldHVybiExfX1mdW5jdGlvbiBLKGkpe3JldHVybiAxPGkubGVuZ3RoP2Z1bmN0aW9uKGUsdCxuKXt2YXIgcj1pLmxlbmd0aDt3aGlsZShyLS0paWYoIWlbcl0oZSx0LG4pKXJldHVybiExO3JldHVybiEwfTppWzBdfWZ1bmN0aW9uIFooZSx0LG4scixpKXtmb3IodmFyIG8sYT1bXSxzPTAsdT1lLmxlbmd0aCxsPW51bGwhPXQ7czx1O3MrKykobz1lW3NdKSYmKG4mJiFuKG8scixpKXx8KGEucHVzaChvKSxsJiZ0LnB1c2gocykpKTtyZXR1cm4gYX1mdW5jdGlvbiBlZShkLGgsZyx2LHksZSl7cmV0dXJuIHYmJiF2W1NdJiYodj1lZSh2KSkseSYmIXlbU10mJih5PWVlKHksZSkpLEYoZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbyxhLHMsdT1bXSxsPVtdLGM9dC5sZW5ndGgsZj1lfHxmdW5jdGlvbihlLHQsbil7Zm9yKHZhciByPTAsaT10Lmxlbmd0aDtyPGk7cisrKUkoZSx0W3JdLG4pO3JldHVybiBufShofHwiKiIsbi5ub2RlVHlwZT9bbl06bixbXSkscD0hZHx8IWUmJmg/ZjpaKGYsdSxkLG4scik7aWYoZz9nKHAscz15fHwoZT9kOmN8fHYpP1tdOnQsbixyKTpzPXAsdil7aT1aKHMsbCksdihpLFtdLG4sciksbz1pLmxlbmd0aDt3aGlsZShvLS0pKGE9aVtvXSkmJihzW2xbb11dPSEocFtsW29dXT1hKSl9aWYoZSl7aWYoeXx8ZCl7aWYoeSl7aT1bXSxvPXMubGVuZ3RoO3doaWxlKG8tLSkoYT1zW29dKSYmaS5wdXNoKHBbb109YSk7eShudWxsLHM9W10saSxyKX1vPXMubGVuZ3RoO3doaWxlKG8tLSkoYT1zW29dKSYmLTE8KGk9eT9zZS5jYWxsKGUsYSk6dVtvXSkmJihlW2ldPSEodFtpXT1hKSl9fWVsc2Ugcz1aKHM9PT10P3Muc3BsaWNlKGMscy5sZW5ndGgpOnMpLHk/eShudWxsLHQscyxyKTprLmFwcGx5KHQscyl9KX1mdW5jdGlvbiB0ZShlKXtmb3IodmFyIGksdCxuLHI9ZS5sZW5ndGgsbz1iLnJlbGF0aXZlW2VbMF0udHlwZV0sYT1vfHxiLnJlbGF0aXZlWyIgIl0scz1vPzE6MCx1PUooZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT1pfSxhLCEwKSxsPUooZnVuY3Rpb24oZSl7cmV0dXJuLTE8c2UuY2FsbChpLGUpfSxhLCEwKSxjPVtmdW5jdGlvbihlLHQsbil7dmFyIHI9IW8mJihufHx0IT13KXx8KChpPXQpLm5vZGVUeXBlP3UoZSx0LG4pOmwoZSx0LG4pKTtyZXR1cm4gaT1udWxsLHJ9XTtzPHI7cysrKWlmKHQ9Yi5yZWxhdGl2ZVtlW3NdLnR5cGVdKWM9W0ooSyhjKSx0KV07ZWxzZXtpZigodD1iLmZpbHRlcltlW3NdLnR5cGVdLmFwcGx5KG51bGwsZVtzXS5tYXRjaGVzKSlbU10pe2ZvcihuPSsrcztuPHI7bisrKWlmKGIucmVsYXRpdmVbZVtuXS50eXBlXSlicmVhaztyZXR1cm4gZWUoMTxzJiZLKGMpLDE8cyYmUShlLnNsaWNlKDAscy0xKS5jb25jYXQoe3ZhbHVlOiIgIj09PWVbcy0yXS50eXBlPyIqIjoiIn0pKS5yZXBsYWNlKHZlLCIkMSIpLHQsczxuJiZ0ZShlLnNsaWNlKHMsbikpLG48ciYmdGUoZT1lLnNsaWNlKG4pKSxuPHImJlEoZSkpfWMucHVzaCh0KX1yZXR1cm4gSyhjKX1mdW5jdGlvbiBuZShlLHQpe3ZhciBuLHYseSxtLHgscixpPVtdLG89W10sYT11W2UrIiAiXTtpZighYSl7dHx8KHQ9WShlKSksbj10Lmxlbmd0aDt3aGlsZShuLS0pKGE9dGUodFtuXSkpW1NdP2kucHVzaChhKTpvLnB1c2goYSk7KGE9dShlLCh2PW8sbT0wPCh5PWkpLmxlbmd0aCx4PTA8di5sZW5ndGgscj1mdW5jdGlvbihlLHQsbixyLGkpe3ZhciBvLGEscyx1PTAsbD0iMCIsYz1lJiZbXSxmPVtdLHA9dyxkPWV8fHgmJmIuZmluZC5UQUcoIioiLGkpLGg9RSs9bnVsbD09cD8xOk1hdGgucmFuZG9tKCl8fC4xLGc9ZC5sZW5ndGg7Zm9yKGkmJih3PXQ9PVR8fHR8fGkpO2whPT1nJiZudWxsIT0obz1kW2xdKTtsKyspe2lmKHgmJm8pe2E9MCx0fHxvLm93bmVyRG9jdW1lbnQ9PVR8fChWKG8pLG49IUMpO3doaWxlKHM9dlthKytdKWlmKHMobyx0fHxULG4pKXtrLmNhbGwocixvKTticmVha31pJiYoRT1oKX1tJiYoKG89IXMmJm8pJiZ1LS0sZSYmYy5wdXNoKG8pKX1pZih1Kz1sLG0mJmwhPT11KXthPTA7d2hpbGUocz15W2ErK10pcyhjLGYsdCxuKTtpZihlKXtpZigwPHUpd2hpbGUobC0tKWNbbF18fGZbbF18fChmW2xdPXBlLmNhbGwocikpO2Y9WihmKX1rLmFwcGx5KHIsZiksaSYmIWUmJjA8Zi5sZW5ndGgmJjE8dSt5Lmxlbmd0aCYmY2UudW5pcXVlU29ydChyKX1yZXR1cm4gaSYmKEU9aCx3PXApLGN9LG0/RihyKTpyKSkpLnNlbGVjdG9yPWV9cmV0dXJuIGF9ZnVuY3Rpb24gcmUoZSx0LG4scil7dmFyIGksbyxhLHMsdSxsPSJmdW5jdGlvbiI9PXR5cGVvZiBlJiZlLGM9IXImJlkoZT1sLnNlbGVjdG9yfHxlKTtpZihuPW58fFtdLDE9PT1jLmxlbmd0aCl7aWYoMjwobz1jWzBdPWNbMF0uc2xpY2UoMCkpLmxlbmd0aCYmIklEIj09PShhPW9bMF0pLnR5cGUmJjk9PT10Lm5vZGVUeXBlJiZDJiZiLnJlbGF0aXZlW29bMV0udHlwZV0pe2lmKCEodD0oYi5maW5kLklEKGEubWF0Y2hlc1swXS5yZXBsYWNlKE8sUCksdCl8fFtdKVswXSkpcmV0dXJuIG47bCYmKHQ9dC5wYXJlbnROb2RlKSxlPWUuc2xpY2Uoby5zaGlmdCgpLnZhbHVlLmxlbmd0aCl9aT1ELm5lZWRzQ29udGV4dC50ZXN0KGUpPzA6by5sZW5ndGg7d2hpbGUoaS0tKXtpZihhPW9baV0sYi5yZWxhdGl2ZVtzPWEudHlwZV0pYnJlYWs7aWYoKHU9Yi5maW5kW3NdKSYmKHI9dShhLm1hdGNoZXNbMF0ucmVwbGFjZShPLFApLEgudGVzdChvWzBdLnR5cGUpJiZVKHQucGFyZW50Tm9kZSl8fHQpKSl7aWYoby5zcGxpY2UoaSwxKSwhKGU9ci5sZW5ndGgmJlEobykpKXJldHVybiBrLmFwcGx5KG4sciksbjticmVha319fXJldHVybihsfHxuZShlLGMpKShyLHQsIUMsbiwhdHx8SC50ZXN0KGUpJiZVKHQucGFyZW50Tm9kZSl8fHQpLG59Ry5wcm90b3R5cGU9Yi5maWx0ZXJzPWIucHNldWRvcyxiLnNldEZpbHRlcnM9bmV3IEcsbGUuc29ydFN0YWJsZT1TLnNwbGl0KCIiKS5zb3J0KGwpLmpvaW4oIiIpPT09UyxWKCksbGUuc29ydERldGFjaGVkPSQoZnVuY3Rpb24oZSl7cmV0dXJuIDEmZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihULmNyZWF0ZUVsZW1lbnQoImZpZWxkc2V0IikpfSksY2UuZmluZD1JLGNlLmV4cHJbIjoiXT1jZS5leHByLnBzZXVkb3MsY2UudW5pcXVlPWNlLnVuaXF1ZVNvcnQsSS5jb21waWxlPW5lLEkuc2VsZWN0PXJlLEkuc2V0RG9jdW1lbnQ9VixJLnRva2VuaXplPVksSS5lc2NhcGU9Y2UuZXNjYXBlU2VsZWN0b3IsSS5nZXRUZXh0PWNlLnRleHQsSS5pc1hNTD1jZS5pc1hNTERvYyxJLnNlbGVjdG9ycz1jZS5leHByLEkuc3VwcG9ydD1jZS5zdXBwb3J0LEkudW5pcXVlU29ydD1jZS51bmlxdWVTb3J0fSgpO3ZhciBkPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1bXSxpPXZvaWQgMCE9PW47d2hpbGUoKGU9ZVt0XSkmJjkhPT1lLm5vZGVUeXBlKWlmKDE9PT1lLm5vZGVUeXBlKXtpZihpJiZjZShlKS5pcyhuKSlicmVhaztyLnB1c2goZSl9cmV0dXJuIHJ9LGg9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49W107ZTtlPWUubmV4dFNpYmxpbmcpMT09PWUubm9kZVR5cGUmJmUhPT10JiZuLnB1c2goZSk7cmV0dXJuIG59LGI9Y2UuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQsdz0vXjwoW2Etel1bXlwvXDA+Olx4MjBcdFxyXG5cZl0qKVtceDIwXHRcclxuXGZdKlwvPz4oPzo8XC9cMT58KSQvaTtmdW5jdGlvbiBUKGUsbixyKXtyZXR1cm4gdihuKT9jZS5ncmVwKGUsZnVuY3Rpb24oZSx0KXtyZXR1cm4hIW4uY2FsbChlLHQsZSkhPT1yfSk6bi5ub2RlVHlwZT9jZS5ncmVwKGUsZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT1uIT09cn0pOiJzdHJpbmciIT10eXBlb2Ygbj9jZS5ncmVwKGUsZnVuY3Rpb24oZSl7cmV0dXJuLTE8c2UuY2FsbChuLGUpIT09cn0pOmNlLmZpbHRlcihuLGUscil9Y2UuZmlsdGVyPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10WzBdO3JldHVybiBuJiYoZT0iOm5vdCgiK2UrIikiKSwxPT09dC5sZW5ndGgmJjE9PT1yLm5vZGVUeXBlP2NlLmZpbmQubWF0Y2hlc1NlbGVjdG9yKHIsZSk/W3JdOltdOmNlLmZpbmQubWF0Y2hlcyhlLGNlLmdyZXAodCxmdW5jdGlvbihlKXtyZXR1cm4gMT09PWUubm9kZVR5cGV9KSl9LGNlLmZuLmV4dGVuZCh7ZmluZDpmdW5jdGlvbihlKXt2YXIgdCxuLHI9dGhpcy5sZW5ndGgsaT10aGlzO2lmKCJzdHJpbmciIT10eXBlb2YgZSlyZXR1cm4gdGhpcy5wdXNoU3RhY2soY2UoZSkuZmlsdGVyKGZ1bmN0aW9uKCl7Zm9yKHQ9MDt0PHI7dCsrKWlmKGNlLmNvbnRhaW5zKGlbdF0sdGhpcykpcmV0dXJuITB9KSk7Zm9yKG49dGhpcy5wdXNoU3RhY2soW10pLHQ9MDt0PHI7dCsrKWNlLmZpbmQoZSxpW3RdLG4pO3JldHVybiAxPHI/Y2UudW5pcXVlU29ydChuKTpufSxmaWx0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucHVzaFN0YWNrKFQodGhpcyxlfHxbXSwhMSkpfSxub3Q6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucHVzaFN0YWNrKFQodGhpcyxlfHxbXSwhMCkpfSxpczpmdW5jdGlvbihlKXtyZXR1cm4hIVQodGhpcywic3RyaW5nIj09dHlwZW9mIGUmJmIudGVzdChlKT9jZShlKTplfHxbXSwhMSkubGVuZ3RofX0pO3ZhciBrLFM9L14oPzpccyooPFtcd1xXXSs+KVtePl0qfCMoW1x3LV0rKSkkLzsoY2UuZm4uaW5pdD1mdW5jdGlvbihlLHQsbil7dmFyIHIsaTtpZighZSlyZXR1cm4gdGhpcztpZihuPW58fGssInN0cmluZyI9PXR5cGVvZiBlKXtpZighKHI9IjwiPT09ZVswXSYmIj4iPT09ZVtlLmxlbmd0aC0xXSYmMzw9ZS5sZW5ndGg/W251bGwsZSxudWxsXTpTLmV4ZWMoZSkpfHwhclsxXSYmdClyZXR1cm4hdHx8dC5qcXVlcnk/KHR8fG4pLmZpbmQoZSk6dGhpcy5jb25zdHJ1Y3Rvcih0KS5maW5kKGUpO2lmKHJbMV0pe2lmKHQ9dCBpbnN0YW5jZW9mIGNlP3RbMF06dCxjZS5tZXJnZSh0aGlzLGNlLnBhcnNlSFRNTChyWzFdLHQmJnQubm9kZVR5cGU/dC5vd25lckRvY3VtZW50fHx0OkMsITApKSx3LnRlc3QoclsxXSkmJmNlLmlzUGxhaW5PYmplY3QodCkpZm9yKHIgaW4gdCl2KHRoaXNbcl0pP3RoaXNbcl0odFtyXSk6dGhpcy5hdHRyKHIsdFtyXSk7cmV0dXJuIHRoaXN9cmV0dXJuKGk9Qy5nZXRFbGVtZW50QnlJZChyWzJdKSkmJih0aGlzWzBdPWksdGhpcy5sZW5ndGg9MSksdGhpc31yZXR1cm4gZS5ub2RlVHlwZT8odGhpc1swXT1lLHRoaXMubGVuZ3RoPTEsdGhpcyk6dihlKT92b2lkIDAhPT1uLnJlYWR5P24ucmVhZHkoZSk6ZShjZSk6Y2UubWFrZUFycmF5KGUsdGhpcyl9KS5wcm90b3R5cGU9Y2UuZm4saz1jZShDKTt2YXIgRT0vXig/OnBhcmVudHN8cHJldig/OlVudGlsfEFsbCkpLyxqPXtjaGlsZHJlbjohMCxjb250ZW50czohMCxuZXh0OiEwLHByZXY6ITB9O2Z1bmN0aW9uIEEoZSx0KXt3aGlsZSgoZT1lW3RdKSYmMSE9PWUubm9kZVR5cGUpO3JldHVybiBlfWNlLmZuLmV4dGVuZCh7aGFzOmZ1bmN0aW9uKGUpe3ZhciB0PWNlKGUsdGhpcyksbj10Lmxlbmd0aDtyZXR1cm4gdGhpcy5maWx0ZXIoZnVuY3Rpb24oKXtmb3IodmFyIGU9MDtlPG47ZSsrKWlmKGNlLmNvbnRhaW5zKHRoaXMsdFtlXSkpcmV0dXJuITB9KX0sY2xvc2VzdDpmdW5jdGlvbihlLHQpe3ZhciBuLHI9MCxpPXRoaXMubGVuZ3RoLG89W10sYT0ic3RyaW5nIiE9dHlwZW9mIGUmJmNlKGUpO2lmKCFiLnRlc3QoZSkpZm9yKDtyPGk7cisrKWZvcihuPXRoaXNbcl07biYmbiE9PXQ7bj1uLnBhcmVudE5vZGUpaWYobi5ub2RlVHlwZTwxMSYmKGE/LTE8YS5pbmRleChuKToxPT09bi5ub2RlVHlwZSYmY2UuZmluZC5tYXRjaGVzU2VsZWN0b3IobixlKSkpe28ucHVzaChuKTticmVha31yZXR1cm4gdGhpcy5wdXNoU3RhY2soMTxvLmxlbmd0aD9jZS51bmlxdWVTb3J0KG8pOm8pfSxpbmRleDpmdW5jdGlvbihlKXtyZXR1cm4gZT8ic3RyaW5nIj09dHlwZW9mIGU/c2UuY2FsbChjZShlKSx0aGlzWzBdKTpzZS5jYWxsKHRoaXMsZS5qcXVlcnk/ZVswXTplKTp0aGlzWzBdJiZ0aGlzWzBdLnBhcmVudE5vZGU/dGhpcy5maXJzdCgpLnByZXZBbGwoKS5sZW5ndGg6LTF9LGFkZDpmdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLnB1c2hTdGFjayhjZS51bmlxdWVTb3J0KGNlLm1lcmdlKHRoaXMuZ2V0KCksY2UoZSx0KSkpKX0sYWRkQmFjazpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5hZGQobnVsbD09ZT90aGlzLnByZXZPYmplY3Q6dGhpcy5wcmV2T2JqZWN0LmZpbHRlcihlKSl9fSksY2UuZWFjaCh7cGFyZW50OmZ1bmN0aW9uKGUpe3ZhciB0PWUucGFyZW50Tm9kZTtyZXR1cm4gdCYmMTEhPT10Lm5vZGVUeXBlP3Q6bnVsbH0scGFyZW50czpmdW5jdGlvbihlKXtyZXR1cm4gZChlLCJwYXJlbnROb2RlIil9LHBhcmVudHNVbnRpbDpmdW5jdGlvbihlLHQsbil7cmV0dXJuIGQoZSwicGFyZW50Tm9kZSIsbil9LG5leHQ6ZnVuY3Rpb24oZSl7cmV0dXJuIEEoZSwibmV4dFNpYmxpbmciKX0scHJldjpmdW5jdGlvbihlKXtyZXR1cm4gQShlLCJwcmV2aW91c1NpYmxpbmciKX0sbmV4dEFsbDpmdW5jdGlvbihlKXtyZXR1cm4gZChlLCJuZXh0U2libGluZyIpfSxwcmV2QWxsOmZ1bmN0aW9uKGUpe3JldHVybiBkKGUsInByZXZpb3VzU2libGluZyIpfSxuZXh0VW50aWw6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBkKGUsIm5leHRTaWJsaW5nIixuKX0scHJldlVudGlsOmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZChlLCJwcmV2aW91c1NpYmxpbmciLG4pfSxzaWJsaW5nczpmdW5jdGlvbihlKXtyZXR1cm4gaCgoZS5wYXJlbnROb2RlfHx7fSkuZmlyc3RDaGlsZCxlKX0sY2hpbGRyZW46ZnVuY3Rpb24oZSl7cmV0dXJuIGgoZS5maXJzdENoaWxkKX0sY29udGVudHM6ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGwhPWUuY29udGVudERvY3VtZW50JiZyKGUuY29udGVudERvY3VtZW50KT9lLmNvbnRlbnREb2N1bWVudDooZmUoZSwidGVtcGxhdGUiKSYmKGU9ZS5jb250ZW50fHxlKSxjZS5tZXJnZShbXSxlLmNoaWxkTm9kZXMpKX19LGZ1bmN0aW9uKHIsaSl7Y2UuZm5bcl09ZnVuY3Rpb24oZSx0KXt2YXIgbj1jZS5tYXAodGhpcyxpLGUpO3JldHVybiJVbnRpbCIhPT1yLnNsaWNlKC01KSYmKHQ9ZSksdCYmInN0cmluZyI9PXR5cGVvZiB0JiYobj1jZS5maWx0ZXIodCxuKSksMTx0aGlzLmxlbmd0aCYmKGpbcl18fGNlLnVuaXF1ZVNvcnQobiksRS50ZXN0KHIpJiZuLnJldmVyc2UoKSksdGhpcy5wdXNoU3RhY2sobil9fSk7dmFyIEQ9L1teXHgyMFx0XHJcblxmXSsvZztmdW5jdGlvbiBOKGUpe3JldHVybiBlfWZ1bmN0aW9uIHEoZSl7dGhyb3cgZX1mdW5jdGlvbiBMKGUsdCxuLHIpe3ZhciBpO3RyeXtlJiZ2KGk9ZS5wcm9taXNlKT9pLmNhbGwoZSkuZG9uZSh0KS5mYWlsKG4pOmUmJnYoaT1lLnRoZW4pP2kuY2FsbChlLHQsbik6dC5hcHBseSh2b2lkIDAsW2VdLnNsaWNlKHIpKX1jYXRjaChlKXtuLmFwcGx5KHZvaWQgMCxbZV0pfX1jZS5DYWxsYmFja3M9ZnVuY3Rpb24ocil7dmFyIGUsbjtyPSJzdHJpbmciPT10eXBlb2Ygcj8oZT1yLG49e30sY2UuZWFjaChlLm1hdGNoKEQpfHxbXSxmdW5jdGlvbihlLHQpe25bdF09ITB9KSxuKTpjZS5leHRlbmQoe30scik7dmFyIGksdCxvLGEscz1bXSx1PVtdLGw9LTEsYz1mdW5jdGlvbigpe2ZvcihhPWF8fHIub25jZSxvPWk9ITA7dS5sZW5ndGg7bD0tMSl7dD11LnNoaWZ0KCk7d2hpbGUoKytsPHMubGVuZ3RoKSExPT09c1tsXS5hcHBseSh0WzBdLHRbMV0pJiZyLnN0b3BPbkZhbHNlJiYobD1zLmxlbmd0aCx0PSExKX1yLm1lbW9yeXx8KHQ9ITEpLGk9ITEsYSYmKHM9dD9bXToiIil9LGY9e2FkZDpmdW5jdGlvbigpe3JldHVybiBzJiYodCYmIWkmJihsPXMubGVuZ3RoLTEsdS5wdXNoKHQpKSxmdW5jdGlvbiBuKGUpe2NlLmVhY2goZSxmdW5jdGlvbihlLHQpe3YodCk/ci51bmlxdWUmJmYuaGFzKHQpfHxzLnB1c2godCk6dCYmdC5sZW5ndGgmJiJzdHJpbmciIT09eCh0KSYmbih0KX0pfShhcmd1bWVudHMpLHQmJiFpJiZjKCkpLHRoaXN9LHJlbW92ZTpmdW5jdGlvbigpe3JldHVybiBjZS5lYWNoKGFyZ3VtZW50cyxmdW5jdGlvbihlLHQpe3ZhciBuO3doaWxlKC0xPChuPWNlLmluQXJyYXkodCxzLG4pKSlzLnNwbGljZShuLDEpLG48PWwmJmwtLX0pLHRoaXN9LGhhczpmdW5jdGlvbihlKXtyZXR1cm4gZT8tMTxjZS5pbkFycmF5KGUscyk6MDxzLmxlbmd0aH0sZW1wdHk6ZnVuY3Rpb24oKXtyZXR1cm4gcyYmKHM9W10pLHRoaXN9LGRpc2FibGU6ZnVuY3Rpb24oKXtyZXR1cm4gYT11PVtdLHM9dD0iIix0aGlzfSxkaXNhYmxlZDpmdW5jdGlvbigpe3JldHVybiFzfSxsb2NrOmZ1bmN0aW9uKCl7cmV0dXJuIGE9dT1bXSx0fHxpfHwocz10PSIiKSx0aGlzfSxsb2NrZWQ6ZnVuY3Rpb24oKXtyZXR1cm4hIWF9LGZpcmVXaXRoOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGF8fCh0PVtlLCh0PXR8fFtdKS5zbGljZT90LnNsaWNlKCk6dF0sdS5wdXNoKHQpLGl8fGMoKSksdGhpc30sZmlyZTpmdW5jdGlvbigpe3JldHVybiBmLmZpcmVXaXRoKHRoaXMsYXJndW1lbnRzKSx0aGlzfSxmaXJlZDpmdW5jdGlvbigpe3JldHVybiEhb319O3JldHVybiBmfSxjZS5leHRlbmQoe0RlZmVycmVkOmZ1bmN0aW9uKGUpe3ZhciBvPVtbIm5vdGlmeSIsInByb2dyZXNzIixjZS5DYWxsYmFja3MoIm1lbW9yeSIpLGNlLkNhbGxiYWNrcygibWVtb3J5IiksMl0sWyJyZXNvbHZlIiwiZG9uZSIsY2UuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLGNlLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwwLCJyZXNvbHZlZCJdLFsicmVqZWN0IiwiZmFpbCIsY2UuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLGNlLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwxLCJyZWplY3RlZCJdXSxpPSJwZW5kaW5nIixhPXtzdGF0ZTpmdW5jdGlvbigpe3JldHVybiBpfSxhbHdheXM6ZnVuY3Rpb24oKXtyZXR1cm4gcy5kb25lKGFyZ3VtZW50cykuZmFpbChhcmd1bWVudHMpLHRoaXN9LCJjYXRjaCI6ZnVuY3Rpb24oZSl7cmV0dXJuIGEudGhlbihudWxsLGUpfSxwaXBlOmZ1bmN0aW9uKCl7dmFyIGk9YXJndW1lbnRzO3JldHVybiBjZS5EZWZlcnJlZChmdW5jdGlvbihyKXtjZS5lYWNoKG8sZnVuY3Rpb24oZSx0KXt2YXIgbj12KGlbdFs0XV0pJiZpW3RbNF1dO3NbdFsxXV0oZnVuY3Rpb24oKXt2YXIgZT1uJiZuLmFwcGx5KHRoaXMsYXJndW1lbnRzKTtlJiZ2KGUucHJvbWlzZSk/ZS5wcm9taXNlKCkucHJvZ3Jlc3Moci5ub3RpZnkpLmRvbmUoci5yZXNvbHZlKS5mYWlsKHIucmVqZWN0KTpyW3RbMF0rIldpdGgiXSh0aGlzLG4/W2VdOmFyZ3VtZW50cyl9KX0pLGk9bnVsbH0pLnByb21pc2UoKX0sdGhlbjpmdW5jdGlvbih0LG4scil7dmFyIHU9MDtmdW5jdGlvbiBsKGksbyxhLHMpe3JldHVybiBmdW5jdGlvbigpe3ZhciBuPXRoaXMscj1hcmd1bWVudHMsZT1mdW5jdGlvbigpe3ZhciBlLHQ7aWYoIShpPHUpKXtpZigoZT1hLmFwcGx5KG4scikpPT09by5wcm9taXNlKCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhlbmFibGUgc2VsZi1yZXNvbHV0aW9uIik7dD1lJiYoIm9iamVjdCI9PXR5cGVvZiBlfHwiZnVuY3Rpb24iPT10eXBlb2YgZSkmJmUudGhlbix2KHQpP3M/dC5jYWxsKGUsbCh1LG8sTixzKSxsKHUsbyxxLHMpKToodSsrLHQuY2FsbChlLGwodSxvLE4scyksbCh1LG8scSxzKSxsKHUsbyxOLG8ubm90aWZ5V2l0aCkpKTooYSE9PU4mJihuPXZvaWQgMCxyPVtlXSksKHN8fG8ucmVzb2x2ZVdpdGgpKG4scikpfX0sdD1zP2U6ZnVuY3Rpb24oKXt0cnl7ZSgpfWNhdGNoKGUpe2NlLkRlZmVycmVkLmV4Y2VwdGlvbkhvb2smJmNlLkRlZmVycmVkLmV4Y2VwdGlvbkhvb2soZSx0LmVycm9yKSx1PD1pKzEmJihhIT09cSYmKG49dm9pZCAwLHI9W2VdKSxvLnJlamVjdFdpdGgobixyKSl9fTtpP3QoKTooY2UuRGVmZXJyZWQuZ2V0RXJyb3JIb29rP3QuZXJyb3I9Y2UuRGVmZXJyZWQuZ2V0RXJyb3JIb29rKCk6Y2UuRGVmZXJyZWQuZ2V0U3RhY2tIb29rJiYodC5lcnJvcj1jZS5EZWZlcnJlZC5nZXRTdGFja0hvb2soKSksaWUuc2V0VGltZW91dCh0KSl9fXJldHVybiBjZS5EZWZlcnJlZChmdW5jdGlvbihlKXtvWzBdWzNdLmFkZChsKDAsZSx2KHIpP3I6TixlLm5vdGlmeVdpdGgpKSxvWzFdWzNdLmFkZChsKDAsZSx2KHQpP3Q6TikpLG9bMl1bM10uYWRkKGwoMCxlLHYobik/bjpxKSl9KS5wcm9taXNlKCl9LHByb21pc2U6ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGwhPWU/Y2UuZXh0ZW5kKGUsYSk6YX19LHM9e307cmV0dXJuIGNlLmVhY2gobyxmdW5jdGlvbihlLHQpe3ZhciBuPXRbMl0scj10WzVdO2FbdFsxXV09bi5hZGQsciYmbi5hZGQoZnVuY3Rpb24oKXtpPXJ9LG9bMy1lXVsyXS5kaXNhYmxlLG9bMy1lXVszXS5kaXNhYmxlLG9bMF1bMl0ubG9jayxvWzBdWzNdLmxvY2spLG4uYWRkKHRbM10uZmlyZSksc1t0WzBdXT1mdW5jdGlvbigpe3JldHVybiBzW3RbMF0rIldpdGgiXSh0aGlzPT09cz92b2lkIDA6dGhpcyxhcmd1bWVudHMpLHRoaXN9LHNbdFswXSsiV2l0aCJdPW4uZmlyZVdpdGh9KSxhLnByb21pc2UocyksZSYmZS5jYWxsKHMscyksc30sd2hlbjpmdW5jdGlvbihlKXt2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHQ9bixyPUFycmF5KHQpLGk9YWUuY2FsbChhcmd1bWVudHMpLG89Y2UuRGVmZXJyZWQoKSxhPWZ1bmN0aW9uKHQpe3JldHVybiBmdW5jdGlvbihlKXtyW3RdPXRoaXMsaVt0XT0xPGFyZ3VtZW50cy5sZW5ndGg/YWUuY2FsbChhcmd1bWVudHMpOmUsLS1ufHxvLnJlc29sdmVXaXRoKHIsaSl9fTtpZihuPD0xJiYoTChlLG8uZG9uZShhKHQpKS5yZXNvbHZlLG8ucmVqZWN0LCFuKSwicGVuZGluZyI9PT1vLnN0YXRlKCl8fHYoaVt0XSYmaVt0XS50aGVuKSkpcmV0dXJuIG8udGhlbigpO3doaWxlKHQtLSlMKGlbdF0sYSh0KSxvLnJlamVjdCk7cmV0dXJuIG8ucHJvbWlzZSgpfX0pO3ZhciBIPS9eKEV2YWx8SW50ZXJuYWx8UmFuZ2V8UmVmZXJlbmNlfFN5bnRheHxUeXBlfFVSSSlFcnJvciQvO2NlLkRlZmVycmVkLmV4Y2VwdGlvbkhvb2s9ZnVuY3Rpb24oZSx0KXtpZS5jb25zb2xlJiZpZS5jb25zb2xlLndhcm4mJmUmJkgudGVzdChlLm5hbWUpJiZpZS5jb25zb2xlLndhcm4oImpRdWVyeS5EZWZlcnJlZCBleGNlcHRpb246ICIrZS5tZXNzYWdlLGUuc3RhY2ssdCl9LGNlLnJlYWR5RXhjZXB0aW9uPWZ1bmN0aW9uKGUpe2llLnNldFRpbWVvdXQoZnVuY3Rpb24oKXt0aHJvdyBlfSl9O3ZhciBPPWNlLkRlZmVycmVkKCk7ZnVuY3Rpb24gUCgpe0MucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsUCksaWUucmVtb3ZlRXZlbnRMaXN0ZW5lcigibG9hZCIsUCksY2UucmVhZHkoKX1jZS5mbi5yZWFkeT1mdW5jdGlvbihlKXtyZXR1cm4gTy50aGVuKGUpWyJjYXRjaCJdKGZ1bmN0aW9uKGUpe2NlLnJlYWR5RXhjZXB0aW9uKGUpfSksdGhpc30sY2UuZXh0ZW5kKHtpc1JlYWR5OiExLHJlYWR5V2FpdDoxLHJlYWR5OmZ1bmN0aW9uKGUpeyghMD09PWU/LS1jZS5yZWFkeVdhaXQ6Y2UuaXNSZWFkeSl8fChjZS5pc1JlYWR5PSEwKSE9PWUmJjA8LS1jZS5yZWFkeVdhaXR8fE8ucmVzb2x2ZVdpdGgoQyxbY2VdKX19KSxjZS5yZWFkeS50aGVuPU8udGhlbiwiY29tcGxldGUiPT09Qy5yZWFkeVN0YXRlfHwibG9hZGluZyIhPT1DLnJlYWR5U3RhdGUmJiFDLmRvY3VtZW50RWxlbWVudC5kb1Njcm9sbD9pZS5zZXRUaW1lb3V0KGNlLnJlYWR5KTooQy5hZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixQKSxpZS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIixQKSk7dmFyIE09ZnVuY3Rpb24oZSx0LG4scixpLG8sYSl7dmFyIHM9MCx1PWUubGVuZ3RoLGw9bnVsbD09bjtpZigib2JqZWN0Ij09PXgobikpZm9yKHMgaW4gaT0hMCxuKU0oZSx0LHMsbltzXSwhMCxvLGEpO2Vsc2UgaWYodm9pZCAwIT09ciYmKGk9ITAsdihyKXx8KGE9ITApLGwmJihhPyh0LmNhbGwoZSxyKSx0PW51bGwpOihsPXQsdD1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGwuY2FsbChjZShlKSxuKX0pKSx0KSlmb3IoO3M8dTtzKyspdChlW3NdLG4sYT9yOnIuY2FsbChlW3NdLHMsdChlW3NdLG4pKSk7cmV0dXJuIGk/ZTpsP3QuY2FsbChlKTp1P3QoZVswXSxuKTpvfSxSPS9eLW1zLS8sST0vLShbYS16XSkvZztmdW5jdGlvbiBXKGUsdCl7cmV0dXJuIHQudG9VcHBlckNhc2UoKX1mdW5jdGlvbiBGKGUpe3JldHVybiBlLnJlcGxhY2UoUiwibXMtIikucmVwbGFjZShJLFcpfXZhciAkPWZ1bmN0aW9uKGUpe3JldHVybiAxPT09ZS5ub2RlVHlwZXx8OT09PWUubm9kZVR5cGV8fCErZS5ub2RlVHlwZX07ZnVuY3Rpb24gQigpe3RoaXMuZXhwYW5kbz1jZS5leHBhbmRvK0IudWlkKyt9Qi51aWQ9MSxCLnByb3RvdHlwZT17Y2FjaGU6ZnVuY3Rpb24oZSl7dmFyIHQ9ZVt0aGlzLmV4cGFuZG9dO3JldHVybiB0fHwodD17fSwkKGUpJiYoZS5ub2RlVHlwZT9lW3RoaXMuZXhwYW5kb109dDpPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0aGlzLmV4cGFuZG8se3ZhbHVlOnQsY29uZmlndXJhYmxlOiEwfSkpKSx0fSxzZXQ6ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGk9dGhpcy5jYWNoZShlKTtpZigic3RyaW5nIj09dHlwZW9mIHQpaVtGKHQpXT1uO2Vsc2UgZm9yKHIgaW4gdClpW0YocildPXRbcl07cmV0dXJuIGl9LGdldDpmdW5jdGlvbihlLHQpe3JldHVybiB2b2lkIDA9PT10P3RoaXMuY2FjaGUoZSk6ZVt0aGlzLmV4cGFuZG9dJiZlW3RoaXMuZXhwYW5kb11bRih0KV19LGFjY2VzczpmdW5jdGlvbihlLHQsbil7cmV0dXJuIHZvaWQgMD09PXR8fHQmJiJzdHJpbmciPT10eXBlb2YgdCYmdm9pZCAwPT09bj90aGlzLmdldChlLHQpOih0aGlzLnNldChlLHQsbiksdm9pZCAwIT09bj9uOnQpfSxyZW1vdmU6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPWVbdGhpcy5leHBhbmRvXTtpZih2b2lkIDAhPT1yKXtpZih2b2lkIDAhPT10KXtuPSh0PUFycmF5LmlzQXJyYXkodCk/dC5tYXAoRik6KHQ9Rih0KSlpbiByP1t0XTp0Lm1hdGNoKEQpfHxbXSkubGVuZ3RoO3doaWxlKG4tLSlkZWxldGUgclt0W25dXX0odm9pZCAwPT09dHx8Y2UuaXNFbXB0eU9iamVjdChyKSkmJihlLm5vZGVUeXBlP2VbdGhpcy5leHBhbmRvXT12b2lkIDA6ZGVsZXRlIGVbdGhpcy5leHBhbmRvXSl9fSxoYXNEYXRhOmZ1bmN0aW9uKGUpe3ZhciB0PWVbdGhpcy5leHBhbmRvXTtyZXR1cm4gdm9pZCAwIT09dCYmIWNlLmlzRW1wdHlPYmplY3QodCl9fTt2YXIgXz1uZXcgQix6PW5ldyBCLFg9L14oPzpce1tcd1xXXSpcfXxcW1tcd1xXXSpcXSkkLyxVPS9bQS1aXS9nO2Z1bmN0aW9uIFYoZSx0LG4pe3ZhciByLGk7aWYodm9pZCAwPT09biYmMT09PWUubm9kZVR5cGUpaWYocj0iZGF0YS0iK3QucmVwbGFjZShVLCItJCYiKS50b0xvd2VyQ2FzZSgpLCJzdHJpbmciPT10eXBlb2Yobj1lLmdldEF0dHJpYnV0ZShyKSkpe3RyeXtuPSJ0cnVlIj09PShpPW4pfHwiZmFsc2UiIT09aSYmKCJudWxsIj09PWk/bnVsbDppPT09K2krIiI/K2k6WC50ZXN0KGkpP0pTT04ucGFyc2UoaSk6aSl9Y2F0Y2goZSl7fXouc2V0KGUsdCxuKX1lbHNlIG49dm9pZCAwO3JldHVybiBufWNlLmV4dGVuZCh7aGFzRGF0YTpmdW5jdGlvbihlKXtyZXR1cm4gei5oYXNEYXRhKGUpfHxfLmhhc0RhdGEoZSl9LGRhdGE6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiB6LmFjY2VzcyhlLHQsbil9LHJlbW92ZURhdGE6ZnVuY3Rpb24oZSx0KXt6LnJlbW92ZShlLHQpfSxfZGF0YTpmdW5jdGlvbihlLHQsbil7cmV0dXJuIF8uYWNjZXNzKGUsdCxuKX0sX3JlbW92ZURhdGE6ZnVuY3Rpb24oZSx0KXtfLnJlbW92ZShlLHQpfX0pLGNlLmZuLmV4dGVuZCh7ZGF0YTpmdW5jdGlvbihuLGUpe3ZhciB0LHIsaSxvPXRoaXNbMF0sYT1vJiZvLmF0dHJpYnV0ZXM7aWYodm9pZCAwPT09bil7aWYodGhpcy5sZW5ndGgmJihpPXouZ2V0KG8pLDE9PT1vLm5vZGVUeXBlJiYhXy5nZXQobywiaGFzRGF0YUF0dHJzIikpKXt0PWEubGVuZ3RoO3doaWxlKHQtLSlhW3RdJiYwPT09KHI9YVt0XS5uYW1lKS5pbmRleE9mKCJkYXRhLSIpJiYocj1GKHIuc2xpY2UoNSkpLFYobyxyLGlbcl0pKTtfLnNldChvLCJoYXNEYXRhQXR0cnMiLCEwKX1yZXR1cm4gaX1yZXR1cm4ib2JqZWN0Ij09dHlwZW9mIG4/dGhpcy5lYWNoKGZ1bmN0aW9uKCl7ei5zZXQodGhpcyxuKX0pOk0odGhpcyxmdW5jdGlvbihlKXt2YXIgdDtpZihvJiZ2b2lkIDA9PT1lKXJldHVybiB2b2lkIDAhPT0odD16LmdldChvLG4pKT90OnZvaWQgMCE9PSh0PVYobyxuKSk/dDp2b2lkIDA7dGhpcy5lYWNoKGZ1bmN0aW9uKCl7ei5zZXQodGhpcyxuLGUpfSl9LG51bGwsZSwxPGFyZ3VtZW50cy5sZW5ndGgsbnVsbCwhMCl9LHJlbW92ZURhdGE6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3oucmVtb3ZlKHRoaXMsZSl9KX19KSxjZS5leHRlbmQoe3F1ZXVlOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcjtpZihlKXJldHVybiB0PSh0fHwiZngiKSsicXVldWUiLHI9Xy5nZXQoZSx0KSxuJiYoIXJ8fEFycmF5LmlzQXJyYXkobik/cj1fLmFjY2VzcyhlLHQsY2UubWFrZUFycmF5KG4pKTpyLnB1c2gobikpLHJ8fFtdfSxkZXF1ZXVlOmZ1bmN0aW9uKGUsdCl7dD10fHwiZngiO3ZhciBuPWNlLnF1ZXVlKGUsdCkscj1uLmxlbmd0aCxpPW4uc2hpZnQoKSxvPWNlLl9xdWV1ZUhvb2tzKGUsdCk7ImlucHJvZ3Jlc3MiPT09aSYmKGk9bi5zaGlmdCgpLHItLSksaSYmKCJmeCI9PT10JiZuLnVuc2hpZnQoImlucHJvZ3Jlc3MiKSxkZWxldGUgby5zdG9wLGkuY2FsbChlLGZ1bmN0aW9uKCl7Y2UuZGVxdWV1ZShlLHQpfSxvKSksIXImJm8mJm8uZW1wdHkuZmlyZSgpfSxfcXVldWVIb29rczpmdW5jdGlvbihlLHQpe3ZhciBuPXQrInF1ZXVlSG9va3MiO3JldHVybiBfLmdldChlLG4pfHxfLmFjY2VzcyhlLG4se2VtcHR5OmNlLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKS5hZGQoZnVuY3Rpb24oKXtfLnJlbW92ZShlLFt0KyJxdWV1ZSIsbl0pfSl9KX19KSxjZS5mbi5leHRlbmQoe3F1ZXVlOmZ1bmN0aW9uKHQsbil7dmFyIGU9MjtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIHQmJihuPXQsdD0iZngiLGUtLSksYXJndW1lbnRzLmxlbmd0aDxlP2NlLnF1ZXVlKHRoaXNbMF0sdCk6dm9pZCAwPT09bj90aGlzOnRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBlPWNlLnF1ZXVlKHRoaXMsdCxuKTtjZS5fcXVldWVIb29rcyh0aGlzLHQpLCJmeCI9PT10JiYiaW5wcm9ncmVzcyIhPT1lWzBdJiZjZS5kZXF1ZXVlKHRoaXMsdCl9KX0sZGVxdWV1ZTpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7Y2UuZGVxdWV1ZSh0aGlzLGUpfSl9LGNsZWFyUXVldWU6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucXVldWUoZXx8ImZ4IixbXSl9LHByb21pc2U6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPTEsaT1jZS5EZWZlcnJlZCgpLG89dGhpcyxhPXRoaXMubGVuZ3RoLHM9ZnVuY3Rpb24oKXstLXJ8fGkucmVzb2x2ZVdpdGgobyxbb10pfTsic3RyaW5nIiE9dHlwZW9mIGUmJih0PWUsZT12b2lkIDApLGU9ZXx8ImZ4Ijt3aGlsZShhLS0pKG49Xy5nZXQob1thXSxlKyJxdWV1ZUhvb2tzIikpJiZuLmVtcHR5JiYocisrLG4uZW1wdHkuYWRkKHMpKTtyZXR1cm4gcygpLGkucHJvbWlzZSh0KX19KTt2YXIgRz0vWystXT8oPzpcZCpcLnwpXGQrKD86W2VFXVsrLV0/XGQrfCkvLnNvdXJjZSxZPW5ldyBSZWdFeHAoIl4oPzooWystXSk9fCkoIitHKyIpKFthLXolXSopJCIsImkiKSxRPVsiVG9wIiwiUmlnaHQiLCJCb3R0b20iLCJMZWZ0Il0sSj1DLmRvY3VtZW50RWxlbWVudCxLPWZ1bmN0aW9uKGUpe3JldHVybiBjZS5jb250YWlucyhlLm93bmVyRG9jdW1lbnQsZSl9LFo9e2NvbXBvc2VkOiEwfTtKLmdldFJvb3ROb2RlJiYoSz1mdW5jdGlvbihlKXtyZXR1cm4gY2UuY29udGFpbnMoZS5vd25lckRvY3VtZW50LGUpfHxlLmdldFJvb3ROb2RlKFopPT09ZS5vd25lckRvY3VtZW50fSk7dmFyIGVlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIm5vbmUiPT09KGU9dHx8ZSkuc3R5bGUuZGlzcGxheXx8IiI9PT1lLnN0eWxlLmRpc3BsYXkmJksoZSkmJiJub25lIj09PWNlLmNzcyhlLCJkaXNwbGF5Iil9O2Z1bmN0aW9uIHRlKGUsdCxuLHIpe3ZhciBpLG8sYT0yMCxzPXI/ZnVuY3Rpb24oKXtyZXR1cm4gci5jdXIoKX06ZnVuY3Rpb24oKXtyZXR1cm4gY2UuY3NzKGUsdCwiIil9LHU9cygpLGw9biYmblszXXx8KGNlLmNzc051bWJlclt0XT8iIjoicHgiKSxjPWUubm9kZVR5cGUmJihjZS5jc3NOdW1iZXJbdF18fCJweCIhPT1sJiYrdSkmJlkuZXhlYyhjZS5jc3MoZSx0KSk7aWYoYyYmY1szXSE9PWwpe3UvPTIsbD1sfHxjWzNdLGM9K3V8fDE7d2hpbGUoYS0tKWNlLnN0eWxlKGUsdCxjK2wpLCgxLW8pKigxLShvPXMoKS91fHwuNSkpPD0wJiYoYT0wKSxjLz1vO2MqPTIsY2Uuc3R5bGUoZSx0LGMrbCksbj1ufHxbXX1yZXR1cm4gbiYmKGM9K2N8fCt1fHwwLGk9blsxXT9jKyhuWzFdKzEpKm5bMl06K25bMl0sciYmKHIudW5pdD1sLHIuc3RhcnQ9YyxyLmVuZD1pKSksaX12YXIgbmU9e307ZnVuY3Rpb24gcmUoZSx0KXtmb3IodmFyIG4scixpLG8sYSxzLHUsbD1bXSxjPTAsZj1lLmxlbmd0aDtjPGY7YysrKShyPWVbY10pLnN0eWxlJiYobj1yLnN0eWxlLmRpc3BsYXksdD8oIm5vbmUiPT09biYmKGxbY109Xy5nZXQociwiZGlzcGxheSIpfHxudWxsLGxbY118fChyLnN0eWxlLmRpc3BsYXk9IiIpKSwiIj09PXIuc3R5bGUuZGlzcGxheSYmZWUocikmJihsW2NdPSh1PWE9bz12b2lkIDAsYT0oaT1yKS5vd25lckRvY3VtZW50LHM9aS5ub2RlTmFtZSwodT1uZVtzXSl8fChvPWEuYm9keS5hcHBlbmRDaGlsZChhLmNyZWF0ZUVsZW1lbnQocykpLHU9Y2UuY3NzKG8sImRpc3BsYXkiKSxvLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQobyksIm5vbmUiPT09dSYmKHU9ImJsb2NrIiksbmVbc109dSkpKSk6Im5vbmUiIT09biYmKGxbY109Im5vbmUiLF8uc2V0KHIsImRpc3BsYXkiLG4pKSk7Zm9yKGM9MDtjPGY7YysrKW51bGwhPWxbY10mJihlW2NdLnN0eWxlLmRpc3BsYXk9bFtjXSk7cmV0dXJuIGV9Y2UuZm4uZXh0ZW5kKHtzaG93OmZ1bmN0aW9uKCl7cmV0dXJuIHJlKHRoaXMsITApfSxoaWRlOmZ1bmN0aW9uKCl7cmV0dXJuIHJlKHRoaXMpfSx0b2dnbGU6ZnVuY3Rpb24oZSl7cmV0dXJuImJvb2xlYW4iPT10eXBlb2YgZT9lP3RoaXMuc2hvdygpOnRoaXMuaGlkZSgpOnRoaXMuZWFjaChmdW5jdGlvbigpe2VlKHRoaXMpP2NlKHRoaXMpLnNob3coKTpjZSh0aGlzKS5oaWRlKCl9KX19KTt2YXIgeGUsYmUsd2U9L14oPzpjaGVja2JveHxyYWRpbykkL2ksVGU9LzwoW2Etel1bXlwvXDA+XHgyMFx0XHJcblxmXSopL2ksQ2U9L14kfF5tb2R1bGUkfFwvKD86amF2YXxlY21hKXNjcmlwdC9pO3hlPUMuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLmFwcGVuZENoaWxkKEMuY3JlYXRlRWxlbWVudCgiZGl2IikpLChiZT1DLmNyZWF0ZUVsZW1lbnQoImlucHV0IikpLnNldEF0dHJpYnV0ZSgidHlwZSIsInJhZGlvIiksYmUuc2V0QXR0cmlidXRlKCJjaGVja2VkIiwiY2hlY2tlZCIpLGJlLnNldEF0dHJpYnV0ZSgibmFtZSIsInQiKSx4ZS5hcHBlbmRDaGlsZChiZSksbGUuY2hlY2tDbG9uZT14ZS5jbG9uZU5vZGUoITApLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmNoZWNrZWQseGUuaW5uZXJIVE1MPSI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+IixsZS5ub0Nsb25lQ2hlY2tlZD0hIXhlLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmRlZmF1bHRWYWx1ZSx4ZS5pbm5lckhUTUw9IjxvcHRpb24+PC9vcHRpb24+IixsZS5vcHRpb249ISF4ZS5sYXN0Q2hpbGQ7dmFyIGtlPXt0aGVhZDpbMSwiPHRhYmxlPiIsIjwvdGFibGU+Il0sY29sOlsyLCI8dGFibGU+PGNvbGdyb3VwPiIsIjwvY29sZ3JvdXA+PC90YWJsZT4iXSx0cjpbMiwiPHRhYmxlPjx0Ym9keT4iLCI8L3Rib2R5PjwvdGFibGU+Il0sdGQ6WzMsIjx0YWJsZT48dGJvZHk+PHRyPiIsIjwvdHI+PC90Ym9keT48L3RhYmxlPiJdLF9kZWZhdWx0OlswLCIiLCIiXX07ZnVuY3Rpb24gU2UoZSx0KXt2YXIgbjtyZXR1cm4gbj0idW5kZWZpbmVkIiE9dHlwZW9mIGUuZ2V0RWxlbWVudHNCeVRhZ05hbWU/ZS5nZXRFbGVtZW50c0J5VGFnTmFtZSh0fHwiKiIpOiJ1bmRlZmluZWQiIT10eXBlb2YgZS5xdWVyeVNlbGVjdG9yQWxsP2UucXVlcnlTZWxlY3RvckFsbCh0fHwiKiIpOltdLHZvaWQgMD09PXR8fHQmJmZlKGUsdCk/Y2UubWVyZ2UoW2VdLG4pOm59ZnVuY3Rpb24gRWUoZSx0KXtmb3IodmFyIG49MCxyPWUubGVuZ3RoO248cjtuKyspXy5zZXQoZVtuXSwiZ2xvYmFsRXZhbCIsIXR8fF8uZ2V0KHRbbl0sImdsb2JhbEV2YWwiKSl9a2UudGJvZHk9a2UudGZvb3Q9a2UuY29sZ3JvdXA9a2UuY2FwdGlvbj1rZS50aGVhZCxrZS50aD1rZS50ZCxsZS5vcHRpb258fChrZS5vcHRncm91cD1rZS5vcHRpb249WzEsIjxzZWxlY3QgbXVsdGlwbGU9J211bHRpcGxlJz4iLCI8L3NlbGVjdD4iXSk7dmFyIGplPS88fCYjP1x3KzsvO2Z1bmN0aW9uIEFlKGUsdCxuLHIsaSl7Zm9yKHZhciBvLGEscyx1LGwsYyxmPXQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLHA9W10sZD0wLGg9ZS5sZW5ndGg7ZDxoO2QrKylpZigobz1lW2RdKXx8MD09PW8paWYoIm9iamVjdCI9PT14KG8pKWNlLm1lcmdlKHAsby5ub2RlVHlwZT9bb106byk7ZWxzZSBpZihqZS50ZXN0KG8pKXthPWF8fGYuYXBwZW5kQ2hpbGQodC5jcmVhdGVFbGVtZW50KCJkaXYiKSkscz0oVGUuZXhlYyhvKXx8WyIiLCIiXSlbMV0udG9Mb3dlckNhc2UoKSx1PWtlW3NdfHxrZS5fZGVmYXVsdCxhLmlubmVySFRNTD11WzFdK2NlLmh0bWxQcmVmaWx0ZXIobykrdVsyXSxjPXVbMF07d2hpbGUoYy0tKWE9YS5sYXN0Q2hpbGQ7Y2UubWVyZ2UocCxhLmNoaWxkTm9kZXMpLChhPWYuZmlyc3RDaGlsZCkudGV4dENvbnRlbnQ9IiJ9ZWxzZSBwLnB1c2godC5jcmVhdGVUZXh0Tm9kZShvKSk7Zi50ZXh0Q29udGVudD0iIixkPTA7d2hpbGUobz1wW2QrK10paWYociYmLTE8Y2UuaW5BcnJheShvLHIpKWkmJmkucHVzaChvKTtlbHNlIGlmKGw9SyhvKSxhPVNlKGYuYXBwZW5kQ2hpbGQobyksInNjcmlwdCIpLGwmJkVlKGEpLG4pe2M9MDt3aGlsZShvPWFbYysrXSlDZS50ZXN0KG8udHlwZXx8IiIpJiZuLnB1c2gobyl9cmV0dXJuIGZ9dmFyIERlPS9eKFteLl0qKSg/OlwuKC4rKXwpLztmdW5jdGlvbiBOZSgpe3JldHVybiEwfWZ1bmN0aW9uIHFlKCl7cmV0dXJuITF9ZnVuY3Rpb24gTGUoZSx0LG4scixpLG8pe3ZhciBhLHM7aWYoIm9iamVjdCI9PXR5cGVvZiB0KXtmb3IocyBpbiJzdHJpbmciIT10eXBlb2YgbiYmKHI9cnx8bixuPXZvaWQgMCksdClMZShlLHMsbixyLHRbc10sbyk7cmV0dXJuIGV9aWYobnVsbD09ciYmbnVsbD09aT8oaT1uLHI9bj12b2lkIDApOm51bGw9PWkmJigic3RyaW5nIj09dHlwZW9mIG4/KGk9cixyPXZvaWQgMCk6KGk9cixyPW4sbj12b2lkIDApKSwhMT09PWkpaT1xZTtlbHNlIGlmKCFpKXJldHVybiBlO3JldHVybiAxPT09byYmKGE9aSwoaT1mdW5jdGlvbihlKXtyZXR1cm4gY2UoKS5vZmYoZSksYS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9KS5ndWlkPWEuZ3VpZHx8KGEuZ3VpZD1jZS5ndWlkKyspKSxlLmVhY2goZnVuY3Rpb24oKXtjZS5ldmVudC5hZGQodGhpcyx0LGkscixuKX0pfWZ1bmN0aW9uIEhlKGUscix0KXt0PyhfLnNldChlLHIsITEpLGNlLmV2ZW50LmFkZChlLHIse25hbWVzcGFjZTohMSxoYW5kbGVyOmZ1bmN0aW9uKGUpe3ZhciB0LG49Xy5nZXQodGhpcyxyKTtpZigxJmUuaXNUcmlnZ2VyJiZ0aGlzW3JdKXtpZihuKShjZS5ldmVudC5zcGVjaWFsW3JdfHx7fSkuZGVsZWdhdGVUeXBlJiZlLnN0b3BQcm9wYWdhdGlvbigpO2Vsc2UgaWYobj1hZS5jYWxsKGFyZ3VtZW50cyksXy5zZXQodGhpcyxyLG4pLHRoaXNbcl0oKSx0PV8uZ2V0KHRoaXMsciksXy5zZXQodGhpcyxyLCExKSxuIT09dClyZXR1cm4gZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKSxlLnByZXZlbnREZWZhdWx0KCksdH1lbHNlIG4mJihfLnNldCh0aGlzLHIsY2UuZXZlbnQudHJpZ2dlcihuWzBdLG4uc2xpY2UoMSksdGhpcykpLGUuc3RvcFByb3BhZ2F0aW9uKCksZS5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZD1OZSl9fSkpOnZvaWQgMD09PV8uZ2V0KGUscikmJmNlLmV2ZW50LmFkZChlLHIsTmUpfWNlLmV2ZW50PXtnbG9iYWw6e30sYWRkOmZ1bmN0aW9uKHQsZSxuLHIsaSl7dmFyIG8sYSxzLHUsbCxjLGYscCxkLGgsZyx2PV8uZ2V0KHQpO2lmKCQodCkpe24uaGFuZGxlciYmKG49KG89bikuaGFuZGxlcixpPW8uc2VsZWN0b3IpLGkmJmNlLmZpbmQubWF0Y2hlc1NlbGVjdG9yKEosaSksbi5ndWlkfHwobi5ndWlkPWNlLmd1aWQrKyksKHU9di5ldmVudHMpfHwodT12LmV2ZW50cz1PYmplY3QuY3JlYXRlKG51bGwpKSwoYT12LmhhbmRsZSl8fChhPXYuaGFuZGxlPWZ1bmN0aW9uKGUpe3JldHVybiJ1bmRlZmluZWQiIT10eXBlb2YgY2UmJmNlLmV2ZW50LnRyaWdnZXJlZCE9PWUudHlwZT9jZS5ldmVudC5kaXNwYXRjaC5hcHBseSh0LGFyZ3VtZW50cyk6dm9pZCAwfSksbD0oZT0oZXx8IiIpLm1hdGNoKEQpfHxbIiJdKS5sZW5ndGg7d2hpbGUobC0tKWQ9Zz0ocz1EZS5leGVjKGVbbF0pfHxbXSlbMV0saD0oc1syXXx8IiIpLnNwbGl0KCIuIikuc29ydCgpLGQmJihmPWNlLmV2ZW50LnNwZWNpYWxbZF18fHt9LGQ9KGk/Zi5kZWxlZ2F0ZVR5cGU6Zi5iaW5kVHlwZSl8fGQsZj1jZS5ldmVudC5zcGVjaWFsW2RdfHx7fSxjPWNlLmV4dGVuZCh7dHlwZTpkLG9yaWdUeXBlOmcsZGF0YTpyLGhhbmRsZXI6bixndWlkOm4uZ3VpZCxzZWxlY3RvcjppLG5lZWRzQ29udGV4dDppJiZjZS5leHByLm1hdGNoLm5lZWRzQ29udGV4dC50ZXN0KGkpLG5hbWVzcGFjZTpoLmpvaW4oIi4iKX0sbyksKHA9dVtkXSl8fCgocD11W2RdPVtdKS5kZWxlZ2F0ZUNvdW50PTAsZi5zZXR1cCYmITEhPT1mLnNldHVwLmNhbGwodCxyLGgsYSl8fHQuYWRkRXZlbnRMaXN0ZW5lciYmdC5hZGRFdmVudExpc3RlbmVyKGQsYSkpLGYuYWRkJiYoZi5hZGQuY2FsbCh0LGMpLGMuaGFuZGxlci5ndWlkfHwoYy5oYW5kbGVyLmd1aWQ9bi5ndWlkKSksaT9wLnNwbGljZShwLmRlbGVnYXRlQ291bnQrKywwLGMpOnAucHVzaChjKSxjZS5ldmVudC5nbG9iYWxbZF09ITApfX0scmVtb3ZlOmZ1bmN0aW9uKGUsdCxuLHIsaSl7dmFyIG8sYSxzLHUsbCxjLGYscCxkLGgsZyx2PV8uaGFzRGF0YShlKSYmXy5nZXQoZSk7aWYodiYmKHU9di5ldmVudHMpKXtsPSh0PSh0fHwiIikubWF0Y2goRCl8fFsiIl0pLmxlbmd0aDt3aGlsZShsLS0paWYoZD1nPShzPURlLmV4ZWModFtsXSl8fFtdKVsxXSxoPShzWzJdfHwiIikuc3BsaXQoIi4iKS5zb3J0KCksZCl7Zj1jZS5ldmVudC5zcGVjaWFsW2RdfHx7fSxwPXVbZD0ocj9mLmRlbGVnYXRlVHlwZTpmLmJpbmRUeXBlKXx8ZF18fFtdLHM9c1syXSYmbmV3IFJlZ0V4cCgiKF58XFwuKSIraC5qb2luKCJcXC4oPzouKlxcLnwpIikrIihcXC58JCkiKSxhPW89cC5sZW5ndGg7d2hpbGUoby0tKWM9cFtvXSwhaSYmZyE9PWMub3JpZ1R5cGV8fG4mJm4uZ3VpZCE9PWMuZ3VpZHx8cyYmIXMudGVzdChjLm5hbWVzcGFjZSl8fHImJnIhPT1jLnNlbGVjdG9yJiYoIioqIiE9PXJ8fCFjLnNlbGVjdG9yKXx8KHAuc3BsaWNlKG8sMSksYy5zZWxlY3RvciYmcC5kZWxlZ2F0ZUNvdW50LS0sZi5yZW1vdmUmJmYucmVtb3ZlLmNhbGwoZSxjKSk7YSYmIXAubGVuZ3RoJiYoZi50ZWFyZG93biYmITEhPT1mLnRlYXJkb3duLmNhbGwoZSxoLHYuaGFuZGxlKXx8Y2UucmVtb3ZlRXZlbnQoZSxkLHYuaGFuZGxlKSxkZWxldGUgdVtkXSl9ZWxzZSBmb3IoZCBpbiB1KWNlLmV2ZW50LnJlbW92ZShlLGQrdFtsXSxuLHIsITApO2NlLmlzRW1wdHlPYmplY3QodSkmJl8ucmVtb3ZlKGUsImhhbmRsZSBldmVudHMiKX19LGRpc3BhdGNoOmZ1bmN0aW9uKGUpe3ZhciB0LG4scixpLG8sYSxzPW5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKSx1PWNlLmV2ZW50LmZpeChlKSxsPShfLmdldCh0aGlzLCJldmVudHMiKXx8T2JqZWN0LmNyZWF0ZShudWxsKSlbdS50eXBlXXx8W10sYz1jZS5ldmVudC5zcGVjaWFsW3UudHlwZV18fHt9O2ZvcihzWzBdPXUsdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspc1t0XT1hcmd1bWVudHNbdF07aWYodS5kZWxlZ2F0ZVRhcmdldD10aGlzLCFjLnByZURpc3BhdGNofHwhMSE9PWMucHJlRGlzcGF0Y2guY2FsbCh0aGlzLHUpKXthPWNlLmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcyx1LGwpLHQ9MDt3aGlsZSgoaT1hW3QrK10pJiYhdS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpKXt1LmN1cnJlbnRUYXJnZXQ9aS5lbGVtLG49MDt3aGlsZSgobz1pLmhhbmRsZXJzW24rK10pJiYhdS5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKXUucm5hbWVzcGFjZSYmITEhPT1vLm5hbWVzcGFjZSYmIXUucm5hbWVzcGFjZS50ZXN0KG8ubmFtZXNwYWNlKXx8KHUuaGFuZGxlT2JqPW8sdS5kYXRhPW8uZGF0YSx2b2lkIDAhPT0ocj0oKGNlLmV2ZW50LnNwZWNpYWxbby5vcmlnVHlwZV18fHt9KS5oYW5kbGV8fG8uaGFuZGxlcikuYXBwbHkoaS5lbGVtLHMpKSYmITE9PT0odS5yZXN1bHQ9cikmJih1LnByZXZlbnREZWZhdWx0KCksdS5zdG9wUHJvcGFnYXRpb24oKSkpfXJldHVybiBjLnBvc3REaXNwYXRjaCYmYy5wb3N0RGlzcGF0Y2guY2FsbCh0aGlzLHUpLHUucmVzdWx0fX0saGFuZGxlcnM6ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksbyxhLHM9W10sdT10LmRlbGVnYXRlQ291bnQsbD1lLnRhcmdldDtpZih1JiZsLm5vZGVUeXBlJiYhKCJjbGljayI9PT1lLnR5cGUmJjE8PWUuYnV0dG9uKSlmb3IoO2whPT10aGlzO2w9bC5wYXJlbnROb2RlfHx0aGlzKWlmKDE9PT1sLm5vZGVUeXBlJiYoImNsaWNrIiE9PWUudHlwZXx8ITAhPT1sLmRpc2FibGVkKSl7Zm9yKG89W10sYT17fSxuPTA7bjx1O24rKyl2b2lkIDA9PT1hW2k9KHI9dFtuXSkuc2VsZWN0b3IrIiAiXSYmKGFbaV09ci5uZWVkc0NvbnRleHQ/LTE8Y2UoaSx0aGlzKS5pbmRleChsKTpjZS5maW5kKGksdGhpcyxudWxsLFtsXSkubGVuZ3RoKSxhW2ldJiZvLnB1c2gocik7by5sZW5ndGgmJnMucHVzaCh7ZWxlbTpsLGhhbmRsZXJzOm99KX1yZXR1cm4gbD10aGlzLHU8dC5sZW5ndGgmJnMucHVzaCh7ZWxlbTpsLGhhbmRsZXJzOnQuc2xpY2UodSl9KSxzfSxhZGRQcm9wOmZ1bmN0aW9uKHQsZSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGNlLkV2ZW50LnByb3RvdHlwZSx0LHtlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMCxnZXQ6dihlKT9mdW5jdGlvbigpe2lmKHRoaXMub3JpZ2luYWxFdmVudClyZXR1cm4gZSh0aGlzLm9yaWdpbmFsRXZlbnQpfTpmdW5jdGlvbigpe2lmKHRoaXMub3JpZ2luYWxFdmVudClyZXR1cm4gdGhpcy5vcmlnaW5hbEV2ZW50W3RdfSxzZXQ6ZnVuY3Rpb24oZSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsdCx7ZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITAsd3JpdGFibGU6ITAsdmFsdWU6ZX0pfX0pfSxmaXg6ZnVuY3Rpb24oZSl7cmV0dXJuIGVbY2UuZXhwYW5kb10/ZTpuZXcgY2UuRXZlbnQoZSl9LHNwZWNpYWw6e2xvYWQ6e25vQnViYmxlOiEwfSxjbGljazp7c2V0dXA6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpc3x8ZTtyZXR1cm4gd2UudGVzdCh0LnR5cGUpJiZ0LmNsaWNrJiZmZSh0LCJpbnB1dCIpJiZIZSh0LCJjbGljayIsITApLCExfSx0cmlnZ2VyOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXN8fGU7cmV0dXJuIHdlLnRlc3QodC50eXBlKSYmdC5jbGljayYmZmUodCwiaW5wdXQiKSYmSGUodCwiY2xpY2siKSwhMH0sX2RlZmF1bHQ6ZnVuY3Rpb24oZSl7dmFyIHQ9ZS50YXJnZXQ7cmV0dXJuIHdlLnRlc3QodC50eXBlKSYmdC5jbGljayYmZmUodCwiaW5wdXQiKSYmXy5nZXQodCwiY2xpY2siKXx8ZmUodCwiYSIpfX0sYmVmb3JldW5sb2FkOntwb3N0RGlzcGF0Y2g6ZnVuY3Rpb24oZSl7dm9pZCAwIT09ZS5yZXN1bHQmJmUub3JpZ2luYWxFdmVudCYmKGUub3JpZ2luYWxFdmVudC5yZXR1cm5WYWx1ZT1lLnJlc3VsdCl9fX19LGNlLnJlbW92ZUV2ZW50PWZ1bmN0aW9uKGUsdCxuKXtlLnJlbW92ZUV2ZW50TGlzdGVuZXImJmUucmVtb3ZlRXZlbnRMaXN0ZW5lcih0LG4pfSxjZS5FdmVudD1mdW5jdGlvbihlLHQpe2lmKCEodGhpcyBpbnN0YW5jZW9mIGNlLkV2ZW50KSlyZXR1cm4gbmV3IGNlLkV2ZW50KGUsdCk7ZSYmZS50eXBlPyh0aGlzLm9yaWdpbmFsRXZlbnQ9ZSx0aGlzLnR5cGU9ZS50eXBlLHRoaXMuaXNEZWZhdWx0UHJldmVudGVkPWUuZGVmYXVsdFByZXZlbnRlZHx8dm9pZCAwPT09ZS5kZWZhdWx0UHJldmVudGVkJiYhMT09PWUucmV0dXJuVmFsdWU/TmU6cWUsdGhpcy50YXJnZXQ9ZS50YXJnZXQmJjM9PT1lLnRhcmdldC5ub2RlVHlwZT9lLnRhcmdldC5wYXJlbnROb2RlOmUudGFyZ2V0LHRoaXMuY3VycmVudFRhcmdldD1lLmN1cnJlbnRUYXJnZXQsdGhpcy5yZWxhdGVkVGFyZ2V0PWUucmVsYXRlZFRhcmdldCk6dGhpcy50eXBlPWUsdCYmY2UuZXh0ZW5kKHRoaXMsdCksdGhpcy50aW1lU3RhbXA9ZSYmZS50aW1lU3RhbXB8fERhdGUubm93KCksdGhpc1tjZS5leHBhbmRvXT0hMH0sY2UuRXZlbnQucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpjZS5FdmVudCxpc0RlZmF1bHRQcmV2ZW50ZWQ6cWUsaXNQcm9wYWdhdGlvblN0b3BwZWQ6cWUsaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6cWUsaXNTaW11bGF0ZWQ6ITEscHJldmVudERlZmF1bHQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLm9yaWdpbmFsRXZlbnQ7dGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQ9TmUsZSYmIXRoaXMuaXNTaW11bGF0ZWQmJmUucHJldmVudERlZmF1bHQoKX0sc3RvcFByb3BhZ2F0aW9uOmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5vcmlnaW5hbEV2ZW50O3RoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQ9TmUsZSYmIXRoaXMuaXNTaW11bGF0ZWQmJmUuc3RvcFByb3BhZ2F0aW9uKCl9LHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjpmdW5jdGlvbigpe3ZhciBlPXRoaXMub3JpZ2luYWxFdmVudDt0aGlzLmlzSW1tZWRpYXRlUHJvcGFnYXRpb25TdG9wcGVkPU5lLGUmJiF0aGlzLmlzU2ltdWxhdGVkJiZlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpLHRoaXMuc3RvcFByb3BhZ2F0aW9uKCl9fSxjZS5lYWNoKHthbHRLZXk6ITAsYnViYmxlczohMCxjYW5jZWxhYmxlOiEwLGNoYW5nZWRUb3VjaGVzOiEwLGN0cmxLZXk6ITAsZGV0YWlsOiEwLGV2ZW50UGhhc2U6ITAsbWV0YUtleTohMCxwYWdlWDohMCxwYWdlWTohMCxzaGlmdEtleTohMCx2aWV3OiEwLCJjaGFyIjohMCxjb2RlOiEwLGNoYXJDb2RlOiEwLGtleTohMCxrZXlDb2RlOiEwLGJ1dHRvbjohMCxidXR0b25zOiEwLGNsaWVudFg6ITAsY2xpZW50WTohMCxvZmZzZXRYOiEwLG9mZnNldFk6ITAscG9pbnRlcklkOiEwLHBvaW50ZXJUeXBlOiEwLHNjcmVlblg6ITAsc2NyZWVuWTohMCx0YXJnZXRUb3VjaGVzOiEwLHRvRWxlbWVudDohMCx0b3VjaGVzOiEwLHdoaWNoOiEwfSxjZS5ldmVudC5hZGRQcm9wKSxjZS5lYWNoKHtmb2N1czoiZm9jdXNpbiIsYmx1cjoiZm9jdXNvdXQifSxmdW5jdGlvbihyLGkpe2Z1bmN0aW9uIG8oZSl7aWYoQy5kb2N1bWVudE1vZGUpe3ZhciB0PV8uZ2V0KHRoaXMsImhhbmRsZSIpLG49Y2UuZXZlbnQuZml4KGUpO24udHlwZT0iZm9jdXNpbiI9PT1lLnR5cGU/ImZvY3VzIjoiYmx1ciIsbi5pc1NpbXVsYXRlZD0hMCx0KGUpLG4udGFyZ2V0PT09bi5jdXJyZW50VGFyZ2V0JiZ0KG4pfWVsc2UgY2UuZXZlbnQuc2ltdWxhdGUoaSxlLnRhcmdldCxjZS5ldmVudC5maXgoZSkpfWNlLmV2ZW50LnNwZWNpYWxbcl09e3NldHVwOmZ1bmN0aW9uKCl7dmFyIGU7aWYoSGUodGhpcyxyLCEwKSwhQy5kb2N1bWVudE1vZGUpcmV0dXJuITE7KGU9Xy5nZXQodGhpcyxpKSl8fHRoaXMuYWRkRXZlbnRMaXN0ZW5lcihpLG8pLF8uc2V0KHRoaXMsaSwoZXx8MCkrMSl9LHRyaWdnZXI6ZnVuY3Rpb24oKXtyZXR1cm4gSGUodGhpcyxyKSwhMH0sdGVhcmRvd246ZnVuY3Rpb24oKXt2YXIgZTtpZighQy5kb2N1bWVudE1vZGUpcmV0dXJuITE7KGU9Xy5nZXQodGhpcyxpKS0xKT9fLnNldCh0aGlzLGksZSk6KHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcihpLG8pLF8ucmVtb3ZlKHRoaXMsaSkpfSxfZGVmYXVsdDpmdW5jdGlvbihlKXtyZXR1cm4gXy5nZXQoZS50YXJnZXQscil9LGRlbGVnYXRlVHlwZTppfSxjZS5ldmVudC5zcGVjaWFsW2ldPXtzZXR1cDpmdW5jdGlvbigpe3ZhciBlPXRoaXMub3duZXJEb2N1bWVudHx8dGhpcy5kb2N1bWVudHx8dGhpcyx0PUMuZG9jdW1lbnRNb2RlP3RoaXM6ZSxuPV8uZ2V0KHQsaSk7bnx8KEMuZG9jdW1lbnRNb2RlP3RoaXMuYWRkRXZlbnRMaXN0ZW5lcihpLG8pOmUuYWRkRXZlbnRMaXN0ZW5lcihyLG8sITApKSxfLnNldCh0LGksKG58fDApKzEpfSx0ZWFyZG93bjpmdW5jdGlvbigpe3ZhciBlPXRoaXMub3duZXJEb2N1bWVudHx8dGhpcy5kb2N1bWVudHx8dGhpcyx0PUMuZG9jdW1lbnRNb2RlP3RoaXM6ZSxuPV8uZ2V0KHQsaSktMTtuP18uc2V0KHQsaSxuKTooQy5kb2N1bWVudE1vZGU/dGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKGksbyk6ZS5yZW1vdmVFdmVudExpc3RlbmVyKHIsbywhMCksXy5yZW1vdmUodCxpKSl9fX0pLGNlLmVhY2goe21vdXNlZW50ZXI6Im1vdXNlb3ZlciIsbW91c2VsZWF2ZToibW91c2VvdXQiLHBvaW50ZXJlbnRlcjoicG9pbnRlcm92ZXIiLHBvaW50ZXJsZWF2ZToicG9pbnRlcm91dCJ9LGZ1bmN0aW9uKGUsaSl7Y2UuZXZlbnQuc3BlY2lhbFtlXT17ZGVsZWdhdGVUeXBlOmksYmluZFR5cGU6aSxoYW5kbGU6ZnVuY3Rpb24oZSl7dmFyIHQsbj1lLnJlbGF0ZWRUYXJnZXQscj1lLmhhbmRsZU9iajtyZXR1cm4gbiYmKG49PT10aGlzfHxjZS5jb250YWlucyh0aGlzLG4pKXx8KGUudHlwZT1yLm9yaWdUeXBlLHQ9ci5oYW5kbGVyLmFwcGx5KHRoaXMsYXJndW1lbnRzKSxlLnR5cGU9aSksdH19fSksY2UuZm4uZXh0ZW5kKHtvbjpmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gTGUodGhpcyxlLHQsbixyKX0sb25lOmZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiBMZSh0aGlzLGUsdCxuLHIsMSl9LG9mZjpmdW5jdGlvbihlLHQsbil7dmFyIHIsaTtpZihlJiZlLnByZXZlbnREZWZhdWx0JiZlLmhhbmRsZU9iailyZXR1cm4gcj1lLmhhbmRsZU9iaixjZShlLmRlbGVnYXRlVGFyZ2V0KS5vZmYoci5uYW1lc3BhY2U/ci5vcmlnVHlwZSsiLiIrci5uYW1lc3BhY2U6ci5vcmlnVHlwZSxyLnNlbGVjdG9yLHIuaGFuZGxlciksdGhpcztpZigib2JqZWN0Ij09dHlwZW9mIGUpe2ZvcihpIGluIGUpdGhpcy5vZmYoaSx0LGVbaV0pO3JldHVybiB0aGlzfXJldHVybiExIT09dCYmImZ1bmN0aW9uIiE9dHlwZW9mIHR8fChuPXQsdD12b2lkIDApLCExPT09biYmKG49cWUpLHRoaXMuZWFjaChmdW5jdGlvbigpe2NlLmV2ZW50LnJlbW92ZSh0aGlzLGUsbix0KX0pfX0pO3ZhciBPZT0vPHNjcmlwdHw8c3R5bGV8PGxpbmsvaSxQZT0vY2hlY2tlZFxzKig/OltePV18PVxzKi5jaGVja2VkLikvaSxNZT0vXlxzKjwhXFtDREFUQVxbfFxdXF0+XHMqJC9nO2Z1bmN0aW9uIFJlKGUsdCl7cmV0dXJuIGZlKGUsInRhYmxlIikmJmZlKDExIT09dC5ub2RlVHlwZT90OnQuZmlyc3RDaGlsZCwidHIiKSYmY2UoZSkuY2hpbGRyZW4oInRib2R5IilbMF18fGV9ZnVuY3Rpb24gSWUoZSl7cmV0dXJuIGUudHlwZT0obnVsbCE9PWUuZ2V0QXR0cmlidXRlKCJ0eXBlIikpKyIvIitlLnR5cGUsZX1mdW5jdGlvbiBXZShlKXtyZXR1cm4idHJ1ZS8iPT09KGUudHlwZXx8IiIpLnNsaWNlKDAsNSk/ZS50eXBlPWUudHlwZS5zbGljZSg1KTplLnJlbW92ZUF0dHJpYnV0ZSgidHlwZSIpLGV9ZnVuY3Rpb24gRmUoZSx0KXt2YXIgbixyLGksbyxhLHM7aWYoMT09PXQubm9kZVR5cGUpe2lmKF8uaGFzRGF0YShlKSYmKHM9Xy5nZXQoZSkuZXZlbnRzKSlmb3IoaSBpbiBfLnJlbW92ZSh0LCJoYW5kbGUgZXZlbnRzIikscylmb3Iobj0wLHI9c1tpXS5sZW5ndGg7bjxyO24rKyljZS5ldmVudC5hZGQodCxpLHNbaV1bbl0pO3ouaGFzRGF0YShlKSYmKG89ei5hY2Nlc3MoZSksYT1jZS5leHRlbmQoe30sbyksei5zZXQodCxhKSl9fWZ1bmN0aW9uICRlKG4scixpLG8pe3I9ZyhyKTt2YXIgZSx0LGEscyx1LGwsYz0wLGY9bi5sZW5ndGgscD1mLTEsZD1yWzBdLGg9dihkKTtpZihofHwxPGYmJiJzdHJpbmciPT10eXBlb2YgZCYmIWxlLmNoZWNrQ2xvbmUmJlBlLnRlc3QoZCkpcmV0dXJuIG4uZWFjaChmdW5jdGlvbihlKXt2YXIgdD1uLmVxKGUpO2gmJihyWzBdPWQuY2FsbCh0aGlzLGUsdC5odG1sKCkpKSwkZSh0LHIsaSxvKX0pO2lmKGYmJih0PShlPUFlKHIsblswXS5vd25lckRvY3VtZW50LCExLG4sbykpLmZpcnN0Q2hpbGQsMT09PWUuY2hpbGROb2Rlcy5sZW5ndGgmJihlPXQpLHR8fG8pKXtmb3Iocz0oYT1jZS5tYXAoU2UoZSwic2NyaXB0IiksSWUpKS5sZW5ndGg7YzxmO2MrKyl1PWUsYyE9PXAmJih1PWNlLmNsb25lKHUsITAsITApLHMmJmNlLm1lcmdlKGEsU2UodSwic2NyaXB0IikpKSxpLmNhbGwobltjXSx1LGMpO2lmKHMpZm9yKGw9YVthLmxlbmd0aC0xXS5vd25lckRvY3VtZW50LGNlLm1hcChhLFdlKSxjPTA7YzxzO2MrKyl1PWFbY10sQ2UudGVzdCh1LnR5cGV8fCIiKSYmIV8uYWNjZXNzKHUsImdsb2JhbEV2YWwiKSYmY2UuY29udGFpbnMobCx1KSYmKHUuc3JjJiYibW9kdWxlIiE9PSh1LnR5cGV8fCIiKS50b0xvd2VyQ2FzZSgpP2NlLl9ldmFsVXJsJiYhdS5ub01vZHVsZSYmY2UuX2V2YWxVcmwodS5zcmMse25vbmNlOnUubm9uY2V8fHUuZ2V0QXR0cmlidXRlKCJub25jZSIpfSxsKTptKHUudGV4dENvbnRlbnQucmVwbGFjZShNZSwiIiksdSxsKSl9cmV0dXJuIG59ZnVuY3Rpb24gQmUoZSx0LG4pe2Zvcih2YXIgcixpPXQ/Y2UuZmlsdGVyKHQsZSk6ZSxvPTA7bnVsbCE9KHI9aVtvXSk7bysrKW58fDEhPT1yLm5vZGVUeXBlfHxjZS5jbGVhbkRhdGEoU2UocikpLHIucGFyZW50Tm9kZSYmKG4mJksocikmJkVlKFNlKHIsInNjcmlwdCIpKSxyLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocikpO3JldHVybiBlfWNlLmV4dGVuZCh7aHRtbFByZWZpbHRlcjpmdW5jdGlvbihlKXtyZXR1cm4gZX0sY2xvbmU6ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhLHMsdSxsLGM9ZS5jbG9uZU5vZGUoITApLGY9SyhlKTtpZighKGxlLm5vQ2xvbmVDaGVja2VkfHwxIT09ZS5ub2RlVHlwZSYmMTEhPT1lLm5vZGVUeXBlfHxjZS5pc1hNTERvYyhlKSkpZm9yKGE9U2UoYykscj0wLGk9KG89U2UoZSkpLmxlbmd0aDtyPGk7cisrKXM9b1tyXSx1PWFbcl0sdm9pZCAwLCJpbnB1dCI9PT0obD11Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkpJiZ3ZS50ZXN0KHMudHlwZSk/dS5jaGVja2VkPXMuY2hlY2tlZDoiaW5wdXQiIT09bCYmInRleHRhcmVhIiE9PWx8fCh1LmRlZmF1bHRWYWx1ZT1zLmRlZmF1bHRWYWx1ZSk7aWYodClpZihuKWZvcihvPW98fFNlKGUpLGE9YXx8U2UoYykscj0wLGk9by5sZW5ndGg7cjxpO3IrKylGZShvW3JdLGFbcl0pO2Vsc2UgRmUoZSxjKTtyZXR1cm4gMDwoYT1TZShjLCJzY3JpcHQiKSkubGVuZ3RoJiZFZShhLCFmJiZTZShlLCJzY3JpcHQiKSksY30sY2xlYW5EYXRhOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuLHIsaT1jZS5ldmVudC5zcGVjaWFsLG89MDt2b2lkIDAhPT0obj1lW29dKTtvKyspaWYoJChuKSl7aWYodD1uW18uZXhwYW5kb10pe2lmKHQuZXZlbnRzKWZvcihyIGluIHQuZXZlbnRzKWlbcl0/Y2UuZXZlbnQucmVtb3ZlKG4scik6Y2UucmVtb3ZlRXZlbnQobixyLHQuaGFuZGxlKTtuW18uZXhwYW5kb109dm9pZCAwfW5bei5leHBhbmRvXSYmKG5bei5leHBhbmRvXT12b2lkIDApfX19KSxjZS5mbi5leHRlbmQoe2RldGFjaDpmdW5jdGlvbihlKXtyZXR1cm4gQmUodGhpcyxlLCEwKX0scmVtb3ZlOmZ1bmN0aW9uKGUpe3JldHVybiBCZSh0aGlzLGUpfSx0ZXh0OmZ1bmN0aW9uKGUpe3JldHVybiBNKHRoaXMsZnVuY3Rpb24oZSl7cmV0dXJuIHZvaWQgMD09PWU/Y2UudGV4dCh0aGlzKTp0aGlzLmVtcHR5KCkuZWFjaChmdW5jdGlvbigpezEhPT10aGlzLm5vZGVUeXBlJiYxMSE9PXRoaXMubm9kZVR5cGUmJjkhPT10aGlzLm5vZGVUeXBlfHwodGhpcy50ZXh0Q29udGVudD1lKX0pfSxudWxsLGUsYXJndW1lbnRzLmxlbmd0aCl9LGFwcGVuZDpmdW5jdGlvbigpe3JldHVybiAkZSh0aGlzLGFyZ3VtZW50cyxmdW5jdGlvbihlKXsxIT09dGhpcy5ub2RlVHlwZSYmMTEhPT10aGlzLm5vZGVUeXBlJiY5IT09dGhpcy5ub2RlVHlwZXx8UmUodGhpcyxlKS5hcHBlbmRDaGlsZChlKX0pfSxwcmVwZW5kOmZ1bmN0aW9uKCl7cmV0dXJuICRlKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKGUpe2lmKDE9PT10aGlzLm5vZGVUeXBlfHwxMT09PXRoaXMubm9kZVR5cGV8fDk9PT10aGlzLm5vZGVUeXBlKXt2YXIgdD1SZSh0aGlzLGUpO3QuaW5zZXJ0QmVmb3JlKGUsdC5maXJzdENoaWxkKX19KX0sYmVmb3JlOmZ1bmN0aW9uKCl7cmV0dXJuICRlKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKGUpe3RoaXMucGFyZW50Tm9kZSYmdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLHRoaXMpfSl9LGFmdGVyOmZ1bmN0aW9uKCl7cmV0dXJuICRlKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKGUpe3RoaXMucGFyZW50Tm9kZSYmdGhpcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlLHRoaXMubmV4dFNpYmxpbmcpfSl9LGVtcHR5OmZ1bmN0aW9uKCl7Zm9yKHZhciBlLHQ9MDtudWxsIT0oZT10aGlzW3RdKTt0KyspMT09PWUubm9kZVR5cGUmJihjZS5jbGVhbkRhdGEoU2UoZSwhMSkpLGUudGV4dENvbnRlbnQ9IiIpO3JldHVybiB0aGlzfSxjbG9uZTpmdW5jdGlvbihlLHQpe3JldHVybiBlPW51bGwhPWUmJmUsdD1udWxsPT10P2U6dCx0aGlzLm1hcChmdW5jdGlvbigpe3JldHVybiBjZS5jbG9uZSh0aGlzLGUsdCl9KX0saHRtbDpmdW5jdGlvbihlKXtyZXR1cm4gTSh0aGlzLGZ1bmN0aW9uKGUpe3ZhciB0PXRoaXNbMF18fHt9LG49MCxyPXRoaXMubGVuZ3RoO2lmKHZvaWQgMD09PWUmJjE9PT10Lm5vZGVUeXBlKXJldHVybiB0LmlubmVySFRNTDtpZigic3RyaW5nIj09dHlwZW9mIGUmJiFPZS50ZXN0KGUpJiYha2VbKFRlLmV4ZWMoZSl8fFsiIiwiIl0pWzFdLnRvTG93ZXJDYXNlKCldKXtlPWNlLmh0bWxQcmVmaWx0ZXIoZSk7dHJ5e2Zvcig7bjxyO24rKykxPT09KHQ9dGhpc1tuXXx8e30pLm5vZGVUeXBlJiYoY2UuY2xlYW5EYXRhKFNlKHQsITEpKSx0LmlubmVySFRNTD1lKTt0PTB9Y2F0Y2goZSl7fX10JiZ0aGlzLmVtcHR5KCkuYXBwZW5kKGUpfSxudWxsLGUsYXJndW1lbnRzLmxlbmd0aCl9LHJlcGxhY2VXaXRoOmZ1bmN0aW9uKCl7dmFyIG49W107cmV0dXJuICRlKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMucGFyZW50Tm9kZTtjZS5pbkFycmF5KHRoaXMsbik8MCYmKGNlLmNsZWFuRGF0YShTZSh0aGlzKSksdCYmdC5yZXBsYWNlQ2hpbGQoZSx0aGlzKSl9LG4pfX0pLGNlLmVhY2goe2FwcGVuZFRvOiJhcHBlbmQiLHByZXBlbmRUbzoicHJlcGVuZCIsaW5zZXJ0QmVmb3JlOiJiZWZvcmUiLGluc2VydEFmdGVyOiJhZnRlciIscmVwbGFjZUFsbDoicmVwbGFjZVdpdGgifSxmdW5jdGlvbihlLGEpe2NlLmZuW2VdPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPVtdLHI9Y2UoZSksaT1yLmxlbmd0aC0xLG89MDtvPD1pO28rKyl0PW89PT1pP3RoaXM6dGhpcy5jbG9uZSghMCksY2UocltvXSlbYV0odCkscy5hcHBseShuLHQuZ2V0KCkpO3JldHVybiB0aGlzLnB1c2hTdGFjayhuKX19KTt2YXIgX2U9bmV3IFJlZ0V4cCgiXigiK0crIikoPyFweClbYS16JV0rJCIsImkiKSx6ZT0vXi0tLyxYZT1mdW5jdGlvbihlKXt2YXIgdD1lLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7cmV0dXJuIHQmJnQub3BlbmVyfHwodD1pZSksdC5nZXRDb21wdXRlZFN0eWxlKGUpfSxVZT1mdW5jdGlvbihlLHQsbil7dmFyIHIsaSxvPXt9O2ZvcihpIGluIHQpb1tpXT1lLnN0eWxlW2ldLGUuc3R5bGVbaV09dFtpXTtmb3IoaSBpbiByPW4uY2FsbChlKSx0KWUuc3R5bGVbaV09b1tpXTtyZXR1cm4gcn0sVmU9bmV3IFJlZ0V4cChRLmpvaW4oInwiKSwiaSIpO2Z1bmN0aW9uIEdlKGUsdCxuKXt2YXIgcixpLG8sYSxzPXplLnRlc3QodCksdT1lLnN0eWxlO3JldHVybihuPW58fFhlKGUpKSYmKGE9bi5nZXRQcm9wZXJ0eVZhbHVlKHQpfHxuW3RdLHMmJmEmJihhPWEucmVwbGFjZSh2ZSwiJDEiKXx8dm9pZCAwKSwiIiE9PWF8fEsoZSl8fChhPWNlLnN0eWxlKGUsdCkpLCFsZS5waXhlbEJveFN0eWxlcygpJiZfZS50ZXN0KGEpJiZWZS50ZXN0KHQpJiYocj11LndpZHRoLGk9dS5taW5XaWR0aCxvPXUubWF4V2lkdGgsdS5taW5XaWR0aD11Lm1heFdpZHRoPXUud2lkdGg9YSxhPW4ud2lkdGgsdS53aWR0aD1yLHUubWluV2lkdGg9aSx1Lm1heFdpZHRoPW8pKSx2b2lkIDAhPT1hP2ErIiI6YX1mdW5jdGlvbiBZZShlLHQpe3JldHVybntnZXQ6ZnVuY3Rpb24oKXtpZighZSgpKXJldHVybih0aGlzLmdldD10KS5hcHBseSh0aGlzLGFyZ3VtZW50cyk7ZGVsZXRlIHRoaXMuZ2V0fX19IWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe2lmKGwpe3Uuc3R5bGUuY3NzVGV4dD0icG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDt3aWR0aDo2MHB4O21hcmdpbi10b3A6MXB4O3BhZGRpbmc6MDtib3JkZXI6MCIsbC5zdHlsZS5jc3NUZXh0PSJwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmJsb2NrO2JveC1zaXppbmc6Ym9yZGVyLWJveDtvdmVyZmxvdzpzY3JvbGw7bWFyZ2luOmF1dG87Ym9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo2MCU7dG9wOjElIixKLmFwcGVuZENoaWxkKHUpLmFwcGVuZENoaWxkKGwpO3ZhciBlPWllLmdldENvbXB1dGVkU3R5bGUobCk7bj0iMSUiIT09ZS50b3Ascz0xMj09PXQoZS5tYXJnaW5MZWZ0KSxsLnN0eWxlLnJpZ2h0PSI2MCUiLG89MzY9PT10KGUucmlnaHQpLHI9MzY9PT10KGUud2lkdGgpLGwuc3R5bGUucG9zaXRpb249ImFic29sdXRlIixpPTEyPT09dChsLm9mZnNldFdpZHRoLzMpLEoucmVtb3ZlQ2hpbGQodSksbD1udWxsfX1mdW5jdGlvbiB0KGUpe3JldHVybiBNYXRoLnJvdW5kKHBhcnNlRmxvYXQoZSkpfXZhciBuLHIsaSxvLGEscyx1PUMuY3JlYXRlRWxlbWVudCgiZGl2IiksbD1DLmNyZWF0ZUVsZW1lbnQoImRpdiIpO2wuc3R5bGUmJihsLnN0eWxlLmJhY2tncm91bmRDbGlwPSJjb250ZW50LWJveCIsbC5jbG9uZU5vZGUoITApLnN0eWxlLmJhY2tncm91bmRDbGlwPSIiLGxlLmNsZWFyQ2xvbmVTdHlsZT0iY29udGVudC1ib3giPT09bC5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCxjZS5leHRlbmQobGUse2JveFNpemluZ1JlbGlhYmxlOmZ1bmN0aW9uKCl7cmV0dXJuIGUoKSxyfSxwaXhlbEJveFN0eWxlczpmdW5jdGlvbigpe3JldHVybiBlKCksb30scGl4ZWxQb3NpdGlvbjpmdW5jdGlvbigpe3JldHVybiBlKCksbn0scmVsaWFibGVNYXJnaW5MZWZ0OmZ1bmN0aW9uKCl7cmV0dXJuIGUoKSxzfSxzY3JvbGxib3hTaXplOmZ1bmN0aW9uKCl7cmV0dXJuIGUoKSxpfSxyZWxpYWJsZVRyRGltZW5zaW9uczpmdW5jdGlvbigpe3ZhciBlLHQsbixyO3JldHVybiBudWxsPT1hJiYoZT1DLmNyZWF0ZUVsZW1lbnQoInRhYmxlIiksdD1DLmNyZWF0ZUVsZW1lbnQoInRyIiksbj1DLmNyZWF0ZUVsZW1lbnQoImRpdiIpLGUuc3R5bGUuY3NzVGV4dD0icG9zaXRpb246YWJzb2x1dGU7bGVmdDotMTExMTFweDtib3JkZXItY29sbGFwc2U6c2VwYXJhdGUiLHQuc3R5bGUuY3NzVGV4dD0iYm94LXNpemluZzpjb250ZW50LWJveDtib3JkZXI6MXB4IHNvbGlkIix0LnN0eWxlLmhlaWdodD0iMXB4IixuLnN0eWxlLmhlaWdodD0iOXB4IixuLnN0eWxlLmRpc3BsYXk9ImJsb2NrIixKLmFwcGVuZENoaWxkKGUpLmFwcGVuZENoaWxkKHQpLmFwcGVuZENoaWxkKG4pLHI9aWUuZ2V0Q29tcHV0ZWRTdHlsZSh0KSxhPXBhcnNlSW50KHIuaGVpZ2h0LDEwKStwYXJzZUludChyLmJvcmRlclRvcFdpZHRoLDEwKStwYXJzZUludChyLmJvcmRlckJvdHRvbVdpZHRoLDEwKT09PXQub2Zmc2V0SGVpZ2h0LEoucmVtb3ZlQ2hpbGQoZSkpLGF9fSkpfSgpO3ZhciBRZT1bIldlYmtpdCIsIk1veiIsIm1zIl0sSmU9Qy5jcmVhdGVFbGVtZW50KCJkaXYiKS5zdHlsZSxLZT17fTtmdW5jdGlvbiBaZShlKXt2YXIgdD1jZS5jc3NQcm9wc1tlXXx8S2VbZV07cmV0dXJuIHR8fChlIGluIEplP2U6S2VbZV09ZnVuY3Rpb24oZSl7dmFyIHQ9ZVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSksbj1RZS5sZW5ndGg7d2hpbGUobi0tKWlmKChlPVFlW25dK3QpaW4gSmUpcmV0dXJuIGV9KGUpfHxlKX12YXIgZXQ9L14obm9uZXx0YWJsZSg/IS1jW2VhXSkuKykvLHR0PXtwb3NpdGlvbjoiYWJzb2x1dGUiLHZpc2liaWxpdHk6ImhpZGRlbiIsZGlzcGxheToiYmxvY2sifSxudD17bGV0dGVyU3BhY2luZzoiMCIsZm9udFdlaWdodDoiNDAwIn07ZnVuY3Rpb24gcnQoZSx0LG4pe3ZhciByPVkuZXhlYyh0KTtyZXR1cm4gcj9NYXRoLm1heCgwLHJbMl0tKG58fDApKSsoclszXXx8InB4Iik6dH1mdW5jdGlvbiBpdChlLHQsbixyLGksbyl7dmFyIGE9IndpZHRoIj09PXQ/MTowLHM9MCx1PTAsbD0wO2lmKG49PT0ocj8iYm9yZGVyIjoiY29udGVudCIpKXJldHVybiAwO2Zvcig7YTw0O2ErPTIpIm1hcmdpbiI9PT1uJiYobCs9Y2UuY3NzKGUsbitRW2FdLCEwLGkpKSxyPygiY29udGVudCI9PT1uJiYodS09Y2UuY3NzKGUsInBhZGRpbmciK1FbYV0sITAsaSkpLCJtYXJnaW4iIT09biYmKHUtPWNlLmNzcyhlLCJib3JkZXIiK1FbYV0rIldpZHRoIiwhMCxpKSkpOih1Kz1jZS5jc3MoZSwicGFkZGluZyIrUVthXSwhMCxpKSwicGFkZGluZyIhPT1uP3UrPWNlLmNzcyhlLCJib3JkZXIiK1FbYV0rIldpZHRoIiwhMCxpKTpzKz1jZS5jc3MoZSwiYm9yZGVyIitRW2FdKyJXaWR0aCIsITAsaSkpO3JldHVybiFyJiYwPD1vJiYodSs9TWF0aC5tYXgoMCxNYXRoLmNlaWwoZVsib2Zmc2V0Iit0WzBdLnRvVXBwZXJDYXNlKCkrdC5zbGljZSgxKV0tby11LXMtLjUpKXx8MCksdStsfWZ1bmN0aW9uIG90KGUsdCxuKXt2YXIgcj1YZShlKSxpPSghbGUuYm94U2l6aW5nUmVsaWFibGUoKXx8bikmJiJib3JkZXItYm94Ij09PWNlLmNzcyhlLCJib3hTaXppbmciLCExLHIpLG89aSxhPUdlKGUsdCxyKSxzPSJvZmZzZXQiK3RbMF0udG9VcHBlckNhc2UoKSt0LnNsaWNlKDEpO2lmKF9lLnRlc3QoYSkpe2lmKCFuKXJldHVybiBhO2E9ImF1dG8ifXJldHVybighbGUuYm94U2l6aW5nUmVsaWFibGUoKSYmaXx8IWxlLnJlbGlhYmxlVHJEaW1lbnNpb25zKCkmJmZlKGUsInRyIil8fCJhdXRvIj09PWF8fCFwYXJzZUZsb2F0KGEpJiYiaW5saW5lIj09PWNlLmNzcyhlLCJkaXNwbGF5IiwhMSxyKSkmJmUuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgmJihpPSJib3JkZXItYm94Ij09PWNlLmNzcyhlLCJib3hTaXppbmciLCExLHIpLChvPXMgaW4gZSkmJihhPWVbc10pKSwoYT1wYXJzZUZsb2F0KGEpfHwwKStpdChlLHQsbnx8KGk/ImJvcmRlciI6ImNvbnRlbnQiKSxvLHIsYSkrInB4In1mdW5jdGlvbiBhdChlLHQsbixyLGkpe3JldHVybiBuZXcgYXQucHJvdG90eXBlLmluaXQoZSx0LG4scixpKX1jZS5leHRlbmQoe2Nzc0hvb2tzOntvcGFjaXR5OntnZXQ6ZnVuY3Rpb24oZSx0KXtpZih0KXt2YXIgbj1HZShlLCJvcGFjaXR5Iik7cmV0dXJuIiI9PT1uPyIxIjpufX19fSxjc3NOdW1iZXI6e2FuaW1hdGlvbkl0ZXJhdGlvbkNvdW50OiEwLGFzcGVjdFJhdGlvOiEwLGJvcmRlckltYWdlU2xpY2U6ITAsY29sdW1uQ291bnQ6ITAsZmxleEdyb3c6ITAsZmxleFNocmluazohMCxmb250V2VpZ2h0OiEwLGdyaWRBcmVhOiEwLGdyaWRDb2x1bW46ITAsZ3JpZENvbHVtbkVuZDohMCxncmlkQ29sdW1uU3RhcnQ6ITAsZ3JpZFJvdzohMCxncmlkUm93RW5kOiEwLGdyaWRSb3dTdGFydDohMCxsaW5lSGVpZ2h0OiEwLG9wYWNpdHk6ITAsb3JkZXI6ITAsb3JwaGFuczohMCxzY2FsZTohMCx3aWRvd3M6ITAsekluZGV4OiEwLHpvb206ITAsZmlsbE9wYWNpdHk6ITAsZmxvb2RPcGFjaXR5OiEwLHN0b3BPcGFjaXR5OiEwLHN0cm9rZU1pdGVybGltaXQ6ITAsc3Ryb2tlT3BhY2l0eTohMH0sY3NzUHJvcHM6e30sc3R5bGU6ZnVuY3Rpb24oZSx0LG4scil7aWYoZSYmMyE9PWUubm9kZVR5cGUmJjghPT1lLm5vZGVUeXBlJiZlLnN0eWxlKXt2YXIgaSxvLGEscz1GKHQpLHU9emUudGVzdCh0KSxsPWUuc3R5bGU7aWYodXx8KHQ9WmUocykpLGE9Y2UuY3NzSG9va3NbdF18fGNlLmNzc0hvb2tzW3NdLHZvaWQgMD09PW4pcmV0dXJuIGEmJiJnZXQiaW4gYSYmdm9pZCAwIT09KGk9YS5nZXQoZSwhMSxyKSk/aTpsW3RdOyJzdHJpbmciPT09KG89dHlwZW9mIG4pJiYoaT1ZLmV4ZWMobikpJiZpWzFdJiYobj10ZShlLHQsaSksbz0ibnVtYmVyIiksbnVsbCE9biYmbj09biYmKCJudW1iZXIiIT09b3x8dXx8KG4rPWkmJmlbM118fChjZS5jc3NOdW1iZXJbc10/IiI6InB4IikpLGxlLmNsZWFyQ2xvbmVTdHlsZXx8IiIhPT1ufHwwIT09dC5pbmRleE9mKCJiYWNrZ3JvdW5kIil8fChsW3RdPSJpbmhlcml0IiksYSYmInNldCJpbiBhJiZ2b2lkIDA9PT0obj1hLnNldChlLG4scikpfHwodT9sLnNldFByb3BlcnR5KHQsbik6bFt0XT1uKSl9fSxjc3M6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbyxhLHM9Rih0KTtyZXR1cm4gemUudGVzdCh0KXx8KHQ9WmUocykpLChhPWNlLmNzc0hvb2tzW3RdfHxjZS5jc3NIb29rc1tzXSkmJiJnZXQiaW4gYSYmKGk9YS5nZXQoZSwhMCxuKSksdm9pZCAwPT09aSYmKGk9R2UoZSx0LHIpKSwibm9ybWFsIj09PWkmJnQgaW4gbnQmJihpPW50W3RdKSwiIj09PW58fG4/KG89cGFyc2VGbG9hdChpKSwhMD09PW58fGlzRmluaXRlKG8pP298fDA6aSk6aX19KSxjZS5lYWNoKFsiaGVpZ2h0Iiwid2lkdGgiXSxmdW5jdGlvbihlLHUpe2NlLmNzc0hvb2tzW3VdPXtnZXQ6ZnVuY3Rpb24oZSx0LG4pe2lmKHQpcmV0dXJuIWV0LnRlc3QoY2UuY3NzKGUsImRpc3BsYXkiKSl8fGUuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgmJmUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGg/b3QoZSx1LG4pOlVlKGUsdHQsZnVuY3Rpb24oKXtyZXR1cm4gb3QoZSx1LG4pfSl9LHNldDpmdW5jdGlvbihlLHQsbil7dmFyIHIsaT1YZShlKSxvPSFsZS5zY3JvbGxib3hTaXplKCkmJiJhYnNvbHV0ZSI9PT1pLnBvc2l0aW9uLGE9KG98fG4pJiYiYm9yZGVyLWJveCI9PT1jZS5jc3MoZSwiYm94U2l6aW5nIiwhMSxpKSxzPW4/aXQoZSx1LG4sYSxpKTowO3JldHVybiBhJiZvJiYocy09TWF0aC5jZWlsKGVbIm9mZnNldCIrdVswXS50b1VwcGVyQ2FzZSgpK3Uuc2xpY2UoMSldLXBhcnNlRmxvYXQoaVt1XSktaXQoZSx1LCJib3JkZXIiLCExLGkpLS41KSkscyYmKHI9WS5leGVjKHQpKSYmInB4IiE9PShyWzNdfHwicHgiKSYmKGUuc3R5bGVbdV09dCx0PWNlLmNzcyhlLHUpKSxydCgwLHQscyl9fX0pLGNlLmNzc0hvb2tzLm1hcmdpbkxlZnQ9WWUobGUucmVsaWFibGVNYXJnaW5MZWZ0LGZ1bmN0aW9uKGUsdCl7aWYodClyZXR1cm4ocGFyc2VGbG9hdChHZShlLCJtYXJnaW5MZWZ0IikpfHxlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQtVWUoZSx7bWFyZ2luTGVmdDowfSxmdW5jdGlvbigpe3JldHVybiBlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnR9KSkrInB4In0pLGNlLmVhY2goe21hcmdpbjoiIixwYWRkaW5nOiIiLGJvcmRlcjoiV2lkdGgifSxmdW5jdGlvbihpLG8pe2NlLmNzc0hvb2tzW2krb109e2V4cGFuZDpmdW5jdGlvbihlKXtmb3IodmFyIHQ9MCxuPXt9LHI9InN0cmluZyI9PXR5cGVvZiBlP2Uuc3BsaXQoIiAiKTpbZV07dDw0O3QrKyluW2krUVt0XStvXT1yW3RdfHxyW3QtMl18fHJbMF07cmV0dXJuIG59fSwibWFyZ2luIiE9PWkmJihjZS5jc3NIb29rc1tpK29dLnNldD1ydCl9KSxjZS5mbi5leHRlbmQoe2NzczpmdW5jdGlvbihlLHQpe3JldHVybiBNKHRoaXMsZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbz17fSxhPTA7aWYoQXJyYXkuaXNBcnJheSh0KSl7Zm9yKHI9WGUoZSksaT10Lmxlbmd0aDthPGk7YSsrKW9bdFthXV09Y2UuY3NzKGUsdFthXSwhMSxyKTtyZXR1cm4gb31yZXR1cm4gdm9pZCAwIT09bj9jZS5zdHlsZShlLHQsbik6Y2UuY3NzKGUsdCl9LGUsdCwxPGFyZ3VtZW50cy5sZW5ndGgpfX0pLCgoY2UuVHdlZW49YXQpLnByb3RvdHlwZT17Y29uc3RydWN0b3I6YXQsaW5pdDpmdW5jdGlvbihlLHQsbixyLGksbyl7dGhpcy5lbGVtPWUsdGhpcy5wcm9wPW4sdGhpcy5lYXNpbmc9aXx8Y2UuZWFzaW5nLl9kZWZhdWx0LHRoaXMub3B0aW9ucz10LHRoaXMuc3RhcnQ9dGhpcy5ub3c9dGhpcy5jdXIoKSx0aGlzLmVuZD1yLHRoaXMudW5pdD1vfHwoY2UuY3NzTnVtYmVyW25dPyIiOiJweCIpfSxjdXI6ZnVuY3Rpb24oKXt2YXIgZT1hdC5wcm9wSG9va3NbdGhpcy5wcm9wXTtyZXR1cm4gZSYmZS5nZXQ/ZS5nZXQodGhpcyk6YXQucHJvcEhvb2tzLl9kZWZhdWx0LmdldCh0aGlzKX0scnVuOmZ1bmN0aW9uKGUpe3ZhciB0LG49YXQucHJvcEhvb2tzW3RoaXMucHJvcF07cmV0dXJuIHRoaXMub3B0aW9ucy5kdXJhdGlvbj90aGlzLnBvcz10PWNlLmVhc2luZ1t0aGlzLmVhc2luZ10oZSx0aGlzLm9wdGlvbnMuZHVyYXRpb24qZSwwLDEsdGhpcy5vcHRpb25zLmR1cmF0aW9uKTp0aGlzLnBvcz10PWUsdGhpcy5ub3c9KHRoaXMuZW5kLXRoaXMuc3RhcnQpKnQrdGhpcy5zdGFydCx0aGlzLm9wdGlvbnMuc3RlcCYmdGhpcy5vcHRpb25zLnN0ZXAuY2FsbCh0aGlzLmVsZW0sdGhpcy5ub3csdGhpcyksbiYmbi5zZXQ/bi5zZXQodGhpcyk6YXQucHJvcEhvb2tzLl9kZWZhdWx0LnNldCh0aGlzKSx0aGlzfX0pLmluaXQucHJvdG90eXBlPWF0LnByb3RvdHlwZSwoYXQucHJvcEhvb2tzPXtfZGVmYXVsdDp7Z2V0OmZ1bmN0aW9uKGUpe3ZhciB0O3JldHVybiAxIT09ZS5lbGVtLm5vZGVUeXBlfHxudWxsIT1lLmVsZW1bZS5wcm9wXSYmbnVsbD09ZS5lbGVtLnN0eWxlW2UucHJvcF0/ZS5lbGVtW2UucHJvcF06KHQ9Y2UuY3NzKGUuZWxlbSxlLnByb3AsIiIpKSYmImF1dG8iIT09dD90OjB9LHNldDpmdW5jdGlvbihlKXtjZS5meC5zdGVwW2UucHJvcF0/Y2UuZnguc3RlcFtlLnByb3BdKGUpOjEhPT1lLmVsZW0ubm9kZVR5cGV8fCFjZS5jc3NIb29rc1tlLnByb3BdJiZudWxsPT1lLmVsZW0uc3R5bGVbWmUoZS5wcm9wKV0/ZS5lbGVtW2UucHJvcF09ZS5ub3c6Y2Uuc3R5bGUoZS5lbGVtLGUucHJvcCxlLm5vdytlLnVuaXQpfX19KS5zY3JvbGxUb3A9YXQucHJvcEhvb2tzLnNjcm9sbExlZnQ9e3NldDpmdW5jdGlvbihlKXtlLmVsZW0ubm9kZVR5cGUmJmUuZWxlbS5wYXJlbnROb2RlJiYoZS5lbGVtW2UucHJvcF09ZS5ub3cpfX0sY2UuZWFzaW5nPXtsaW5lYXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGV9LHN3aW5nOmZ1bmN0aW9uKGUpe3JldHVybi41LU1hdGguY29zKGUqTWF0aC5QSSkvMn0sX2RlZmF1bHQ6InN3aW5nIn0sY2UuZng9YXQucHJvdG90eXBlLmluaXQsY2UuZnguc3RlcD17fTt2YXIgc3QsdXQsbHQsY3QsZnQ9L14oPzp0b2dnbGV8c2hvd3xoaWRlKSQvLHB0PS9xdWV1ZUhvb2tzJC87ZnVuY3Rpb24gZHQoKXt1dCYmKCExPT09Qy5oaWRkZW4mJmllLnJlcXVlc3RBbmltYXRpb25GcmFtZT9pZS5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZHQpOmllLnNldFRpbWVvdXQoZHQsY2UuZnguaW50ZXJ2YWwpLGNlLmZ4LnRpY2soKSl9ZnVuY3Rpb24gaHQoKXtyZXR1cm4gaWUuc2V0VGltZW91dChmdW5jdGlvbigpe3N0PXZvaWQgMH0pLHN0PURhdGUubm93KCl9ZnVuY3Rpb24gZ3QoZSx0KXt2YXIgbixyPTAsaT17aGVpZ2h0OmV9O2Zvcih0PXQ/MTowO3I8NDtyKz0yLXQpaVsibWFyZ2luIisobj1RW3JdKV09aVsicGFkZGluZyIrbl09ZTtyZXR1cm4gdCYmKGkub3BhY2l0eT1pLndpZHRoPWUpLGl9ZnVuY3Rpb24gdnQoZSx0LG4pe2Zvcih2YXIgcixpPSh5dC50d2VlbmVyc1t0XXx8W10pLmNvbmNhdCh5dC50d2VlbmVyc1siKiJdKSxvPTAsYT1pLmxlbmd0aDtvPGE7bysrKWlmKHI9aVtvXS5jYWxsKG4sdCxlKSlyZXR1cm4gcn1mdW5jdGlvbiB5dChvLGUsdCl7dmFyIG4sYSxyPTAsaT15dC5wcmVmaWx0ZXJzLmxlbmd0aCxzPWNlLkRlZmVycmVkKCkuYWx3YXlzKGZ1bmN0aW9uKCl7ZGVsZXRlIHUuZWxlbX0pLHU9ZnVuY3Rpb24oKXtpZihhKXJldHVybiExO2Zvcih2YXIgZT1zdHx8aHQoKSx0PU1hdGgubWF4KDAsbC5zdGFydFRpbWUrbC5kdXJhdGlvbi1lKSxuPTEtKHQvbC5kdXJhdGlvbnx8MCkscj0wLGk9bC50d2VlbnMubGVuZ3RoO3I8aTtyKyspbC50d2VlbnNbcl0ucnVuKG4pO3JldHVybiBzLm5vdGlmeVdpdGgobyxbbCxuLHRdKSxuPDEmJmk/dDooaXx8cy5ub3RpZnlXaXRoKG8sW2wsMSwwXSkscy5yZXNvbHZlV2l0aChvLFtsXSksITEpfSxsPXMucHJvbWlzZSh7ZWxlbTpvLHByb3BzOmNlLmV4dGVuZCh7fSxlKSxvcHRzOmNlLmV4dGVuZCghMCx7c3BlY2lhbEVhc2luZzp7fSxlYXNpbmc6Y2UuZWFzaW5nLl9kZWZhdWx0fSx0KSxvcmlnaW5hbFByb3BlcnRpZXM6ZSxvcmlnaW5hbE9wdGlvbnM6dCxzdGFydFRpbWU6c3R8fGh0KCksZHVyYXRpb246dC5kdXJhdGlvbix0d2VlbnM6W10sY3JlYXRlVHdlZW46ZnVuY3Rpb24oZSx0KXt2YXIgbj1jZS5Ud2VlbihvLGwub3B0cyxlLHQsbC5vcHRzLnNwZWNpYWxFYXNpbmdbZV18fGwub3B0cy5lYXNpbmcpO3JldHVybiBsLnR3ZWVucy5wdXNoKG4pLG59LHN0b3A6ZnVuY3Rpb24oZSl7dmFyIHQ9MCxuPWU/bC50d2VlbnMubGVuZ3RoOjA7aWYoYSlyZXR1cm4gdGhpcztmb3IoYT0hMDt0PG47dCsrKWwudHdlZW5zW3RdLnJ1bigxKTtyZXR1cm4gZT8ocy5ub3RpZnlXaXRoKG8sW2wsMSwwXSkscy5yZXNvbHZlV2l0aChvLFtsLGVdKSk6cy5yZWplY3RXaXRoKG8sW2wsZV0pLHRoaXN9fSksYz1sLnByb3BzO2ZvcighZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksbyxhO2ZvcihuIGluIGUpaWYoaT10W3I9RihuKV0sbz1lW25dLEFycmF5LmlzQXJyYXkobykmJihpPW9bMV0sbz1lW25dPW9bMF0pLG4hPT1yJiYoZVtyXT1vLGRlbGV0ZSBlW25dKSwoYT1jZS5jc3NIb29rc1tyXSkmJiJleHBhbmQiaW4gYSlmb3IobiBpbiBvPWEuZXhwYW5kKG8pLGRlbGV0ZSBlW3JdLG8pbiBpbiBlfHwoZVtuXT1vW25dLHRbbl09aSk7ZWxzZSB0W3JdPWl9KGMsbC5vcHRzLnNwZWNpYWxFYXNpbmcpO3I8aTtyKyspaWYobj15dC5wcmVmaWx0ZXJzW3JdLmNhbGwobCxvLGMsbC5vcHRzKSlyZXR1cm4gdihuLnN0b3ApJiYoY2UuX3F1ZXVlSG9va3MobC5lbGVtLGwub3B0cy5xdWV1ZSkuc3RvcD1uLnN0b3AuYmluZChuKSksbjtyZXR1cm4gY2UubWFwKGMsdnQsbCksdihsLm9wdHMuc3RhcnQpJiZsLm9wdHMuc3RhcnQuY2FsbChvLGwpLGwucHJvZ3Jlc3MobC5vcHRzLnByb2dyZXNzKS5kb25lKGwub3B0cy5kb25lLGwub3B0cy5jb21wbGV0ZSkuZmFpbChsLm9wdHMuZmFpbCkuYWx3YXlzKGwub3B0cy5hbHdheXMpLGNlLmZ4LnRpbWVyKGNlLmV4dGVuZCh1LHtlbGVtOm8sYW5pbTpsLHF1ZXVlOmwub3B0cy5xdWV1ZX0pKSxsfWNlLkFuaW1hdGlvbj1jZS5leHRlbmQoeXQse3R3ZWVuZXJzOnsiKiI6W2Z1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5jcmVhdGVUd2VlbihlLHQpO3JldHVybiB0ZShuLmVsZW0sZSxZLmV4ZWModCksbiksbn1dfSx0d2VlbmVyOmZ1bmN0aW9uKGUsdCl7dihlKT8odD1lLGU9WyIqIl0pOmU9ZS5tYXRjaChEKTtmb3IodmFyIG4scj0wLGk9ZS5sZW5ndGg7cjxpO3IrKyluPWVbcl0seXQudHdlZW5lcnNbbl09eXQudHdlZW5lcnNbbl18fFtdLHl0LnR3ZWVuZXJzW25dLnVuc2hpZnQodCl9LHByZWZpbHRlcnM6W2Z1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG8sYSxzLHUsbCxjLGY9IndpZHRoImluIHR8fCJoZWlnaHQiaW4gdCxwPXRoaXMsZD17fSxoPWUuc3R5bGUsZz1lLm5vZGVUeXBlJiZlZShlKSx2PV8uZ2V0KGUsImZ4c2hvdyIpO2ZvcihyIGluIG4ucXVldWV8fChudWxsPT0oYT1jZS5fcXVldWVIb29rcyhlLCJmeCIpKS51bnF1ZXVlZCYmKGEudW5xdWV1ZWQ9MCxzPWEuZW1wdHkuZmlyZSxhLmVtcHR5LmZpcmU9ZnVuY3Rpb24oKXthLnVucXVldWVkfHxzKCl9KSxhLnVucXVldWVkKysscC5hbHdheXMoZnVuY3Rpb24oKXtwLmFsd2F5cyhmdW5jdGlvbigpe2EudW5xdWV1ZWQtLSxjZS5xdWV1ZShlLCJmeCIpLmxlbmd0aHx8YS5lbXB0eS5maXJlKCl9KX0pKSx0KWlmKGk9dFtyXSxmdC50ZXN0KGkpKXtpZihkZWxldGUgdFtyXSxvPW98fCJ0b2dnbGUiPT09aSxpPT09KGc/ImhpZGUiOiJzaG93Iikpe2lmKCJzaG93IiE9PWl8fCF2fHx2b2lkIDA9PT12W3JdKWNvbnRpbnVlO2c9ITB9ZFtyXT12JiZ2W3JdfHxjZS5zdHlsZShlLHIpfWlmKCh1PSFjZS5pc0VtcHR5T2JqZWN0KHQpKXx8IWNlLmlzRW1wdHlPYmplY3QoZCkpZm9yKHIgaW4gZiYmMT09PWUubm9kZVR5cGUmJihuLm92ZXJmbG93PVtoLm92ZXJmbG93LGgub3ZlcmZsb3dYLGgub3ZlcmZsb3dZXSxudWxsPT0obD12JiZ2LmRpc3BsYXkpJiYobD1fLmdldChlLCJkaXNwbGF5IikpLCJub25lIj09PShjPWNlLmNzcyhlLCJkaXNwbGF5IikpJiYobD9jPWw6KHJlKFtlXSwhMCksbD1lLnN0eWxlLmRpc3BsYXl8fGwsYz1jZS5jc3MoZSwiZGlzcGxheSIpLHJlKFtlXSkpKSwoImlubGluZSI9PT1jfHwiaW5saW5lLWJsb2NrIj09PWMmJm51bGwhPWwpJiYibm9uZSI9PT1jZS5jc3MoZSwiZmxvYXQiKSYmKHV8fChwLmRvbmUoZnVuY3Rpb24oKXtoLmRpc3BsYXk9bH0pLG51bGw9PWwmJihjPWguZGlzcGxheSxsPSJub25lIj09PWM/IiI6YykpLGguZGlzcGxheT0iaW5saW5lLWJsb2NrIikpLG4ub3ZlcmZsb3cmJihoLm92ZXJmbG93PSJoaWRkZW4iLHAuYWx3YXlzKGZ1bmN0aW9uKCl7aC5vdmVyZmxvdz1uLm92ZXJmbG93WzBdLGgub3ZlcmZsb3dYPW4ub3ZlcmZsb3dbMV0saC5vdmVyZmxvd1k9bi5vdmVyZmxvd1syXX0pKSx1PSExLGQpdXx8KHY/ImhpZGRlbiJpbiB2JiYoZz12LmhpZGRlbik6dj1fLmFjY2VzcyhlLCJmeHNob3ciLHtkaXNwbGF5Omx9KSxvJiYodi5oaWRkZW49IWcpLGcmJnJlKFtlXSwhMCkscC5kb25lKGZ1bmN0aW9uKCl7Zm9yKHIgaW4gZ3x8cmUoW2VdKSxfLnJlbW92ZShlLCJmeHNob3ciKSxkKWNlLnN0eWxlKGUscixkW3JdKX0pKSx1PXZ0KGc/dltyXTowLHIscCksciBpbiB2fHwodltyXT11LnN0YXJ0LGcmJih1LmVuZD11LnN0YXJ0LHUuc3RhcnQ9MCkpfV0scHJlZmlsdGVyOmZ1bmN0aW9uKGUsdCl7dD95dC5wcmVmaWx0ZXJzLnVuc2hpZnQoZSk6eXQucHJlZmlsdGVycy5wdXNoKGUpfX0pLGNlLnNwZWVkPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1lJiYib2JqZWN0Ij09dHlwZW9mIGU/Y2UuZXh0ZW5kKHt9LGUpOntjb21wbGV0ZTpufHwhbiYmdHx8dihlKSYmZSxkdXJhdGlvbjplLGVhc2luZzpuJiZ0fHx0JiYhdih0KSYmdH07cmV0dXJuIGNlLmZ4Lm9mZj9yLmR1cmF0aW9uPTA6Im51bWJlciIhPXR5cGVvZiByLmR1cmF0aW9uJiYoci5kdXJhdGlvbiBpbiBjZS5meC5zcGVlZHM/ci5kdXJhdGlvbj1jZS5meC5zcGVlZHNbci5kdXJhdGlvbl06ci5kdXJhdGlvbj1jZS5meC5zcGVlZHMuX2RlZmF1bHQpLG51bGwhPXIucXVldWUmJiEwIT09ci5xdWV1ZXx8KHIucXVldWU9ImZ4Iiksci5vbGQ9ci5jb21wbGV0ZSxyLmNvbXBsZXRlPWZ1bmN0aW9uKCl7dihyLm9sZCkmJnIub2xkLmNhbGwodGhpcyksci5xdWV1ZSYmY2UuZGVxdWV1ZSh0aGlzLHIucXVldWUpfSxyfSxjZS5mbi5leHRlbmQoe2ZhZGVUbzpmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gdGhpcy5maWx0ZXIoZWUpLmNzcygib3BhY2l0eSIsMCkuc2hvdygpLmVuZCgpLmFuaW1hdGUoe29wYWNpdHk6dH0sZSxuLHIpfSxhbmltYXRlOmZ1bmN0aW9uKHQsZSxuLHIpe3ZhciBpPWNlLmlzRW1wdHlPYmplY3QodCksbz1jZS5zcGVlZChlLG4sciksYT1mdW5jdGlvbigpe3ZhciBlPXl0KHRoaXMsY2UuZXh0ZW5kKHt9LHQpLG8pOyhpfHxfLmdldCh0aGlzLCJmaW5pc2giKSkmJmUuc3RvcCghMCl9O3JldHVybiBhLmZpbmlzaD1hLGl8fCExPT09by5xdWV1ZT90aGlzLmVhY2goYSk6dGhpcy5xdWV1ZShvLnF1ZXVlLGEpfSxzdG9wOmZ1bmN0aW9uKGksZSxvKXt2YXIgYT1mdW5jdGlvbihlKXt2YXIgdD1lLnN0b3A7ZGVsZXRlIGUuc3RvcCx0KG8pfTtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIGkmJihvPWUsZT1pLGk9dm9pZCAwKSxlJiZ0aGlzLnF1ZXVlKGl8fCJmeCIsW10pLHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBlPSEwLHQ9bnVsbCE9aSYmaSsicXVldWVIb29rcyIsbj1jZS50aW1lcnMscj1fLmdldCh0aGlzKTtpZih0KXJbdF0mJnJbdF0uc3RvcCYmYShyW3RdKTtlbHNlIGZvcih0IGluIHIpclt0XSYmclt0XS5zdG9wJiZwdC50ZXN0KHQpJiZhKHJbdF0pO2Zvcih0PW4ubGVuZ3RoO3QtLTspblt0XS5lbGVtIT09dGhpc3x8bnVsbCE9aSYmblt0XS5xdWV1ZSE9PWl8fChuW3RdLmFuaW0uc3RvcChvKSxlPSExLG4uc3BsaWNlKHQsMSkpOyFlJiZvfHxjZS5kZXF1ZXVlKHRoaXMsaSl9KX0sZmluaXNoOmZ1bmN0aW9uKGEpe3JldHVybiExIT09YSYmKGE9YXx8ImZ4IiksdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGUsdD1fLmdldCh0aGlzKSxuPXRbYSsicXVldWUiXSxyPXRbYSsicXVldWVIb29rcyJdLGk9Y2UudGltZXJzLG89bj9uLmxlbmd0aDowO2Zvcih0LmZpbmlzaD0hMCxjZS5xdWV1ZSh0aGlzLGEsW10pLHImJnIuc3RvcCYmci5zdG9wLmNhbGwodGhpcywhMCksZT1pLmxlbmd0aDtlLS07KWlbZV0uZWxlbT09PXRoaXMmJmlbZV0ucXVldWU9PT1hJiYoaVtlXS5hbmltLnN0b3AoITApLGkuc3BsaWNlKGUsMSkpO2ZvcihlPTA7ZTxvO2UrKyluW2VdJiZuW2VdLmZpbmlzaCYmbltlXS5maW5pc2guY2FsbCh0aGlzKTtkZWxldGUgdC5maW5pc2h9KX19KSxjZS5lYWNoKFsidG9nZ2xlIiwic2hvdyIsImhpZGUiXSxmdW5jdGlvbihlLHIpe3ZhciBpPWNlLmZuW3JdO2NlLmZuW3JdPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbnVsbD09ZXx8ImJvb2xlYW4iPT10eXBlb2YgZT9pLmFwcGx5KHRoaXMsYXJndW1lbnRzKTp0aGlzLmFuaW1hdGUoZ3QociwhMCksZSx0LG4pfX0pLGNlLmVhY2goe3NsaWRlRG93bjpndCgic2hvdyIpLHNsaWRlVXA6Z3QoImhpZGUiKSxzbGlkZVRvZ2dsZTpndCgidG9nZ2xlIiksZmFkZUluOntvcGFjaXR5OiJzaG93In0sZmFkZU91dDp7b3BhY2l0eToiaGlkZSJ9LGZhZGVUb2dnbGU6e29wYWNpdHk6InRvZ2dsZSJ9fSxmdW5jdGlvbihlLHIpe2NlLmZuW2VdPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdGhpcy5hbmltYXRlKHIsZSx0LG4pfX0pLGNlLnRpbWVycz1bXSxjZS5meC50aWNrPWZ1bmN0aW9uKCl7dmFyIGUsdD0wLG49Y2UudGltZXJzO2ZvcihzdD1EYXRlLm5vdygpO3Q8bi5sZW5ndGg7dCsrKShlPW5bdF0pKCl8fG5bdF0hPT1lfHxuLnNwbGljZSh0LS0sMSk7bi5sZW5ndGh8fGNlLmZ4LnN0b3AoKSxzdD12b2lkIDB9LGNlLmZ4LnRpbWVyPWZ1bmN0aW9uKGUpe2NlLnRpbWVycy5wdXNoKGUpLGNlLmZ4LnN0YXJ0KCl9LGNlLmZ4LmludGVydmFsPTEzLGNlLmZ4LnN0YXJ0PWZ1bmN0aW9uKCl7dXR8fCh1dD0hMCxkdCgpKX0sY2UuZnguc3RvcD1mdW5jdGlvbigpe3V0PW51bGx9LGNlLmZ4LnNwZWVkcz17c2xvdzo2MDAsZmFzdDoyMDAsX2RlZmF1bHQ6NDAwfSxjZS5mbi5kZWxheT1mdW5jdGlvbihyLGUpe3JldHVybiByPWNlLmZ4JiZjZS5meC5zcGVlZHNbcl18fHIsZT1lfHwiZngiLHRoaXMucXVldWUoZSxmdW5jdGlvbihlLHQpe3ZhciBuPWllLnNldFRpbWVvdXQoZSxyKTt0LnN0b3A9ZnVuY3Rpb24oKXtpZS5jbGVhclRpbWVvdXQobil9fSl9LGx0PUMuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSxjdD1DLmNyZWF0ZUVsZW1lbnQoInNlbGVjdCIpLmFwcGVuZENoaWxkKEMuY3JlYXRlRWxlbWVudCgib3B0aW9uIikpLGx0LnR5cGU9ImNoZWNrYm94IixsZS5jaGVja09uPSIiIT09bHQudmFsdWUsbGUub3B0U2VsZWN0ZWQ9Y3Quc2VsZWN0ZWQsKGx0PUMuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSkudmFsdWU9InQiLGx0LnR5cGU9InJhZGlvIixsZS5yYWRpb1ZhbHVlPSJ0Ij09PWx0LnZhbHVlO3ZhciBtdCx4dD1jZS5leHByLmF0dHJIYW5kbGU7Y2UuZm4uZXh0ZW5kKHthdHRyOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIE0odGhpcyxjZS5hdHRyLGUsdCwxPGFyZ3VtZW50cy5sZW5ndGgpfSxyZW1vdmVBdHRyOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXtjZS5yZW1vdmVBdHRyKHRoaXMsZSl9KX19KSxjZS5leHRlbmQoe2F0dHI6ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbz1lLm5vZGVUeXBlO2lmKDMhPT1vJiY4IT09byYmMiE9PW8pcmV0dXJuInVuZGVmaW5lZCI9PXR5cGVvZiBlLmdldEF0dHJpYnV0ZT9jZS5wcm9wKGUsdCxuKTooMT09PW8mJmNlLmlzWE1MRG9jKGUpfHwoaT1jZS5hdHRySG9va3NbdC50b0xvd2VyQ2FzZSgpXXx8KGNlLmV4cHIubWF0Y2guYm9vbC50ZXN0KHQpP210OnZvaWQgMCkpLHZvaWQgMCE9PW4/bnVsbD09PW4/dm9pZCBjZS5yZW1vdmVBdHRyKGUsdCk6aSYmInNldCJpbiBpJiZ2b2lkIDAhPT0ocj1pLnNldChlLG4sdCkpP3I6KGUuc2V0QXR0cmlidXRlKHQsbisiIiksbik6aSYmImdldCJpbiBpJiZudWxsIT09KHI9aS5nZXQoZSx0KSk/cjpudWxsPT0ocj1jZS5maW5kLmF0dHIoZSx0KSk/dm9pZCAwOnIpfSxhdHRySG9va3M6e3R5cGU6e3NldDpmdW5jdGlvbihlLHQpe2lmKCFsZS5yYWRpb1ZhbHVlJiYicmFkaW8iPT09dCYmZmUoZSwiaW5wdXQiKSl7dmFyIG49ZS52YWx1ZTtyZXR1cm4gZS5zZXRBdHRyaWJ1dGUoInR5cGUiLHQpLG4mJihlLnZhbHVlPW4pLHR9fX19LHJlbW92ZUF0dHI6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPTAsaT10JiZ0Lm1hdGNoKEQpO2lmKGkmJjE9PT1lLm5vZGVUeXBlKXdoaWxlKG49aVtyKytdKWUucmVtb3ZlQXR0cmlidXRlKG4pfX0pLG10PXtzZXQ6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiExPT09dD9jZS5yZW1vdmVBdHRyKGUsbik6ZS5zZXRBdHRyaWJ1dGUobixuKSxufX0sY2UuZWFjaChjZS5leHByLm1hdGNoLmJvb2wuc291cmNlLm1hdGNoKC9cdysvZyksZnVuY3Rpb24oZSx0KXt2YXIgYT14dFt0XXx8Y2UuZmluZC5hdHRyO3h0W3RdPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG89dC50b0xvd2VyQ2FzZSgpO3JldHVybiBufHwoaT14dFtvXSx4dFtvXT1yLHI9bnVsbCE9YShlLHQsbik/bzpudWxsLHh0W29dPWkpLHJ9fSk7dmFyIGJ0PS9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2ksd3Q9L14oPzphfGFyZWEpJC9pO2Z1bmN0aW9uIFR0KGUpe3JldHVybihlLm1hdGNoKEQpfHxbXSkuam9pbigiICIpfWZ1bmN0aW9uIEN0KGUpe3JldHVybiBlLmdldEF0dHJpYnV0ZSYmZS5nZXRBdHRyaWJ1dGUoImNsYXNzIil8fCIifWZ1bmN0aW9uIGt0KGUpe3JldHVybiBBcnJheS5pc0FycmF5KGUpP2U6InN0cmluZyI9PXR5cGVvZiBlJiZlLm1hdGNoKEQpfHxbXX1jZS5mbi5leHRlbmQoe3Byb3A6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gTSh0aGlzLGNlLnByb3AsZSx0LDE8YXJndW1lbnRzLmxlbmd0aCl9LHJlbW92ZVByb3A6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe2RlbGV0ZSB0aGlzW2NlLnByb3BGaXhbZV18fGVdfSl9fSksY2UuZXh0ZW5kKHtwcm9wOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG89ZS5ub2RlVHlwZTtpZigzIT09byYmOCE9PW8mJjIhPT1vKXJldHVybiAxPT09byYmY2UuaXNYTUxEb2MoZSl8fCh0PWNlLnByb3BGaXhbdF18fHQsaT1jZS5wcm9wSG9va3NbdF0pLHZvaWQgMCE9PW4/aSYmInNldCJpbiBpJiZ2b2lkIDAhPT0ocj1pLnNldChlLG4sdCkpP3I6ZVt0XT1uOmkmJiJnZXQiaW4gaSYmbnVsbCE9PShyPWkuZ2V0KGUsdCkpP3I6ZVt0XX0scHJvcEhvb2tzOnt0YWJJbmRleDp7Z2V0OmZ1bmN0aW9uKGUpe3ZhciB0PWNlLmZpbmQuYXR0cihlLCJ0YWJpbmRleCIpO3JldHVybiB0P3BhcnNlSW50KHQsMTApOmJ0LnRlc3QoZS5ub2RlTmFtZSl8fHd0LnRlc3QoZS5ub2RlTmFtZSkmJmUuaHJlZj8wOi0xfX19LHByb3BGaXg6eyJmb3IiOiJodG1sRm9yIiwiY2xhc3MiOiJjbGFzc05hbWUifX0pLGxlLm9wdFNlbGVjdGVkfHwoY2UucHJvcEhvb2tzLnNlbGVjdGVkPXtnZXQ6ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5wYXJlbnROb2RlO3JldHVybiB0JiZ0LnBhcmVudE5vZGUmJnQucGFyZW50Tm9kZS5zZWxlY3RlZEluZGV4LG51bGx9LHNldDpmdW5jdGlvbihlKXt2YXIgdD1lLnBhcmVudE5vZGU7dCYmKHQuc2VsZWN0ZWRJbmRleCx0LnBhcmVudE5vZGUmJnQucGFyZW50Tm9kZS5zZWxlY3RlZEluZGV4KX19KSxjZS5lYWNoKFsidGFiSW5kZXgiLCJyZWFkT25seSIsIm1heExlbmd0aCIsImNlbGxTcGFjaW5nIiwiY2VsbFBhZGRpbmciLCJyb3dTcGFuIiwiY29sU3BhbiIsInVzZU1hcCIsImZyYW1lQm9yZGVyIiwiY29udGVudEVkaXRhYmxlIl0sZnVuY3Rpb24oKXtjZS5wcm9wRml4W3RoaXMudG9Mb3dlckNhc2UoKV09dGhpc30pLGNlLmZuLmV4dGVuZCh7YWRkQ2xhc3M6ZnVuY3Rpb24odCl7dmFyIGUsbixyLGksbyxhO3JldHVybiB2KHQpP3RoaXMuZWFjaChmdW5jdGlvbihlKXtjZSh0aGlzKS5hZGRDbGFzcyh0LmNhbGwodGhpcyxlLEN0KHRoaXMpKSl9KTooZT1rdCh0KSkubGVuZ3RoP3RoaXMuZWFjaChmdW5jdGlvbigpe2lmKHI9Q3QodGhpcyksbj0xPT09dGhpcy5ub2RlVHlwZSYmIiAiK1R0KHIpKyIgIil7Zm9yKG89MDtvPGUubGVuZ3RoO28rKylpPWVbb10sbi5pbmRleE9mKCIgIitpKyIgIik8MCYmKG4rPWkrIiAiKTthPVR0KG4pLHIhPT1hJiZ0aGlzLnNldEF0dHJpYnV0ZSgiY2xhc3MiLGEpfX0pOnRoaXN9LHJlbW92ZUNsYXNzOmZ1bmN0aW9uKHQpe3ZhciBlLG4scixpLG8sYTtyZXR1cm4gdih0KT90aGlzLmVhY2goZnVuY3Rpb24oZSl7Y2UodGhpcykucmVtb3ZlQ2xhc3ModC5jYWxsKHRoaXMsZSxDdCh0aGlzKSkpfSk6YXJndW1lbnRzLmxlbmd0aD8oZT1rdCh0KSkubGVuZ3RoP3RoaXMuZWFjaChmdW5jdGlvbigpe2lmKHI9Q3QodGhpcyksbj0xPT09dGhpcy5ub2RlVHlwZSYmIiAiK1R0KHIpKyIgIil7Zm9yKG89MDtvPGUubGVuZ3RoO28rKyl7aT1lW29dO3doaWxlKC0xPG4uaW5kZXhPZigiICIraSsiICIpKW49bi5yZXBsYWNlKCIgIitpKyIgIiwiICIpfWE9VHQobiksciE9PWEmJnRoaXMuc2V0QXR0cmlidXRlKCJjbGFzcyIsYSl9fSk6dGhpczp0aGlzLmF0dHIoImNsYXNzIiwiIil9LHRvZ2dsZUNsYXNzOmZ1bmN0aW9uKHQsbil7dmFyIGUscixpLG8sYT10eXBlb2YgdCxzPSJzdHJpbmciPT09YXx8QXJyYXkuaXNBcnJheSh0KTtyZXR1cm4gdih0KT90aGlzLmVhY2goZnVuY3Rpb24oZSl7Y2UodGhpcykudG9nZ2xlQ2xhc3ModC5jYWxsKHRoaXMsZSxDdCh0aGlzKSxuKSxuKX0pOiJib29sZWFuIj09dHlwZW9mIG4mJnM/bj90aGlzLmFkZENsYXNzKHQpOnRoaXMucmVtb3ZlQ2xhc3ModCk6KGU9a3QodCksdGhpcy5lYWNoKGZ1bmN0aW9uKCl7aWYocylmb3Iobz1jZSh0aGlzKSxpPTA7aTxlLmxlbmd0aDtpKyspcj1lW2ldLG8uaGFzQ2xhc3Mocik/by5yZW1vdmVDbGFzcyhyKTpvLmFkZENsYXNzKHIpO2Vsc2Ugdm9pZCAwIT09dCYmImJvb2xlYW4iIT09YXx8KChyPUN0KHRoaXMpKSYmXy5zZXQodGhpcywiX19jbGFzc05hbWVfXyIsciksdGhpcy5zZXRBdHRyaWJ1dGUmJnRoaXMuc2V0QXR0cmlidXRlKCJjbGFzcyIscnx8ITE9PT10PyIiOl8uZ2V0KHRoaXMsIl9fY2xhc3NOYW1lX18iKXx8IiIpKX0pKX0saGFzQ2xhc3M6ZnVuY3Rpb24oZSl7dmFyIHQsbixyPTA7dD0iICIrZSsiICI7d2hpbGUobj10aGlzW3IrK10paWYoMT09PW4ubm9kZVR5cGUmJi0xPCgiICIrVHQoQ3QobikpKyIgIikuaW5kZXhPZih0KSlyZXR1cm4hMDtyZXR1cm4hMX19KTt2YXIgU3Q9L1xyL2c7Y2UuZm4uZXh0ZW5kKHt2YWw6ZnVuY3Rpb24obil7dmFyIHIsZSxpLHQ9dGhpc1swXTtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8oaT12KG4pLHRoaXMuZWFjaChmdW5jdGlvbihlKXt2YXIgdDsxPT09dGhpcy5ub2RlVHlwZSYmKG51bGw9PSh0PWk/bi5jYWxsKHRoaXMsZSxjZSh0aGlzKS52YWwoKSk6bik/dD0iIjoibnVtYmVyIj09dHlwZW9mIHQ/dCs9IiI6QXJyYXkuaXNBcnJheSh0KSYmKHQ9Y2UubWFwKHQsZnVuY3Rpb24oZSl7cmV0dXJuIG51bGw9PWU/IiI6ZSsiIn0pKSwocj1jZS52YWxIb29rc1t0aGlzLnR5cGVdfHxjZS52YWxIb29rc1t0aGlzLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCldKSYmInNldCJpbiByJiZ2b2lkIDAhPT1yLnNldCh0aGlzLHQsInZhbHVlIil8fCh0aGlzLnZhbHVlPXQpKX0pKTp0PyhyPWNlLnZhbEhvb2tzW3QudHlwZV18fGNlLnZhbEhvb2tzW3Qubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0pJiYiZ2V0ImluIHImJnZvaWQgMCE9PShlPXIuZ2V0KHQsInZhbHVlIikpP2U6InN0cmluZyI9PXR5cGVvZihlPXQudmFsdWUpP2UucmVwbGFjZShTdCwiIik6bnVsbD09ZT8iIjplOnZvaWQgMH19KSxjZS5leHRlbmQoe3ZhbEhvb2tzOntvcHRpb246e2dldDpmdW5jdGlvbihlKXt2YXIgdD1jZS5maW5kLmF0dHIoZSwidmFsdWUiKTtyZXR1cm4gbnVsbCE9dD90OlR0KGNlLnRleHQoZSkpfX0sc2VsZWN0OntnZXQ6ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGk9ZS5vcHRpb25zLG89ZS5zZWxlY3RlZEluZGV4LGE9InNlbGVjdC1vbmUiPT09ZS50eXBlLHM9YT9udWxsOltdLHU9YT9vKzE6aS5sZW5ndGg7Zm9yKHI9bzwwP3U6YT9vOjA7cjx1O3IrKylpZigoKG49aVtyXSkuc2VsZWN0ZWR8fHI9PT1vKSYmIW4uZGlzYWJsZWQmJighbi5wYXJlbnROb2RlLmRpc2FibGVkfHwhZmUobi5wYXJlbnROb2RlLCJvcHRncm91cCIpKSl7aWYodD1jZShuKS52YWwoKSxhKXJldHVybiB0O3MucHVzaCh0KX1yZXR1cm4gc30sc2V0OmZ1bmN0aW9uKGUsdCl7dmFyIG4scixpPWUub3B0aW9ucyxvPWNlLm1ha2VBcnJheSh0KSxhPWkubGVuZ3RoO3doaWxlKGEtLSkoKHI9aVthXSkuc2VsZWN0ZWQ9LTE8Y2UuaW5BcnJheShjZS52YWxIb29rcy5vcHRpb24uZ2V0KHIpLG8pKSYmKG49ITApO3JldHVybiBufHwoZS5zZWxlY3RlZEluZGV4PS0xKSxvfX19fSksY2UuZWFjaChbInJhZGlvIiwiY2hlY2tib3giXSxmdW5jdGlvbigpe2NlLnZhbEhvb2tzW3RoaXNdPXtzZXQ6ZnVuY3Rpb24oZSx0KXtpZihBcnJheS5pc0FycmF5KHQpKXJldHVybiBlLmNoZWNrZWQ9LTE8Y2UuaW5BcnJheShjZShlKS52YWwoKSx0KX19LGxlLmNoZWNrT258fChjZS52YWxIb29rc1t0aGlzXS5nZXQ9ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGw9PT1lLmdldEF0dHJpYnV0ZSgidmFsdWUiKT8ib24iOmUudmFsdWV9KX0pO3ZhciBFdD1pZS5sb2NhdGlvbixqdD17Z3VpZDpEYXRlLm5vdygpfSxBdD0vXD8vO2NlLnBhcnNlWE1MPWZ1bmN0aW9uKGUpe3ZhciB0LG47aWYoIWV8fCJzdHJpbmciIT10eXBlb2YgZSlyZXR1cm4gbnVsbDt0cnl7dD0obmV3IGllLkRPTVBhcnNlcikucGFyc2VGcm9tU3RyaW5nKGUsInRleHQveG1sIil9Y2F0Y2goZSl7fXJldHVybiBuPXQmJnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoInBhcnNlcmVycm9yIilbMF0sdCYmIW58fGNlLmVycm9yKCJJbnZhbGlkIFhNTDogIisobj9jZS5tYXAobi5jaGlsZE5vZGVzLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRleHRDb250ZW50fSkuam9pbigiXG4iKTplKSksdH07dmFyIER0PS9eKD86Zm9jdXNpbmZvY3VzfGZvY3Vzb3V0Ymx1cikkLyxOdD1mdW5jdGlvbihlKXtlLnN0b3BQcm9wYWdhdGlvbigpfTtjZS5leHRlbmQoY2UuZXZlbnQse3RyaWdnZXI6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbyxhLHMsdSxsLGMsZixwPVtufHxDXSxkPXVlLmNhbGwoZSwidHlwZSIpP2UudHlwZTplLGg9dWUuY2FsbChlLCJuYW1lc3BhY2UiKT9lLm5hbWVzcGFjZS5zcGxpdCgiLiIpOltdO2lmKG89Zj1hPW49bnx8QywzIT09bi5ub2RlVHlwZSYmOCE9PW4ubm9kZVR5cGUmJiFEdC50ZXN0KGQrY2UuZXZlbnQudHJpZ2dlcmVkKSYmKC0xPGQuaW5kZXhPZigiLiIpJiYoZD0oaD1kLnNwbGl0KCIuIikpLnNoaWZ0KCksaC5zb3J0KCkpLHU9ZC5pbmRleE9mKCI6Iik8MCYmIm9uIitkLChlPWVbY2UuZXhwYW5kb10/ZTpuZXcgY2UuRXZlbnQoZCwib2JqZWN0Ij09dHlwZW9mIGUmJmUpKS5pc1RyaWdnZXI9cj8yOjMsZS5uYW1lc3BhY2U9aC5qb2luKCIuIiksZS5ybmFtZXNwYWNlPWUubmFtZXNwYWNlP25ldyBSZWdFeHAoIihefFxcLikiK2guam9pbigiXFwuKD86LipcXC58KSIpKyIoXFwufCQpIik6bnVsbCxlLnJlc3VsdD12b2lkIDAsZS50YXJnZXR8fChlLnRhcmdldD1uKSx0PW51bGw9PXQ/W2VdOmNlLm1ha2VBcnJheSh0LFtlXSksYz1jZS5ldmVudC5zcGVjaWFsW2RdfHx7fSxyfHwhYy50cmlnZ2VyfHwhMSE9PWMudHJpZ2dlci5hcHBseShuLHQpKSl7aWYoIXImJiFjLm5vQnViYmxlJiYheShuKSl7Zm9yKHM9Yy5kZWxlZ2F0ZVR5cGV8fGQsRHQudGVzdChzK2QpfHwobz1vLnBhcmVudE5vZGUpO287bz1vLnBhcmVudE5vZGUpcC5wdXNoKG8pLGE9bzthPT09KG4ub3duZXJEb2N1bWVudHx8QykmJnAucHVzaChhLmRlZmF1bHRWaWV3fHxhLnBhcmVudFdpbmRvd3x8aWUpfWk9MDt3aGlsZSgobz1wW2krK10pJiYhZS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpKWY9byxlLnR5cGU9MTxpP3M6Yy5iaW5kVHlwZXx8ZCwobD0oXy5nZXQobywiZXZlbnRzIil8fE9iamVjdC5jcmVhdGUobnVsbCkpW2UudHlwZV0mJl8uZ2V0KG8sImhhbmRsZSIpKSYmbC5hcHBseShvLHQpLChsPXUmJm9bdV0pJiZsLmFwcGx5JiYkKG8pJiYoZS5yZXN1bHQ9bC5hcHBseShvLHQpLCExPT09ZS5yZXN1bHQmJmUucHJldmVudERlZmF1bHQoKSk7cmV0dXJuIGUudHlwZT1kLHJ8fGUuaXNEZWZhdWx0UHJldmVudGVkKCl8fGMuX2RlZmF1bHQmJiExIT09Yy5fZGVmYXVsdC5hcHBseShwLnBvcCgpLHQpfHwhJChuKXx8dSYmdihuW2RdKSYmIXkobikmJigoYT1uW3VdKSYmKG5bdV09bnVsbCksY2UuZXZlbnQudHJpZ2dlcmVkPWQsZS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpJiZmLmFkZEV2ZW50TGlzdGVuZXIoZCxOdCksbltkXSgpLGUuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSYmZi5yZW1vdmVFdmVudExpc3RlbmVyKGQsTnQpLGNlLmV2ZW50LnRyaWdnZXJlZD12b2lkIDAsYSYmKG5bdV09YSkpLGUucmVzdWx0fX0sc2ltdWxhdGU6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPWNlLmV4dGVuZChuZXcgY2UuRXZlbnQsbix7dHlwZTplLGlzU2ltdWxhdGVkOiEwfSk7Y2UuZXZlbnQudHJpZ2dlcihyLG51bGwsdCl9fSksY2UuZm4uZXh0ZW5kKHt0cmlnZ2VyOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe2NlLmV2ZW50LnRyaWdnZXIoZSx0LHRoaXMpfSl9LHRyaWdnZXJIYW5kbGVyOmZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpc1swXTtpZihuKXJldHVybiBjZS5ldmVudC50cmlnZ2VyKGUsdCxuLCEwKX19KTt2YXIgcXQ9L1xbXF0kLyxMdD0vXHI/XG4vZyxIdD0vXig/OnN1Ym1pdHxidXR0b258aW1hZ2V8cmVzZXR8ZmlsZSkkL2ksT3Q9L14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8a2V5Z2VuKS9pO2Z1bmN0aW9uIFB0KG4sZSxyLGkpe3ZhciB0O2lmKEFycmF5LmlzQXJyYXkoZSkpY2UuZWFjaChlLGZ1bmN0aW9uKGUsdCl7cnx8cXQudGVzdChuKT9pKG4sdCk6UHQobisiWyIrKCJvYmplY3QiPT10eXBlb2YgdCYmbnVsbCE9dD9lOiIiKSsiXSIsdCxyLGkpfSk7ZWxzZSBpZihyfHwib2JqZWN0IiE9PXgoZSkpaShuLGUpO2Vsc2UgZm9yKHQgaW4gZSlQdChuKyJbIit0KyJdIixlW3RdLHIsaSl9Y2UucGFyYW09ZnVuY3Rpb24oZSx0KXt2YXIgbixyPVtdLGk9ZnVuY3Rpb24oZSx0KXt2YXIgbj12KHQpP3QoKTp0O3Jbci5sZW5ndGhdPWVuY29kZVVSSUNvbXBvbmVudChlKSsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KG51bGw9PW4/IiI6bil9O2lmKG51bGw9PWUpcmV0dXJuIiI7aWYoQXJyYXkuaXNBcnJheShlKXx8ZS5qcXVlcnkmJiFjZS5pc1BsYWluT2JqZWN0KGUpKWNlLmVhY2goZSxmdW5jdGlvbigpe2kodGhpcy5uYW1lLHRoaXMudmFsdWUpfSk7ZWxzZSBmb3IobiBpbiBlKVB0KG4sZVtuXSx0LGkpO3JldHVybiByLmpvaW4oIiYiKX0sY2UuZm4uZXh0ZW5kKHtzZXJpYWxpemU6ZnVuY3Rpb24oKXtyZXR1cm4gY2UucGFyYW0odGhpcy5zZXJpYWxpemVBcnJheSgpKX0sc2VyaWFsaXplQXJyYXk6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24oKXt2YXIgZT1jZS5wcm9wKHRoaXMsImVsZW1lbnRzIik7cmV0dXJuIGU/Y2UubWFrZUFycmF5KGUpOnRoaXN9KS5maWx0ZXIoZnVuY3Rpb24oKXt2YXIgZT10aGlzLnR5cGU7cmV0dXJuIHRoaXMubmFtZSYmIWNlKHRoaXMpLmlzKCI6ZGlzYWJsZWQiKSYmT3QudGVzdCh0aGlzLm5vZGVOYW1lKSYmIUh0LnRlc3QoZSkmJih0aGlzLmNoZWNrZWR8fCF3ZS50ZXN0KGUpKX0pLm1hcChmdW5jdGlvbihlLHQpe3ZhciBuPWNlKHRoaXMpLnZhbCgpO3JldHVybiBudWxsPT1uP251bGw6QXJyYXkuaXNBcnJheShuKT9jZS5tYXAobixmdW5jdGlvbihlKXtyZXR1cm57bmFtZTp0Lm5hbWUsdmFsdWU6ZS5yZXBsYWNlKEx0LCJcclxuIil9fSk6e25hbWU6dC5uYW1lLHZhbHVlOm4ucmVwbGFjZShMdCwiXHJcbiIpfX0pLmdldCgpfX0pO3ZhciBNdD0vJTIwL2csUnQ9LyMuKiQvLEl0PS8oWz8mXSlfPVteJl0qLyxXdD0vXiguKj8pOlsgXHRdKihbXlxyXG5dKikkL2dtLEZ0PS9eKD86R0VUfEhFQUQpJC8sJHQ9L15cL1wvLyxCdD17fSxfdD17fSx6dD0iKi8iLmNvbmNhdCgiKiIpLFh0PUMuY3JlYXRlRWxlbWVudCgiYSIpO2Z1bmN0aW9uIFV0KG8pe3JldHVybiBmdW5jdGlvbihlLHQpeyJzdHJpbmciIT10eXBlb2YgZSYmKHQ9ZSxlPSIqIik7dmFyIG4scj0wLGk9ZS50b0xvd2VyQ2FzZSgpLm1hdGNoKEQpfHxbXTtpZih2KHQpKXdoaWxlKG49aVtyKytdKSIrIj09PW5bMF0/KG49bi5zbGljZSgxKXx8IioiLChvW25dPW9bbl18fFtdKS51bnNoaWZ0KHQpKToob1tuXT1vW25dfHxbXSkucHVzaCh0KX19ZnVuY3Rpb24gVnQodCxpLG8sYSl7dmFyIHM9e30sdT10PT09X3Q7ZnVuY3Rpb24gbChlKXt2YXIgcjtyZXR1cm4gc1tlXT0hMCxjZS5lYWNoKHRbZV18fFtdLGZ1bmN0aW9uKGUsdCl7dmFyIG49dChpLG8sYSk7cmV0dXJuInN0cmluZyIhPXR5cGVvZiBufHx1fHxzW25dP3U/IShyPW4pOnZvaWQgMDooaS5kYXRhVHlwZXMudW5zaGlmdChuKSxsKG4pLCExKX0pLHJ9cmV0dXJuIGwoaS5kYXRhVHlwZXNbMF0pfHwhc1siKiJdJiZsKCIqIil9ZnVuY3Rpb24gR3QoZSx0KXt2YXIgbixyLGk9Y2UuYWpheFNldHRpbmdzLmZsYXRPcHRpb25zfHx7fTtmb3IobiBpbiB0KXZvaWQgMCE9PXRbbl0mJigoaVtuXT9lOnJ8fChyPXt9KSlbbl09dFtuXSk7cmV0dXJuIHImJmNlLmV4dGVuZCghMCxlLHIpLGV9WHQuaHJlZj1FdC5ocmVmLGNlLmV4dGVuZCh7YWN0aXZlOjAsbGFzdE1vZGlmaWVkOnt9LGV0YWc6e30sYWpheFNldHRpbmdzOnt1cmw6RXQuaHJlZix0eXBlOiJHRVQiLGlzTG9jYWw6L14oPzphYm91dHxhcHB8YXBwLXN0b3JhZ2V8ListZXh0ZW5zaW9ufGZpbGV8cmVzfHdpZGdldCk6JC8udGVzdChFdC5wcm90b2NvbCksZ2xvYmFsOiEwLHByb2Nlc3NEYXRhOiEwLGFzeW5jOiEwLGNvbnRlbnRUeXBlOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7IGNoYXJzZXQ9VVRGLTgiLGFjY2VwdHM6eyIqIjp6dCx0ZXh0OiJ0ZXh0L3BsYWluIixodG1sOiJ0ZXh0L2h0bWwiLHhtbDoiYXBwbGljYXRpb24veG1sLCB0ZXh0L3htbCIsanNvbjoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9qYXZhc2NyaXB0In0sY29udGVudHM6e3htbDovXGJ4bWxcYi8saHRtbDovXGJodG1sLyxqc29uOi9cYmpzb25cYi99LHJlc3BvbnNlRmllbGRzOnt4bWw6InJlc3BvbnNlWE1MIix0ZXh0OiJyZXNwb25zZVRleHQiLGpzb246InJlc3BvbnNlSlNPTiJ9LGNvbnZlcnRlcnM6eyIqIHRleHQiOlN0cmluZywidGV4dCBodG1sIjohMCwidGV4dCBqc29uIjpKU09OLnBhcnNlLCJ0ZXh0IHhtbCI6Y2UucGFyc2VYTUx9LGZsYXRPcHRpb25zOnt1cmw6ITAsY29udGV4dDohMH19LGFqYXhTZXR1cDpmdW5jdGlvbihlLHQpe3JldHVybiB0P0d0KEd0KGUsY2UuYWpheFNldHRpbmdzKSx0KTpHdChjZS5hamF4U2V0dGluZ3MsZSl9LGFqYXhQcmVmaWx0ZXI6VXQoQnQpLGFqYXhUcmFuc3BvcnQ6VXQoX3QpLGFqYXg6ZnVuY3Rpb24oZSx0KXsib2JqZWN0Ij09dHlwZW9mIGUmJih0PWUsZT12b2lkIDApLHQ9dHx8e307dmFyIGMsZixwLG4sZCxyLGgsZyxpLG8sdj1jZS5hamF4U2V0dXAoe30sdCkseT12LmNvbnRleHR8fHYsbT12LmNvbnRleHQmJih5Lm5vZGVUeXBlfHx5LmpxdWVyeSk/Y2UoeSk6Y2UuZXZlbnQseD1jZS5EZWZlcnJlZCgpLGI9Y2UuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLHc9di5zdGF0dXNDb2RlfHx7fSxhPXt9LHM9e30sdT0iY2FuY2VsZWQiLFQ9e3JlYWR5U3RhdGU6MCxnZXRSZXNwb25zZUhlYWRlcjpmdW5jdGlvbihlKXt2YXIgdDtpZihoKXtpZighbil7bj17fTt3aGlsZSh0PVd0LmV4ZWMocCkpblt0WzFdLnRvTG93ZXJDYXNlKCkrIiAiXT0oblt0WzFdLnRvTG93ZXJDYXNlKCkrIiAiXXx8W10pLmNvbmNhdCh0WzJdKX10PW5bZS50b0xvd2VyQ2FzZSgpKyIgIl19cmV0dXJuIG51bGw9PXQ/bnVsbDp0LmpvaW4oIiwgIil9LGdldEFsbFJlc3BvbnNlSGVhZGVyczpmdW5jdGlvbigpe3JldHVybiBoP3A6bnVsbH0sc2V0UmVxdWVzdEhlYWRlcjpmdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1oJiYoZT1zW2UudG9Mb3dlckNhc2UoKV09c1tlLnRvTG93ZXJDYXNlKCldfHxlLGFbZV09dCksdGhpc30sb3ZlcnJpZGVNaW1lVHlwZTpmdW5jdGlvbihlKXtyZXR1cm4gbnVsbD09aCYmKHYubWltZVR5cGU9ZSksdGhpc30sc3RhdHVzQ29kZTpmdW5jdGlvbihlKXt2YXIgdDtpZihlKWlmKGgpVC5hbHdheXMoZVtULnN0YXR1c10pO2Vsc2UgZm9yKHQgaW4gZSl3W3RdPVt3W3RdLGVbdF1dO3JldHVybiB0aGlzfSxhYm9ydDpmdW5jdGlvbihlKXt2YXIgdD1lfHx1O3JldHVybiBjJiZjLmFib3J0KHQpLGwoMCx0KSx0aGlzfX07aWYoeC5wcm9taXNlKFQpLHYudXJsPSgoZXx8di51cmx8fEV0LmhyZWYpKyIiKS5yZXBsYWNlKCR0LEV0LnByb3RvY29sKyIvLyIpLHYudHlwZT10Lm1ldGhvZHx8dC50eXBlfHx2Lm1ldGhvZHx8di50eXBlLHYuZGF0YVR5cGVzPSh2LmRhdGFUeXBlfHwiKiIpLnRvTG93ZXJDYXNlKCkubWF0Y2goRCl8fFsiIl0sbnVsbD09di5jcm9zc0RvbWFpbil7cj1DLmNyZWF0ZUVsZW1lbnQoImEiKTt0cnl7ci5ocmVmPXYudXJsLHIuaHJlZj1yLmhyZWYsdi5jcm9zc0RvbWFpbj1YdC5wcm90b2NvbCsiLy8iK1h0Lmhvc3QhPXIucHJvdG9jb2wrIi8vIityLmhvc3R9Y2F0Y2goZSl7di5jcm9zc0RvbWFpbj0hMH19aWYodi5kYXRhJiZ2LnByb2Nlc3NEYXRhJiYic3RyaW5nIiE9dHlwZW9mIHYuZGF0YSYmKHYuZGF0YT1jZS5wYXJhbSh2LmRhdGEsdi50cmFkaXRpb25hbCkpLFZ0KEJ0LHYsdCxUKSxoKXJldHVybiBUO2ZvcihpIGluKGc9Y2UuZXZlbnQmJnYuZ2xvYmFsKSYmMD09Y2UuYWN0aXZlKysmJmNlLmV2ZW50LnRyaWdnZXIoImFqYXhTdGFydCIpLHYudHlwZT12LnR5cGUudG9VcHBlckNhc2UoKSx2Lmhhc0NvbnRlbnQ9IUZ0LnRlc3Qodi50eXBlKSxmPXYudXJsLnJlcGxhY2UoUnQsIiIpLHYuaGFzQ29udGVudD92LmRhdGEmJnYucHJvY2Vzc0RhdGEmJjA9PT0odi5jb250ZW50VHlwZXx8IiIpLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpJiYodi5kYXRhPXYuZGF0YS5yZXBsYWNlKE10LCIrIikpOihvPXYudXJsLnNsaWNlKGYubGVuZ3RoKSx2LmRhdGEmJih2LnByb2Nlc3NEYXRhfHwic3RyaW5nIj09dHlwZW9mIHYuZGF0YSkmJihmKz0oQXQudGVzdChmKT8iJiI6Ij8iKSt2LmRhdGEsZGVsZXRlIHYuZGF0YSksITE9PT12LmNhY2hlJiYoZj1mLnJlcGxhY2UoSXQsIiQxIiksbz0oQXQudGVzdChmKT8iJiI6Ij8iKSsiXz0iK2p0Lmd1aWQrKytvKSx2LnVybD1mK28pLHYuaWZNb2RpZmllZCYmKGNlLmxhc3RNb2RpZmllZFtmXSYmVC5zZXRSZXF1ZXN0SGVhZGVyKCJJZi1Nb2RpZmllZC1TaW5jZSIsY2UubGFzdE1vZGlmaWVkW2ZdKSxjZS5ldGFnW2ZdJiZULnNldFJlcXVlc3RIZWFkZXIoIklmLU5vbmUtTWF0Y2giLGNlLmV0YWdbZl0pKSwodi5kYXRhJiZ2Lmhhc0NvbnRlbnQmJiExIT09di5jb250ZW50VHlwZXx8dC5jb250ZW50VHlwZSkmJlQuc2V0UmVxdWVzdEhlYWRlcigiQ29udGVudC1UeXBlIix2LmNvbnRlbnRUeXBlKSxULnNldFJlcXVlc3RIZWFkZXIoIkFjY2VwdCIsdi5kYXRhVHlwZXNbMF0mJnYuYWNjZXB0c1t2LmRhdGFUeXBlc1swXV0/di5hY2NlcHRzW3YuZGF0YVR5cGVzWzBdXSsoIioiIT09di5kYXRhVHlwZXNbMF0/IiwgIit6dCsiOyBxPTAuMDEiOiIiKTp2LmFjY2VwdHNbIioiXSksdi5oZWFkZXJzKVQuc2V0UmVxdWVzdEhlYWRlcihpLHYuaGVhZGVyc1tpXSk7aWYodi5iZWZvcmVTZW5kJiYoITE9PT12LmJlZm9yZVNlbmQuY2FsbCh5LFQsdil8fGgpKXJldHVybiBULmFib3J0KCk7aWYodT0iYWJvcnQiLGIuYWRkKHYuY29tcGxldGUpLFQuZG9uZSh2LnN1Y2Nlc3MpLFQuZmFpbCh2LmVycm9yKSxjPVZ0KF90LHYsdCxUKSl7aWYoVC5yZWFkeVN0YXRlPTEsZyYmbS50cmlnZ2VyKCJhamF4U2VuZCIsW1Qsdl0pLGgpcmV0dXJuIFQ7di5hc3luYyYmMDx2LnRpbWVvdXQmJihkPWllLnNldFRpbWVvdXQoZnVuY3Rpb24oKXtULmFib3J0KCJ0aW1lb3V0Iil9LHYudGltZW91dCkpO3RyeXtoPSExLGMuc2VuZChhLGwpfWNhdGNoKGUpe2lmKGgpdGhyb3cgZTtsKC0xLGUpfX1lbHNlIGwoLTEsIk5vIFRyYW5zcG9ydCIpO2Z1bmN0aW9uIGwoZSx0LG4scil7dmFyIGksbyxhLHMsdSxsPXQ7aHx8KGg9ITAsZCYmaWUuY2xlYXJUaW1lb3V0KGQpLGM9dm9pZCAwLHA9cnx8IiIsVC5yZWFkeVN0YXRlPTA8ZT80OjAsaT0yMDA8PWUmJmU8MzAwfHwzMDQ9PT1lLG4mJihzPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG8sYSxzPWUuY29udGVudHMsdT1lLmRhdGFUeXBlczt3aGlsZSgiKiI9PT11WzBdKXUuc2hpZnQoKSx2b2lkIDA9PT1yJiYocj1lLm1pbWVUeXBlfHx0LmdldFJlc3BvbnNlSGVhZGVyKCJDb250ZW50LVR5cGUiKSk7aWYocilmb3IoaSBpbiBzKWlmKHNbaV0mJnNbaV0udGVzdChyKSl7dS51bnNoaWZ0KGkpO2JyZWFrfWlmKHVbMF1pbiBuKW89dVswXTtlbHNle2ZvcihpIGluIG4pe2lmKCF1WzBdfHxlLmNvbnZlcnRlcnNbaSsiICIrdVswXV0pe289aTticmVha31hfHwoYT1pKX1vPW98fGF9aWYobylyZXR1cm4gbyE9PXVbMF0mJnUudW5zaGlmdChvKSxuW29dfSh2LFQsbikpLCFpJiYtMTxjZS5pbkFycmF5KCJzY3JpcHQiLHYuZGF0YVR5cGVzKSYmY2UuaW5BcnJheSgianNvbiIsdi5kYXRhVHlwZXMpPDAmJih2LmNvbnZlcnRlcnNbInRleHQgc2NyaXB0Il09ZnVuY3Rpb24oKXt9KSxzPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpLG8sYSxzLHUsbD17fSxjPWUuZGF0YVR5cGVzLnNsaWNlKCk7aWYoY1sxXSlmb3IoYSBpbiBlLmNvbnZlcnRlcnMpbFthLnRvTG93ZXJDYXNlKCldPWUuY29udmVydGVyc1thXTtvPWMuc2hpZnQoKTt3aGlsZShvKWlmKGUucmVzcG9uc2VGaWVsZHNbb10mJihuW2UucmVzcG9uc2VGaWVsZHNbb11dPXQpLCF1JiZyJiZlLmRhdGFGaWx0ZXImJih0PWUuZGF0YUZpbHRlcih0LGUuZGF0YVR5cGUpKSx1PW8sbz1jLnNoaWZ0KCkpaWYoIioiPT09bylvPXU7ZWxzZSBpZigiKiIhPT11JiZ1IT09byl7aWYoIShhPWxbdSsiICIrb118fGxbIiogIitvXSkpZm9yKGkgaW4gbClpZigocz1pLnNwbGl0KCIgIikpWzFdPT09byYmKGE9bFt1KyIgIitzWzBdXXx8bFsiKiAiK3NbMF1dKSl7ITA9PT1hP2E9bFtpXTohMCE9PWxbaV0mJihvPXNbMF0sYy51bnNoaWZ0KHNbMV0pKTticmVha31pZighMCE9PWEpaWYoYSYmZVsidGhyb3dzIl0pdD1hKHQpO2Vsc2UgdHJ5e3Q9YSh0KX1jYXRjaChlKXtyZXR1cm57c3RhdGU6InBhcnNlcmVycm9yIixlcnJvcjphP2U6Ik5vIGNvbnZlcnNpb24gZnJvbSAiK3UrIiB0byAiK299fX1yZXR1cm57c3RhdGU6InN1Y2Nlc3MiLGRhdGE6dH19KHYscyxULGkpLGk/KHYuaWZNb2RpZmllZCYmKCh1PVQuZ2V0UmVzcG9uc2VIZWFkZXIoIkxhc3QtTW9kaWZpZWQiKSkmJihjZS5sYXN0TW9kaWZpZWRbZl09dSksKHU9VC5nZXRSZXNwb25zZUhlYWRlcigiZXRhZyIpKSYmKGNlLmV0YWdbZl09dSkpLDIwND09PWV8fCJIRUFEIj09PXYudHlwZT9sPSJub2NvbnRlbnQiOjMwND09PWU/bD0ibm90bW9kaWZpZWQiOihsPXMuc3RhdGUsbz1zLmRhdGEsaT0hKGE9cy5lcnJvcikpKTooYT1sLCFlJiZsfHwobD0iZXJyb3IiLGU8MCYmKGU9MCkpKSxULnN0YXR1cz1lLFQuc3RhdHVzVGV4dD0odHx8bCkrIiIsaT94LnJlc29sdmVXaXRoKHksW28sbCxUXSk6eC5yZWplY3RXaXRoKHksW1QsbCxhXSksVC5zdGF0dXNDb2RlKHcpLHc9dm9pZCAwLGcmJm0udHJpZ2dlcihpPyJhamF4U3VjY2VzcyI6ImFqYXhFcnJvciIsW1QsdixpP286YV0pLGIuZmlyZVdpdGgoeSxbVCxsXSksZyYmKG0udHJpZ2dlcigiYWpheENvbXBsZXRlIixbVCx2XSksLS1jZS5hY3RpdmV8fGNlLmV2ZW50LnRyaWdnZXIoImFqYXhTdG9wIikpKX1yZXR1cm4gVH0sZ2V0SlNPTjpmdW5jdGlvbihlLHQsbil7cmV0dXJuIGNlLmdldChlLHQsbiwianNvbiIpfSxnZXRTY3JpcHQ6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gY2UuZ2V0KGUsdm9pZCAwLHQsInNjcmlwdCIpfX0pLGNlLmVhY2goWyJnZXQiLCJwb3N0Il0sZnVuY3Rpb24oZSxpKXtjZVtpXT1mdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gdih0KSYmKHI9cnx8bixuPXQsdD12b2lkIDApLGNlLmFqYXgoY2UuZXh0ZW5kKHt1cmw6ZSx0eXBlOmksZGF0YVR5cGU6cixkYXRhOnQsc3VjY2VzczpufSxjZS5pc1BsYWluT2JqZWN0KGUpJiZlKSl9fSksY2UuYWpheFByZWZpbHRlcihmdW5jdGlvbihlKXt2YXIgdDtmb3IodCBpbiBlLmhlYWRlcnMpImNvbnRlbnQtdHlwZSI9PT10LnRvTG93ZXJDYXNlKCkmJihlLmNvbnRlbnRUeXBlPWUuaGVhZGVyc1t0XXx8IiIpfSksY2UuX2V2YWxVcmw9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBjZS5hamF4KHt1cmw6ZSx0eXBlOiJHRVQiLGRhdGFUeXBlOiJzY3JpcHQiLGNhY2hlOiEwLGFzeW5jOiExLGdsb2JhbDohMSxjb252ZXJ0ZXJzOnsidGV4dCBzY3JpcHQiOmZ1bmN0aW9uKCl7fX0sZGF0YUZpbHRlcjpmdW5jdGlvbihlKXtjZS5nbG9iYWxFdmFsKGUsdCxuKX19KX0sY2UuZm4uZXh0ZW5kKHt3cmFwQWxsOmZ1bmN0aW9uKGUpe3ZhciB0O3JldHVybiB0aGlzWzBdJiYodihlKSYmKGU9ZS5jYWxsKHRoaXNbMF0pKSx0PWNlKGUsdGhpc1swXS5vd25lckRvY3VtZW50KS5lcSgwKS5jbG9uZSghMCksdGhpc1swXS5wYXJlbnROb2RlJiZ0Lmluc2VydEJlZm9yZSh0aGlzWzBdKSx0Lm1hcChmdW5jdGlvbigpe3ZhciBlPXRoaXM7d2hpbGUoZS5maXJzdEVsZW1lbnRDaGlsZCllPWUuZmlyc3RFbGVtZW50Q2hpbGQ7cmV0dXJuIGV9KS5hcHBlbmQodGhpcykpLHRoaXN9LHdyYXBJbm5lcjpmdW5jdGlvbihuKXtyZXR1cm4gdihuKT90aGlzLmVhY2goZnVuY3Rpb24oZSl7Y2UodGhpcykud3JhcElubmVyKG4uY2FsbCh0aGlzLGUpKX0pOnRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBlPWNlKHRoaXMpLHQ9ZS5jb250ZW50cygpO3QubGVuZ3RoP3Qud3JhcEFsbChuKTplLmFwcGVuZChuKX0pfSx3cmFwOmZ1bmN0aW9uKHQpe3ZhciBuPXYodCk7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihlKXtjZSh0aGlzKS53cmFwQWxsKG4/dC5jYWxsKHRoaXMsZSk6dCl9KX0sdW53cmFwOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnBhcmVudChlKS5ub3QoImJvZHkiKS5lYWNoKGZ1bmN0aW9uKCl7Y2UodGhpcykucmVwbGFjZVdpdGgodGhpcy5jaGlsZE5vZGVzKX0pLHRoaXN9fSksY2UuZXhwci5wc2V1ZG9zLmhpZGRlbj1mdW5jdGlvbihlKXtyZXR1cm4hY2UuZXhwci5wc2V1ZG9zLnZpc2libGUoZSl9LGNlLmV4cHIucHNldWRvcy52aXNpYmxlPWZ1bmN0aW9uKGUpe3JldHVybiEhKGUub2Zmc2V0V2lkdGh8fGUub2Zmc2V0SGVpZ2h0fHxlLmdldENsaWVudFJlY3RzKCkubGVuZ3RoKX0sY2UuYWpheFNldHRpbmdzLnhocj1mdW5jdGlvbigpe3RyeXtyZXR1cm4gbmV3IGllLlhNTEh0dHBSZXF1ZXN0fWNhdGNoKGUpe319O3ZhciBZdD17MDoyMDAsMTIyMzoyMDR9LFF0PWNlLmFqYXhTZXR0aW5ncy54aHIoKTtsZS5jb3JzPSEhUXQmJiJ3aXRoQ3JlZGVudGlhbHMiaW4gUXQsbGUuYWpheD1RdD0hIVF0LGNlLmFqYXhUcmFuc3BvcnQoZnVuY3Rpb24oaSl7dmFyIG8sYTtpZihsZS5jb3JzfHxRdCYmIWkuY3Jvc3NEb21haW4pcmV0dXJue3NlbmQ6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPWkueGhyKCk7aWYoci5vcGVuKGkudHlwZSxpLnVybCxpLmFzeW5jLGkudXNlcm5hbWUsaS5wYXNzd29yZCksaS54aHJGaWVsZHMpZm9yKG4gaW4gaS54aHJGaWVsZHMpcltuXT1pLnhockZpZWxkc1tuXTtmb3IobiBpbiBpLm1pbWVUeXBlJiZyLm92ZXJyaWRlTWltZVR5cGUmJnIub3ZlcnJpZGVNaW1lVHlwZShpLm1pbWVUeXBlKSxpLmNyb3NzRG9tYWlufHxlWyJYLVJlcXVlc3RlZC1XaXRoIl18fChlWyJYLVJlcXVlc3RlZC1XaXRoIl09IlhNTEh0dHBSZXF1ZXN0IiksZSlyLnNldFJlcXVlc3RIZWFkZXIobixlW25dKTtvPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbigpe28mJihvPWE9ci5vbmxvYWQ9ci5vbmVycm9yPXIub25hYm9ydD1yLm9udGltZW91dD1yLm9ucmVhZHlzdGF0ZWNoYW5nZT1udWxsLCJhYm9ydCI9PT1lP3IuYWJvcnQoKToiZXJyb3IiPT09ZT8ibnVtYmVyIiE9dHlwZW9mIHIuc3RhdHVzP3QoMCwiZXJyb3IiKTp0KHIuc3RhdHVzLHIuc3RhdHVzVGV4dCk6dChZdFtyLnN0YXR1c118fHIuc3RhdHVzLHIuc3RhdHVzVGV4dCwidGV4dCIhPT0oci5yZXNwb25zZVR5cGV8fCJ0ZXh0Iil8fCJzdHJpbmciIT10eXBlb2Ygci5yZXNwb25zZVRleHQ/e2JpbmFyeTpyLnJlc3BvbnNlfTp7dGV4dDpyLnJlc3BvbnNlVGV4dH0sci5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSkpfX0sci5vbmxvYWQ9bygpLGE9ci5vbmVycm9yPXIub250aW1lb3V0PW8oImVycm9yIiksdm9pZCAwIT09ci5vbmFib3J0P3Iub25hYm9ydD1hOnIub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7ND09PXIucmVhZHlTdGF0ZSYmaWUuc2V0VGltZW91dChmdW5jdGlvbigpe28mJmEoKX0pfSxvPW8oImFib3J0Iik7dHJ5e3Iuc2VuZChpLmhhc0NvbnRlbnQmJmkuZGF0YXx8bnVsbCl9Y2F0Y2goZSl7aWYobyl0aHJvdyBlfX0sYWJvcnQ6ZnVuY3Rpb24oKXtvJiZvKCl9fX0pLGNlLmFqYXhQcmVmaWx0ZXIoZnVuY3Rpb24oZSl7ZS5jcm9zc0RvbWFpbiYmKGUuY29udGVudHMuc2NyaXB0PSExKX0pLGNlLmFqYXhTZXR1cCh7YWNjZXB0czp7c2NyaXB0OiJ0ZXh0L2phdmFzY3JpcHQsIGFwcGxpY2F0aW9uL2phdmFzY3JpcHQsIGFwcGxpY2F0aW9uL2VjbWFzY3JpcHQsIGFwcGxpY2F0aW9uL3gtZWNtYXNjcmlwdCJ9LGNvbnRlbnRzOntzY3JpcHQ6L1xiKD86amF2YXxlY21hKXNjcmlwdFxiL30sY29udmVydGVyczp7InRleHQgc2NyaXB0IjpmdW5jdGlvbihlKXtyZXR1cm4gY2UuZ2xvYmFsRXZhbChlKSxlfX19KSxjZS5hamF4UHJlZmlsdGVyKCJzY3JpcHQiLGZ1bmN0aW9uKGUpe3ZvaWQgMD09PWUuY2FjaGUmJihlLmNhY2hlPSExKSxlLmNyb3NzRG9tYWluJiYoZS50eXBlPSJHRVQiKX0pLGNlLmFqYXhUcmFuc3BvcnQoInNjcmlwdCIsZnVuY3Rpb24obil7dmFyIHIsaTtpZihuLmNyb3NzRG9tYWlufHxuLnNjcmlwdEF0dHJzKXJldHVybntzZW5kOmZ1bmN0aW9uKGUsdCl7cj1jZSgiPHNjcmlwdD4iKS5hdHRyKG4uc2NyaXB0QXR0cnN8fHt9KS5wcm9wKHtjaGFyc2V0Om4uc2NyaXB0Q2hhcnNldCxzcmM6bi51cmx9KS5vbigibG9hZCBlcnJvciIsaT1mdW5jdGlvbihlKXtyLnJlbW92ZSgpLGk9bnVsbCxlJiZ0KCJlcnJvciI9PT1lLnR5cGU/NDA0OjIwMCxlLnR5cGUpfSksQy5oZWFkLmFwcGVuZENoaWxkKHJbMF0pfSxhYm9ydDpmdW5jdGlvbigpe2kmJmkoKX19fSk7dmFyIEp0LEt0PVtdLFp0PS8oPSlcPyg/PSZ8JCl8XD9cPy87Y2UuYWpheFNldHVwKHtqc29ucDoiY2FsbGJhY2siLGpzb25wQ2FsbGJhY2s6ZnVuY3Rpb24oKXt2YXIgZT1LdC5wb3AoKXx8Y2UuZXhwYW5kbysiXyIranQuZ3VpZCsrO3JldHVybiB0aGlzW2VdPSEwLGV9fSksY2UuYWpheFByZWZpbHRlcigianNvbiBqc29ucCIsZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhPSExIT09ZS5qc29ucCYmKFp0LnRlc3QoZS51cmwpPyJ1cmwiOiJzdHJpbmciPT10eXBlb2YgZS5kYXRhJiYwPT09KGUuY29udGVudFR5cGV8fCIiKS5pbmRleE9mKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKSYmWnQudGVzdChlLmRhdGEpJiYiZGF0YSIpO2lmKGF8fCJqc29ucCI9PT1lLmRhdGFUeXBlc1swXSlyZXR1cm4gcj1lLmpzb25wQ2FsbGJhY2s9dihlLmpzb25wQ2FsbGJhY2spP2UuanNvbnBDYWxsYmFjaygpOmUuanNvbnBDYWxsYmFjayxhP2VbYV09ZVthXS5yZXBsYWNlKFp0LCIkMSIrcik6ITEhPT1lLmpzb25wJiYoZS51cmwrPShBdC50ZXN0KGUudXJsKT8iJiI6Ij8iKStlLmpzb25wKyI9IityKSxlLmNvbnZlcnRlcnNbInNjcmlwdCBqc29uIl09ZnVuY3Rpb24oKXtyZXR1cm4gb3x8Y2UuZXJyb3IocisiIHdhcyBub3QgY2FsbGVkIiksb1swXX0sZS5kYXRhVHlwZXNbMF09Impzb24iLGk9aWVbcl0saWVbcl09ZnVuY3Rpb24oKXtvPWFyZ3VtZW50c30sbi5hbHdheXMoZnVuY3Rpb24oKXt2b2lkIDA9PT1pP2NlKGllKS5yZW1vdmVQcm9wKHIpOmllW3JdPWksZVtyXSYmKGUuanNvbnBDYWxsYmFjaz10Lmpzb25wQ2FsbGJhY2ssS3QucHVzaChyKSksbyYmdihpKSYmaShvWzBdKSxvPWk9dm9pZCAwfSksInNjcmlwdCJ9KSxsZS5jcmVhdGVIVE1MRG9jdW1lbnQ9KChKdD1DLmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikuYm9keSkuaW5uZXJIVE1MPSI8Zm9ybT48L2Zvcm0+PGZvcm0+PC9mb3JtPiIsMj09PUp0LmNoaWxkTm9kZXMubGVuZ3RoKSxjZS5wYXJzZUhUTUw9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiJzdHJpbmciIT10eXBlb2YgZT9bXTooImJvb2xlYW4iPT10eXBlb2YgdCYmKG49dCx0PSExKSx0fHwobGUuY3JlYXRlSFRNTERvY3VtZW50Pygocj0odD1DLmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikpLmNyZWF0ZUVsZW1lbnQoImJhc2UiKSkuaHJlZj1DLmxvY2F0aW9uLmhyZWYsdC5oZWFkLmFwcGVuZENoaWxkKHIpKTp0PUMpLG89IW4mJltdLChpPXcuZXhlYyhlKSk/W3QuY3JlYXRlRWxlbWVudChpWzFdKV06KGk9QWUoW2VdLHQsbyksbyYmby5sZW5ndGgmJmNlKG8pLnJlbW92ZSgpLGNlLm1lcmdlKFtdLGkuY2hpbGROb2RlcykpKTt2YXIgcixpLG99LGNlLmZuLmxvYWQ9ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhPXRoaXMscz1lLmluZGV4T2YoIiAiKTtyZXR1cm4tMTxzJiYocj1UdChlLnNsaWNlKHMpKSxlPWUuc2xpY2UoMCxzKSksdih0KT8obj10LHQ9dm9pZCAwKTp0JiYib2JqZWN0Ij09dHlwZW9mIHQmJihpPSJQT1NUIiksMDxhLmxlbmd0aCYmY2UuYWpheCh7dXJsOmUsdHlwZTppfHwiR0VUIixkYXRhVHlwZToiaHRtbCIsZGF0YTp0fSkuZG9uZShmdW5jdGlvbihlKXtvPWFyZ3VtZW50cyxhLmh0bWwocj9jZSgiPGRpdj4iKS5hcHBlbmQoY2UucGFyc2VIVE1MKGUpKS5maW5kKHIpOmUpfSkuYWx3YXlzKG4mJmZ1bmN0aW9uKGUsdCl7YS5lYWNoKGZ1bmN0aW9uKCl7bi5hcHBseSh0aGlzLG98fFtlLnJlc3BvbnNlVGV4dCx0LGVdKX0pfSksdGhpc30sY2UuZXhwci5wc2V1ZG9zLmFuaW1hdGVkPWZ1bmN0aW9uKHQpe3JldHVybiBjZS5ncmVwKGNlLnRpbWVycyxmdW5jdGlvbihlKXtyZXR1cm4gdD09PWUuZWxlbX0pLmxlbmd0aH0sY2Uub2Zmc2V0PXtzZXRPZmZzZXQ6ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhLHMsdSxsPWNlLmNzcyhlLCJwb3NpdGlvbiIpLGM9Y2UoZSksZj17fTsic3RhdGljIj09PWwmJihlLnN0eWxlLnBvc2l0aW9uPSJyZWxhdGl2ZSIpLHM9Yy5vZmZzZXQoKSxvPWNlLmNzcyhlLCJ0b3AiKSx1PWNlLmNzcyhlLCJsZWZ0IiksKCJhYnNvbHV0ZSI9PT1sfHwiZml4ZWQiPT09bCkmJi0xPChvK3UpLmluZGV4T2YoImF1dG8iKT8oYT0ocj1jLnBvc2l0aW9uKCkpLnRvcCxpPXIubGVmdCk6KGE9cGFyc2VGbG9hdChvKXx8MCxpPXBhcnNlRmxvYXQodSl8fDApLHYodCkmJih0PXQuY2FsbChlLG4sY2UuZXh0ZW5kKHt9LHMpKSksbnVsbCE9dC50b3AmJihmLnRvcD10LnRvcC1zLnRvcCthKSxudWxsIT10LmxlZnQmJihmLmxlZnQ9dC5sZWZ0LXMubGVmdCtpKSwidXNpbmciaW4gdD90LnVzaW5nLmNhbGwoZSxmKTpjLmNzcyhmKX19LGNlLmZuLmV4dGVuZCh7b2Zmc2V0OmZ1bmN0aW9uKHQpe2lmKGFyZ3VtZW50cy5sZW5ndGgpcmV0dXJuIHZvaWQgMD09PXQ/dGhpczp0aGlzLmVhY2goZnVuY3Rpb24oZSl7Y2Uub2Zmc2V0LnNldE9mZnNldCh0aGlzLHQsZSl9KTt2YXIgZSxuLHI9dGhpc1swXTtyZXR1cm4gcj9yLmdldENsaWVudFJlY3RzKCkubGVuZ3RoPyhlPXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksbj1yLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcse3RvcDplLnRvcCtuLnBhZ2VZT2Zmc2V0LGxlZnQ6ZS5sZWZ0K24ucGFnZVhPZmZzZXR9KTp7dG9wOjAsbGVmdDowfTp2b2lkIDB9LHBvc2l0aW9uOmZ1bmN0aW9uKCl7aWYodGhpc1swXSl7dmFyIGUsdCxuLHI9dGhpc1swXSxpPXt0b3A6MCxsZWZ0OjB9O2lmKCJmaXhlZCI9PT1jZS5jc3MociwicG9zaXRpb24iKSl0PXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7ZWxzZXt0PXRoaXMub2Zmc2V0KCksbj1yLm93bmVyRG9jdW1lbnQsZT1yLm9mZnNldFBhcmVudHx8bi5kb2N1bWVudEVsZW1lbnQ7d2hpbGUoZSYmKGU9PT1uLmJvZHl8fGU9PT1uLmRvY3VtZW50RWxlbWVudCkmJiJzdGF0aWMiPT09Y2UuY3NzKGUsInBvc2l0aW9uIikpZT1lLnBhcmVudE5vZGU7ZSYmZSE9PXImJjE9PT1lLm5vZGVUeXBlJiYoKGk9Y2UoZSkub2Zmc2V0KCkpLnRvcCs9Y2UuY3NzKGUsImJvcmRlclRvcFdpZHRoIiwhMCksaS5sZWZ0Kz1jZS5jc3MoZSwiYm9yZGVyTGVmdFdpZHRoIiwhMCkpfXJldHVybnt0b3A6dC50b3AtaS50b3AtY2UuY3NzKHIsIm1hcmdpblRvcCIsITApLGxlZnQ6dC5sZWZ0LWkubGVmdC1jZS5jc3MociwibWFyZ2luTGVmdCIsITApfX19LG9mZnNldFBhcmVudDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm1hcChmdW5jdGlvbigpe3ZhciBlPXRoaXMub2Zmc2V0UGFyZW50O3doaWxlKGUmJiJzdGF0aWMiPT09Y2UuY3NzKGUsInBvc2l0aW9uIikpZT1lLm9mZnNldFBhcmVudDtyZXR1cm4gZXx8Sn0pfX0pLGNlLmVhY2goe3Njcm9sbExlZnQ6InBhZ2VYT2Zmc2V0IixzY3JvbGxUb3A6InBhZ2VZT2Zmc2V0In0sZnVuY3Rpb24odCxpKXt2YXIgbz0icGFnZVlPZmZzZXQiPT09aTtjZS5mblt0XT1mdW5jdGlvbihlKXtyZXR1cm4gTSh0aGlzLGZ1bmN0aW9uKGUsdCxuKXt2YXIgcjtpZih5KGUpP3I9ZTo5PT09ZS5ub2RlVHlwZSYmKHI9ZS5kZWZhdWx0Vmlldyksdm9pZCAwPT09bilyZXR1cm4gcj9yW2ldOmVbdF07cj9yLnNjcm9sbFRvKG8/ci5wYWdlWE9mZnNldDpuLG8/bjpyLnBhZ2VZT2Zmc2V0KTplW3RdPW59LHQsZSxhcmd1bWVudHMubGVuZ3RoKX19KSxjZS5lYWNoKFsidG9wIiwibGVmdCJdLGZ1bmN0aW9uKGUsbil7Y2UuY3NzSG9va3Nbbl09WWUobGUucGl4ZWxQb3NpdGlvbixmdW5jdGlvbihlLHQpe2lmKHQpcmV0dXJuIHQ9R2UoZSxuKSxfZS50ZXN0KHQpP2NlKGUpLnBvc2l0aW9uKClbbl0rInB4Ijp0fSl9KSxjZS5lYWNoKHtIZWlnaHQ6ImhlaWdodCIsV2lkdGg6IndpZHRoIn0sZnVuY3Rpb24oYSxzKXtjZS5lYWNoKHtwYWRkaW5nOiJpbm5lciIrYSxjb250ZW50OnMsIiI6Im91dGVyIithfSxmdW5jdGlvbihyLG8pe2NlLmZuW29dPWZ1bmN0aW9uKGUsdCl7dmFyIG49YXJndW1lbnRzLmxlbmd0aCYmKHJ8fCJib29sZWFuIiE9dHlwZW9mIGUpLGk9cnx8KCEwPT09ZXx8ITA9PT10PyJtYXJnaW4iOiJib3JkZXIiKTtyZXR1cm4gTSh0aGlzLGZ1bmN0aW9uKGUsdCxuKXt2YXIgcjtyZXR1cm4geShlKT8wPT09by5pbmRleE9mKCJvdXRlciIpP2VbImlubmVyIithXTplLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsiY2xpZW50IithXTo5PT09ZS5ub2RlVHlwZT8ocj1lLmRvY3VtZW50RWxlbWVudCxNYXRoLm1heChlLmJvZHlbInNjcm9sbCIrYV0sclsic2Nyb2xsIithXSxlLmJvZHlbIm9mZnNldCIrYV0sclsib2Zmc2V0IithXSxyWyJjbGllbnQiK2FdKSk6dm9pZCAwPT09bj9jZS5jc3MoZSx0LGkpOmNlLnN0eWxlKGUsdCxuLGkpfSxzLG4/ZTp2b2lkIDAsbil9fSl9KSxjZS5lYWNoKFsiYWpheFN0YXJ0IiwiYWpheFN0b3AiLCJhamF4Q29tcGxldGUiLCJhamF4RXJyb3IiLCJhamF4U3VjY2VzcyIsImFqYXhTZW5kIl0sZnVuY3Rpb24oZSx0KXtjZS5mblt0XT1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5vbih0LGUpfX0pLGNlLmZuLmV4dGVuZCh7YmluZDpmdW5jdGlvbihlLHQsbil7cmV0dXJuIHRoaXMub24oZSxudWxsLHQsbil9LHVuYmluZDpmdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLm9mZihlLG51bGwsdCl9LGRlbGVnYXRlOmZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiB0aGlzLm9uKHQsZSxuLHIpfSx1bmRlbGVnYXRlOmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gMT09PWFyZ3VtZW50cy5sZW5ndGg/dGhpcy5vZmYoZSwiKioiKTp0aGlzLm9mZih0LGV8fCIqKiIsbil9LGhvdmVyOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMub24oIm1vdXNlZW50ZXIiLGUpLm9uKCJtb3VzZWxlYXZlIix0fHxlKX19KSxjZS5lYWNoKCJibHVyIGZvY3VzIGZvY3VzaW4gZm9jdXNvdXQgcmVzaXplIHNjcm9sbCBjbGljayBkYmxjbGljayBtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGNvbnRleHRtZW51Ii5zcGxpdCgiICIpLGZ1bmN0aW9uKGUsbil7Y2UuZm5bbl09ZnVuY3Rpb24oZSx0KXtyZXR1cm4gMDxhcmd1bWVudHMubGVuZ3RoP3RoaXMub24obixudWxsLGUsdCk6dGhpcy50cmlnZ2VyKG4pfX0pO3ZhciBlbj0vXltcc1x1RkVGRlx4QTBdK3woW15cc1x1RkVGRlx4QTBdKVtcc1x1RkVGRlx4QTBdKyQvZztjZS5wcm94eT1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaTtpZigic3RyaW5nIj09dHlwZW9mIHQmJihuPWVbdF0sdD1lLGU9biksdihlKSlyZXR1cm4gcj1hZS5jYWxsKGFyZ3VtZW50cywyKSwoaT1mdW5jdGlvbigpe3JldHVybiBlLmFwcGx5KHR8fHRoaXMsci5jb25jYXQoYWUuY2FsbChhcmd1bWVudHMpKSl9KS5ndWlkPWUuZ3VpZD1lLmd1aWR8fGNlLmd1aWQrKyxpfSxjZS5ob2xkUmVhZHk9ZnVuY3Rpb24oZSl7ZT9jZS5yZWFkeVdhaXQrKzpjZS5yZWFkeSghMCl9LGNlLmlzQXJyYXk9QXJyYXkuaXNBcnJheSxjZS5wYXJzZUpTT049SlNPTi5wYXJzZSxjZS5ub2RlTmFtZT1mZSxjZS5pc0Z1bmN0aW9uPXYsY2UuaXNXaW5kb3c9eSxjZS5jYW1lbENhc2U9RixjZS50eXBlPXgsY2Uubm93PURhdGUubm93LGNlLmlzTnVtZXJpYz1mdW5jdGlvbihlKXt2YXIgdD1jZS50eXBlKGUpO3JldHVybigibnVtYmVyIj09PXR8fCJzdHJpbmciPT09dCkmJiFpc05hTihlLXBhcnNlRmxvYXQoZSkpfSxjZS50cmltPWZ1bmN0aW9uKGUpe3JldHVybiBudWxsPT1lPyIiOihlKyIiKS5yZXBsYWNlKGVuLCIkMSIpfSwiZnVuY3Rpb24iPT10eXBlb2YgZGVmaW5lJiZkZWZpbmUuYW1kJiZkZWZpbmUoImpxdWVyeSIsW10sZnVuY3Rpb24oKXtyZXR1cm4gY2V9KTt2YXIgdG49aWUualF1ZXJ5LG5uPWllLiQ7cmV0dXJuIGNlLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oZSl7cmV0dXJuIGllLiQ9PT1jZSYmKGllLiQ9bm4pLGUmJmllLmpRdWVyeT09PWNlJiYoaWUualF1ZXJ5PXRuKSxjZX0sInVuZGVmaW5lZCI9PXR5cGVvZiBlJiYoaWUualF1ZXJ5PWllLiQ9Y2UpLGNlfSk7CiJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBfc2xpY2VkVG9BcnJheShlLHQpe3JldHVybiBfYXJyYXlXaXRoSG9sZXMoZSl8fF9pdGVyYWJsZVRvQXJyYXlMaW1pdChlLHQpfHxfdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkoZSx0KXx8X25vbkl0ZXJhYmxlUmVzdCgpfWZ1bmN0aW9uIF9ub25JdGVyYWJsZVJlc3QoKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIGF0dGVtcHQgdG8gZGVzdHJ1Y3R1cmUgbm9uLWl0ZXJhYmxlIGluc3RhbmNlLlxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLiIpfWZ1bmN0aW9uIF9pdGVyYWJsZVRvQXJyYXlMaW1pdChlLHQpe3ZhciBuPW51bGw9PWU/bnVsbDoidW5kZWZpbmVkIiE9dHlwZW9mIFN5bWJvbCYmZVtTeW1ib2wuaXRlcmF0b3JdfHxlWyJAQGl0ZXJhdG9yIl07aWYobnVsbCE9bil7dmFyIHIsYSxvLGkscz1bXSxjPSEwLGw9ITE7dHJ5e2lmKG89KG49bi5jYWxsKGUpKS5uZXh0LDA9PT10KXtpZihPYmplY3QobikhPT1uKXJldHVybjtjPSExfWVsc2UgZm9yKDshKGM9KHI9by5jYWxsKG4pKS5kb25lKSYmKHMucHVzaChyLnZhbHVlKSxzLmxlbmd0aCE9PXQpO2M9ITApO31jYXRjaChlKXtsPSEwLGE9ZX1maW5hbGx5e3RyeXtpZighYyYmbnVsbCE9bi5yZXR1cm4mJihpPW4ucmV0dXJuKCksT2JqZWN0KGkpIT09aSkpcmV0dXJufWZpbmFsbHl7aWYobCl0aHJvdyBhfX1yZXR1cm4gc319ZnVuY3Rpb24gX2FycmF5V2l0aEhvbGVzKGUpe2lmKEFycmF5LmlzQXJyYXkoZSkpcmV0dXJuIGV9ZnVuY3Rpb24gb3duS2V5cyh0LGUpe3ZhciBuLHI9T2JqZWN0LmtleXModCk7cmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMmJihuPU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHModCksZSYmKG49bi5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxlKS5lbnVtZXJhYmxlfSkpLHIucHVzaC5hcHBseShyLG4pKSxyfWZ1bmN0aW9uIF9vYmplY3RTcHJlYWQodCl7Zm9yKHZhciBlPTE7ZTxhcmd1bWVudHMubGVuZ3RoO2UrKyl7dmFyIG49bnVsbCE9YXJndW1lbnRzW2VdP2FyZ3VtZW50c1tlXTp7fTtlJTI/b3duS2V5cyhPYmplY3QobiksITApLmZvckVhY2goZnVuY3Rpb24oZSl7X2RlZmluZVByb3BlcnR5KHQsZSxuW2VdKX0pOk9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzP09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHQsT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMobikpOm93bktleXMoT2JqZWN0KG4pKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LGUsT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihuLGUpKX0pfXJldHVybiB0fWZ1bmN0aW9uIF9kZWZpbmVQcm9wZXJ0eShlLHQsbil7cmV0dXJuKHQ9X3RvUHJvcGVydHlLZXkodCkpaW4gZT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHt2YWx1ZTpuLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVt0XT1uLGV9ZnVuY3Rpb24gX3RvUHJvcGVydHlLZXkoZSl7ZT1fdG9QcmltaXRpdmUoZSwic3RyaW5nIik7cmV0dXJuInN5bWJvbCI9PV90eXBlb2YoZSk/ZTpTdHJpbmcoZSl9ZnVuY3Rpb24gX3RvUHJpbWl0aXZlKGUsdCl7aWYoIm9iamVjdCIhPV90eXBlb2YoZSl8fCFlKXJldHVybiBlO3ZhciBuPWVbU3ltYm9sLnRvUHJpbWl0aXZlXTtpZih2b2lkIDA9PT1uKXJldHVybigic3RyaW5nIj09PXQ/U3RyaW5nOk51bWJlcikoZSk7bj1uLmNhbGwoZSx0fHwiZGVmYXVsdCIpO2lmKCJvYmplY3QiIT1fdHlwZW9mKG4pKXJldHVybiBuO3Rocm93IG5ldyBUeXBlRXJyb3IoIkBAdG9QcmltaXRpdmUgbXVzdCByZXR1cm4gYSBwcmltaXRpdmUgdmFsdWUuIil9ZnVuY3Rpb24gX3RvQ29uc3VtYWJsZUFycmF5KGUpe3JldHVybiBfYXJyYXlXaXRob3V0SG9sZXMoZSl8fF9pdGVyYWJsZVRvQXJyYXkoZSl8fF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShlKXx8X25vbkl0ZXJhYmxlU3ByZWFkKCl9ZnVuY3Rpb24gX25vbkl0ZXJhYmxlU3ByZWFkKCl7dGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBhdHRlbXB0IHRvIHNwcmVhZCBub24taXRlcmFibGUgaW5zdGFuY2UuXG5JbiBvcmRlciB0byBiZSBpdGVyYWJsZSwgbm9uLWFycmF5IG9iamVjdHMgbXVzdCBoYXZlIGEgW1N5bWJvbC5pdGVyYXRvcl0oKSBtZXRob2QuIil9ZnVuY3Rpb24gX2l0ZXJhYmxlVG9BcnJheShlKXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIFN5bWJvbCYmbnVsbCE9ZVtTeW1ib2wuaXRlcmF0b3JdfHxudWxsIT1lWyJAQGl0ZXJhdG9yIl0pcmV0dXJuIEFycmF5LmZyb20oZSl9ZnVuY3Rpb24gX2FycmF5V2l0aG91dEhvbGVzKGUpe2lmKEFycmF5LmlzQXJyYXkoZSkpcmV0dXJuIF9hcnJheUxpa2VUb0FycmF5KGUpfWZ1bmN0aW9uIF90eXBlb2YoZSl7cmV0dXJuKF90eXBlb2Y9ImZ1bmN0aW9uIj09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09dHlwZW9mIFN5bWJvbCYmZS5jb25zdHJ1Y3Rvcj09PVN5bWJvbCYmZSE9PVN5bWJvbC5wcm90b3R5cGU/InN5bWJvbCI6dHlwZW9mIGV9KShlKX1mdW5jdGlvbiBfY3JlYXRlRm9yT2ZJdGVyYXRvckhlbHBlcihlLHQpe3ZhciBuLHIsYSxvLGk9InVuZGVmaW5lZCIhPXR5cGVvZiBTeW1ib2wmJmVbU3ltYm9sLml0ZXJhdG9yXXx8ZVsiQEBpdGVyYXRvciJdO2lmKGkpcmV0dXJuIHI9IShuPSEwKSx7czpmdW5jdGlvbigpe2k9aS5jYWxsKGUpfSxuOmZ1bmN0aW9uKCl7dmFyIGU9aS5uZXh0KCk7cmV0dXJuIG49ZS5kb25lLGV9LGU6ZnVuY3Rpb24oZSl7cj0hMCxhPWV9LGY6ZnVuY3Rpb24oKXt0cnl7bnx8bnVsbD09aS5yZXR1cm58fGkucmV0dXJuKCl9ZmluYWxseXtpZihyKXRocm93IGF9fX07aWYoQXJyYXkuaXNBcnJheShlKXx8KGk9X3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5KGUpKXx8dCYmZSYmIm51bWJlciI9PXR5cGVvZiBlLmxlbmd0aClyZXR1cm4gaSYmKGU9aSksbz0wLHtzOnQ9ZnVuY3Rpb24oKXt9LG46ZnVuY3Rpb24oKXtyZXR1cm4gbz49ZS5sZW5ndGg/e2RvbmU6ITB9Ontkb25lOiExLHZhbHVlOmVbbysrXX19LGU6ZnVuY3Rpb24oZSl7dGhyb3cgZX0sZjp0fTt0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIGF0dGVtcHQgdG8gaXRlcmF0ZSBub24taXRlcmFibGUgaW5zdGFuY2UuXG5JbiBvcmRlciB0byBiZSBpdGVyYWJsZSwgbm9uLWFycmF5IG9iamVjdHMgbXVzdCBoYXZlIGEgW1N5bWJvbC5pdGVyYXRvcl0oKSBtZXRob2QuIil9ZnVuY3Rpb24gX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5KGUsdCl7dmFyIG47aWYoZSlyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGU/X2FycmF5TGlrZVRvQXJyYXkoZSx0KToiTWFwIj09PShuPSJPYmplY3QiPT09KG49T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpLnNsaWNlKDgsLTEpKSYmZS5jb25zdHJ1Y3Rvcj9lLmNvbnN0cnVjdG9yLm5hbWU6bil8fCJTZXQiPT09bj9BcnJheS5mcm9tKGUpOiJBcmd1bWVudHMiPT09bnx8L14oPzpVaXxJKW50KD86OHwxNnwzMikoPzpDbGFtcGVkKT9BcnJheSQvLnRlc3Qobik/X2FycmF5TGlrZVRvQXJyYXkoZSx0KTp2b2lkIDB9ZnVuY3Rpb24gX2FycmF5TGlrZVRvQXJyYXkoZSx0KXsobnVsbD09dHx8dD5lLmxlbmd0aCkmJih0PWUubGVuZ3RoKTtmb3IodmFyIG49MCxyPW5ldyBBcnJheSh0KTtuPHQ7bisrKXJbbl09ZVtuXTtyZXR1cm4gcn1kZWZpbmUoImVuZ2luZSIsWyJqcXVlcnkiLCJ1dGlscyIsInN0YXRlIiwic2VjdGlvbiIsInBhc3NhZ2VzIl0sZnVuY3Rpb24oTixqLFAsUixJKXt2YXIgdCxWPWouaW1wb3NzaWJsZSxNPWoucGFzc2FnZVNlbGVjdG9yLEQ9ai50cmFuc2l0aW9uT3V0LEY9ai5vcHRpb25zO2Z1bmN0aW9uIEwoZSx0LG4pe3ZhciByLGEsbztpZihuPyhuPW4uZ2V0KCJuYW1lIiksKGE9SS5nZXRUcmVlKG4pKS5jaGlsZHJlbi5sZW5ndGgmJihyPXt0eXBlOiJpbmNsdWRlIix0YWc6dCxuYW1lOm4sY2hpbGRyZW46YS5jaGlsZHJlbix0ZXh0OmEudGV4dH0pKTpyPUkuZ2V0VHJlZSh0KSxyKXtmb3IoOyhvPWVbZS5sZW5ndGgtMV0pJiYoInJvb3QiPT09by50eXBlfHwiaW5jbHVkZSI9PT1vLnR5cGUpJiZvLmNoaWxkcmVuLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUudHlwZS5zdGFydHNXaXRoKCJ1bmNsb3NlZCIpfSk7KWVbZS5sZW5ndGgtMV09T2JqZWN0LmNyZWF0ZShvKSxlPWVbZS5sZW5ndGgtMV0uY2hpbGRyZW49by5jaGlsZHJlbi5zbGljZSgpO2UucHVzaChyKX19ZnVuY3Rpb24gbihlKXt2YXIgdCxuPTE8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxyPW4ubG9hZGVkR2FtZSxhPUkuZ2V0KGUpLG89ai5zdG9yeUVsZW1lbnQsaT1vLnBhcmVudCgpLHM9bi5zdHJldGNoLG49bi50cmFuc2l0aW9uLG49dm9pZCAwPT09bj97fTpuLGM9bi5kZXBhcnQsYz12b2lkIDA9PT1jPyJpbnN0YW50IjpjLGw9bi5hcnJpdmUsbD12b2lkIDA9PT1sPyJkaXNzb2x2ZSI6bCx1PW4uZGVwYXJ0T3JpZ2luLHA9bi5hcnJpdmVPcmlnaW4sbj1uLnRpbWUsZD0oaS5maW5kQW5kRmlsdGVyKCJ0dy1lbmNoYW50bWVudCIpLmVhY2goZnVuY3Rpb24oZSx0KXt2YXIgbj0odD1OKHQpKS5kYXRhKCJlbmNoYW50ZWRQcm9wZXJ0aWVzIik7biYmby5jc3Mobi5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XT0iIixlfSx7fSkpLHRbMF09PT1pWzBdJiYoaT1vLnVud3JhcCgpLnBhcmVudCgpKX0pLEkuaGFzVmFsaWQoZSl8fFYoIkVuZ2luZS5zaG93UGFzc2FnZSIsIlRoZXJlJ3Mgbm8gcGFzc2FnZSB3aXRoIHRoZSBuYW1lIFwiIitlKyciIScpLG8uY2hpbGRyZW4oTSkubm90KCIudHJhbnNpdGlvbi1vdXQsIC50cmFuc2l0aW9uLW91dCAqIikpLGE9KGEuZ2V0KCJ0YWdzIil8fFtdKS5qb2luKCIgIiksZj0odD1OKCI8dHctcGFzc2FnZT48dHctc2lkZWJhcj4iKSxmPXQuY2hpbGRyZW4oInR3LXNpZGViYXIiKSxoPU4oJzx0dy1pY29uIHRhYmluZGV4PTAgYWx0PSJVbmRvIiB0aXRsZT0iVW5kbyI+JiM4NjMwOzwvdHctaWNvbj4nKSxnPU4oJzx0dy1pY29uIHRhYmluZGV4PTAgYWx0PSJSZWRvIiB0aXRsZT0iUmVkbyI+JiM4NjMxOzwvdHctaWNvbj4nKSxQLnBhc3RMZW5ndGg8PTAmJmguY3NzKCJ2aXNpYmlsaXR5IiwiaGlkZGVuIiksUC5mdXR1cmVMZW5ndGg8PTAmJmcuY3NzKCJ2aXNpYmlsaXR5IiwiaGlkZGVuIiksZi5hcHBlbmQoaCxnKSx0KSxoPSgiZnVuY3Rpb24iPT10eXBlb2YgdSYmKHU9dS5jYWxsKGQpKSwiZnVuY3Rpb24iPT10eXBlb2YgcCYmKHA9cC5jYWxsKGYpKSwhcyYmYyksbT1oJiZkLmNzcygid2lkdGgiKSxnPShqLmRldGFjaFN0b3J5RWxlbWVudCgpLGYuYXBwZW5kVG8obykuYXR0cih7dGFnczphfSksaCYmKEQoZCxjLG4sMCwwLDAsdSksZC5jc3Moe3Bvc2l0aW9uOiJhYnNvbHV0ZSIsd2lkdGg6ZnVuY3Rpb24oKXtyZXR1cm4iMHB4IiE9PW0/bToiMTAwJSJ9fSkpLG8uYXR0cih7dGFnczphfSksUi5jcmVhdGUoZikpLHk9KHImJihnLmxvYWRlZEdhbWU9ITApLFtdKTtpZihQLnBhc3RMZW5ndGg8PTAmJjE9PT1QLnR1cm5zKXt2YXIgYix2PV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKEkuZ2V0VGFnZ2VkKCJzdGFydHVwIikpO3RyeXtmb3Iodi5zKCk7IShiPXYubigpKS5kb25lOylMKHksInN0YXJ0dXAiLGIudmFsdWUpfWNhdGNoKGUpe3YuZShlKX1maW5hbGx5e3YuZigpfWlmKEYuZGVidWcpe3ZhciB3LGs9X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIoSS5nZXRUYWdnZWQoImRlYnVnLXN0YXJ0dXAiKSk7dHJ5e2ZvcihrLnMoKTshKHc9ay5uKCkpLmRvbmU7KUwoeSwiZGVidWctc3RhcnR1cCIsdy52YWx1ZSl9Y2F0Y2goZSl7ay5lKGUpfWZpbmFsbHl7ay5mKCl9fX12YXIgUyxUPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKEkuZ2V0VGFnZ2VkKCJoZWFkZXIiKSk7dHJ5e2ZvcihULnMoKTshKFM9VC5uKCkpLmRvbmU7KUwoeSwiaGVhZGVyIixTLnZhbHVlKX1jYXRjaChlKXtULmUoZSl9ZmluYWxseXtULmYoKX1pZihGLmRlYnVnKXt2YXIgXyx4PV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKEkuZ2V0VGFnZ2VkKCJkZWJ1Zy1oZWFkZXIiKSk7dHJ5e2Zvcih4LnMoKTshKF89eC5uKCkpLmRvbmU7KUwoeSwiZGVidWctaGVhZGVyIixfLnZhbHVlKX1jYXRjaChlKXt4LmUoZSl9ZmluYWxseXt4LmYoKX19TCh5LGUpO3ZhciBPLEE9X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIoSS5nZXRUYWdnZWQoImZvb3RlciIpKTt0cnl7Zm9yKEEucygpOyEoTz1BLm4oKSkuZG9uZTspTCh5LCJmb290ZXIiLE8udmFsdWUpfWNhdGNoKGUpe0EuZShlKX1maW5hbGx5e0EuZigpfWlmKEYuZGVidWcpe3ZhciBDLEU9X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIoSS5nZXRUYWdnZWQoImRlYnVnLWZvb3RlciIpKTt0cnl7Zm9yKEUucygpOyEoQz1FLm4oKSkuZG9uZTspTCh5LCJkZWJ1Zy1mb290ZXIiLEMudmFsdWUpfWNhdGNoKGUpe0UuZShlKX1maW5hbGx5e0UuZigpfX1nLnJlbmRlckludG8oeSxmLHt0cmFuc2l0aW9uOmwsdHJhbnNpdGlvblRpbWU6bix0cmFuc2l0aW9uT3JpZ2luOnB9KSxnLmxvYWRlZEdhbWU9ITEsai5yZWF0dGFjaFN0b3J5RWxlbWVudCgpLHNjcm9sbCgwLHM/Zi5vZmZzZXQoKS50b3AtLjA1Kk4od2luZG93KS5oZWlnaHQoKTpvWzBdLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCtkb2N1bWVudC5ib2R5LnNjcm9sbFRvcCl9cmV0dXJuIE9iamVjdC5mcmVlemUoe2dvQmFjazpmdW5jdGlvbihlKXtQLnJld2luZCgpJiZuKFAucGFzc2FnZSxlKX0sZ29Gb3J3YXJkOmZ1bmN0aW9uKGUpe1AuZmFzdEZvcndhcmQoKSYmbihQLnBhc3NhZ2UsZSl9LGdvVG9QYXNzYWdlOmZ1bmN0aW9uKGUsdCl7UC5wbGF5KGUpLG4oZSx0KX0scmVkaXJlY3Q6ZnVuY3Rpb24oZSx0KXtQLnJlZGlyZWN0KGUpLG4oZSx0KX0sdG9nZ2xlRnVsbHNjcmVlbjpmdW5jdGlvbigpe3ZhciBlPWRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudD9kb2N1bWVudC5leGl0RnVsbHNjcmVlbigpOmRvY3VtZW50Lm1zRnVsbHNjcmVlbkVsZW1lbnQ/ZG9jdW1lbnQubXNFeGl0RnVsbHNjcmVlbigpOihlLm1zUmVxdWVzdEZ1bGxzY3JlZW58fGUucmVxdWVzdEZ1bGxzY3JlZW4pLmNhbGwoZSl9LHNob3dQYXNzYWdlOm4sZW5hYmxlRGVidWdNb2RlOmZ1bmN0aW9uKCl7dCYmdCgpfSxyZWdpc3RlckRlYnVnTW9kZTpmdW5jdGlvbihlKXt0PXR8fGV9fSl9KSxkZWZpbmUoImhhcmxvd2UiLFsianF1ZXJ5IiwiZGVidWdtb2RlL21vZGUiLCJyZW5kZXJlciIsInN0YXRlIiwic2VjdGlvbiIsImVuZ2luZSIsInBhc3NhZ2VzIiwidXRpbHMiLCJ1dGlscy9yZW5kZXJ1dGlscyIsImludGVybmFsdHlwZXMvdmFyc2NvcGUiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJtYWNyb3MiLCJtYWNyb2xpYi92YWx1ZXMiLCJtYWNyb2xpYi9jb21tYW5kcyIsIm1hY3JvbGliL2RhdGFzdHJ1Y3R1cmVzIiwibWFjcm9saWIvc3R5bGVjaGFuZ2VycyIsIm1hY3JvbGliL2VuY2hhbnRtZW50cyIsIm1hY3JvbGliL21ldGFkYXRhIiwibWFjcm9saWIvcGF0dGVybnMiLCJtYWNyb2xpYi9saW5rcyIsIm1hY3JvbGliL2N1c3RvbW1hY3JvcyIsInV0aWxzL2pxdWVyeXBsdWdpbnMiLCJyZXBsIl0sZnVuY3Rpb24oJCxEZWJ1Z01vZGUsUmVuZGVyZXIsU3RhdGUsU2VjdGlvbixFbmdpbmUsUGFzc2FnZXMsVXRpbHMsX3JlZixWYXJTY29wZSl7dmFyIGRpYWxvZz1fcmVmLmRpYWxvZztmdW5jdGlvbiBfX0hhcmxvd2VFdmFsKHRleHQpe2V2YWwodGV4dCsiIil9ZnVuY3Rpb24gcHJpbnRKU0Vycm9yKGUpe3ZhciB0LG49IiIuY29uY2F0KGUubmFtZSwiOiAiKS5jb25jYXQoZS5tZXNzYWdlKTtyZXR1cm4gZS5zdGFjayYmKHQ9KGU9ZS5zdGFjay5zcGxpdCgiXG4iKSkuZmluZEluZGV4KGZ1bmN0aW9uKGUpe3JldHVybiBlLmluY2x1ZGVzKCJfX0hhcmxvd2VFdmFsIil9KSxuKz0iXG4iLmNvbmNhdChlLnNsaWNlKDAsdCkuam9pbigiXG4iKS5yZXBsYWNlKC9cKFteKV0rXCkvZywiIikpKSwiPGRpdiBzdHlsZT0nZm9udC1mYW1pbHk6bW9ub3NwYWNlO292ZXJmbG93LXk6c2Nyb2xsO21heC1oZWlnaHQ6MzB2aCc+YGBgIituKyJgYGA8L2Rpdj4ifSFmdW5jdGlvbihvKXt3aW5kb3cub25lcnJvcj1mdW5jdGlvbihlLHQsbixyLGEpe3dpbmRvdy5vbmVycm9yPW8sVXRpbHMuc3RvcnlFbGVtZW50LnBhcmVudCgpLmFwcGVuZChkaWFsb2coe21lc3NhZ2U6IlNvcnJ5IHRvIGludGVycnVwdCwgYnV0IHRoaXMgcGFnZSdzIGNvZGUgaGFzIGdvdCBpdHNlbGYgaW4gYSBtZXNzLlxuXG4iLmNvbmNhdChwcmludEpTRXJyb3IoYSksIlxuKFRoaXMgaXMgcHJvYmFibHkgZHVlIHRvIGEgYnVnIGluIHRoZSBIYXJsb3dlIGdhbWUgZW5naW5lLikiKX0pLmFkZENsYXNzKCJoYXJsb3dlLWNyYXNoIikpLCJmdW5jdGlvbiI9PXR5cGVvZiBvJiZvLmFwcGx5KHZvaWQgMCxhcmd1bWVudHMpfX0od2luZG93Lm9uZXJyb3IpLFV0aWxzLm9uU3RhcnR1cChmdW5jdGlvbigpe3ZhciBuLGUsdCxyLGE9JCgidHctc3RvcnlkYXRhIik7MCE9PWEubGVuZ3RoJiYoVXRpbHMub3B0aW9ucy5pZmlkPWEuYXR0cigiaWZpZCIpLChhLmF0dHIoInRhZ3MiKXx8IiIpLnNwbGl0KC9ccy8pLmZvckVhY2goZnVuY3Rpb24oZSl7InVuY29tcHJlc3NlZC1wdXJlLXZhbHVlcyIhPT1lJiYidW5jb21wcmVzc2VkLXNhdmVzIiE9PWV8fChVdGlscy5vcHRpb25zLnVuY29tcHJlc3NlZFB1cmVWYWx1ZXM9ITApLCJ1bmNvbXByZXNzZWQtc3RydWN0dXJlcyIhPT1lJiYidW5jb21wcmVzc2VkLXNhdmVzIiE9PWV8fChVdGlscy5vcHRpb25zLnVuY29tcHJlc3NlZFN0cnVjdHVyZXM9ITApfSksKGEuYXR0cigib3B0aW9ucyIpfHwiIikuc3BsaXQoL1xzLykuZm9yRWFjaChmdW5jdGlvbihlKXtlJiYoVXRpbHMub3B0aW9uc1tlXT0hMCksImRlYnVnIj09PWUmJkRlYnVnTW9kZSgpfSksYT0oYT1hLmF0dHIoInN0YXJ0bm9kZSIpKXx8W10ucmVkdWNlLmNhbGwoJCgidHctcGFzc2FnZWRhdGEiKSxmdW5jdGlvbihlLHQpe3Q9dC5nZXRBdHRyaWJ1dGUoInBpZCIpO3JldHVybiB0PGU/dDplfSwxLzApLGE9JCgidHctcGFzc2FnZWRhdGFbcGlkPSciK2ErIiddIikuYXR0cigibmFtZSIpLCQoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KS5vbigia2V5ZG93biIsZnVuY3Rpb24oZSl7MTM9PT1lLndoaWNoJiYiMCI9PT1lLnRhcmdldC5nZXRBdHRyaWJ1dGUoInRhYmluZGV4IikmJiQoZS50YXJnZXQpLnRyaWdnZXIoImNsaWNrIil9KSxuPSExLCQoIltyb2xlPXNjcmlwdF0iKS5lYWNoKGZ1bmN0aW9uKHQpe3RyeXtfX0hhcmxvd2VFdmFsKCQodGhpcykuaHRtbCgpKX1jYXRjaChlKXtufHwobj0hMCxkaWFsb2coe3BhcmVudDpVdGlscy5zdG9yeUVsZW1lbnQucGFyZW50KCksbWVzc2FnZToiVGhlcmUgaXMgYSBwcm9ibGVtIHdpdGggdGhpcyBzdG9yeSdzICIrVXRpbHMubnRoKHQrMSkrIiBzY3JpcHQ6XG5cbiIrcHJpbnRKU0Vycm9yKGUpfSkpfX0pLCQoIltyb2xlPXN0eWxlc2hlZXRdIikuZWFjaChmdW5jdGlvbihlLHQpeyQoZG9jdW1lbnQuaGVhZCkuYXBwZW5kKCI8c3R5bGUgZGF0YS10aXRsZT1cIlN0b3J5IHN0eWxlc2hlZXQgJyIuY29uY2F0KGUrMSwiJ1wiPiIpLmNvbmNhdCgkKHQpLmh0bWwoKSkpfSksKGU9U2VjdGlvbi5jcmVhdGUoKSkuc3RhY2s9W3t0ZW1wVmFyaWFibGVzOk9iamVjdC5jcmVhdGUoVmFyU2NvcGUpfV0sKHI9UGFzc2FnZXMubG9hZE1ldGFkYXRhKGUpKS5sZW5ndGgmJih0PWRpYWxvZyh7cGFyZW50OlV0aWxzLnN0b3J5RWxlbWVudC5wYXJlbnQoKSxtZXNzYWdlOiJUaGVzZSBlcnJvcnMgb2NjdXJyZWQgd2hlbiBydW5uaW5nIHRoZSBgKG1ldGFkYXRhOilgIG1hY3JvIGNhbGxzIGluIHRoaXMgc3RvcnkncyBwYXNzYWdlczo8cD48L3A+In0pLHIuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gdC5maW5kKCJwIikuYXBwZW5kKGUucmVuZGVyKCkpfSkpLChyPSFVdGlscy5vcHRpb25zLmRlYnVnJiZTdGF0ZS5oYXNTZXNzaW9uU3RvcmFnZSYmc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSgiU2F2ZWQgU2Vzc2lvbiIpKSYmITA9PT1TdGF0ZS5kZXNlcmlhbGlzZShlLHIpP0VuZ2luZS5zaG93UGFzc2FnZShTdGF0ZS5wYXNzYWdlKTpFbmdpbmUuZ29Ub1Bhc3NhZ2UoYSkpfSl9KSxkZWZpbmUoIm1hY3JvcyIsWyJ1dGlscy9uYXR1cmFsc29ydCIsInV0aWxzIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJkYXRhdHlwZXMvY3VzdG9tbWFjcm8iLCJkYXRhdHlwZXMvbGFtYmRhIiwiZGF0YXR5cGVzL2NvZGVob29rIiwiaW50ZXJuYWx0eXBlcy9jaGFuZ2VkZXNjcmlwdG9yIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oZyxlLHQsbyxyLHksYixwLHYpe3ZhciB3PWUuaW5zZW5zaXRpdmVOYW1lLGs9ZS5udGgsUz1lLmFuZExpc3QsVD10Lm9iamVjdE5hbWUsXz10LnR5cGVOYW1lLGQ9dC50b1NvdXJjZSx4PUFycmF5LmlzQXJyYXksaT17fTtmdW5jdGlvbiBPKGUpe3JldHVybiBlPT09cy5UeXBlU2lnbmF0dXJlLkFueXx8KHgoZS5pbm5lclR5cGUpP2UuaW5uZXJUeXBlLnNvbWUoTyk6ISFlLmlubmVyVHlwZSYmTyhlLmlubmVyVHlwZSkpfWZ1bmN0aW9uIGEoZSx0LG4scil7dmFyIGEsbyxpLHMsYyxsLHUscCxkPXQuZm4sZj10LnR5cGVTaWduYXR1cmUsaD10LnJldHVyblR5cGUsbT0ocj1mdW5jdGlvbihlKXtmb3IodmFyIHQsbixyLGE9W10sbz0wO288ZS5sZW5ndGg7bys9MSlvIGluIGUmJighMD09PShudWxsPT0odD1lW29dKT92b2lkIDA6dC5zcHJlYWRlcik/KG49dC52YWx1ZSwocj12LmNvbnRhaW5zRXJyb3IobikpP2EucHVzaChyKTp4KG4pfHwic3RyaW5nIj09dHlwZW9mIG4/YS5wdXNoLmFwcGx5KGEsX3RvQ29uc3VtYWJsZUFycmF5KG4pKTpuIGluc3RhbmNlb2YgU2V0P2EucHVzaC5hcHBseShhLF90b0NvbnN1bWFibGVBcnJheShBcnJheS5mcm9tKG4pLnNvcnQoZygiZW4iKSkpKTphLnB1c2godi5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3Qgc3ByZWFkIG91dCAiK1QobikrIiwgYmVjYXVzZSBpdCBpcyBub3QgYSBzdHJpbmcsIGRhdGFzZXQsIG9yIGFycmF5LiIpKSk6YS5wdXNoKHQpKTtyZXR1cm4gYX0ociksInN0cmluZyIhPXR5cGVvZiBlJiYoYT1lLGU9IiIpLGE/IiI6IigiKyh4KGUpJiYxPGUubGVuZ3RoP2VbMF06ZSkrIjopIik7Zm9yKGU9YT9hLlR3aW5lU2NyaXB0X0tub3duTmFtZT8idGhlIGN1c3RvbSBtYWNybywgIi5jb25jYXQoYS5Ud2luZVNjcmlwdF9Lbm93bk5hbWUpOiJhbiB1bm5hbWVkIGN1c3RvbSBtYWNybyI6InRoZSAiLmNvbmNhdChtLCIgbWFjcm8iKSxvPTA8Zi5sZW5ndGg/MT09PWYubGVuZ3RoJiZPKGZbMF0pPzE9PT1yLmxlbmd0aD8iVGhhdCB2YWx1ZSBjYW4ndCBiZSBnaXZlbiB0byBtYWNyb3MgYXMtaXMuIjoiR2l2ZSBvbmx5IGEgc2luZ2xlIHZhbHVlIHRvIHRoaXMgbWFjcm8uIjplKyIgbXVzdCBvbmx5IGJlIGdpdmVuICIrUyhmLm1hcChfKSkrKDE8Zi5sZW5ndGg/IiwgaW4gdGhhdCBvcmRlciI6Ii4iKTplKyIgbXVzdCBub3QgYmUgZ2l2ZW4gYW55IGRhdGEuIisoYT8iIjoiIEp1c3Qgd3JpdGUgIittKSxzPTAsYz1NYXRoLm1heChyLmxlbmd0aCxmLmxlbmd0aCk7czxjO3MrPTEpe2lmKHA9ZltzXSxsPXJbc10sdi5jb250YWluc0Vycm9yKGwpKXJldHVybiBsO2lmKHM+PWYubGVuZ3RoJiYhaSlyZXR1cm4gdi5jcmVhdGUoImRhdGF0eXBlIixyLmxlbmd0aC1mLmxlbmd0aCsiIHRvbyBtYW55IHZhbHVlcyB3ZXJlIGdpdmVuIHRvICIrZSsiLiIsbyk7aWYoIShwPXB8fGkpLmlubmVyVHlwZXx8InJlc3QiIT09cC5wYXR0ZXJuJiYiemVybyBvciBtb3JlIiE9PXAucGF0dGVybnx8KGk9cC5pbm5lclR5cGUsInJlc3QiPT09cC5wYXR0ZXJuJiYocD1wLmlubmVyVHlwZSkpLCFmdW5jdGlvbiBlKHQsbil7aWYobnVsbD09PW4pcmV0dXJuIHZvaWQgMD09PXQ7dmFyIHI9X3R5cGVvZih0KTtpZigiZnVuY3Rpb24iIT10eXBlb2YgbiYmbi5wYXR0ZXJuKXtpZigib3B0aW9uYWwiPT09bi5wYXR0ZXJufHwiemVybyBvciBtb3JlIj09PW4ucGF0dGVybilyZXR1cm4gdm9pZCAwPT09dHx8ZSh0LG4uaW5uZXJUeXBlKTtpZigiZWl0aGVyIj09PW4ucGF0dGVybil7Zm9yKHZhciBhPTA7YTxuLmlubmVyVHlwZS5sZW5ndGg7YSs9MSlpZihlKHQsbi5pbm5lclR5cGVbYV0pKXJldHVybiEwO3JldHVybiExfWlmKCJsYW1iZGEiPT09bi5wYXR0ZXJuJiZlKHQsbi5pbm5lclR5cGUpKXJldHVybiBuLmNsYXVzZXMuaW5jbHVkZXMoIndoZXJlIik9PT0oIndoZXJlImluIHR8fCJlYWNoImluIHQpJiZuLmNsYXVzZXMuaW5jbHVkZXMoIm1ha2luZyIpPT09Im1ha2luZyJpbiB0JiZuLmNsYXVzZXMuaW5jbHVkZXMoInZpYSIpPT09InZpYSJpbiB0JiZuLmNsYXVzZXMuaW5jbHVkZXMoIndpdGgiKT09PSJ3aXRoImluIHQ7aWYoImluc2Vuc2l0aXZlIHNldCI9PT1uLnBhdHRlcm4pcmV0dXJuIG4uaW5uZXJUeXBlLmluY2x1ZGVzKHcodCkpO2lmKCJyYW5nZSI9PT1uLnBhdHRlcm4pcmV0dXJuIG4ucmFuZ2UodCk7aWYoIndyYXBwZWQiPT09bi5wYXR0ZXJuKXJldHVybiBlKHQsbi5pbm5lclR5cGUpfXJldHVybih2b2lkIDA9PT1ufHx2b2lkIDAhPT10KSYmKCJhbnl0aGluZyI9PT1uLlR3aW5lU2NyaXB0X1R5cGVOYW1lJiZ2b2lkIDAhPT10JiYhdC5Ud2luZVNjcmlwdF9VbnN0b3JhYmxlfHwiZXZlcnl0aGluZyI9PT1uLlR3aW5lU2NyaXB0X1R5cGVOYW1lJiZ2b2lkIDAhPT10fHwobj09PVN0cmluZz8ic3RyaW5nIj09PXI6bj09PUJvb2xlYW4/ImJvb2xlYW4iPT09cjpuPT09cGFyc2VJbnQ/Im51bWJlciI9PT1yJiYhTnVtYmVyLmlzTmFOKHQpJiYhKHQrIiIpLmluY2x1ZGVzKCIuIik6bj09PU51bWJlcj8ibnVtYmVyIj09PXImJiFOdW1iZXIuaXNOYU4odCk6bj09PUFycmF5P3godCk6bj09PU1hcHx8bj09PVNldD90IGluc3RhbmNlb2YgbjpPYmplY3QuaXNQcm90b3R5cGVPZi5jYWxsKG4sdCkpKX0obCxwKSlyZXR1cm4gdm9pZCAwPT09bD8odT1mLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hKCJvcHRpb25hbCI9PT1lLnBhdHRlcm58fCJ6ZXJvIG9yIG1vcmUiPT09ZS5wYXR0ZXJuKX0pLmxlbmd0aCx2LmNyZWF0ZSgiZGF0YXR5cGUiLCIiLmNvbmNhdChlLCIgd2FzIGdpdmVuICIpLmNvbmNhdChyLmxlbmd0aD9TKHIubWFwKFQpKToibm90aGluZyIsIiwgYnV0IG5lZWRzICIpLmNvbmNhdCh1LXMsIiBtb3JlIHZhbHVlIikuY29uY2F0KDE8dS1zPyJzIjoiIiwiLiIpLG8pKTpudWxsIT0odT1sKSYmdS5Ud2luZVNjcmlwdF9VbnN0b3JhYmxlJiZPKHApP3YuY3JlYXRlKCJkYXRhdHlwZSIsZSsiJ3MgIitrKHMrMSkrIiB2YWx1ZSwgIitUKGwpKyIsIGlzIG5vdCB2YWxpZCBkYXRhIGZvciB0aGlzIG1hY3JvLiIsbyk6Yi5pc1Byb3RvdHlwZU9mKGwpJiYiQ2hhbmdlciI9PT1oP3YuY3JlYXRlKCJzeW50YXgiLCJQbGVhc2UgcHV0IHRoaXMgaG9vayBvdXRzaWRlIHRoZSBwYXJlbnRoZXNlcyBvZiAiK2UrIiwgbm90IGluc2lkZSBpdC4iLCJIb29rcyBzaG91bGQgYXBwZWFyIGFmdGVyIGEgbWFjcm8iKyhhPyIuIjoiOiAiK20rIltTb21lIHRleHRdIikpOmwmJnkuaXNQcm90b3R5cGVPZihsKSYmImxhbWJkYSI9PT1wLnBhdHRlcm4/di5jcmVhdGUoImRhdGF0eXBlIixlKyIncyAiK2socysxKSsiIHZhbHVlIChhIGxhbWJkYSkgc2hvdWxkIGhhdmUgIitTKFsid2hlcmUiLCJ3aGVuIiwibWFraW5nIiwidmlhIiwid2l0aCJdLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gcC5jbGF1c2VzLmluY2x1ZGVzKGUpfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiJhICciK2UrIicgY2xhdXNlIn0pKSsiLCBub3QgIitTKFsid2hlcmUiLCJ3aGVuIiwibWFraW5nIiwidmlhIiwid2l0aCJdLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZSBpbiBsfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiJhICciK2UrIicgY2xhdXNlIn0pKSsiLiIpOiJpbnNlbnNpdGl2ZSBzZXQiPT09cC5wYXR0ZXJuP3YuY3JlYXRlKCJkYXRhdHlwZSIsVChsKSsiIGlzIG5vdCBhIHZhbGlkIG5hbWUgc3RyaW5nIGZvciAiK2UrIi4iLCJPbmx5IHRoZSBmb2xsb3dpbmcgbmFtZXMgYXJlIHJlY29nbmlzZWQgKGNhcGl0YWxpc2F0aW9uIGFuZCBoeXBoZW5zIGlnbm9yZWQpOiAiK1MocC5pbm5lclR5cGUpKyIuIik6di5jcmVhdGUoImRhdGF0eXBlIiwiIi5jb25jYXQoZSwiJ3MgIikuY29uY2F0KGsocysxKSwiIHZhbHVlIGlzICIpLmNvbmNhdChUKGwpLCIsIGJ1dCBzaG91bGQgYmUgIikuY29uY2F0KF8ocCksIi4iKSxwLm1lc3NhZ2V8fG8pfXJldHVybiBkLmFwcGx5KG51bGwsW25dLmNvbmNhdChyKSl9ZnVuY3Rpb24gZihlLHQsbixyKXt2YXIgYT17Zm46bix0eXBlU2lnbmF0dXJlOnI9W10uY29uY2F0KHJ8fFtdKSxyZXR1cm5UeXBlOnR9O09iamVjdC5mcmVlemUoYSksW10uY29uY2F0KGUpLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpLHcoZSkse3ZhbHVlOmF9KX0pfXZhciBzPXtoYXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU9dyhlKSxoYXNPd25Qcm9wZXJ0eS5jYWxsKGksZSl9LGdldDpmdW5jdGlvbihlKXtyZXR1cm4gZT13KGUpLGhhc093blByb3BlcnR5LmNhbGwoaSxlKSYmaVtlXX0sYWRkOmZ1bmN0aW9uIGUodCxuLHIsYSl7cmV0dXJuIGYodCxuLHIsYSksZX0sYWRkQ2hhbmdlcjpmdW5jdGlvbiBlKHQsbixyLGEpe3JldHVybiBmKHQsIkNoYW5nZXIiLG4sYSksby5yZWdpc3Rlcih4KHQpP3RbMF06dCxyKSxlfSxhZGRDb21tYW5kOmZ1bmN0aW9uIGUodCxuLHIsYSl7dmFyIHMsYyxsLHUsbz0hKDQ8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzRdKXx8YXJndW1lbnRzWzRdLGk9W10uY29uY2F0KHQpWzBdO3JldHVybiBmKHQsIkNvbW1hbmQiLChzPWksYz1uLGw9cix1PW8sZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3ZhciBhLG8saT1jLmFwcGx5KHZvaWQgMCxuKTtyZXR1cm4gaXx8KGE9cC5jcmVhdGUoKSxvPV9vYmplY3RTcHJlYWQoe1R3aW5lU2NyaXB0X1R5cGVJRDoiY29tbWFuZCIsVHdpbmVTY3JpcHRfT2JqZWN0TmFtZToiYSAoIi5jb25jYXQocywiOikgY29tbWFuZCIpLFR3aW5lU2NyaXB0X1R5cGVOYW1lOiJhICgiLmNvbmNhdChzLCI6KSBjb21tYW5kIiksVHdpbmVTY3JpcHRfUHJpbnQ6ZnVuY3Rpb24oKXtyZXR1cm4iYFtBICgiLmNvbmNhdChzLCI6KSBjb21tYW5kXWAiKX0sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4iKCIuY29uY2F0KHMsIjoiKS5jb25jYXQobi5tYXAoZCksIikiKX0sVHdpbmVTY3JpcHRfaXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGQodGhpcyk9PT1kKGUpfX0sdT97VHdpbmVTY3JpcHRfQXR0YWNoOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGEuc2VjdGlvbj1lLHQucnVuKGEpLG99LFR3aW5lU2NyaXB0X1J1bjpmdW5jdGlvbihlKXtlPWwuYXBwbHkodm9pZCAwLFthLGVdLmNvbmNhdChuKSk7cmV0dXJuIGE9cC5jcmVhdGUoKSxlfX06e1R3aW5lU2NyaXB0X1J1bjpmdW5jdGlvbihlKXtyZXR1cm4gbC5hcHBseSh2b2lkIDAsW2VdLmNvbmNhdChuKSl9fSkpfSksYSksZX0sVHlwZVNpZ25hdHVyZTp7b3B0aW9uYWw6ZnVuY3Rpb24oZSl7cmV0dXJue3BhdHRlcm46Im9wdGlvbmFsIixpbm5lclR5cGU6ZX19LHplcm9Pck1vcmU6ZnVuY3Rpb24oZSl7cmV0dXJue3BhdHRlcm46Inplcm8gb3IgbW9yZSIsaW5uZXJUeXBlOmV9fSxlaXRoZXI6ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm57cGF0dGVybjoiZWl0aGVyIixpbm5lclR5cGU6dH19LHJlc3Q6ZnVuY3Rpb24oZSl7cmV0dXJue3BhdHRlcm46InJlc3QiLGlubmVyVHlwZTplfX0saW5zZW5zaXRpdmVTZXQ6ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm57cGF0dGVybjoiaW5zZW5zaXRpdmUgc2V0Iixpbm5lclR5cGU6dH19LG51bWJlclJhbmdlOmZ1bmN0aW9uKCl7dmFyIHQ9MDxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOjAsbj0xPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06MS8wO3JldHVybntwYXR0ZXJuOiJyYW5nZSIsbWluOnQsbWF4Om4scmFuZ2U6ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiYhTnVtYmVyLmlzTmFOKGUpJiZ0PD1lJiZlPD1ufX19LG5vbk5lZ2F0aXZlSW50ZWdlcjp7cGF0dGVybjoicmFuZ2UiLGludGVnZXI6ITAsbWluOjAsbWF4OjEvMCxyYW5nZTpmdW5jdGlvbihlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJiFOdW1iZXIuaXNOYU4oZSkmJjA8PWUmJiEoZSsiIikuaW5jbHVkZXMoIi4iKX19LHBvc2l0aXZlSW50ZWdlcjp7cGF0dGVybjoicmFuZ2UiLGludGVnZXI6ITAsbWluOjEsbWF4OjEvMCxyYW5nZTpmdW5jdGlvbihlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJiFOdW1iZXIuaXNOYU4oZSkmJjE8PWUmJiEoZSsiIikuaW5jbHVkZXMoIi4iKX19LHdyYXBwZWQ6ZnVuY3Rpb24oZSx0KXtyZXR1cm57cGF0dGVybjoid3JhcHBlZCIsaW5uZXJUeXBlOmUsbWVzc2FnZTp0fX0sQW55OntUd2luZVNjcmlwdF9UeXBlTmFtZToiYW55dGhpbmcifSxFdmVyeXRoaW5nOntUd2luZVNjcmlwdF9UeXBlTmFtZToiZXZlcnl0aGluZyJ9fSxydW46ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBzLmhhcyhlKT9hKGUscy5nZXQoZSksdCxuKTp2LmNyZWF0ZSgibWFjcm9jYWxsIiwiSSBjYW4ndCBydW4gdGhlIG1hY3JvICciK2UrIicgYmVjYXVzZSBpdCBkb2Vzbid0IGV4aXN0LiIsIkRpZCB5b3UgbWVhbiB0byBydW4gYSBtYWNybz8gSWYgeW91IGhhdmUgYSB3b3JkIHdyaXR0ZW4gbGlrZSAodGhpczopLCBpdCBpcyByZWdhcmRlZCBhcyBhIG1hY3JvIG5hbWUuIil9LHJ1bkN1c3RvbTpmdW5jdGlvbihlLHQsbil7cmV0dXJuIHIuaXNQcm90b3R5cGVPZihlKT9hKGUsZSx0LG4pOnYuY29udGFpbnNFcnJvcihlKT9lOnYuY3JlYXRlKCJtYWNyb2NhbGwiLCJJIGNhbid0IGNhbGwgIi5jb25jYXQoVChlKSwiIGJlY2F1c2UgaXQgaXNuJ3QgYSBjdXN0b20gbWFjcm8uIikpfX07cmV0dXJuIE9iamVjdC5hc3NpZ24ocy5UeXBlU2lnbmF0dXJlLHtwb3NpdGl2ZU51bWJlcjpzLlR5cGVTaWduYXR1cmUubnVtYmVyUmFuZ2UoTWF0aC5wb3coMiwtNTIpLDEvMCksbm9uTmVnYXRpdmVOdW1iZXI6cy5UeXBlU2lnbmF0dXJlLm51bWJlclJhbmdlKDAsMS8wKSxwZXJjZW50OnMuVHlwZVNpZ25hdHVyZS5udW1iZXJSYW5nZSgwLDEpfSksT2JqZWN0LmZyZWV6ZShzKX0pLGRlZmluZSgicGFzc2FnZXMiLFsianF1ZXJ5IiwidXRpbHMvbmF0dXJhbHNvcnQiLCJ1dGlscyIsIm1hcmt1cCIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKHQscyxlLGMsbCl7dmFyIHU9ZS5pbnNlbnNpdGl2ZU5hbWUscD1lLnVuZXNjYXBlLG49ZS5vblN0YXJ0dXAsbz1lLmltcG9zc2libGUsZD1PYmplY3QuYXNzaWduLGY9UmVnRXhwKGMuUGF0dGVybnMubWFjcm9Gcm9udCtjLlBhdHRlcm5zLm1hY3JvTmFtZSwiaWciKTtmdW5jdGlvbiByKGUpe3ZhciB0LHIsYSxvLG49ZS5hdHRyKCJuYW1lIiksaT1wKGUuaHRtbCgpKSxzPSh0PW4sbz1bIm1ldGFkYXRhIiwic3RvcnlsZXQiLCJleGNsdXNpdml0eSIsInVyZ2VuY3kiXSwoKHM9aSkubWF0Y2goZil8fFtdKS5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiBvLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIHUodC5zbGljZSgxLC0xKSk9PT1lfSl9KT8ocj0hMSxhPXt9LGMubGV4KHMsdCkuY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiBlKHQpe2lmKCJtYWNybyI9PT10LnR5cGUpe3ZhciBuPXUodC5uYW1lKTtpZihvLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIG49PT1lfSkpe2lmKGwuaXNQcm90b3R5cGVPZihhW25dKSlyZXR1cm47aWYocilyZXR1cm4gdm9pZChhW25dPWwuY3JlYXRlKCJzeW50YXgiLCJUaGUgKCIuY29uY2F0KHQubmFtZSwiOikgbWFjcm8gY2FuJ3QgYXBwZWFyIGFmdGVyIG5vbi1tZXRhZGF0YSBtYWNyb3MuIikpKTtpZihhW25dKXJldHVybiB2b2lkKGFbbl09bC5jcmVhdGUoInN5bnRheCIsIlRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgKCIuY29uY2F0KHQubmFtZSwiOikgbWFjcm8uIikpKTthW25dPXR9ZWxzZSByPSEwO3QuY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiBlKHQpe3ZhciBuPXUodC5uYW1lKTsibWFjcm8iPT09dC50eXBlJiZvLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIG49PT1lfSk/YVtuXT1sLmNyZWF0ZSgic3ludGF4IiwiVGhlICgiLmNvbmNhdCh0Lm5hbWUsIjopIG1hY3JvIGNhbid0IGJlIGluc2lkZSBhbm90aGVyIG1hY3JvLiIpKTp0LmNoaWxkcmVuLmZvckVhY2goZSl9KX1lbHNlIHQuY2hpbGRyZW4uZm9yRWFjaChlKX0pLGEpOnt9KTtyZXR1cm4gZChuZXcgTWFwKFtbInNvdXJjZSIsaV0sWyJ0YWdzIiwoZS5hdHRyKCJ0YWdzIil8fCIiKS5zcGxpdCgvXHMvKXx8W11dLFsibmFtZSIsbl1dKSx7VHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgcGFzc2FnZSBkYXRhbWFwIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhIHBhc3NhZ2UgZGF0YW1hcCIsbWV0YWRhdGE6cyx0cmVlOm51bGx9KX12YXIgYT1PYmplY3QuY3JlYXRlKG51bGwpLGk9W10saD1udWxsLG09ZChuZXcgTWFwLHtUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJ0aGUgUGFzc2FnZXMgZGF0YW1hcCIsZ2V0VGFnZ2VkOmZ1bmN0aW9uKG4pe3ZhciBlLHI7cmV0dXJuIGFbbl18fChlPXMoImVuIixmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXQoIm5hbWUiKX0pLHI9W10sdGhpcy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUgaW5zdGFuY2VvZiBNYXAmJmUuZ2V0KCJ0YWdzIik7QXJyYXkuaXNBcnJheSh0KSYmdC5pbmNsdWRlcyhuKSYmci5wdXNoKGUpfSksci5zb3J0KGUpLGFbbl09cil9LGNsZWFyVGFnQ2FjaGU6ZnVuY3Rpb24oKXthPU9iamVjdC5jcmVhdGUobnVsbCl9LGNsZWFyOmZ1bmN0aW9uKCl7TWFwLnByb3RvdHlwZS5jbGVhci5jYWxsKHRoaXMpLHRoaXMuY2xlYXJUYWdDYWNoZSgpLHRoaXMuY2xlYXJUcmVlQ2FjaGUoKSx0aGlzLmNsZWFyU3RvcnlsZXRDYWNoZSgpfSxkZWxldGU6ZnVuY3Rpb24oKXt2YXIgZTsoZT1NYXAucHJvdG90eXBlLmRlbGV0ZSkuY2FsbC5hcHBseShlLFt0aGlzXS5jb25jYXQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpLHRoaXMuY2xlYXJUYWdDYWNoZSgpLHRoaXMuY2xlYXJUcmVlQ2FjaGUoKSx0aGlzLmNsZWFyU3RvcnlsZXRDYWNoZSgpfSxnZXRUcmVlOmZ1bmN0aW9uKGUpe2lmKCF0aGlzLmhhcyhlKSlyZXR1cm4gbygiUGFzc2FnZXMuZ2V0VHJlZSIsIk5vIHBhc3NhZ2UgbmFtZT8iKSxbXTt2YXIgdD10aGlzLmdldChlKSxuPXQuZ2V0KCJ0YWdzIik7aWYobi5pbmNsdWRlcygiaGVhZGVyIil8fG4uaW5jbHVkZXMoImZvb3RlciIpfHxuLmluY2x1ZGVzKCJkZWJ1Zy1oZWFkZXIiKXx8bi5pbmNsdWRlcygiZGVidWctZm9vdGVyIikpcmV0dXJuIHQudHJlZXx8KHQudHJlZT1jLmxleCh0LmdldCgic291cmNlIiksZSkpLHQudHJlZTtmb3IodmFyIHIsYT0wO2E8aS5sZW5ndGg7YSs9MSlpZihpW2FdJiZpW2FdLnBsYWNlPT09ZSlyZXR1cm4gcj1pLnNwbGljZShhLDEpWzBdLGkudW5zaGlmdChyKSxyO249Yy5sZXgodC5nZXQoInNvdXJjZSIpLGUpO3JldHVybiBpLnVuc2hpZnQobiksMTY8aS5sZW5ndGgmJmkucG9wKCksbn0sY2xlYXJUcmVlQ2FjaGU6ZnVuY3Rpb24oKXtpPVtdfSxnZXRTdG9yeWxldHM6ZnVuY3Rpb24ocixlKXt2YXIgYSxvLGksZT1lP2UuZmlsdGVyKHIsX3RvQ29uc3VtYWJsZUFycmF5KG0udmFsdWVzKCkpKTpfdG9Db25zdW1hYmxlQXJyYXkobS52YWx1ZXMoKSk7cmV0dXJuIGwuY29udGFpbnNFcnJvcihlKT9lOihhPVtdLG89LTEvMCxlLnJlZHVjZShmdW5jdGlvbihlLHQpe2lmKGUpcmV0dXJuIGU7ZT10LmdldCgic3RvcnlsZXQiKTtpZihlKXt2YXIgbj1yLnNwZWN1bGF0ZShlLHQuZ2V0KCJuYW1lIiksImEgKHN0b3J5bGV0OikgbWFjcm8iKTtpZihsLmNvbnRhaW5zRXJyb3IobikpcmV0dXJuIG4ubWVzc2FnZT0iVGhlcmUncyBhbiBlcnJvciBpbiB0aGUgc3RvcnlsZXQgcGFzc2FnZSBcIiIrdC5nZXQoIm5hbWUiKSsnIjpcbicrbi5tZXNzYWdlLG4uc291cmNlPWUuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKSxuO24mJihlPXQuZ2V0KCJleGNsdXNpdml0eSIpLG89TWF0aC5tYXgobywibnVtYmVyIj09dHlwZW9mIGU/ZTowKSxhLnB1c2godCkpfX0sdm9pZCAwKXx8KGk9cygiZW4iKSxhLmZpbHRlcihmdW5jdGlvbihlKXtlPWUuZ2V0KCJleGNsdXNpdml0eSIpO3JldHVybigibnVtYmVyIj09dHlwZW9mIGU/ZTowKT09PW99KS5zb3J0KGZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5nZXQoInVyZ2VuY3kiKSxyPXQuZ2V0KCJ1cmdlbmN5Iik7cmV0dXJuKG49Im51bWJlciI9PXR5cGVvZiBuP246MCkhPT0ocj0ibnVtYmVyIj09dHlwZW9mIHI/cjowKT9yLW46aShlLmdldCgibmFtZSIpLHQuZ2V0KCJuYW1lIikpfSkpKX0sYWxsU3RvcnlsZXRzOmZ1bmN0aW9uKCl7cmV0dXJuIGg9aHx8X3RvQ29uc3VtYWJsZUFycmF5KG0udmFsdWVzKCkpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXQoInN0b3J5bGV0Iil9KX0sY2xlYXJTdG9yeWxldENhY2hlOmZ1bmN0aW9uKCl7aD1udWxsfSxsb2FkTWV0YWRhdGE6ZnVuY3Rpb24oaSl7dmFyIHM9W107cmV0dXJuIG0uZm9yRWFjaChmdW5jdGlvbihvKXtvLm1ldGFkYXRhJiZPYmplY3Qua2V5cyhvLm1ldGFkYXRhKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0LG4scjtmdW5jdGlvbiBhKGUsdCl7by5oYXMoZSk/cy5wdXNoKGwuY3JlYXRlKCJzeW50YXgiLCJUaGlzIHBhc3NhZ2UncyBkYXRhbWFwIGFscmVhZHkgaGFzIGEgJyIrSlNPTi5zdHJpbmdpZnkoZSkrIicgZGF0YSBuYW1lLiIpKTpvLnNldChlLHQpfWwuY29udGFpbnNFcnJvcihvLm1ldGFkYXRhW2VdKT9zLnB1c2goby5tZXRhZGF0YVtlXSk6KHQ9by5tZXRhZGF0YVtlXSxuPWkuc3BlY3VsYXRlKHQsby5nZXQoIm5hbWUiKSwiYSAoIitlKyI6KSBtYWNybyIpLHI9J0luICInK28uZ2V0KCJuYW1lIikrJyI6XG4nLGwuY29udGFpbnNFcnJvcihuKT8obi5tZXNzYWdlPXIrbi5tZXNzYWdlLG4uc291cmNlPXQudGV4dCxzLnB1c2gobikpOm4gaW5zdGFuY2VvZiBNYXA/bi5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGEodCxlKX0pOmEoZSxuKSl9KSxvLm1ldGFkYXRhPXZvaWQgMH0pLHN9LGhhc1ZhbGlkOmZ1bmN0aW9uKGUpe2U9dGhpcy5nZXQoZSk7cmV0dXJuIGUmJmUgaW5zdGFuY2VvZiBNYXAmJmUuaGFzKCJzb3VyY2UiKX0sY3JlYXRlOnJ9KTtyZXR1cm4gbihmdW5jdGlvbigpe3QoInR3LXN0b3J5ZGF0YSA+IHR3LXBhc3NhZ2VkYXRhIikuZ2V0KCkuZm9yRWFjaChmdW5jdGlvbihlKXtlPXQoZSksbS5zZXQoZS5hdHRyKCJuYW1lIiksbmV3IHIoZSkpfSl9KSxtfSksZGVmaW5lKCJyZW5kZXJlciIsWyJqcXVlcnkiLCJ1dGlscyIsIm1hcmt1cCIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGEsZSxTLFQpe3ZhciBfPWUuZXNjYXBlLHg9ZS5pbnNlbnNpdGl2ZU5hbWUsTz1lLm9wdGlvbnM7ZnVuY3Rpb24gQShlLHQsbil7bj0yPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PW4/bjoiIjtyZXR1cm4iPCIrdCsobj8iICIrbjoiIikrIj4iK2UrIjwvIit0KyI+In12YXIgQz0idGV4dC1hbGlnbjogY2VudGVyOyBtYXgtd2lkdGg6NTAlOyAiO2Z1bmN0aW9uIEUobSxnKXtmdW5jdGlvbiB5KGUsdCxuKXtlPUUoZS5jaGlsZHJlbixnKTtyZXR1cm4gZSYmQShlLHQsbil9dmFyIGI9IiIsdj1bXTtpZihtKWZvcih2YXIgZSx3PShtPUFycmF5LmlzQXJyYXkobSk/bTpbbV0pLmxlbmd0aCxrPTA7azx3O2srPTEpaWYoZT1mdW5jdGlvbihlKXt2YXIgbj1tW2VdO3N3aXRjaChuLnR5cGUpe2Nhc2UiaW5jbHVkZSI6Yis9eShuLCJ0dy0iK24udHlwZSwndHlwZT0iJy5jb25jYXQobi50YWcsJyIgbmFtZT0iJykuY29uY2F0KG4ubmFtZSwnIicpKTticmVhaztjYXNlImVycm9yIjpiKz1ULmNyZWF0ZSgic3ludGF4IixuLm1lc3NhZ2Usbi5leHBsYW5hdGlvbikucmVuZGVyKF8obi50ZXh0KSlbMF0ub3V0ZXJIVE1MO2JyZWFrO2Nhc2UibnVtYmVyZWQiOmNhc2UiYnVsbGV0ZWQiOmZvcih2YXIgdD0ibnVtYmVyZWQiPT09bi50eXBlPyJvbCI6InVsIixyPShiKz0iPCIrdCsiPiIsMSk7ZTx3JiZtW2VdOyl7aWYoImJyIj09PW1bZV0udHlwZSl7aWYoYis9IjwvbGk+IiwhbVtlKzFdfHxtW2UrMV0udHlwZSE9PW4udHlwZSlicmVha31lbHNlIG1bZV0udHlwZT09PW4udHlwZT8oYj0oYis9KCI8Iit0KyI+IikucmVwZWF0KE1hdGgubWF4KDAsbVtlXS5kZXB0aC1yKSkpKygiPC8iK3QrIj4iKS5yZXBlYXQoTWF0aC5tYXgoMCxyLW1bZV0uZGVwdGgpKSsiPGxpPiIscj1tW2VdLmRlcHRoKTpiKz1FKFttW2VdXSxnKTtlKz0xfWIrPSgiPC8iK3QrIj4iKS5yZXBlYXQocisxKTticmVhaztjYXNlImFsaWduIjpmb3IoO24mJiJhbGlnbiI9PT1uLnR5cGU7KXt2YXIgYT1uLmFsaWduLG89ZSs9MTtpZigibGVmdCI9PT1hKXstLWU7YnJlYWt9Zm9yKDtlPHcmJm1bZV0mJiJhbGlnbiIhPT1tW2VdLnR5cGU7KWUrPTE7dmFyIG89RShtLnNsaWNlKG8sZSksZyksaT0iIjtzd2l0Y2goYSl7Y2FzZSJjZW50ZXIiOmkrPUMrIm1hcmdpbi1sZWZ0OiBhdXRvOyBtYXJnaW4tcmlnaHQ6IGF1dG87IjticmVhaztjYXNlImp1c3RpZnkiOmNhc2UicmlnaHQiOmkrPSJ0ZXh0LWFsaWduOiAiK2ErIjsiO2JyZWFrO2RlZmF1bHQ6K2EmJihpKz1DKyJtYXJnaW4tbGVmdDogIithKyIlOyIpfWIrPSI8dHctYWxpZ24gIisoaT8nc3R5bGU9IicraSsnIic6IiIpKyI+IitvKyI8L3R3LWFsaWduPlxuIixuPW1bZV19YnJlYWs7Y2FzZSJjb2x1bW4iOmZvcih2YXIgcyxjPVtdO24mJiJjb2x1bW4iPT09bi50eXBlOyl7dmFyIGw9bi5jb2x1bW4sdT1lKz0xO2lmKCJub25lIj09PWwpey0tZTticmVha31mb3IoO2U8dyYmbVtlXSYmImNvbHVtbiIhPT1tW2VdLnR5cGU7KWUrPTE7Yy5wdXNoKHt0ZXh0Om4udGV4dCx0eXBlOmwsYm9keTpFKG0uc2xpY2UodSxlKSxnKSx3aWR0aDpuLndpZHRoLG1hcmdpbkxlZnQ6bi5tYXJnaW5MZWZ0LG1hcmdpblJpZ2h0Om4ubWFyZ2luUmlnaHR9KSxuPW1bZV19Yy5sZW5ndGgmJihzPWMucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUrdC53aWR0aH0sMCksYis9Ijx0dy1jb2x1bW5zPiIrYy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIjx0dy1jb2x1bW4gdHlwZT0iLmNvbmNhdChlLnR5cGUsIiAiLCcgc3R5bGU9IndpZHRoOicpLmNvbmNhdChlLndpZHRoL3MqMTAwLCIlOyBtYXJnaW4tbGVmdDogIikuY29uY2F0KGUubWFyZ2luTGVmdCwiZW07IG1hcmdpbi1yaWdodDogIikuY29uY2F0KGUubWFyZ2luUmlnaHQsJ2VtOyI+JykuY29uY2F0KGUuYm9keSwiPC90dy1jb2x1bW4+XG4iKX0pLmpvaW4oIiIpKyI8L3R3LWNvbHVtbnM+Iik7YnJlYWs7Y2FzZSJoZWFkaW5nIjpmb3IoYis9IjxoIituLmRlcHRoKyI+IjsrK2U8dyYmbVtlXTspe2lmKCJiciI9PT1tW2VdLnR5cGUpe2IrPSI8L2giK24uZGVwdGgrIj4iO2JyZWFrfWIrPUUoW21bZV1dLGcpfWJyZWFrO2Nhc2UiYnIiOmlmKCF2Lmxlbmd0aHx8L3RkfHRoLy50ZXN0KHZbMF0pKXtiKz0iPGJyPiI7Zm9yKHZhciBwPW1bZSsxXTtwJiYoImJyIj09PXAudHlwZXx8InRhZyI9PT1wLnR5cGUmJi9ePGJyXGIvaS50ZXN0KHAudGV4dCkpOyliKz0iPHR3LWNvbnNlY3V0aXZlLWJyIisoInRhZyI9PT1wLnR5cGU/IiBkYXRhLXJhdyI6IiIpKyI+PC90dy1jb25zZWN1dGl2ZS1icj4iLHA9bVsoZSs9MSkrMV19YnJlYWs7Y2FzZSJociI6Yis9Ijxocj4iO2JyZWFrO2Nhc2UiZXNjYXBlZExpbmUiOmNhc2UiY29tbWVudCI6YnJlYWs7Y2FzZSJpbmxpbmVVcmwiOmIrPSc8YSBjbGFzcz0ibGluayIgaHJlZj0iJytfKG4udGV4dCkrJyI+JytuLnRleHQrIjwvYT4iO2JyZWFrO2Nhc2Uic2NyaXB0U3R5bGVUYWciOmNhc2UidGFnIjp2YXIgZD1uLnRleHQudG9Mb3dlckNhc2UoKTsvXjxcLz8oPzp0YWJsZXx0aGVhZHx0Ym9keXx0cnx0Zm9vdHx0ZHx0aHxzdmcpXGIvLnRlc3QoZCkmJiFuLnRleHQuZW5kc1dpdGgoIi8+IikmJnZbbi50ZXh0LnN0YXJ0c1dpdGgoIjwvIik/InNoaWZ0IjoidW5zaGlmdCJdKGQpLGIrPW4udGV4dC5zdGFydHNXaXRoKCI8LyIpP24udGV4dDpuLnRleHQucmVwbGFjZSgvKFwvKT8+JC8sZnVuY3Rpb24oZSx0KXtyZXR1cm4iIGRhdGEtcmF3Ii5jb25jYXQodD8iPjwvIi5jb25jYXQobi50ZXh0Lm1hdGNoKC9bXHctXSsvKSk6IiIsIj4iKX0pO2JyZWFrO2Nhc2Uic3ViIjpjYXNlInN1cCI6Y2FzZSJzdHJvbmciOmNhc2UiZW0iOmIrPXkobixuLnR5cGUpO2JyZWFrO2Nhc2Uic3RyaWtlIjpiKz15KG4sInMiKTticmVhaztjYXNlImJvbGQiOmIrPXkobiwiYiIpO2JyZWFrO2Nhc2UiaXRhbGljIjpiKz15KG4sImkiKTticmVhaztjYXNlInR3aW5lTGluayI6ZD1fc2xpY2VkVG9BcnJheShTLmxleCgiKGxpbmstZ290bzoiK0pTT04uc3RyaW5naWZ5KG4uaW5uZXJUZXh0KSsiLCIrSlNPTi5zdHJpbmdpZnkobi5wYXNzYWdlKSsiKSIpLmNoaWxkcmVuLDEpWzBdO2IrPSc8dHctZXhwcmVzc2lvbiB0eXBlPSJtYWNybyIgbmFtZT0ibGluay1nb3RvIicrKE8uZGVidWc/JyB0aXRsZT0iJytfKG4udGV4dCkrJyInOiIiKSsnIGNvZGU9IicrZy5jb2RlLmxlbmd0aCsnIj48L3R3LWV4cHJlc3Npb24+JyxnLmNvZGUucHVzaChkKTticmVhaztjYXNlImhvb2siOmIrPSI8dHctaG9vayAiKyhuLmhpZGRlbj8iaGlkZGVuICI6IiIpKyhuLm5hbWU/J25hbWU9IicreChuLm5hbWUpKyciJzoiIikrKE8uZGVidWcmJm4ubmFtZT8nIHRpdGxlPSJIb29rOiA/JytuLm5hbWUrJyInOiIiKSsnIHNvdXJjZT0iJytnLnNvdXJjZS5sZW5ndGgrJyI+PC90dy1ob29rPicsZy5zb3VyY2UucHVzaChuLmNoaWxkcmVuKTticmVhaztjYXNlInVuY2xvc2VkSG9vayI6cmV0dXJuIGIrPSI8dHctaG9vayAiKyhuLmhpZGRlbj8iaGlkZGVuICI6IiIpKyhuLm5hbWU/J25hbWU9IicreChuLm5hbWUpKyciJzoiIikrJ3NvdXJjZT0iJytnLnNvdXJjZS5sZW5ndGgrJyI+PC90dy1ob29rPicsZy5zb3VyY2UucHVzaChtLnNsaWNlKGUrMSx3KSkse3Y6Yn07Y2FzZSJ2ZXJiYXRpbSI6Yis9QShfKG4uaW5uZXJUZXh0KS5yZXBsYWNlKC9cbi9nLCI8YnI+IiksInR3LXZlcmJhdGltIik7YnJlYWs7Y2FzZSJjb2xsYXBzZWQiOmIrPXkobiwidHctY29sbGFwc2VkIik7YnJlYWs7Y2FzZSJ1bmNsb3NlZENvbGxhcHNlZCI6cmV0dXJue3Y6Yis9Ijx0dy1jb2xsYXBzZWQ+IitFKG0uc2xpY2UoZSsxLHcpLGcpKyI8L3R3LWNvbGxhcHNlZD4ifTtjYXNlInZhcmlhYmxlIjpjYXNlInRlbXBWYXJpYWJsZSI6Y2FzZSJtYWNybyI6dmFyIGY9W10saD1bXTtpZigibWFjcm8iPT09bi50eXBlJiYhZnVuY3Rpb24gZSh0KXsic3RyaW5nIiE9PXQudHlwZSYmImhvb2siIT09dC50eXBlJiZ0LmNoaWxkcmVuLmV2ZXJ5KGUpO3ZhciBuPXgodC5uYW1lKTtpZigibWFjcm8iIT09dC50eXBlfHwicHJvbXB0IiE9PW4mJiJjb25maXJtIiE9PW4pe2lmKCJob29rIj09PXQudHlwZSYmIXQuZXZlcnlMZWFmKGZ1bmN0aW9uKGUpe3JldHVybiJlcnJvciIhPT1lLnR5cGV8fChoLnB1c2goZSksITEpfSkpcmV0dXJuITF9ZWxzZSBmLnB1c2godCk7cmV0dXJuITB9KG4pLGgubGVuZ3RoKXJldHVybnt2OlQuY3JlYXRlKCJzeW50YXgiLCJUaGlzIGNvZGUgaG9vaydzIG1hcmt1cCBjb250YWluZWQgIitoLmxlbmd0aCsiIGVycm9yIisoaC5sZW5ndGg/InMiOiIiKSsiOjxicj5cdTIwMTQiK2gubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLm1lc3NhZ2V9KS5qb2luKCI8YnI+XHUyMDE0IikpLnJlbmRlcihfKG4udGV4dCkpWzBdLm91dGVySFRNTH07ZD1mLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5ibG9ja2VyVHJlZT1nLmJsb2NrZXJzLmxlbmd0aCxnLmJsb2NrZXJzLnB1c2goZSksZS5ibG9ja2VyVHJlZX0pO2IrPSc8dHctZXhwcmVzc2lvbiB0eXBlPSInK24udHlwZSsnIiBuYW1lPSInK18obi5uYW1lfHxuLnRleHQpKyciJysoTy5kZWJ1Zz8nIHRpdGxlPSInK18obi50ZXh0KSsnIic6IiIpKyhkLmxlbmd0aD8nIGJsb2NrZXJzPSInK2QrJyInOiIiKSsnIGNvZGU9IicrZy5jb2RlLmxlbmd0aCsnIj48L3R3LWV4cHJlc3Npb24+JyxnLmNvZGUucHVzaChuKTticmVhaztkZWZhdWx0OmIrPW4uY2hpbGRyZW4mJm4uY2hpbGRyZW4ubGVuZ3RoP0Uobi5jaGlsZHJlbixnKTpuLnRleHR9az1lfShrKSlyZXR1cm4gZS52O3JldHVybiBifXJldHVybiBPYmplY3QuZnJlZXplKHtleGVjOmZ1bmN0aW9uKGUpe3ZhciByPXtjb2RlOltdLGJsb2NrZXJzOltdLHNvdXJjZTpbXX0sZT1FKGU9InN0cmluZyI9PXR5cGVvZiBlP1MubGV4KGUpLmNoaWxkcmVuOmUsciksZT1hKGEucGFyc2VIVE1MKGUsZG9jdW1lbnQsITApKTtyZXR1cm4gZS5maW5kQW5kRmlsdGVyKCJzY3JpcHQ6bm90KFtzcmNdKSIpLmVhY2goZnVuY3Rpb24oZSx0KXt2YXIgbj10LmdldEF0dHJpYnV0ZSgidHlwZSIpO24mJiJ0ZXh0L2phdmFzY3JpcHQiIT09bi50b0xvd2VyQ2FzZSgpfHx0LnNldEF0dHJpYnV0ZSgidHlwZSIsImFwcGxpY2F0aW9uL3gtaGFybG93ZSIpfSksci5ibG9ja2Vycz1yLmJsb2NrZXJzLm1hcChmdW5jdGlvbihlKXtlLmJsb2NrZWRWYWx1ZT0hMDtlPU9iamVjdC5jcmVhdGUoZSk7cmV0dXJuIGUuYmxvY2tlZFZhbHVlPSExLGV9KSxlLmZpbmRBbmRGaWx0ZXIoInR3LWV4cHJlc3Npb25bY29kZV06bm90KFtkYXRhLXJhd10pLCB0dy1leHByZXNzaW9uW2Jsb2NrZXJzXTpub3QoW2RhdGEtcmF3XSksIHR3LWhvb2tbc291cmNlXTpub3QoW2RhdGEtcmF3XSkiKS5lYWNoKGZ1bmN0aW9uKGUsdCl7dmFyIG47KHQ9YSh0KSkuYXR0cigiYmxvY2tlcnMiKSYmKG49dC5wb3BBdHRyKCJibG9ja2VycyIpLnNwbGl0KCIsIikubWFwKGZ1bmN0aW9uKGUpe3JldHVybiByLmJsb2NrZXJzW2VdfSksdC5kYXRhKCJibG9ja2VycyIsbikpLHQuYXR0cigic291cmNlIikmJnQuZGF0YSgic291cmNlIixyLnNvdXJjZVt0LnBvcEF0dHIoInNvdXJjZSIpXSksdC5hdHRyKCJjb2RlIikmJnQuZGF0YSgiY29kZSIsci5jb2RlW3QucG9wQXR0cigiY29kZSIpXSl9KSxlfX0pfSksZGVmaW5lKCJyZXBsIixbInV0aWxzIiwibWFya3VwIiwic2VjdGlvbiJdLGZ1bmN0aW9uKGUsdCxuKXtlLm9uU3RhcnR1cChmdW5jdGlvbigpe3JldHVybiBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ZS5vcHRpb25zLmRlYnVnJiYod2luZG93LlJFUEw9ZnVuY3Rpb24oZSl7ZT1uLmNyZWF0ZSgpLmV2YWwodC5sZXgoIihwcmludDoiK2UrIikiKSk7cmV0dXJuIGUuVHdpbmVTY3JpcHRfUnVuP2UuVHdpbmVTY3JpcHRfUnVuKCkuc291cmNlOmV9LHdpbmRvdy5MRVg9ZnVuY3Rpb24oZSl7ZT10LmxleChlKTtyZXR1cm4gMT09PWUubGVuZ3RoP2VbMF06ZX0pfSl9KX0pLGRlZmluZSgic2VjdGlvbiIsWyJqcXVlcnkiLCJ1dGlscyIsInR3aW5lc2NyaXB0L3J1bm5lciIsInR3aW5lc2NyaXB0L29wZXJhdGlvbnMiLCJzdGF0ZSIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwidXRpbHMvcmVuZGVydXRpbHMiLCJ1dGlscy9zY3JpcHR0YWciLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJkYXRhdHlwZXMvY29sb3VyIiwiZGF0YXR5cGVzL2xhbWJkYSIsImRhdGF0eXBlcy9jb2RlaG9vayIsImludGVybmFsdHlwZXMvY2hhbmdlZGVzY3JpcHRvciIsImludGVybmFsdHlwZXMvdmFyc2NvcGUiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJpbnRlcm5hbHR5cGVzL3R3aW5lbm90aWZpZXIiXSxmdW5jdGlvbihwLGYsYSx1LHIsZSx0LGksZCxoLG8sbSxnLHksYix2KXt2YXIgdz1lLnByaW50QnVpbHRpblZhbHVlLGs9ZS5vYmplY3ROYW1lLFM9ZS50eXBlSUQsVD1lLmlzT2JqZWN0LHM9dC5jb2xsYXBzZSxfPU9iamVjdC5hc3NpZ24seD1PYmplY3QuY3JlYXRlLE89T2JqZWN0LmtleXM7ZnVuY3Rpb24gQShlLHQsbil7aWYodCYmIm9iamVjdCI9PT1fdHlwZW9mKHQpJiZkLmlzUHJvdG90eXBlT2YodCkpe3ZhciByPW4ucG9wRGF0YSgic291cmNlIil8fChudWxsPT0ocj1uWzBdLmNhY2hlZERhdGEpP3ZvaWQgMDpyLnNvdXJjZSksYT0obnVsbCE9KGE9blswXSkmJmEuY2FjaGVkRGF0YSYmKG5bMF0uY2FjaGVkRGF0YS5zb3VyY2U9dm9pZCAwKSxuLmRhdGEoIm9yaWdpbmFsU291cmNlIixyKSxnLmNyZWF0ZSh7dGFyZ2V0Om4sc291cmNlOnIsc2VjdGlvbjp0aGlzLGFwcGVuZDoiYXBwZW5kIn0pKSxvPXQucnVuKGEpO2lmKGIuY29udGFpbnNFcnJvcihvKSYmZS5yZXBsYWNlV2l0aChvLnJlbmRlcihlLmF0dHIoInRpdGxlIikpKSwhdGhpcy5yZW5kZXJJbnRvKHIsbnVsbCxhKSlyZXR1cm4gbz1mLmluc2Vuc2l0aXZlTmFtZShlLmF0dHIoIm5hbWUiKSksWyJpZiIsImVsc2VpZiIsInVubGVzcyIsImVsc2UiLCJ0ZXN0ZmFsc2UiXS5pbmNsdWRlcyhvKSYmKGUuYWRkQ2xhc3MoImZhbHNlIiksImVsc2VpZiIhPT1vKSYmKHRoaXMuc3RhY2tUb3AubGFzdEhvb2tTaG93bj0hMSksbi5kYXRhKCJsaXZlIikmJmZ1bmN0aW9uKHQsbixyKXtmdW5jdGlvbiBhKGUpe3AmJihkLT0oZS1wKSooZi5vcHRpb25zLmRlYnVnJiZ2b2lkIDAhPT1mLm9wdGlvbnMuc3BlZWRNdWx0aXBsaWVyP2Yub3B0aW9ucy5zcGVlZE11bHRpcGxpZXI6MSkpLHA9ZSwwPGQ/cmVxdWVzdEFuaW1hdGlvbkZyYW1lKGEpOihkPXMsbygpKX12YXIgbyxpPXRoaXMsZT1yLmRhdGEoImxpdmUiKSxzPWUuZGVsYXksYz1lLmV2ZW50LGw9KChuPV9vYmplY3RTcHJlYWQoX29iamVjdFNwcmVhZCh7fSxuKSx7fSx7YXBwZW5kOiJyZXBsYWNlIix0cmFuc2l0aW9uRGVmZXJyZWQ6ITEsZW5hYmxlZDohMH0pKS5kYXRhPV9vYmplY3RTcHJlYWQoX29iamVjdFNwcmVhZCh7fSxuLmRhdGEpLHt9LHtsaXZlOnZvaWQgMH0pLHIuZGF0YSgib3JpZ2luYWxTb3VyY2UiKXx8IiIpLHU9dGhpcy5zdGFja1RvcC50ZW1wVmFyaWFibGVzLHA9bnVsbCxkPXM7bz10aGlzLndoZW5VbmJsb2NrZWQuYmluZCh0aGlzLGZ1bmN0aW9uKCl7dmFyIGU7aS5pbkRPTSgpJiYoZT1udWxsPT1jP3ZvaWQgMDpjLmZpbHRlcihpLFshMF0sdSksYi5jb250YWluc0Vycm9yKGUpP2UucmVuZGVyKGksdC5hdHRyKCJ0aXRsZSIpKS5yZXBsYWNlQWxsKHQpOmMmJiFlWzBdP3JlcXVlc3RBbmltYXRpb25GcmFtZShhKTooaS5yZW5kZXJJbnRvKGwscixuLHUpLGV8fHIuZmluZCgidHctZXhwcmVzc2lvbltuYW1lPSdzdG9wJ10iKS5sZW5ndGh8fGkuaW5ET00oKSYmcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGEpKSl9KSxyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoYSl9LmNhbGwodGhpcyxlLGEsbiksITB9ZWxzZXtpZighMT09PXQpcmV0dXJuIG89bi5wb3BEYXRhKCJzb3VyY2UiKXx8KG51bGw9PShyPW5bMF0uY2FjaGVkRGF0YSk/dm9pZCAwOnIuc291cmNlKSxudWxsIT0oYT1uWzBdKSYmYS5jYWNoZWREYXRhJiYoblswXS5jYWNoZWREYXRhLnNvdXJjZT12b2lkIDApLG8mJihuLmNhY2hlZERhdGEmJihuLmNhY2hlZERhdGEuc291cmNlPXZvaWQgMCksbi5kYXRhKCJvcmlnaW5hbFNvdXJjZSIsbyksbi5kYXRhKCJoaWRkZW4iLCEwKSksZS5hZGRDbGFzcygiZmFsc2UiKSwhKHRoaXMuc3RhY2tUb3AubGFzdEhvb2tTaG93bj0hMSk7aWYoITAhPT10KXJldHVybiExfXJldHVybiB0aGlzLnN0YWNrVG9wLmxhc3RIb29rU2hvd249ITB9ZnVuY3Rpb24gQyhlKXt2YXIgdCxuLGU9KGUgaW5zdGFuY2VvZiBwP2VbMF06ZSkubmV4dFNpYmxpbmc7cmV0dXJuIGUmJihlIGluc3RhbmNlb2YgVGV4dCYmIWUudGV4dENvbnRlbnQudHJpbSgpfHxbImJyIiwidHctY29uc2VjdXRpdmUtYnIiXS5pbmNsdWRlcygoZS50YWdOYW1lfHwiIikudG9Mb3dlckNhc2UoKSkpPyh0PShuPUMoZSkpLndoaXRlc3BhY2Usbj1uLm5leHRFbGVtLHt3aGl0ZXNwYWNlOnAoZSkuYWRkKHQpLG5leHRFbGVtOm59KTp7d2hpdGVzcGFjZTpwKCksbmV4dEVsZW06cChlKX19ZnVuY3Rpb24gRShlKXtpZihudWxsIT1lJiZlLmxlbmd0aClyZXR1cm4gcCgiPHR3LW9wZW4tYnV0dG9uIHJlcGxheSBsYWJlbD0nXHVkODNkXHVkZDBkJz4iKS5kYXRhKCJldmFsUmVwbGF5IixlKX1mdW5jdGlvbiBjKGUsdCl7dmFyIG49dGhpcy5ldmFsKHQpO2UuYXBwZW5kKEUodGhpcy5ldmFsUmVwbGF5KSksZS5hcHBlbmQoZnVuY3Rpb24oZSx0KXtpZigvYSBcKChnby10b3x1bmRvfHJlZGlyZWN0fHJlc3RhcnQpOlwpIGNvbW1hbmQvLmV4ZWMobnVsbD09dD92b2lkIDA6dC5Ud2luZVNjcmlwdF9UeXBlTmFtZSkpcmV0dXJuIHAoIjx0dy1vcGVuLWJ1dHRvbiBnb3RvIGxhYmVsPSdHTyc+IikuZGF0YSgiZ290byIse3NlY3Rpb246ZSxjb21tYW5kOnR9KX0odGhpcyxuKSksdGhpcy5zdGFja1RvcC5ldmFsdWF0ZU9ubHkmJm4mJihkLmlzUHJvdG90eXBlT2Yobil8fCJmdW5jdGlvbiI9PXR5cGVvZiBuLlR3aW5lU2NyaXB0X1J1bikmJihuPWIuY3JlYXRlKCJzeW50YXgiLCJJIGNhbid0IHdvcmsgb3V0IHdoYXQgIi5jb25jYXQodGhpcy5zdGFja1RvcC5ldmFsdWF0ZU9ubHksIiBzaG91bGQgZXZhbHVhdGUgdG8sIGJlY2F1c2UgaXQgY29udGFpbnMgYSAiKS5jb25jYXQoZC5pc1Byb3RvdHlwZU9mKG4pPyJjaGFuZ2VyLiI6ImNvbW1hbmQuIiksIlBsZWFzZSByZXdyaXRlIHRoaXMgd2l0aG91dCBwdXR0aW5nIGNoYW5nZXJzIG9yIGNvbW1hbmRzIGhlcmUuIikpO3ZhciByPXAoKTtmb3IoaT1lO2QuaXNQcm90b3R5cGVPZihuKTspe3ZhciBhPUMoaSksbz1hLndoaXRlc3BhY2U7aWYoKGk9YS5uZXh0RWxlbSlbMF0mJmlbMF0ubm9kZVR5cGU9PT1Ob2RlLlRFWFRfTk9ERSYmIisiPT09aVswXS50ZXh0Q29udGVudC50cmltKCkpe3ZhciBpLGE9aSxzPUMoYSksYz1zLndoaXRlc3BhY2U7aWYoKGk9cy5uZXh0RWxlbSkuaXMoInR3LWV4cHJlc3Npb24iKSl7dmFyIHM9aS5wb3BEYXRhKCJjb2RlIil8fChudWxsPT0ocz1pWzBdKXx8bnVsbD09KHM9cy5jYWNoZWREYXRhKT92b2lkIDA6cy5jb2RlKSxsPShudWxsIT0obD1pWzBdKSYmbC5jYWNoZWREYXRhJiYoaVswXS5jYWNoZWREYXRhLmNvZGU9dm9pZCAwKSx0aGlzLmV2YWwocykpO2lmKGIuY29udGFpbnNFcnJvcihsKSl7bj1sO2JyZWFrfXM9dVsiKyJdKG4sbCk7cChvKS5hZGQoYSkuYWRkKGMpLnJlbW92ZSgpLG49Yi5jb250YWluc0Vycm9yKHMpP2IuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IGNvbWJpbmUgIitrKG4pKyIgd2l0aCAiK2sobCkrIi4iLCJmdW5jdGlvbiI9PXR5cGVvZiBsLlR3aW5lU2NyaXB0X1J1bj8iSWYgeW91IHdhbnQgdG8gYXR0YWNoIHRoaXMgY2hhbmdlciB0byAiLmNvbmNhdChrKGwpLCIsIHJlbW92ZSB0aGUgKyBiZXR3ZWVuIHRoZW0uIik6IkNoYW5nZXJzIGNhbiBvbmx5IGJlIGFkZGVkIHRvIG90aGVyIGNoYW5nZXJzLiIpOnM7Y29udGludWV9fWlmKGkuaXMoInR3LWV4cHJlc3Npb24iKSl7Yz1pLnBvcERhdGEoImNvZGUiKXx8KG51bGw9PShhPWlbMF0pfHxudWxsPT0oYT1hLmNhY2hlZERhdGEpP3ZvaWQgMDphLmNvZGUpLHM9KG51bGwhPShsPWlbMF0pJiZsLmNhY2hlZERhdGEmJihpWzBdLmNhY2hlZERhdGEuY29kZT12b2lkIDApLHRoaXMuZXZhbChjKSk7aWYoaS5hcHBlbmQoRSh0aGlzLmV2YWxSZXBsYXkpKSxiLmNvbnRhaW5zRXJyb3Iocykpe249czticmVha31pZihzJiYib2JqZWN0Ij09PV90eXBlb2YocykmJiJmdW5jdGlvbiI9PXR5cGVvZiBzLlR3aW5lU2NyaXB0X0F0dGFjaCl7bj1zLlR3aW5lU2NyaXB0X0F0dGFjaCh0aGlzLG4pO2JyZWFrfXJldHVybiBkLmlzUHJvdG90eXBlT2Yocyk/dm9pZCBlLnJlcGxhY2VXaXRoKGIuY3JlYXRlKCJvcGVyYXRpb24iLCJDaGFuZ2VycyBsaWtlICgiLmNvbmNhdChuLm1hY3JvTmFtZSwiOikgbmVlZCB0byBiZSBjb21iaW5lZCB1c2luZyArIGJldHdlZW4gdGhlbS4iKSwiUGxhY2UgdGhlICsgYmV0d2VlbiB0aGUgY2hhbmdlciBtYWNyb3MsIG9yIHRoZSB2YXJpYWJsZXMgaG9sZGluZyB0aGVtLiBUaGUgKyBpcyBhYnNlbnQgb25seSBiZXR3ZWVuIGEgY2hhbmdlciBhbmQgaXRzIGF0dGFjaGVkIGhvb2sgb3IgY29tbWFuZC4iKS5yZW5kZXIoZS5hdHRyKCJ0aXRsZSIpKSk6dm9pZCBlLnJlcGxhY2VXaXRoKGIuY3JlYXRlKCJvcGVyYXRpb24iLCIiLmNvbmNhdChrKHMpLCIgY2FuJ3QgaGF2ZSBjaGFuZ2VycyBsaWtlICgiKS5jb25jYXQobi5tYWNyb05hbWUsIjopIGF0dGFjaGVkLiIpLCJDaGFuZ2VycyBwbGFjZWQganVzdCBiZWZvcmUgaG9va3MsIGxpbmtzIGFuZCBjb21tYW5kcyB3aWxsIGF0dGVtcHQgdG8gYXR0YWNoLCBidXQgaW4gdGhpcyBjYXNlIGl0IGRpZG4ndCB3b3JrLiIpLnJlbmRlcihlLmF0dHIoInRpdGxlIikpKX1pZihpLmlzKCJ0dy1ob29rIikpe28ucmVtb3ZlKCkscj1pO2JyZWFrfW4ubWFjcm9OYW1lfHxmLmltcG9zc2libGUoIlNlY3Rpb24ucnVuRXhwcmVzc2lvbiIsImNoYW5nZXIgaGFzIG5vIG1hY3JvTmFtZSIpO2E9ZS5hdHRyKCJ0aXRsZSIpfHwiKCIrbi5tYWNyb05hbWUrIjogLi4uKSI7cmV0dXJuIHZvaWQgZS5yZXBsYWNlV2l0aChiLmNyZWF0ZSgic3ludGF4IiwiVGhlICgiLmNvbmNhdChuLm1hY3JvTmFtZSwiOikgY2hhbmdlciBzaG91bGQgYmUgc3RvcmVkIGluIGEgdmFyaWFibGUgb3IgYXR0YWNoZWQgdG8gYSBob29rLiIpLCJNYWNyb3MgbGlrZSB0aGlzIHNob3VsZCBhcHBlYXIgYmVmb3JlIGEgaG9vazogIi5jb25jYXQoYSwiW1NvbWUgdGV4dF0iKSkucmVuZGVyKGUuYXR0cigidGl0bGUiKSkpfWUuYXR0cigicmV0dXJuIixTKG4pKSxyPXIubGVuZ3RoP3I6QyhlKS5uZXh0RWxlbS5maWx0ZXIoInR3LWhvb2siKSwodD1iLmNvbnRhaW5zRXJyb3IobikpP2UucmVwbGFjZVdpdGgodC5yZW5kZXIoZS5hdHRyKCJ0aXRsZSIpKS5hcHBlbmQoRSh0aGlzLmV2YWxSZXBsYXkpKSk6di5pc1Byb3RvdHlwZU9mKG4pP2UuYXBwZW5kKG4ucmVuZGVyKCkpOm4mJiJmdW5jdGlvbiI9PXR5cGVvZiBuLlR3aW5lU2NyaXB0X1J1bj8obj1uLlR3aW5lU2NyaXB0X1J1bih0aGlzKSxiLmNvbnRhaW5zRXJyb3Iobik/ZS5yZXBsYWNlV2l0aChuLnJlbmRlcihlLmF0dHIoInRpdGxlIikpKTpnLmlzUHJvdG90eXBlT2Yobik/bnVsbCE9KHQ9bi5kYXRhKSYmdC5saXZlP2UucmVwbGFjZVdpdGgoYi5jcmVhdGUoInVuaW1wbGVtZW50ZWQiLCJJIGN1cnJlbnRseSBjYW4ndCBhdHRhY2ggKGxpdmU6KSBvciAoZXZlbnQ6KSBtYWNyb3MgdG8gY29tbWFuZHMgLSBvbmx5IGhvb2tzLiIpLnJlbmRlcihlLmF0dHIoInRpdGxlIikpKToobi5zZWN0aW9uPXRoaXMsbi50YXJnZXQ9aSx0aGlzLnJlbmRlckludG8oIiIsaSxuKSk6VChuKSYmbi5ibG9ja2VkPyh0aGlzLnN0YWNrVG9wLmJsb2NrZWQ9bi5ibG9ja2VkLGUuZGF0YSgiY29kZSIse3R5cGU6Im1hY3JvIixibG9ja2VkVmFsdWU6ITAsdGV4dDplLmF0dHIoInRpdGxlIil8fCIiLHN0YXJ0OjAsZW5kOihlLmF0dHIoInRpdGxlIil8fCIiKS5sZW5ndGh9KSk6biYmZi5pbXBvc3NpYmxlKCJTZWN0aW9uLnJ1bkV4cHJlc3Npb24iLCJUd2luZVNjcmlwdF9SdW4oKSByZXR1cm5lZCBhIG5vbi1DaGFuZ2VEZXNjcmlwdG9yICIuY29uY2F0KF90eXBlb2YobiksJzogIicpLmNvbmNhdChuLCciJykpKTpyLmxlbmd0aCYmQS5jYWxsKHRoaXMsZSxuLHIpfHwoInN0cmluZyI9PXR5cGVvZiBufHwibnVtYmVyIj09dHlwZW9mIG58fG4gaW5zdGFuY2VvZiBNYXB8fG4gaW5zdGFuY2VvZiBTZXR8fEFycmF5LmlzQXJyYXkobil8fGguaXNQcm90b3R5cGVPZihuKXx8bS5pc1Byb3RvdHlwZU9mKG4pfHxuJiYiZnVuY3Rpb24iPT10eXBlb2Ygbi5Ud2luZVNjcmlwdF9QcmludCYmIWQuaXNQcm90b3R5cGVPZihuKT8obj13KG4pLGIuY29udGFpbnNFcnJvcihuKT9lLnJlcGxhY2VXaXRoKG4ucmVuZGVyKGUuYXR0cigidGl0bGUiKSkpOiJzdHJpbmciPT10eXBlb2Ygbnx8QXJyYXkuaXNBcnJheShuKT90aGlzLnJlbmRlckludG8obixlKTpmLmltcG9zc2libGUoInByaW50QnVpbHRpblZhbHVlKCkgcHJvZHVjZWQgYSBub24tc3RyaW5nIG5vbi1hcnJheSAiLmNvbmNhdChfdHlwZW9mKG4pKSkpOmQuaXNQcm90b3R5cGVPZihuKXx8ImJvb2xlYW4iPT10eXBlb2Ygbnx8Zi5pbXBvc3NpYmxlKCJTZWN0aW9uLnJ1bkV4cHJlc3Npb24iLCJUaGUgZXhwcmVzc2lvbiBldmFsdWF0ZWQgdG8gYW4gdW5rbm93biB2YWx1ZTogIi5jb25jYXQobikpKX12YXIgbD17YWRkOltdLHJlbW92ZTpbXX07cmV0dXJuIE9iamVjdC5wcmV2ZW50RXh0ZW5zaW9ucyh7Y3JlYXRlOmZ1bmN0aW9uKCl7dmFyIGU9MDxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOmYuc3RvcnlFbGVtZW50LG49Xyh4KHRoaXMpLHt0aW1lc3RhbXA6RGF0ZS5ub3coKSxkb206ZSxzdGFjazpbXSxlbmNoYW50bWVudHM6W10sdW5ibG9ja0NhbGxiYWNrczpbXSxmcmVlVmFyaWFibGVzOm51bGwsZXZhbFJlcGxheTpudWxsLGxvYWRlZEdhbWU6ITEsSWRlbnRpZmllcnM6e1R3aW5lU2NyaXB0X0lkZW50aWZpZXJzOiEwLGl0OjAsZ2V0IHRpbWUoKXt2YXIgZTtyZXR1cm4gbnVsbCE9KGU9bi5zdGFja1RvcCkmJmUuZXZhbHVhdGVPbmx5P2IuY3JlYXRlKCJvcGVyYXRpb24iLCIndGltZScgY2FuJ3QgYmUgdXNlZCBpbiAiLmNvbmNhdChuLnN0YWNrVG9wLmV2YWx1YXRlT25seSwiLiIpKTooRGF0ZS5ub3coKS1uLnRpbWVzdGFtcCkqKGYub3B0aW9ucy5kZWJ1ZyYmdm9pZCAwIT09Zi5vcHRpb25zLnNwZWVkTXVsdGlwbGllcj9mLm9wdGlvbnMuc3BlZWRNdWx0aXBsaWVyOjEpfSxnZXQgdHVybnMoKXtyZXR1cm4gci50dXJuc30sZ2V0IHR1cm4oKXtyZXR1cm4gci50dXJuc30sZ2V0IHZpc2l0cygpe3ZhciB0PW4uc3RhY2tUb3Auc3BlY3VsYXRpdmVQYXNzYWdlO3JldHVybiByLmhpc3RvcnkoKS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT0odHx8ci5wYXNzYWdlKX0pLmxlbmd0aCsoIXR8fHQ9PT1yLnBhc3NhZ2UpfSxnZXQgdmlzaXQoKXtyZXR1cm4gbi5JZGVudGlmaWVycy52aXNpdHN9LGdldCBleGl0cygpe3ZhciBlO3JldHVybiBudWxsIT0oZT1uLnN0YWNrVG9wKSYmZS5ldmFsdWF0ZU9ubHk/Yi5jcmVhdGUoIm9wZXJhdGlvbiIsIidleGl0JyBhbmQgJ2V4aXRzJyBjYW4ndCBiZSB1c2VkIGluICIuY29uY2F0KG4uc3RhY2tUb3AuZXZhbHVhdGVPbmx5LCIuIikpOm4uZG9tLmZpbmQoInR3LWVuY2hhbnRtZW50LCB0dy1saW5rIikuZmlsdGVyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ9cCh0KSkuZGF0YSgiZW5jaGFudG1lbnRFdmVudCIpfHx0LnBhcmVudCgpLmRhdGEoImxpbmtQYXNzYWdlTmFtZSIpfHx0LnBhcmVudCgpLmRhdGEoImNsaWNrRXZlbnQiKX0pLmxlbmd0aH0sZ2V0IGV4aXQoKXtyZXR1cm4gbi5JZGVudGlmaWVycy5leGl0c30sZ2V0IHBvcygpe3JldHVybiBuLnN0YWNrVG9wJiYhbi5zdGFja1RvcC5ldmFsdWF0ZU9ubHkmJm4uc3RhY2tUb3AubGFtYmRhUG9zPytuLnN0YWNrVG9wLmxhbWJkYVBvc3x8MTpiLmNyZWF0ZSgib3BlcmF0aW9uIiwiJ3BvcycgY2FuIG9ubHkgYmUgdXNlZCBpbiBsYW1iZGFzIHRoYXQgYXJlbid0ICd3aGVuJyBsYW1iZGFzLiIpfX19KTtyZXR1cm4gbn0sZXZhbDpmdW5jdGlvbih0KXt2YXIgZSxuO2Yub3B0aW9ucy5kZWJ1ZyYmZi5vcHRpb25zLmV2YWxSZXBsYXkmJihuPUFycmF5LmlzQXJyYXkodCk/dC5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSt0LnRleHR9LCIiKTp0LnRleHR8fCIiLHRoaXMuZXZhbFJlcGxheT1be2NvZGU6bixmcm9tQ29kZTpuLGJhc2lzOihBcnJheS5pc0FycmF5KHQpP3RbMF06dCkuc3RhcnQsc3RhcnQ6MCxlbmQ6bi5sZW5ndGgsZGlmZjowfV0pO3RyeXtlPWEodGhpcyx0KX1jYXRjaChlKXtyZXR1cm4gbnVsbCE9KG49d2luZG93LmNvbnNvbGUpJiZuLmVycm9yKGUpLHRoaXMuZXZhbFJlcGxheT1udWxsLGIuY3JlYXRlKCIiLCJBbiBpbnRlcm5hbCBlcnJvciBvY2N1cnJlZCB3aGlsZSB0cnlpbmcgdG8gcnVuICIuY29uY2F0KFtdLmNvbmNhdCh0KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudGV4dH0pLmpvaW4oIiIpLCIuIiksJ1RoZSBlcnJvciB3YXMgIicuY29uY2F0KGUubWVzc2FnZSwnIi5cbklmIHRoaXMgaXMgdGhlIGxhdGVzdCB2ZXJzaW9uIG9mIEhhcmxvd2UsIHBsZWFzZSBjb25zaWRlciByZXBvcnRpbmcgYSBidWcgKHNlZSB0aGUgZG9jdW1lbnRhdGlvbikuJykpfXJldHVybiB0aGlzLmV2YWxSZXBsYXkmJjI9PT10aGlzLmV2YWxSZXBsYXkubGVuZ3RoJiZ0aGlzLmV2YWxSZXBsYXkuc2hpZnQoKSxlfSxnZXQgc3RhY2tUb3AoKXtyZXR1cm4gdGhpcy5zdGFja1swXX0saW5ET006ZnVuY3Rpb24oKXtyZXR1cm4gMDxmLnN0b3J5RWxlbWVudC5maW5kKHRoaXMuZG9tKS5sZW5ndGh9LGV2YWx1YXRlVHdpbmVNYXJrdXA6ZnVuY3Rpb24oZSx0KXt2YXIgbj1wKCI8cD4iKTtyZXR1cm4gdGhpcy5zdGFjay51bnNoaWZ0KHtkZXNjOmcuY3JlYXRlKHt0YXJnZXQ6bixzb3VyY2U6ZSxzZWN0aW9uOnRoaXMsYXBwZW5kOiJhcHBlbmQifSksdGVtcFZhcmlhYmxlczp0aGlzLnN0YWNrVG9wLnRlbXBWYXJpYWJsZXMsZXZhbHVhdGVPbmx5OnQsZmluYWxJdGVyOiEwfSksdGhpcy5leGVjdXRlKCksMDwoZT1uLmZpbmQoInR3LWVycm9yIikpLmxlbmd0aD9lOm59LHNwZWN1bGF0ZTpmdW5jdGlvbihlLHQsbil7dGhpcy5zdGFjay51bnNoaWZ0KHtldmFsdWF0ZU9ubHk6bixmaW5hbEl0ZXI6ITAsdGVtcFZhcmlhYmxlczpfKHgoeSkse1R3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU6e3R5cGU6InRlbXAiLG5hbWU6bn19KSxzcGVjdWxhdGl2ZVBhc3NhZ2U6dH0pO3ZhciByLG49dGhpcy5ldmFsUmVwbGF5O3JldHVybiB0aGlzLmV2YWxSZXBsYXk9bnVsbCxvLmlzUHJvdG90eXBlT2YoZSk/cj1lLmFwcGx5KHRoaXMse2ZhaWw6ITEscGFzczohMH0pOmUmJihyPWEodGhpcyxlKSksdGhpcy5zdGFjay5zaGlmdCgpLHRoaXMuZXZhbFJlcGxheT1uLHJ9LHJlbmRlckludG86ZnVuY3Rpb24oZSxhLHQpe3ZhciBvPXRoaXMscj0zPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106bnVsbCxpPWcuY3JlYXRlKHt0YXJnZXQ6YSxzb3VyY2U6ZSxzZWN0aW9uOnRoaXMsYXBwZW5kOiJhcHBlbmQifSk7aWYodClpZihkLmlzUHJvdG90eXBlT2YodCkpe3ZhciBlPXQucnVuKGkpO2lmKGIuY29udGFpbnNFcnJvcihlKSlyZXR1cm4gZS5yZW5kZXIoYS5hdHRyKCJ0aXRsZSIpKS5yZXBsYWNlQWxsKGEpLCExfWVsc2UgXyhpLHQpO2lmKChhPWkudGFyZ2V0LDUwPD10aGlzLnN0YWNrLmxlbmd0aCkmJjUwPD10aGlzLnN0YWNrLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlKyEhdC5maW5hbEl0ZXJ9LDApKXJldHVybiBiLmNyZWF0ZSgiaW5maW5pdGUiLCJQcmludGluZyB0aGlzIGV4cHJlc3Npb24gbWF5IGhhdmUgdHJhcHBlZCBtZSBpbiBhbiBpbmZpbml0ZSBsb29wLiIpLnJlbmRlcihhLmF0dHIoInRpdGxlIikpLnJlcGxhY2VBbGwoYSksITE7dmFyIHM9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPWEgaW5zdGFuY2VvZiBwJiZhLmlzKCJ0dy1ob29rIikmJjA8YS5wYXJlbnRzKCJ0dy1jb2xsYXBzZWQsW2NvbGxhcHNpbmc9dHJ1ZV0iKS5sZW5ndGg7by5zdGFjay51bnNoaWZ0KHtkZXNjOmUsZmluYWxJdGVyOm4sdGVtcFZhcmlhYmxlczp0LGNvbGxhcHNlczpyLGV2YWx1YXRlT25seTpvLnN0YWNrVG9wJiZvLnN0YWNrVG9wLmV2YWx1YXRlT25seX0pfSxyPXJ8fHgodGhpcy5zdGFjay5sZW5ndGg/dGhpcy5zdGFja1RvcC50ZW1wVmFyaWFibGVzOnkpLHQ9KGhhc093blByb3BlcnR5LmNhbGwociwiVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSIpfHwodD1udWxsPT0oZT1hKT92b2lkIDA6ZS50YWcoKSxyLlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU9e3R5cGU6InRlbXAiLG5hbWU6InR3LWhvb2siPT09dD9hLmF0dHIoIm5hbWUiKT8iPyIrYS5hdHRyKCJuYW1lIik6ImFuIHVubmFtZWQgaG9vayI6InR3LWV4cHJlc3Npb24iPT09dD8iYSAiK2EuYXR0cigidHlwZSIpKyIgZXhwcmVzc2lvbiI6InR3LXBhc3NhZ2UiPT09dD8idGhpcyBwYXNzYWdlIjoiYW4gdW5rbm93biBzY29wZSJ9KSxudWxsPT0oZT10aGlzLnN0YWNrVG9wKT92b2lkIDA6ZS5ibG9ja2VkKTtpZihPKGkubG9vcFZhcnMpLmxlbmd0aCl7dmFyIGM9X29iamVjdFNwcmVhZCh7fSxpLmxvb3BWYXJzKSxsPU1hdGgubWluLmFwcGx5KE1hdGgsX3RvQ29uc3VtYWJsZUFycmF5KE8oYykubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBjW2VdLmxlbmd0aH0pKSk7aWYodi5jcmVhdGUobCsiIGxvb3AiKygxIT09bD8icyI6IiIpKS5yZW5kZXIoKS5wcmVwZW5kVG8oYSksbCl7Zm9yKHZhciBuPWwtMTswPD1uOy0tbikhZnVuY3Rpb24obil7cyhpLE8oYykucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdF09Y1t0XVtuXSxlfSx4KHIpLG49PT1sLTEpKX0obik7Zm9yKHZhciB1PWwtMTswPD11JiYhdGhpcy5zdGFja1RvcC5ibG9ja2VkOy0tdSl0aGlzLmV4ZWN1dGUoKX19ZWxzZSBzKGksciwhMCksdGhpcy5leGVjdXRlKCk7cmV0dXJuKDA9PT10aGlzLnN0YWNrLmxlbmd0aHx8IXQmJm51bGwhPShlPXRoaXMuc3RhY2tUb3ApJiZlLmJsb2NrZWQpJiZ0aGlzLnVwZGF0ZUVuY2hhbnRtZW50cygpLGkuZW5hYmxlZH0sZXhlY3V0ZTpmdW5jdGlvbigpe3ZhciBhPXRoaXMsZT10aGlzLnN0YWNrVG9wLHQ9ZS5kZXNjLG49ZS5kb20scj1lLmNvbGxhcHNlcyxvPWUuZXZhbHVhdGVPbmx5O3QmJiFuJiYobj10LnJlbmRlcigpLHRoaXMuc3RhY2tUb3AuZG9tPW4sdGhpcy5zdGFja1RvcC5kZXNjPXZvaWQgMCksbi5maW5kQW5kRmlsdGVyKCd0dy1ob29rLHR3LWV4cHJlc3Npb24sc2NyaXB0W3R5cGU9ImFwcGxpY2F0aW9uL3gtaGFybG93ZSJdJykuZWFjaChmdW5jdGlvbihlLHQpe3ZhciBuPXAodCkuZGF0YSgpO3QuY2FjaGVkRGF0YT17YmxvY2tlcnM6bi5ibG9ja2Vycyxjb2RlOm4uY29kZSxzb3VyY2U6bi5zb3VyY2V9fSkuZWFjaChmdW5jdGlvbihlLHQpe2lmKGEuc3RhY2tUb3AuYmxvY2tlZClyZXR1cm4hMTt2YXIgbj10LmNhY2hlZERhdGE7c3dpdGNoKG4mJih0LmNhY2hlZERhdGE9dm9pZCAwKSwodD1wKHQpKS50YWcoKSl7Y2FzZSJ0dy1ob29rIjp2YXIgcj10LnBvcERhdGEoInNvdXJjZSIpfHwobnVsbD09bj92b2lkIDA6bi5zb3VyY2UpOyhyJiZ0LmRhdGEoIm9yaWdpbmFsU291cmNlIixyKSx0LmRhdGEoInRlbXBWYXJpYWJsZXMiLGEuc3RhY2tUb3AudGVtcFZhcmlhYmxlcyksdC5wb3BBdHRyKCJoaWRkZW4iKSk/dC5kYXRhKCJoaWRkZW4iLCEwKTpyJiZhLnJlbmRlckludG8ocix0KTticmVhaztjYXNlInR3LWV4cHJlc3Npb24iOnZhciByPXQuZGF0YSgiYmxvY2tlcnMiKXx8KG51bGw9PW4/dm9pZCAwOm4uYmxvY2tlcnMpO2lmKHIpe2lmKG8pcmV0dXJuIHZvaWQgdC5yZW1vdmVEYXRhKCJibG9ja2VycyIpLnJlbW92ZURhdGEoImNvZGUiKS5yZXBsYWNlV2l0aChiLmNyZWF0ZSgic3ludGF4IiwiSSBjYW4ndCB1c2UgYSBtYWNybyBsaWtlIChwcm9tcHQ6KSBvciAoY29uZmlybTopIGluICIuY29uY2F0KG8sIi4iKSwiUGxlYXNlIHJld3JpdGUgdGhpcyB3aXRob3V0IHB1dHRpbmcgc3VjaCBtYWNyb3MgaGVyZS4iKS5yZW5kZXIodC5hdHRyKCJ0aXRsZSIpLHQpKTtpZihyLmxlbmd0aClyZXR1cm4gYS5zdGFja1RvcC5ibG9ja2VkPSEwLHI9YS5ldmFsKHIuc2hpZnQoKSksYi5jb250YWluc0Vycm9yKHIpJiYoYS5zdGFja1RvcC5ibG9ja2VkPSExLHQucmVtb3ZlRGF0YSgiYmxvY2tlcnMiKS5yZXBsYWNlV2l0aChyLnJlbmRlcih0LmF0dHIoInRpdGxlIiksdCkpKSwhMTt0LnJlbW92ZURhdGEoImJsb2NrZXJzIil9cj10LnBvcERhdGEoImNvZGUiKXx8KG51bGw9PW4/dm9pZCAwOm4uY29kZSk7ciYmYy5jYWxsKGEsdCxyKTticmVhaztjYXNlInNjcmlwdCI6aWYoZi5yZWF0dGFjaFN0b3J5RWxlbWVudCgpLHQudGV4dCgpKXRyeXtpKHQudGV4dCgpLGEuc3RhY2tUb3AudGVtcFZhcmlhYmxlcyl9Y2F0Y2goZSl7Yi5pc1Byb3RvdHlwZU9mKGUpP3QucmVwbGFjZVdpdGgoZS5yZW5kZXIodC50ZXh0KCksdCkpOihudWxsIT0ocj13aW5kb3cuY29uc29sZSkmJnIuZXJyb3IoZSksdC5yZXBsYWNlV2l0aChiLmNyZWF0ZSgiIiwiQSBKYXZhc2NyaXB0IGVycm9yIG9jY3VycmVkIHdoaWxlIHJ1bm5pbmcgdGhpcyA8c2NyaXB0PiBlbGVtZW50LiIsJ1RoZSBlcnJvciB3YXMgIicuY29uY2F0KGUsJyIuIENoZWNrIHRoZSBicm93c2VyIGNvbnNvbGUgZm9yIG1vcmUgZGV0YWlscy4nKSkucmVuZGVyKHQudGV4dCgpLHQpKSl9fX0pLHRoaXMuc3RhY2tUb3AuYmxvY2tlZHx8KG4ubGVuZ3RoJiZyJiZzKG4pLG4uZmluZEFuZEZpbHRlcigidHctY29sbGFwc2VkLFtjb2xsYXBzaW5nPXRydWVdIikuZWFjaChmdW5jdGlvbigpe3MocCh0aGlzKSl9KSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIG4uZmluZCgiaW5wdXQsIHRleHRhcmVhIikuZmlyc3QoKS5mb2N1cygpfSwxMDApLHRoaXMuc3RhY2suc2hpZnQoKSl9LHVwZGF0ZUVuY2hhbnRtZW50czpmdW5jdGlvbigpe3RoaXMuZW5jaGFudG1lbnRzLmZvckVhY2goZnVuY3Rpb24oZSl7ZS5kaXNlbmNoYW50KCksZS5lbmNoYW50U2NvcGUoKX0pfSxvbjpmdW5jdGlvbihlLHQpe3JldHVybiBsW2VdLnB1c2godCksdGhpc30sYWRkRW5jaGFudG1lbnQ6ZnVuY3Rpb24odCl7dmFyIG49dGhpczt0aGlzLmVuY2hhbnRtZW50cy5wdXNoKHQpLGwuYWRkLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUobix0KX0pfSxyZW1vdmVFbmNoYW50bWVudDpmdW5jdGlvbih0KXt2YXIgbj10aGlzLGU9dGhpcy5lbmNoYW50bWVudHMuaW5kZXhPZih0KTt0aGlzLmVuY2hhbnRtZW50cy5zcGxpY2UoZSwxKSx0LmRpc2VuY2hhbnQoKSxsLnJlbW92ZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKG4sdCl9KX0sdW5ibG9jazpmdW5jdGlvbihlKXtmb3IodGhpcy5zdGFjay5sZW5ndGh8fGYuaW1wb3NzaWJsZSgiU2VjdGlvbi51bmJsb2NrIiwic3RhY2sgaXMgZW1wdHkiKSx0aGlzLnN0YWNrVG9wLmJsb2NrZWQ9ITEsdm9pZCAwIT09ZSYmKHRoaXMuc3RhY2tUb3AuYmxvY2tlZFZhbHVlcz0odGhpcy5zdGFja1RvcC5ibG9ja2VkVmFsdWVzfHxbXSkuY29uY2F0KGUpKTt0aGlzLnN0YWNrLmxlbmd0aCYmIXRoaXMuc3RhY2tUb3AuYmxvY2tlZDspdGhpcy5leGVjdXRlKCk7aWYoIXRoaXMuc3RhY2subGVuZ3RoKWZvcig7MDx0aGlzLnVuYmxvY2tDYWxsYmFja3MubGVuZ3RoOyl7dmFyIHQ7aWYodGhpcy51bmJsb2NrQ2FsbGJhY2tzLnNoaWZ0KCkoKSxudWxsIT0odD10aGlzLnN0YWNrVG9wKSYmdC5ibG9ja2VkKXJldHVybn19LHdoZW5VbmJsb2NrZWQ6ZnVuY3Rpb24oZSx0KXt0aGlzLnN0YWNrLmxlbmd0aCYmdGhpcy5zdGFja1RvcC5ibG9ja2VkP3RoaXMudW5ibG9ja0NhbGxiYWNrcz10aGlzLnVuYmxvY2tDYWxsYmFja3MuY29uY2F0KGUpOih0fHxlKSgpfSxibG9ja2VkVmFsdWU6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnN0YWNrVG9wO3JldHVybiBlP2UuYmxvY2tlZFZhbHVlcyYmZS5ibG9ja2VkVmFsdWVzLmxlbmd0aD9lLmJsb2NrZWRWYWx1ZXMuc2hpZnQoKTooZi5pbXBvc3NpYmxlKCJTZWN0aW9uLmJsb2NrZWRWYWx1ZSIsImJsb2NrZWRWYWx1ZXMgaXMgbWlzc2luZyBvciBlbXB0eSIpLDApOihmLmltcG9zc2libGUoIlNlY3Rpb24uYmxvY2tlZFZhbHVlIiwic3RhY2sgaXMgZW1wdHkiKSwwKX19KX0pLGRlZmluZSgic3RhdGUiLFsianF1ZXJ5IiwidXRpbHMiLCJwYXNzYWdlcyIsImRhdGF0eXBlcy9jdXN0b21jb21tYW5kIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJtYXJrdXAiXSxmdW5jdGlvbihuLHksYix2LGUsdCl7dmFyIGksdyxDPWUudG9Tb3VyY2UsRT1lLmlzLGs9dC5sZXgsbz1PYmplY3QuYXNzaWduLGg9T2JqZWN0LmNyZWF0ZSxlPU9iamVjdC5kZWZpbmVQcm9wZXJ0eSxOPUFycmF5LmlzQXJyYXkscz1NYXRoLmltdWwsdD0oZShNYXAucHJvdG90eXBlLCJ0b0pTT04iLHt2YWx1ZTp2b2lkIDB9KSxlKFNldC5wcm90b3R5cGUsInRvSlNPTiIse3ZhbHVlOnZvaWQgMH0pLFsibG9jYWxTdG9yYWdlIiwic2Vzc2lvblN0b3JhZ2UiXS5tYXAoZnVuY3Rpb24oZSl7dHJ5e3JldHVybiEhd2luZG93W2VdJiYod2luZG93W2VdLnNldEl0ZW0oInRlc3QiLCIxIiksd2luZG93W2VdLnJlbW92ZUl0ZW0oInRlc3QiKSwhMCl9Y2F0Y2goZSl7cmV0dXJuITF9fSkpO2Z1bmN0aW9uIFMoZSx0KXt2YXIgbj0wPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWU/ZTpTdHJpbmcuZnJvbUNvZGVQb2ludChEYXRlLm5vdygpJTExMTQxMTIpLGU9MTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT10P3Q6MDtpLnNlZWRJdGVyPWUsaS5zZWVkPW47Zm9yKHZhciByLGE9MCxvPTIxNjYxMzYyNjE7YTxuLmxlbmd0aDthKz0xKXI9cyhuLmNoYXJDb2RlQXQoYSksMzQzMjkxODM1Myksb149cyhyPDwxNXxyPj4+MTcsNDYxODQ1OTA3KSxvPXMobz1vPDwxM3xvPj4+MTksNSkrMzg2NDI5MjE5NnwwO3JldHVybiBvXj1uLmxlbmd0aCxvPXMob149bz4+PjE2LDIyNDY4MjI1MDcpLG89cyhvXj1vPj4+MTMsMzI2NjQ4OTkwOSksbz0oKG9ePW8+Pj4xNik+Pj4wKSsxODMxNTY1ODEzKmUsZnVuY3Rpb24oKXtpLnNlZWRJdGVyKz0xO3ZhciBlPW8rPTE4MzE1NjU4MTMsZT1zKGVeZT4+PjE1LDF8ZSk7cmV0dXJuKCgoZV49ZStzKGVeZT4+PjcsNjF8ZSkpXmU+Pj4xNCk+Pj4wKS80Mjk0OTY3Mjk2fX1mdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuLHI9dC52YXJpYWJsZXMsYT1oKG51bGwpLG89ZS5sZW5ndGgtMTswPD1vOy0tbyl7Zm9yKHZhciBpLHMsYz1lW29dLGw9MCx1PVsibW9ja1Zpc2l0cyIsIm1vY2tUdXJucyIsInNlZWQiLCJzZWVkSXRlciJdO2w8dS5sZW5ndGg7bCsrKXt2YXIgcD11W2xdO2hhc093blByb3BlcnR5LmNhbGwoYyxwKSYmIWhhc093blByb3BlcnR5LmNhbGwodCxwKSYmKHRbcF09Y1twXSl9Zm9yKGkgaW4gYy5mb3JnZXRWaXNpdHMmJih0LmZvcmdldFZpc2l0cz1NYXRoLm1heCh0LmZvcmdldFZpc2l0c3x8MCxjLmZvcmdldFZpc2l0cykpLHZvaWQgMCE9PWMudHVybnMmJih0LnR1cm5zPSh0LnR1cm5zfHwwKStjLnR1cm5zKSx0LnBhc3RWaXNpdHN8fCh0LnBhc3RWaXNpdHM9W10pLG8hPT1lLmxlbmd0aC0xJiYodm9pZCAwIT09ZVtvKzFdLnZpc2l0cyYmQXJyYXkuaXNBcnJheSh0LnBhc3RWaXNpdHNbMF0pP3QucGFzdFZpc2l0c1swXTp0LnBhc3RWaXNpdHMpLnVuc2hpZnQoYy5wYXNzYWdlKSx2b2lkIDAhPT1jLnBhc3RWaXNpdHMmJnQucGFzdFZpc2l0cy51bnNoaWZ0KGMucGFzdFZpc2l0cyksdm9pZCAwIT09Yy52aXNpdHMmJnQucGFzdFZpc2l0cy51bnNoaWZ0KGMudmlzaXRzKSxjLnZhcmlhYmxlcylpZigiVHdpbmVTY3JpcHRfVHlwZURlZnMiPT09aSlmb3IodmFyIGQgaW4gcltpXXx8KHJbaV09aChudWxsKSksYy52YXJpYWJsZXNbaV0pcltpXVtkXXx8KHJbaV1bZF09Yy52YXJpYWJsZXNbaV1bZF0pO2Vsc2UgaS5zdGFydHNXaXRoKCJUd2luZVNjcmlwdF8iKXx8aSBpbiByfHwobnVsbD09PWMudmFyaWFibGVzW2ldJiYoYVtpXT0hMCksYVtpXSl8fChyW2ldPWMudmFyaWFibGVzW2ldLCEocz1jLnZhbHVlUmVmc1tpXSkpfHwidmlhImluIHN8fHQudmFsdWVSZWZzW2ldfHwodC52YWx1ZVJlZnNbaV09cyl9Zm9yKG4gaW4gdC52YWx1ZVJlZnMpe3ZhciBmPXQudmFsdWVSZWZzW25dO2YmJiJ2aWEiaW4gZiYmZGVsZXRlIHQudmFsdWVSZWZzW25dfX12YXIgYSxjPXtwYXNzYWdlOiIiLHZhcmlhYmxlczpoKG51bGwpLHZpc2l0czp2b2lkIDAsdHVybnM6dm9pZCAwLHNlZWQ6dm9pZCAwLHNlZWRJdGVyOnZvaWQgMCxtb2NrVmlzaXRzOnZvaWQgMCxtb2NrVHVybnM6dm9pZCAwLGZvcmdldFZpc2l0czp2b2lkIDAsY3JlYXRlOmZ1bmN0aW9uKGUpe3ZhciB0PWgoYyk7cmV0dXJuIHQucGFzc2FnZT1lfHwiIix0LnZhcmlhYmxlcz1oKG51bGwpLHQudmFsdWVSZWZzPWgobnVsbCksdH19LGw9e2ZvcndhcmQ6W10sYmFjazpbXSxsb2FkOltdLGJlZm9yZUZvcndhcmQ6W10sYmVmb3JlQmFjazpbXSxiZWZvcmVMb2FkOltdLGZvcmdldFVuZG9zOltdfSx1PVtdLHA9LTEsZD1jLmNyZWF0ZSgpLGY9IiI7ZnVuY3Rpb24gbSgpe2kuaGlzdG9yeT1pLnBhc3RWaXNpdHMuc2xpY2UoaS5mb3JnZXRWaXNpdHMpLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlLmNvbmNhdCh0KX0sW10pLGkubW9ja1Zpc2l0cyYmKGkuaGlzdG9yeT1pLm1vY2tWaXNpdHMuY29uY2F0KGkuaGlzdG9yeSkpfWZ1bmN0aW9uIGcoKXt2YXIgZT1jLmNyZWF0ZSgpO2UucGFzdFZpc2l0cz1bXSxvKGUudmFyaWFibGVzLHtUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJ0aGlzIHN0b3J5J3MgdmFyaWFibGVzIixUd2luZVNjcmlwdF9UeXBlRGVmczpoKG51bGwpLFR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU6e3R5cGU6Imdsb2JhbCIsbmFtZToidGhpcyBzdG9yeSdzIHZhcmlhYmxlcyJ9LFR3aW5lU2NyaXB0X0RlbGV0ZTpmdW5jdGlvbihlKXtkZWxldGUgdGhpc1tlXSxkLnZhcmlhYmxlc1tlXT1udWxsLGRlbGV0ZSBkLnZhbHVlUmVmc1tlXX0sVHdpbmVTY3JpcHRfU2V0OmZ1bmN0aW9uKGUsdCxuKXtpZih0aGlzW2VdPXQsZC52YXJpYWJsZXNbZV09dCxuKWQudmFsdWVSZWZzW2VdPW47ZWxzZSBpZigoTih0KXx8dCBpbnN0YW5jZW9mIE1hcHx8dCBpbnN0YW5jZW9mIFNldHx8InN0cmluZyI9PXR5cGVvZiB0KSYmIXkub3B0aW9ucy51bmNvbXByZXNzZWRTdHJ1Y3R1cmVzKWZvcih2YXIgcj1wOzA8PXI7LS1yKXt2YXIgYT11W3JdLnZhcmlhYmxlc1tlXTtpZih2b2lkIDAhPT1hKXthPWZ1bmN0aW9uIGUodCxuLHIpe3ZhciBhPSJpdCI9PT1yPyJpdHMiOnIrIidzIixvPSIiO2lmKE4obikmJk4odCkmJm4ubGVuZ3RoKXtmb3IodmFyIGk9bi5sZW5ndGg9PT10Lmxlbmd0aCxvPSIoYToiLHM9MDtzPG4ubGVuZ3RoO3MrPTEpe3ZhciBjLGwsdSxwPW5bc107RShwLHRbc10pPyhjPUMocCksbD0iIi5jb25jYXQoYSwiICIpLmNvbmNhdChzKzEsInRoIiksbys9KGMubGVuZ3RoPGwubGVuZ3RoP2M6bCkrIiwiKTooaT0hMSwtMTwoYz10LmluZGV4T2YocCkpPyhsPUMocCksdT0iIi5jb25jYXQoYSwiICIpLmNvbmNhdChjKzEsInRoIiksbys9KGwubGVuZ3RoPHUubGVuZ3RoP2w6dSkrIiwiKTpvKz1lKHRbc10scCwiIi5jb25jYXQoYSwiICIpLmNvbmNhdChzKzEsInRoIikpKyIsIil9bz1pP3I6by5zbGljZSgwLC0xKSsiKSJ9ZWxzZSBpZihuIGluc3RhbmNlb2YgTWFwJiZ0IGluc3RhbmNlb2YgTWFwJiZuLnNpemUpe3ZhciBkLGY9bi5zaXplPT09dC5zaXplLGg9KG89IihkbToiLF9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKG4uZW50cmllcygpKSk7dHJ5e2ZvcihoLnMoKTshKGQ9aC5uKCkpLmRvbmU7KXt2YXIgbSxnLHk9X3NsaWNlZFRvQXJyYXkoZC52YWx1ZSwyKSxiPXlbMF0sdj15WzFdO28rPSIiLmNvbmNhdChDKGIpLCIsIiksRSh2LHQuZ2V0KGIpKT8obT1DKHYpLGc9IiIuY29uY2F0KGEsIiAoIikuY29uY2F0KEMoYiksIikiKSxvKz0obS5sZW5ndGg8Zy5sZW5ndGg/bTpnKSsiLCIpOihmPSExLG8rPWUodC5nZXQoYiksdiwiIi5jb25jYXQoYSwiICgiKS5jb25jYXQoQyhiKSwiKSIpKSsiLCIpfX1jYXRjaChlKXtoLmUoZSl9ZmluYWxseXtoLmYoKX1vPWY/cjpvLnNsaWNlKDAsLTEpKyIpIn1lbHNlIGlmKG4gaW5zdGFuY2VvZiBTZXQmJnQgaW5zdGFuY2VvZiBTZXQmJm4uc2l6ZSl7dmFyIHcsaz1uZXcgU2V0LFM9bmV3IFNldCxUPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKHQpO3RyeXtmb3IoVC5zKCk7ISh3PVQubigpKS5kb25lOyl7dmFyIF89dy52YWx1ZTtuLmhhcyhfKXx8ay5hZGQoXyl9fWNhdGNoKGUpe1QuZShlKX1maW5hbGx5e1QuZigpfXZhciB4LE89X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIobik7dHJ5e2ZvcihPLnMoKTshKHg9Ty5uKCkpLmRvbmU7KXt2YXIgQT14LnZhbHVlO3QuaGFzKEEpfHxTLmFkZChBKX19Y2F0Y2goZSl7Ty5lKGUpfWZpbmFsbHl7Ty5mKCl9ay5zaXplfHxTLnNpemV8fChvPXIpLG89ay5zaXplK1Muc2l6ZT5uLnNpemU/QyhuKTpyKyhTLnNpemU/IisiK0MoUyk6IiIpKyhrLnNpemU/Ii0iK0Moayk6IiIpfWVsc2Uic3RyaW5nIj09dHlwZW9mIG4mJiJzdHJpbmciPT10eXBlb2YgdCYmbiYmKG4uc3RhcnRzV2l0aCh0KT9vPXIrIisiK0Mobi5zbGljZSh0Lmxlbmd0aCkpOm4uZW5kc1dpdGgodCkmJihvPUMobi5zbGljZSgwLG4ubGVuZ3RoLXQubGVuZ3RoKSkrIisiK3IpKTtyZXR1cm4gbz8iaXQiPT09cj97dmlhOm99Om86Iml0Ij09PXI/dm9pZCAwOkMobil9KGEsdCwiaXQiKTthJiYoIml0Ij09PWEudmlhP2RlbGV0ZSBkLnZhcmlhYmxlc1tlXTpkLnZhbHVlUmVmc1tlXT1hKTticmVha319fSxUd2luZVNjcmlwdF9HZXRQcm9wZXJ0eTpmdW5jdGlvbihlKXtyZXR1cm4gdGhpc1tlXX0sVHdpbmVTY3JpcHRfRGVmaW5lVHlwZTpmdW5jdGlvbihlLHQpe3RoaXMuVHdpbmVTY3JpcHRfVHlwZURlZnNbZV09dCxoYXNPd25Qcm9wZXJ0eS5jYWxsKGQudmFyaWFibGVzLCJUd2luZVNjcmlwdF9UeXBlRGVmcyIpfHwoZC52YXJpYWJsZXMuVHdpbmVTY3JpcHRfVHlwZURlZnM9aChudWxsKSksZC52YXJpYWJsZXMuVHdpbmVTY3JpcHRfVHlwZURlZnNbZV09dH19KSxyKHUuc2xpY2UoMCxwKzEpLGUpLGk9ZSxtKCksdz1TKGUuc2VlZCxlLnNlZWRJdGVyKX1mdW5jdGlvbiBUKGUpe2Q9Yy5jcmVhdGUoZSk7ZT1hLnNlcmlhbGlzZSghMCksZj1lLnBhc3QsZT1lLnBhc3RBbmRQcmVzZW50O2lmKGEuaGFzU2Vzc2lvblN0b3JhZ2UmJiJzdHJpbmciPT10eXBlb2YgZSl0cnl7c2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbSgiU2F2ZWQgU2Vzc2lvbiIsZSl9Y2F0Y2goZSl7fX1mdW5jdGlvbiBfKGUsdCxuLHIpe2Zvcih2YXIgYSBpbiByKWlmKGhhc093blByb3BlcnR5LmNhbGwocixhKSYmIWEuc3RhcnRzV2l0aCgiVHdpbmVTY3JpcHRfIikpaWYoIm9iamVjdCI9PT1fdHlwZW9mKHJbYV0pKWlmKGhhc093blByb3BlcnR5LmNhbGwoclthXSwiYXQiKSl7bi52YWx1ZVJlZnNbYV09clthXTt2YXIgbz1yW2FdLGk9by5hdCxzPW8uZnJvbSxjPW8udG8sbD1vLmhhc2gsdT1vLnNlZWQscD1vLnNlZWRJdGVyLG89by5ibG9ja2VkVmFsdWVzO2lmKCFiLmhhcyhpKSl0aHJvdyBFcnJvcignVGhlIGRhdGEgcmVmZXJzIHRvIGEgcGFzc2FnZSBuYW1lZCBgIicuY29uY2F0KG4ucGFzc2FnZSwiXCJgLCBidXQgaXQgaXNuJ3QgaW4gdGhpcyBzdG9yeS4iKSk7dmFyIGQ9Yi5nZXQoaSkuZ2V0KCJzb3VyY2UiKSxmPWQuc2xpY2UocyxjKTtpZih2b2lkIDAhPT1sKWZvcih2YXIgaD0wLG09Yy1zO3kuaGFzaChmKS50b1N0cmluZygxNikhPT1sOyl7aWYoaCttPj1kLmxlbmd0aCl0aHJvdyBFcnJvcigiVGhlIHZhbHVlIChvciB0eXBlKSBvZiB0aGUgdmFyaWFibGUgYCQiLmNvbmNhdChhLCJgIGNvdWxkbid0IGJlIGZvdW5kIGluIHRoZSBwYXNzYWdlIGBcIiIpLmNvbmNhdChpLCciYC4nKSk7KGgrPTEpPT09cyYmKGgrPTEpLGY9ZC5zbGljZShoLGgrbSl9Yz1rKGYsIiIsIm1hY3JvIik7dm9pZCAwIT09dSYmdm9pZCAwIT09cCYmKHc9Uyh1LHApKSx2b2lkIDAhPT1vJiYoZS5zdGFja1RvcC5ibG9ja2VkVmFsdWVzPW8sYy5mb3JFYWNoKGZ1bmN0aW9uIGUodCl7dmFyIG47InN0cmluZyIhPT10LnR5cGUmJiJob29rIiE9PXQudHlwZSYmdC5jaGlsZHJlbi5ldmVyeShlKSwibWFjcm8iIT09dC50eXBlfHwicHJvbXB0IiE9PShuPXkuaW5zZW5zaXRpdmVOYW1lKHQubmFtZSkpJiYiY29uZmlybSIhPT1ufHwodC5ibG9ja2VkVmFsdWU9ITApfSkpLHJbYV09ZS5ldmFsKGMpfWVsc2UgaWYoaGFzT3duUHJvcGVydHkuY2FsbChyW2FdLCJ2aWEiKSl7Zm9yKHZhciBnPXQubGVuZ3RoLTE7MDw9ZzstLWcpaWYoaGFzT3duUHJvcGVydHkuY2FsbCh0W2ddLnZhcmlhYmxlcyxhKSl7ZS5JZGVudGlmaWVycy5pdD10W2ddLnZhcmlhYmxlc1thXTticmVha31yW2FdPWUuZXZhbChrKHJbYV0udmlhLCIiLCJtYWNybyIpKSxlLklkZW50aWZpZXJzLml0PTB9ZWxzZSBoYXNPd25Qcm9wZXJ0eS5jYWxsKHJbYV0sImNoYW5nZXIiKSYmKHJbYV0uY2hhbmdlcj1lLmV2YWwoayhyW2FdLmNoYW5nZXIsIiIsIm1hY3JvIikpLHJbYV0uaG9vaz1lLmV2YWwoayhyW2FdLmhvb2ssIiIsIm1hY3JvIikpLF8oZSx0LG4sclthXS52YXJpYWJsZXMpLHJbYV09di5jcmVhdGUoclthXSkpO2Vsc2UgclthXT1lLmV2YWwoayhyW2FdLCIiLCJtYWNybyIpKTtlbHNlIlR3aW5lU2NyaXB0X01vY2tWaXNpdHMiPT09YSYmKG4ubW9ja1Zpc2l0cz1yW2FdKX1yZXR1cm4gZygpLGQuc2VlZD1pLnNlZWQsZC5zZWVkSXRlcj0wLChhPXtnZXQgcGFzc2FnZSgpe3JldHVybiBkLnBhc3NhZ2V9LGdldCB2YXJpYWJsZXMoKXtyZXR1cm4gaS52YXJpYWJsZXN9LGdldCBwYXN0TGVuZ3RoKCl7cmV0dXJuIHB9LGdldCB0dXJucygpe3JldHVybiBwKzErKGkudHVybnN8fDApKyhpLm1vY2tUdXJuc3x8MCl9LGdldCBmdXR1cmVMZW5ndGgoKXtyZXR1cm4gdS5sZW5ndGgtMS1wfSxnZXQgbW9ja1Zpc2l0cygpe3JldHVybiBpLm1vY2tWaXNpdHN8fFtdfSxzZXQgbW9ja1Zpc2l0cyhlKXtpLm1vY2tWaXNpdHM9ZSxkLm1vY2tWaXNpdHM9ZSxtKCl9LGdldCBtb2NrVHVybnMoKXtyZXR1cm4gaS5tb2NrVHVybnN8fDB9LHNldCBtb2NrVHVybnMoZSl7aS5tb2NrVHVybnM9ZSxkLm1vY2tUdXJucz1lfSxoaXN0b3J5OmZ1bmN0aW9uKCl7cmV0dXJuIGkuaGlzdG9yeX0sZm9yZ2V0VW5kb3M6ZnVuY3Rpb24oZSl7ZTwwJiYoZT11Lmxlbmd0aCtlKTt2YXIgdCxlPXUuc3BsaWNlKDAsTWF0aC5taW4odS5sZW5ndGgtMSxlKSk7ZS5sZW5ndGgmJihwPXUubGVuZ3RoLTEsdD11WzBdLHIoZSx0KSx0LnBhc3RWaXNpdHMucHVzaChlW2UubGVuZ3RoLTFdLnBhc3NhZ2UpLHQudHVybnM9KHQudHVybnN8fDApK2UubGVuZ3RoLGkudHVybnM9KGkudHVybnN8fDApK2UubGVuZ3RoLHQuZm9yZ2V0VmlzaXRzJiYodC5wYXN0VmlzaXRzPXQucGFzdFZpc2l0cy5zbGljZSh0LmZvcmdldFZpc2l0cy10LnR1cm5zKSx0LmZvcmdldFZpc2l0cy09dC50dXJucyksZj0iIiwwPT09cCYmbigidHctbGlua1t1bmRvXSwgdHctaWNvblthbHQ9J1VuZG8nXSIseS5zdG9yeUVsZW1lbnQpLmVhY2goZnVuY3Rpb24oZSx0KXsobih0KS5jbG9zZXN0KCJ0dy1leHByZXNzaW9uLCB0dy1ob29rIikuZGF0YSgiZm9yZ2V0VW5kb3NFdmVudCIpfHxPYmplY3QpKHQpfSksbC5mb3JnZXRVbmRvcy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKCl9KSl9LGZvcmdldFZpc2l0czpmdW5jdGlvbihlKXsoZT1lPDA/dS5sZW5ndGgrZTplKT5wK2kudHVybnMmJihlPXAraS50dXJucyksZC5mb3JnZXRWaXNpdHM9aS5mb3JnZXRWaXNpdHM9TWF0aC5tYXgoaS5mb3JnZXRWaXNpdHN8fDAsZSksbSgpfSxwYXNzYWdlTmFtZVZpc2l0ZWQ6ZnVuY3Rpb24oZSl7dmFyIHQ9MDtpZighYi5nZXQoZSkpcmV0dXJuIDA7Zm9yKHZhciBuPTA7bjxpLmhpc3RvcnkubGVuZ3RoO24rKyl0Kz0rKGU9PT1pLmhpc3Rvcnlbbl0pO3JldHVybiB0fSxnZXQgdGltZWxpbmUoKXtyZXR1cm4gdX0scGxheTpmdW5jdGlvbih0KXt2YXIgZTtkfHx5LmltcG9zc2libGUoIlN0YXRlLnBsYXkiLCJwcmVzZW50IGlzIHVuZGVmaW5lZCEiKSxsLmJlZm9yZUZvcndhcmQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZSgpfSksZC5wYXNzYWdlJiYoKG51bGwhPShlPWQudmlzaXRzKSYmZS5sZW5ndGgmJkFycmF5LmlzQXJyYXkoaS5wYXN0VmlzaXRzW2kucGFzdFZpc2l0cy5sZW5ndGgtMV0pP2kucGFzdFZpc2l0c1tpLnBhc3RWaXNpdHMubGVuZ3RoLTFdOmkucGFzdFZpc2l0cykucHVzaChkLnBhc3NhZ2UpLGkuaGlzdG9yeS5wdXNoKGQucGFzc2FnZSkpLGQucGFzc2FnZT10LHU9dS5zbGljZSgwLHArMSkuY29uY2F0KGQpLHArPTEsVCh0KSxsLmZvcndhcmQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZSh0KX0pfSxyZWRpcmVjdDpmdW5jdGlvbihlKXt2YXIgdDtkfHx5LmltcG9zc2libGUoIlN0YXRlLnJlZGlyZWN0IiwicHJlc2VudCBpcyB1bmRlZmluZWQhIiksZC5wYXNzYWdlJiYobnVsbCE9KHQ9ZC52aXNpdHMpJiZ0Lmxlbmd0aCYmQXJyYXkuaXNBcnJheShpLnBhc3RWaXNpdHNbaS5wYXN0VmlzaXRzLmxlbmd0aC0xXSk/aS5wYXN0VmlzaXRzW2kucGFzdFZpc2l0cy5sZW5ndGgtMV0ucHVzaChkLnBhc3NhZ2UpOmkucGFzdFZpc2l0cy5wdXNoKFtkLnBhc3NhZ2VdKSxpLmhpc3RvcnkucHVzaChkLnBhc3NhZ2UpKSxkLnZpc2l0cz0oZC52aXNpdHN8fFtdKS5jb25jYXQoZSksZC5wYXNzYWdlPWV9LHJld2luZDpmdW5jdGlvbihlKXtmb3IodmFyIHQ9dm9pZCAwIT09ZT9lOjEsbj0hMTswPHQmJjA8cDt0LS0pbj0hMCwtLXA7cmV0dXJuIG4mJihsLmJlZm9yZUJhY2suZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZSgpfSksZj0iIixUKHVbcF0ucGFzc2FnZSksZygpLGwuYmFjay5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKCl9KSksbn0sZmFzdEZvcndhcmQ6ZnVuY3Rpb24oZSl7dmFyIHQ9MSxuPSExO2ZvcigibnVtYmVyIj09dHlwZW9mIGUmJih0PWUpOzA8dCYmMDx1Lmxlbmd0aDt0LS0pbj0hMCxwKz0xO3JldHVybiBuJiYobC5iZWZvcmVGb3J3YXJkLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUoKX0pLFQodVtwXS5wYXNzYWdlKSxnKCksbC5mb3J3YXJkLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUodVtwXS5wYXNzYWdlLCJmYXN0Rm9yd2FyZCIpfSkpLG59LG9uOmZ1bmN0aW9uKGUsdCl7aWYoZSBpbiBsKXJldHVybiJmdW5jdGlvbiIhPXR5cGVvZiB0fHxsW2VdLmluY2x1ZGVzKHQpfHxsW2VdLnB1c2godCksYTt5LmltcG9zc2libGUoIlN0YXRlLm9uIiwiaW52YWxpZCBldmVudCBuYW1lIil9LHJlc2V0OmZ1bmN0aW9uKCl7bC5iZWZvcmVMb2FkLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUoKX0pLHU9W10scD0tMSxnKCksKGQ9Yy5jcmVhdGUoKSkuc2VlZD1pLnNlZWQsZC5zZWVkSXRlcj0wLGY9IiIsdz1TKCksbC5sb2FkLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUodSl9KX0saGFzU3RvcmFnZTp0WzBdLGhhc1Nlc3Npb25TdG9yYWdlOnRbMV0sc2V0U2VlZDpmdW5jdGlvbihlKXt3PVMoZSksZC5zZWVkPWkuc2VlZCxkLnNlZWRJdGVyPTB9LGdldCBzZWVkKCl7cmV0dXJuIGkuc2VlZH0sZ2V0IHNlZWRJdGVyKCl7cmV0dXJuIGkuc2VlZEl0ZXJ9LHJhbmRvbTpmdW5jdGlvbigpe3ZhciBlPXcoKTtyZXR1cm4gZC5zZWVkSXRlcj1pLnNlZWRJdGVyLGV9LHNodWZmbGVkOmZ1bmN0aW9uKCl7Zm9yKHZhciBhPXRoaXMsZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3ZhciByPXQucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1hLnJhbmRvbSgpKihuKzEpfDA7cmV0dXJuIHI9PT1uP2UucHVzaCh0KTooZS5wdXNoKGVbcl0pLGVbcl09dCksZX0sW10pO3JldHVybiBkLnNlZWRJdGVyPWkuc2VlZEl0ZXIscn19KS5zZXJpYWxpc2U9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gbyhlLHQpe2lmKCJUd2luZVNjcmlwdF9UeXBlRGVmcyI9PT10KXt2YXIgbixyPXt9O2ZvcihuIGluIGVbdF0pcltuXT1DKGVbdF1bbl0pO3JldHVybiByfXZhciBhO3JldHVybiBudWxsPT09ZVt0XT9udWxsOmVbdF0mJmhhc093blByb3BlcnR5LmNhbGwoZVt0XSwiVHdpbmVTY3JpcHRfQ3VzdG9tQ29tbWFuZCIpPyhhPWVbdF0uVHdpbmVTY3JpcHRfQ3VzdG9tQ29tbWFuZCgpLHtjaGFuZ2VyOkMoYS5jaGFuZ2VyKSx0b1NvdXJjZTphLnRvU291cmNlLGhvb2s6QyhhLmhvb2spLHZhcmlhYmxlczpPYmplY3Qua2V5cyhhLnZhcmlhYmxlcykucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdF09byhhLnZhcmlhYmxlcyx0KSxlfSx7fSl9KTpDKGVbdF0pfWZ1bmN0aW9uIHQoZSx0KXtpZihjLmlzUHJvdG90eXBlT2YodCkmJnZvaWQgMD09PXQudmlzaXRzJiZ2b2lkIDA9PT10LnR1cm5zJiZ2b2lkIDA9PT10Lm1vY2tWaXNpdHMmJnZvaWQgMD09PXQuZm9yZ2V0VmlzaXRzJiZ2b2lkIDA9PT10LnBhc3RWaXNpdHMmJnZvaWQgMD09PXQubW9ja1R1cm5zJiZ2b2lkIDA9PT10LnNlZWQmJnZvaWQgMD09PXQuc2VlZEl0ZXImJk9iamVjdC5rZXlzKHQudmFyaWFibGVzKS5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gZS5zdGFydHNXaXRoKCJUd2luZVNjcmlwdF8iKX0pKXJldHVybiB0LnBhc3NhZ2U7aWYoIWMuaXNQcm90b3R5cGVPZih0aGlzKXx8InZhbHVlUmVmcyIhPT1lKXtpZihjLmlzUHJvdG90eXBlT2YodGhpcykmJiJ2YXJpYWJsZXMiPT09ZSl7dmFyIG4scj17fTtmb3IobiBpbiB0aGlzLnZhcmlhYmxlcyl0aGlzLnZhbHVlUmVmc1tuXT9yW25dPXRoaXMudmFsdWVSZWZzW25dOnJbbl09byh0aGlzLnZhcmlhYmxlcyxuKTtyZXR1cm4gcn1yZXR1cm4gdH19dmFyIGU9dS5zbGljZShmP2U/cC0xOnA6MCxwKzEpLG49ZS5zbGljZSgwLC0xKSxyPWY7dHJ5e3JldHVybntwYXN0OnI9bi5sZW5ndGg/KHI/ci5zbGljZSgwLC0xKSsiLCI6IlsiKStKU09OLnN0cmluZ2lmeShuLHQpLnNsaWNlKDEpOnIscGFzdEFuZFByZXNlbnQ6ci5zbGljZSgwLC0xKSsocj8iLCI6IlsiKStKU09OLnN0cmluZ2lmeShlLnNsaWNlKC0xKSx0KS5zbGljZSgxKX19Y2F0Y2goZSl7cmV0dXJue3Bhc3Q6ITEscGFzdEFuZFByZXNlbnQ6ITF9fX0sYS5kZXNlcmlhbGlzZT1mdW5jdGlvbihlLHQpe3ZhciBuO3RyeXtuPUpTT04ucGFyc2UodCl9Y2F0Y2goZSl7cmV0dXJuIEVycm9yKCJUaGUgc2F2ZSBkYXRhIGlzIHVuaW50ZWxsaWdpYmxlLiIpfWlmKCFOKG4pKXJldHVybiBFcnJvcigiVGhlIHNhdmUgZGF0YSBpc24ndCBhIHNlcXVlbmNlIG9mIHBhc3QgdHVybnMuIik7Zm9yKHZhciByPTA7cjxuLmxlbmd0aDtyKz0xKXt2YXIgYT1uW3JdO2lmKCJzdHJpbmciPT10eXBlb2YgYSlhPXtwYXNzYWdlOmEsdmFyaWFibGVzOnt9fTtlbHNlIGlmKCJvYmplY3QiIT09X3R5cGVvZihhKXx8IWhhc093blByb3BlcnR5LmNhbGwoYSwidmFyaWFibGVzIikpe24uc3BsaWNlKHItLSwxKTtjb250aW51ZX1pZihhLnZhbHVlUmVmcz1oKG51bGwpLGEudmFyaWFibGVzPW8oaChudWxsKSxhLnZhcmlhYmxlcyksIWIuaGFzVmFsaWQoYS5wYXNzYWdlKSlyZXR1cm4gRXJyb3IoJ1RoZSBkYXRhIHJlZmVycyB0byBhIHBhc3NhZ2UgbmFtZWQgYCInLmNvbmNhdChhLnBhc3NhZ2UsIlwiYCwgYnV0IGl0IGlzbid0IGluIHRoaXMgc3RvcnkuIikpO2lmKGhhc093blByb3BlcnR5LmNhbGwoYS52YXJpYWJsZXMsIlR3aW5lU2NyaXB0X1R5cGVEZWZzIikpdHJ5e18oZSxuLnNsaWNlKDAsciksYSxhLnZhcmlhYmxlcy5Ud2luZVNjcmlwdF9UeXBlRGVmcyl9Y2F0Y2goZSl7cmV0dXJuIEVycm9yKCJUaGUgdmFyaWFibGUgdHlwZXMgb24gdHVybiAiLmNvbmNhdChyKzEsIiBjb3VsZG4ndCBiZSByZWNvbnN0cnVjdGVkLiIpLmNvbmNhdChlLm1lc3NhZ2U/IiAoIi5jb25jYXQoZS5tZXNzYWdlLCIpIik6IiIpKX10cnl7XyhlLG4uc2xpY2UoMCxyKSxhLGEudmFyaWFibGVzKX1jYXRjaChlKXtyZXR1cm4gRXJyb3IoIlRoZSB2YXJpYWJsZXMgb24gdHVybiAiLmNvbmNhdChyKzEsIiBjb3VsZG4ndCBiZSByZWNvbnN0cnVjdGVkLiIpLmNvbmNhdChlLm1lc3NhZ2U/IiAoIi5jb25jYXQoZS5tZXNzYWdlLCIpIik6IiIpKX1uW3JdPW8oaChjKSxhKX1yZXR1cm4gcD0odT1uKS5sZW5ndGgtMSxsLmxvYWQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZSh1KX0pLGY9IiIsZygpLFQodVtwXS5wYXNzYWdlKSwhMH0sT2JqZWN0LnNlYWwoYyksT2JqZWN0LmZyZWV6ZShhKX0pLGRlZmluZSgidXRpbHMiLFsianF1ZXJ5IiwibWFya3VwIiwidXRpbHMvcG9seWZpbGxzIl0sZnVuY3Rpb24oZCl7dmFyIHI9U3RyaW5nLmZyb21DaGFyQ29kZSxuPSJhdWRpbyxibG9ja3F1b3RlLGNhbnZhcyxkaXYsaDEsaDIsaDMsaDQsaDUsaHIsb2wscCxwcmUsdGFibGUsdWwsdmlkZW8sdHctYWxpZ24sdHctc3RvcnksdHctcGFzc2FnZSx0dy1zaWRlYmFyLHR3LWNvbHVtbnMsdHctY29sdW1uLHR3LW1ldGVyIi5zcGxpdCgiLCIpLGE9ImEsYixpLGVtLHN0cm9uZyxzdXAsc3ViLGFiYnIsYWNyb255bSxzLHN0cmlrZSxkZWwsYmlnLHNtYWxsLHNjcmlwdCxpbWcsYnV0dG9uLGlucHV0LHR3LWxpbmssdHctYnJva2VuLWxpbmssdHctdmVyYmF0aW0sdHctY29sbGFwc2VkLHR3LWVycm9yLHR3LWNvbG91cix0dy1pY29uIi5zcGxpdCgiLCIpLGY9WyJhdWRpbyJdLGU9X3NsaWNlZFRvQXJyYXkoW2Z1bmN0aW9uKGUpe3JldHVybiByKGUpIT09cihlKS50b0xvd2VyQ2FzZSgpfSxmdW5jdGlvbihlKXtyZXR1cm4gcihlKSE9PXIoZSkudG9VcHBlckNhc2UoKX0sZnVuY3Rpb24oZSl7cmV0dXJuIHIoZSkudG9Mb3dlckNhc2UoKSE9PXIoZSkudG9VcHBlckNhc2UoKX1dLm1hcChmdW5jdGlvbihlKXtyZXR1cm4iWyIrQXJyYXkuZnJvbShBcnJheSg1NzM0MykpLm1hcChmdW5jdGlvbihlLHQpe3JldHVybiB0fSkuZmlsdGVyKGUpLm1hcChmdW5jdGlvbihlLHQsbil7cmV0dXJuIGU9PT1uW3QtMV0rMSYmZT09PW5bdCsxXS0xPyItIjpyKGUpfSkuam9pbigiIikucmVwbGFjZSgvLSsvZywiLSIpKyJdIn0pLDMpLHQ9ZVswXSxvPWVbMV0sZT1lWzJdO2Z1bmN0aW9uIHMoZSl7cmV0dXJuImluc3RhbnQiPT09ZT8wOjgwMH12YXIgaSxjLGw9W10sdT17fSxwPTAsaD17fSxtPTAsZz17fTtmdW5jdGlvbiB5KG4scixlLGEsbyl7dmFyIGk9bnVsbCxzPTAsYz1yK2U7ZnVuY3Rpb24gbChlKXt2YXIgdDsxJm5bMF0uY29tcGFyZURvY3VtZW50UG9zaXRpb24oZG9jdW1lbnQpJiYoYz0wKSxpJiYoYy09dD1lLWkpLGk9ZSwwPGEmJjA8cCttJiZuLmRhdGEoImV4cGVkaXRlQW5pbSIpKGEpLGM8PXImJihzKz10fHwwLCJwYXVzZWQiPT09bi5jc3MoImFuaW1hdGlvbi1wbGF5LXN0YXRlIikpJiZuLmNzcyh7dmlzaWJpbGl0eToiIiwiYW5pbWF0aW9uLXBsYXktc3RhdGUiOiJydW5uaW5nIn0pLGM8PTA/KG4ucmVtb3ZlRGF0YSgiZXhwZWRpdGVBbmltIiksbygpKTpyZXF1ZXN0QW5pbWF0aW9uRnJhbWUobCl9bi5kYXRhKCJleHBlZGl0ZUFuaW0iLGZ1bmN0aW9uKGUpe3ZhciB0O2MtPWU9dm9pZCAwPT09ZT9zOmUsInJ1bm5pbmciPT09bi5jc3MoImFuaW1hdGlvbi1wbGF5LXN0YXRlIikmJm4uY3NzKCJhbmltYXRpb24tZGVsYXkiLCgoIm1zIj09PSh0PSh0PW4uY3NzKCJhbmltYXRpb24tZGVsYXkiKSkudG9Mb3dlckNhc2UoKSkuc2xpY2UoLTIpPyt0LnNsaWNlKDAsLTIpfHwwOiJzIj09PXQuc2xpY2UoLTEpJiYxZTMqK3Quc2xpY2UoMCwtMSl8fDApfHwwKS1lKyJtcyIpfSksYz9yZXF1ZXN0QW5pbWF0aW9uRnJhbWUobCk6bCgpfWQoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KS5vbigia2V5ZG93biBrZXl1cCBtb3VzZWRvd24gbW91c2V1cCIsZnVuY3Rpb24oZSl7dmFyIHQ9ZS5rZXksbj1lLmJ1dHRvbixlPWUudHlwZS5pbmNsdWRlcygiZG93biIpLHI9dD91Omgsbj10JiZ2Lmluc2Vuc2l0aXZlTmFtZSh0KXx8bjtyW25dJiYhZT90P3A9TWF0aC5tYXgocC0xLDApOm09TWF0aC5tYXgobS0xLDApOiFyW25dJiZlJiYodD9wKz0xOm0rPTEpLHJbbl09ZX0pLm9uKCJtb3VzZW1vdmUiLGZ1bmN0aW9uKGUpe3ZhciB0PWUucGFnZVgsZT1lLnBhZ2VZO2cueD10LGcueT1lfSk7dmFyIGI9Ly18Xy9nLHY9e2hhc2g6ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTksbj1lLmxlbmd0aDswPG47KS0tbix0PU1hdGguaW11bCh0XmUuY2hhckNvZGVBdChuKSxNYXRoLnBvdyg5LDkpKTtyZXR1cm4odF50Pj4+OSk+Pj4wfSxwZXJtdXRhdGlvbnM6ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtmb3IodmFyIHIsYSxvPXQubGVuZ3RoLGk9W1tdLmNvbmNhdCh0KV0scz1BcnJheShvKS5maWxsKDApLGM9MTtjPG87KXNbY108Yz8ocj1jJTImJnNbY10sYT10W2NdLHRbY109dFtyXSx0W3JdPWEsKytzW2NdLGM9MSxpLnB1c2goW10uY29uY2F0KHQpKSk6KHNbY109MCwrK2MpO3JldHVybiBpfSxudGg6ZnVuY3Rpb24oZSl7dmFyIHQ9K2UrIiI7cmV0dXJuIGUrKCIxIiE9PXRbdC5sZW5ndGgtMV18fDEhPT10Lmxlbmd0aCYmIjEiPT09dFt0Lmxlbmd0aC0yXT8iMiIhPT10W3QubGVuZ3RoLTFdfHwxIT09dC5sZW5ndGgmJiIxIj09PXRbdC5sZW5ndGgtMl0/IjMiIT09dFt0Lmxlbmd0aC0xXXx8MSE9PXQubGVuZ3RoJiYiMSI9PT10W3QubGVuZ3RoLTJdPyJ0aCI6InJkIjoibmQiOiJzdCIpfSxwbHVyYWw6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlKyIgIisoMSE9PU1hdGguYWJzKGUpP258fHQrInMiOnQpfSxhbmRMaXN0OmZ1bmN0aW9uKGUpe3JldHVybiBlLmxlbmd0aDw9MT9lWzBdOmUuc2xpY2UoMCwtMSkuam9pbigiLCAiKSsiIGFuZCAiK2VbZS5sZW5ndGgtMV19LHJlYWxXaGl0ZXNwYWNlOiJbIFxcblxcclxcZlxcdFxcdlxcdTAwYTBcXHUyMDAwLVxcdTIwMGFcXHUyMDI4XFx1MjAyOVxcdTIwMmZcXHUyMDVmXFx1MzAwMF0iLGFueVJlYWxMZXR0ZXI6IltcXGRBLVphLXpcXHUwMGMwLVxcdTAwZGVcXHUwMGRmLVxcdTAwZmZcXHUwMTUwXFx1MDE3MFxcdTAxNTFcXHUwMTcxXFx1RDgwMC1cXHVERkZGXSIsYW55VXBwZXJjYXNlOnQsYW55TG93ZXJjYXNlOm8sYW55Q2FzZWRMZXR0ZXI6ZSxhbnlOZXdsaW5lOiIoPzpcXG58XFxyfFxcclxcbikiLHVuZXNjYXBlOmZ1bmN0aW9uKGUpe3JldHVybiBlLnJlcGxhY2UoLyYoPzphbXB8bHR8Z3R8cXVvdHxuYnNwfHp3bmp8IzM5fCM5Nik7L2csZnVuY3Rpb24oZSl7cmV0dXJueyImYW1wOyI6IiYiLCImZ3Q7IjoiPiIsIiZsdDsiOiI8IiwiJnF1b3Q7IjonIicsIiYjMzk7IjoiJyIsIiZuYnNwOyI6U3RyaW5nLmZyb21DaGFyQ29kZSgxNjApLCImenduajsiOlN0cmluZy5mcm9tQ2hhckNvZGUoODIwNCl9W2VdfSl9LGVzY2FwZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5yZXBsYWNlKC9bJj48IiddL2csZnVuY3Rpb24oZSl7cmV0dXJueyImIjoiJmFtcDsiLCI+IjoiJmd0OyIsIjwiOiImbHQ7IiwnIic6IiZxdW90OyIsIiciOiImIzM5OyJ9W2VdfSl9LGluc2Vuc2l0aXZlTmFtZTpmdW5jdGlvbihlKXtyZXR1cm4oZSsiIikudG9Mb3dlckNhc2UoKS5yZXBsYWNlKGIsIiIpfSxhbGxLZXlzRG93bjpmdW5jdGlvbigpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3JldHVybiB0LmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiB1W2VdfSl9LHNvbWVLZXlzRG93bjpmdW5jdGlvbigpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3JldHVybiB0LnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIHVbZV19KX0sYnV0dG9uc0Rvd246ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm4gdC5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gaFtlXX0pfSxhbnlJbnB1dERvd246ZnVuY3Rpb24oKXtyZXR1cm4gMDxwK219LG1vdXNlQ29vcmRzOmcscGFyZW50Q29sb3VyczpmdW5jdGlvbihlKXtmb3IodmFyIHQsbj17Y29sb3VyOm51bGwsYmFja2dyb3VuZENvbG91cjpudWxsfSxyPS9eXHcrYVwoLis/LFxzKjBccypcKSR8XnRyYW5zcGFyZW50JC87ZS5sZW5ndGgmJmVbMF0hPT1kb2N1bWVudDtlPWUucGFyZW50KCkpaWYobi5iYWNrZ3JvdW5kQ29sb3VyfHwodD1lLmNzcygiYmFja2dyb3VuZC1jb2xvciIpKS5tYXRjaChyKXx8KG4uYmFja2dyb3VuZENvbG91cj10KSxuLmNvbG91cnx8KHQ9ZS5jc3MoImNvbG9yIikpLm1hdGNoKHIpfHwobi5jb2xvdXI9dCksbi5jb2xvdXImJm4uYmFja2dyb3VuZENvbG91cilyZXR1cm4gbjtyZXR1cm57Y29sb3VyOiIjZmZmIixiYWNrZ3JvdW5kQ29sb3VyOiIjMDAwIn19LGNoaWxkcmVuUHJvYmFibHlJbmxpbmU6ZnVuY3Rpb24oZSl7dmFyIHQ9W107cmV0dXJuW10uZXZlcnkuY2FsbChlLmZpbmRBbmRGaWx0ZXIoIioiKSxmdW5jdGlvbihlKXtpZighKGUuaGlkZGVufHwvbm9uZXxpbmxpbmUvLnRlc3QoZS5zdHlsZS5kaXNwbGF5KXx8L2Rpc3BsYXk6IChub25lfGlubGluZSkvLnRlc3QoZS5nZXRBdHRyaWJ1dGUoInN0eWxlIikpKSl7aWYobi5pbmNsdWRlcyhlLnRhZ05hbWUudG9Mb3dlckNhc2UoKSl8fC9kaXNwbGF5OiAoPyFub25lfGlubGluZXxpbmhlcml0fHVuc2V0KS8udGVzdChlLmdldEF0dHJpYnV0ZSgic3R5bGUiKSkpcmV0dXJuITE7YS5pbmNsdWRlcyhlLnRhZ05hbWUudG9Mb3dlckNhc2UoKSl8fHQucHVzaChlKX1yZXR1cm4hMH0pJiZ0LmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybi9pbmxpbmV8bm9uZS8udGVzdCh3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlKS5kaXNwbGF5KX0pfSx0cmFuc2l0aW9uT3V0OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj0zPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106MCxhPTQ8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzRdP2FyZ3VtZW50c1s0XTowLG89NTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbNV0/YXJndW1lbnRzWzVdOjAsaT02PGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1s2XT9hcmd1bWVudHNbNl06dm9pZCAwOzAhPT1lLmxlbmd0aCYmKG49bnx8cyh0KSwhKDE8ZS5sZW5ndGgpJiZ2LmNoaWxkcmVuUHJvYmFibHlJbmxpbmUoZSkmJlsidHctaG9vayIsInR3LXBhc3NhZ2UiLCJ0dy1zaWRlYmFyIiwidHctZXhwcmVzc2lvbiJdLmluY2x1ZGVzKGUudGFnKCkpfHwoZT1lLndyYXBBbGwoIjx0dy10cmFuc2l0aW9uLWNvbnRhaW5lcj4iKS5wYXJlbnQoKSksaSYmZS5jc3MoInRyYW5zZm9ybS1vcmlnaW4iLGkpLGUuYXR0cigiZGF0YS10OG4iLHQpLmFkZENsYXNzKCJ0cmFuc2l0aW9uLW91dCIpLmNzcyh7ImFuaW1hdGlvbi1kdXJhdGlvbiI6IiIuY29uY2F0KG4sIm1zIiksImFuaW1hdGlvbi1kZWxheSI6IiIuY29uY2F0KC1vLCJtcyIpLCJhbmltYXRpb24tcGxheS1zdGF0ZSI6InBhdXNlZCJ9KSxyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXt2LmNoaWxkcmVuUHJvYmFibHlJbmxpbmUoZSk/ZS5jc3MoImRpc3BsYXkiLCJpbmxpbmUiKTplLnBhcmVudCgpLmlzKCJ0dy1iYWNrZHJvcCx0dy1zdG9yeSIpfHxlWzBdLnNldEF0dHJpYnV0ZSgic3R5bGUiLGVbMF0uZ2V0QXR0cmlidXRlKCJzdHlsZSIpKyJkaXNwbGF5OmJsb2NrICFpbXBvcnRhbnQ7d2lkdGg6MTAwJSIpfSkseShlLG4sci1vLGEsZnVuY3Rpb24oKXtlLnJlbW92ZSgpfSkpfSx0cmFuc2l0aW9uSW46ZnVuY3Rpb24odSxlLHQpe3ZhciBwLG49Mzxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbM10/YXJndW1lbnRzWzNdOjAscj00PGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1s0XT9hcmd1bWVudHNbNF06MCxhPTU8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzVdP2FyZ3VtZW50c1s1XTowLG89Njxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbNl0/YXJndW1lbnRzWzZdOnZvaWQgMDswIT09dS5sZW5ndGgmJih0PXR8fHMoZSksKHA9MTx1Lmxlbmd0aHx8IXYuY2hpbGRyZW5Qcm9iYWJseUlubGluZSh1KXx8IVsidHctaG9vayIsInR3LXBhc3NhZ2UiLCJ0dy1zaWRlYmFyIiwidHctZXhwcmVzc2lvbiJdLmluY2x1ZGVzKHUudGFnKCkpKSYmKHU9dS53cmFwQWxsKCI8dHctdHJhbnNpdGlvbi1jb250YWluZXI+IikucGFyZW50KCkpLG8mJnUuY3NzKCJ0cmFuc2Zvcm0tb3JpZ2luIixvKSx1LmF0dHIoImRhdGEtdDhuIixlKS5hZGRDbGFzcygidHJhbnNpdGlvbi1pbiIpLmNzcyhfb2JqZWN0U3ByZWFkKHsiYW5pbWF0aW9uLWR1cmF0aW9uIjoiIi5jb25jYXQodCwibXMiKSwiYW5pbWF0aW9uLWRlbGF5IjoiIi5jb25jYXQoLWEsIm1zIil9LG4tYT97dmlzaWJpbGl0eToiaGlkZGVuIiwiYW5pbWF0aW9uLXBsYXktc3RhdGUiOiJwYXVzZWQifTp7fSkpLHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbigpe3YuY2hpbGRyZW5Qcm9iYWJseUlubGluZSh1KT91LmNzcygiZGlzcGxheSIsImlubGluZSIpOnUucGFyZW50KCkuaXMoInR3LWJhY2tkcm9wLHR3LXN0b3J5Iil8fHVbMF0uc2V0QXR0cmlidXRlKCJzdHlsZSIsdVswXS5nZXRBdHRyaWJ1dGUoInN0eWxlIikrImRpc3BsYXk6YmxvY2sgIWltcG9ydGFudDt3aWR0aDoxMDAlIil9KSx5KHUsdCxuLWEscixmdW5jdGlvbigpe3ZhciBlPTA9PT11LmZpbHRlcihmLmpvaW4oIiwiKSkubGVuZ3RoO2lmKHAmJmUpe3UuZmluZCgidHctdHJhbnNpdGlvbi1jb250YWluZXIsIC50cmFuc2l0aW9uLWluLCAudHJhbnNpdGlvbi1vdXQiKS5lYWNoKGZ1bmN0aW9uKGUsdCl7KCh0PWQodCkpLmRhdGEoImV4cGVkaXRlQW5pbSIpfHxPYmplY3QpKCl9KTtmb3IodmFyIHQ9W10sbj11LmZpbmQoIioiKSxyPTA7cjxuLmxlbmd0aDtyKz0xKXt2YXIgYT1uW3JdOzA9PT1hLnNjcm9sbFRvcCYmMD09PWEuc2Nyb2xsTGVmdHx8dC5wdXNoKFthLGEuc2Nyb2xsTGVmdCxhLnNjcm9sbFRvcF0pfWU9dS5maW5kKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpO3UuY29udGVudHMoKS51bndyYXAoKTtmb3IodmFyIG89MCxpPXQ7bzxpLmxlbmd0aDtvKyspe3ZhciBzPV9zbGljZWRUb0FycmF5KGlbb10sMyksYz1zWzBdLGw9c1sxXSxzPXNbMl07Yy5zY3JvbGxMZWZ0PWwsYy5zY3JvbGxUb3A9c31lLmxlbmd0aCYmZVswXS5mb2N1cygpfWVsc2UgdS5yZW1vdmVDbGFzcygidHJhbnNpdGlvbi1pbiIpLnJlbW92ZUF0dHIoImRhdGEtdDhuIil9KSl9LGRlYm91bmNlOmZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXszMDA8RGF0ZS5ub3coKS1sfHxzPD11Pyh1PW49MCxwPSFpLG8/KGUoYyksYz1bXSk6ZS5hcHBseSh2b2lkIDAsX3RvQ29uc3VtYWJsZUFycmF5KGMpKSxwPSExKTpuPXJlcXVlc3RBbmltYXRpb25GcmFtZSh0KX12YXIgbixyPTE8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxhPXIuYmF0Y2gsbz12b2lkIDAhPT1hJiZhLGE9ci5yZWN1cixpPXZvaWQgMCE9PWEmJmEsYT1yLm1heFdhaXQscz12b2lkIDA9PT1hPzEvMDphLGM9W10sbD0wLHU9MCxwPSExO3JldHVybiBmdW5jdGlvbigpe3ZhciBlO3B8fChlPURhdGUubm93KCksdSs9ZS1sLGw9ZSxvP2MucHVzaChhcmd1bWVudHMpOmM9YXJndW1lbnRzLG4mJmNhbmNlbEFuaW1hdGlvbkZyYW1lKG4pLG49cmVxdWVzdEFuaW1hdGlvbkZyYW1lKHQpKX19LGltcG9zc2libGU6ZnVuY3Rpb24oZSx0KXt3aW5kb3cuY29uc29sZSYmY29uc29sZS5lcnJvcihlKyIoKTogIit0KX0sb25TdGFydHVwOmZ1bmN0aW9uKGUpe2w/bC5wdXNoKGUpOmUoKX0sZ2V0IHN0b3J5RWxlbWVudCgpe3JldHVybiBpfSxkZXRhY2hTdG9yeUVsZW1lbnQ6ZnVuY3Rpb24oKXtkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY29udGFpbnMoaVswXSkmJihjPWkucGFyZW50KCksaS5kZXRhY2goKSl9LHJlYXR0YWNoU3RvcnlFbGVtZW50OmZ1bmN0aW9uKCl7ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNvbnRhaW5zKGlbMF0pfHwoY3x8ZChkb2N1bWVudC5ib2R5KSkuYXBwZW5kKGkucGFyZW50cygpLmxlbmd0aD9pLnBhcmVudHMoKS5sYXN0KCk6aSl9LG9wdGlvbnM6e3NwZWVkTXVsdGlwbGllcjoxfX07cmV0dXJuIGQoZnVuY3Rpb24oKXtpPWQoInR3LXN0b3J5IiksbC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKCl9KSxsPW51bGx9KSxPYmplY3QuZnJlZXplKHYpfSksZGVmaW5lKCJkYXRhdHlwZXMvYXNzaWdubWVudHJlcXVlc3QiLFsidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJkYXRhdHlwZXMvdHlwZWR2YXIiLCJkYXRhdHlwZXMvZGF0YXR5cGUiLCJpbnRlcm5hbHR5cGVzL3ZhcnJlZiIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGUseSxiLHYsdyl7dmFyIGs9ZS5vYmplY3ROYW1lLFM9ZS5tYXRjaGVzLHQ9ZS50b1NvdXJjZTtyZXR1cm4gT2JqZWN0LmZyZWV6ZSh7YXNzaWdubWVudFJlcXVlc3Q6ITAsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgVmFyaWFibGVUb1ZhbHVlIChhICd0bycgb3IgJ2ludG8nIGV4cHJlc3Npb24pIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhIFZhcmlhYmxlVG9WYWx1ZSAoYSAndG8nIG9yICdpbnRvJyBleHByZXNzaW9uKSIsVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4iaW50byI9PT10aGlzLm9wZXJhdG9yPyIiLmNvbmNhdCh0KHRoaXMuc3JjKSwiICIpLmNvbmNhdCh0aGlzLm9wZXJhdG9yLCIgIikuY29uY2F0KHQodGhpcy5kZXN0KSk6IiIuY29uY2F0KHQodGhpcy5kZXN0KSwiICIpLmNvbmNhdCh0aGlzLm9wZXJhdG9yLCIgIikuY29uY2F0KHQodGhpcy5zcmMpKX0sVHdpbmVTY3JpcHRfVW5zdG9yYWJsZTohMCxzZXQ6ZnVuY3Rpb24oKXt2YXIgZSx0PTA8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzBdJiZhcmd1bWVudHNbMF0sbj1bXSxyPWZ1bmN0aW9uIGUodCxuLHIpe3ZhciBhPSEoMjxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1yKXx8cixvPVtdLGk9biYmdi5pc1Byb3RvdHlwZU9mKG4pP24uZ2V0KCk6bjtpZih3LmNvbnRhaW5zRXJyb3IoaSkpcmV0dXJuIGk7aWYoQXJyYXkuaXNBcnJheShpKSYmQXJyYXkuaXNBcnJheSh0KSl7Zm9yKHZhciBzPTAsYz0wO3M8dC5sZW5ndGgmJmM8aS5sZW5ndGg7KXt2YXIgbD10W3NdLHU9aVtjXTtpZih5LmlzUHJvdG90eXBlT2YobCkmJmwuZGF0YXR5cGUucmVzdHx8Yi5pc1Byb3RvdHlwZU9mKGwpJiZsLnJlc3Qpe2Zvcih2YXIgcD1jO2M8aS5sZW5ndGgmJlMobCx1KTspdT1pW2MrPTFdO3kuaXNQcm90b3R5cGVPZihsKT9sLmRhdGF0eXBlPVtsLmRhdGF0eXBlXTpiLmlzUHJvdG90eXBlT2YobCkmJihsPWIuY3JlYXRlKCJhcnJheSIpKSxvPW8uY29uY2F0KGUobCx2LmlzUHJvdG90eXBlT2Yobik/di5jcmVhdGUobix7Zmlyc3Q6cCsxLGxhc3Q6YysxfSk6aS5zbGljZShwLGMpKSl9ZWxzZSBvPW8uY29uY2F0KGUobCx2LmlzUHJvdG90eXBlT2Yobik/di5jcmVhdGUobixjKzEpOnUpKSxjKz0xO3MrPTF9cmV0dXJuIHM8dC5sZW5ndGg/YSYmdy5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgdW5wYWNrIHRoaXMgYXJyYXkgYmVjYXVzZSBpdCBuZWVkcyAiLmNvbmNhdCh0Lmxlbmd0aC1zLCIgbW9yZSB2YWx1ZSIpLmNvbmNhdCgwPHQubGVuZ3RoLXM/InMiOiIiLCIuIikpOm99aWYodCBpbnN0YW5jZW9mIE1hcCYmaSBpbnN0YW5jZW9mIE1hcCl7dmFyIGQsZj1fY3JlYXRlRm9yT2ZJdGVyYXRvckhlbHBlcih0LmVudHJpZXMoKSk7dHJ5e2ZvcihmLnMoKTshKGQ9Zi5uKCkpLmRvbmU7KXt2YXIgaD1fc2xpY2VkVG9BcnJheShkLnZhbHVlLDIpLG09aFswXSxnPWhbMV07aWYoIWkuaGFzKG0pKXJldHVybiBhJiZ3LmNyZWF0ZSgib3BlcmF0aW9uIiwiSSBjYW4ndCB1bnBhY2sgdGhpcyBkYXRhbWFwIGJlY2F1c2UgaXQgbmVlZHMgYSAnIittKyInIGRhdGEgbmFtZS4iKTtvPW8uY29uY2F0KGUoZyx2LmlzUHJvdG90eXBlT2Yobik/di5jcmVhdGUobixtKTppLmdldChtKSkpfX1jYXRjaChlKXtmLmUoZSl9ZmluYWxseXtmLmYoKX1yZXR1cm4gb31pZih5LmlzUHJvdG90eXBlT2YodCkpe2lmKCJmdW5jdGlvbiI9PXR5cGVvZiB0LmRhdGF0eXBlLmRlc3RydWN0dXJlKXJldHVyblt7ZGVzdDp0LHZhbHVlOmksc3JjOm59XS5jb25jYXQodC5kYXRhdHlwZS5kZXN0cnVjdHVyZShpKSk7aWYoIVMoaSx0LmRhdGF0eXBlKSlyZXR1cm4gYSYmdy5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgcHV0ICIuY29uY2F0KGsoaSksIiBpbnRvICIpLmNvbmNhdCh0LnZhclJlZi5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpLCIgYmVjYXVzZSBpdCBkb2Vzbid0IG1hdGNoICIpLmNvbmNhdCh0LnZhclJlZi5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpLCIncyBkYXRhdHlwZSwgIikuY29uY2F0KGsodC5kYXRhdHlwZSksIi4iKSk7bz1vLmNvbmNhdChlKHQuZGF0YXR5cGUsaSkpfXJldHVybiB2LmlzUHJvdG90eXBlT2YodCl8fHkuaXNQcm90b3R5cGVPZih0KT9vLmNvbmNhdCh7ZGVzdDp0LHZhbHVlOmksc3JjOm59KToiZnVuY3Rpb24iPT10eXBlb2YgdC5kZXN0cnVjdHVyZT9vLmNvbmNhdCh0LmRlc3RydWN0dXJlKGkpKTpTKGksdCk/bzphJiZ3LmNyZWF0ZSgib3BlcmF0aW9uIiwiSSB0cmllZCB0byB1bnBhY2ssIGJ1dCAiK2sodCkrIiBpbiB0aGUgcGF0dGVybiBkaWRuJ3QgbWF0Y2ggIitrKGkpKyIuIil9KHRoaXMuZGVzdCx0aGlzLnNyYyk7aWYoZT13LmNvbnRhaW5zRXJyb3IocikpcmV0dXJuIGU7aWYoIXIubGVuZ3RoKXJldHVybiB3LmNyZWF0ZSgib3BlcmF0aW9uIiwiSSBjYW4ndCBzdG9yZSBhIG5ldyB2YWx1ZSBpbnNpZGUgIitrKHRoaXMuZGVzdCkrIiB0aGF0IGlzbid0IGluIGEgdmFyaWFibGUuIiwiWW91IG5lZWQgYSB2YXJpYWJsZSwgb3IgYSBkYXRhIHN0cnVjdHVyZSBjb250YWluaW5nIHZhcmlhYmxlcyBhdCBjZXJ0YWluIHBvc2l0aW9ucywgdG8gc3RvcmUgdGhlIHZhbHVlLiIpO3ZhciBhLG89X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIoci5yZXZlcnNlKCkpO3RyeXtmb3Ioby5zKCk7IShhPW8ubigpKS5kb25lOyl7dmFyIGk9YS52YWx1ZSxzPWkuZGVzdCxjPWkudmFsdWUsbD1pLnNyYztpZih5LmlzUHJvdG90eXBlT2Yocykpe2lmKGU9dy5jb250YWluc0Vycm9yKHMuZGVmaW5lVHlwZSgpKSlyZXR1cm4gZTtzPXMudmFyUmVmfWlmKGU9cy5zZXQoYyx0aGlzLnNyY1JlZiksdy5pc1Byb3RvdHlwZU9mKGUpKXJldHVybiBlO3QmJmwmJmwuZGVsZXRlKCksbi5zaGlmdChrKHMpKyIgaXMgbm93ICIrayhjKSl9fWNhdGNoKGUpe28uZShlKX1maW5hbGx5e28uZigpfXJldHVybiBuLmpvaW4oIjsgIil9LGNyZWF0ZTpmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gdy5jb250YWluc0Vycm9yKGUpP2U6dy5jb250YWluc0Vycm9yKHQpP3Q6T2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKHRoaXMpLHtkZXN0OmUsc3JjOnQsb3BlcmF0b3I6bixzcmNSZWY6cn0pfX0pfSksZGVmaW5lKCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLFsidXRpbHMiLCJ1dGlscy9vcGVyYXRpb251dGlscyIsImludGVybmFsdHlwZXMvY2hhbmdlZGVzY3JpcHRvciIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPWUucGx1cmFsLGE9ZS5pbXBvc3NpYmxlLG89dC5pcyxzPXQudG9Tb3VyY2UsYz17fSxsPXtUd2luZVNjcmlwdF9UeXBlSUQ6ImNoYW5nZXIiLFR3aW5lU2NyaXB0X1R5cGVOYW1lOiJhIGNoYW5nZXIiLFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuImBbQSAoIit0aGlzLm1hY3JvTmFtZSsiOikgY2hhbmdlcl1gIn0sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4iKCIrdGhpcy5tYWNyb05hbWUrIjoiKygiZWxzZSI9PT10aGlzLm5hbWU/IiI6dGhpcy5wYXJhbXMubWFwKHMpKSsiKSIrKHRoaXMubmV4dD8iKyIrdGhpcy5uZXh0LlR3aW5lU2NyaXB0X1RvU291cmNlKCk6IiIpfSxnZXQgVHdpbmVTY3JpcHRfT2JqZWN0TmFtZSgpezE9PT10aGlzLnBhcmFtcy5sZW5ndGgmJjM2PChlPXModGhpcy5wYXJhbXNbMF0pKS5sZW5ndGgmJihlPXZvaWQgMCk7Zm9yKHZhciBlLHQ9ImEgKCIuY29uY2F0KHRoaXMubWFjcm9OYW1lLCI6IikuY29uY2F0KGV8fCIiLCIpIGNoYW5nZXIiKSxuPXRoaXMubmV4dCxyPShuJiYodCs9IiBjb21iaW5lZCB3aXRoICIpLDApO24mJnQubGVuZ3RoPDQ4Oyl7dmFyIGE9IigiLmNvbmNhdChuLm1hY3JvTmFtZSwiOikiKTt0Kz0oMDxyJiYhbi5uZXh0PyIgYW5kICI6IiIpK2ErKG4ubmV4dD8iLCAiOiIiKSxuPW4ubmV4dCxyKz0xfWZvcih2YXIgbz0wO24mJm88OTk7KW49bi5uZXh0LG8rPTE7cmV0dXJuIDA8byYmKHQrPSIiLmNvbmNhdCgwPHI/IiBhbmQgIjoiIikuY29uY2F0KGkobywib3RoZXIgY2hhbmdlciIpKSksdH0sc3VtbWFyeTpmdW5jdGlvbigpe3ZhciBlPW4uY3JlYXRlKCk7cmV0dXJuIHRoaXMucnVuKGUpLGUuc3VtbWFyeSgpfSxjcmVhdGU6ZnVuY3Rpb24oZSl7dmFyIHQ9MTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOltdLG49Mjxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMl0/YXJndW1lbnRzWzJdOm51bGwscj0hKDM8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzNdKXx8YXJndW1lbnRzWzNdO3JldHVybiBBcnJheS5pc0FycmF5KHQpfHxhKCJDaGFuZ2VyQ29tbWFuZC5jcmVhdGUiLCJwYXJhbXMgd2FzIG5vdCBhbiBhcnJheSBidXQgIit0KSxPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUodGhpcykse21hY3JvTmFtZTplLHBhcmFtczp0LG5leHQ6bixjYW5FbmNoYW50OnJ9KX0sIlR3aW5lU2NyaXB0XysiOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLlR3aW5lU2NyaXB0X0Nsb25lKCksbj10O24ubmV4dDspbj1uLm5leHQ7cmV0dXJuIG4ubmV4dD1lLHQuY2FuRW5jaGFudD10aGlzLmNhbkVuY2hhbnQmJmUuY2FuRW5jaGFudCx0fSxUd2luZVNjcmlwdF9pczpmdW5jdGlvbihlKXtpZihsLmlzUHJvdG90eXBlT2YoZSkpcmV0dXJuIHRoaXMubWFjcm9OYW1lPT09ZS5tYWNyb05hbWUmJm8odGhpcy5wYXJhbXMsZS5wYXJhbXMpJiZvKHRoaXMubmV4dCxlLm5leHQpfSxUd2luZVNjcmlwdF9DbG9uZTpmdW5jdGlvbigpe2Zvcih2YXIgZT1sLmNyZWF0ZSh0aGlzLm1hY3JvTmFtZSx0aGlzLnBhcmFtcyx0aGlzLm5leHQpLHQ9ZTt0Lm5leHQ7KXQ9dC5uZXh0PXQubmV4dC5Ud2luZVNjcmlwdF9DbG9uZSgpO3JldHVybiBlLmNhbkVuY2hhbnQ9dGhpcy5jYW5FbmNoYW50LGV9LHJ1bjpmdW5jdGlvbihlLHQpe3ZhciBuPSJvdXRwdXQiPT09dGhpcy5tYWNyb05hbWU/W3R8fHRoaXNdOnRoaXMucGFyYW1zLG49Y1t0aGlzLm1hY3JvTmFtZV0uYXBwbHkoYyxbZV0uY29uY2F0KF90b0NvbnN1bWFibGVBcnJheShuKSkpO2lmKHIuY29udGFpbnNFcnJvcihuKSlyZXR1cm4gbjt0aGlzLm5leHQmJnRoaXMubmV4dC5ydW4oZSx0fHx0aGlzKX0scmVnaXN0ZXI6ZnVuY3Rpb24oZSx0KXtjW2VdPXR9fTtyZXR1cm4gT2JqZWN0LmZyZWV6ZShsKX0pLGRlZmluZSgiZGF0YXR5cGVzL2NvZGVob29rIixbXSxmdW5jdGlvbigpe3ZhciB0PU9iamVjdC5mcmVlemUoe1R3aW5lU2NyaXB0X1R5cGVOYW1lOiJhIGNvZGUgaG9vayIsVHdpbmVTY3JpcHRfT2JqZWN0TmFtZToiYSBjb2RlIGhvb2siLFR3aW5lU2NyaXB0X1RvU291cmNlOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc291cmNlfSxUd2luZVNjcmlwdF9QcmludDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmNvZGV9LFR3aW5lU2NyaXB0X3RvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc291cmNlfSxUd2luZVNjcmlwdF9pczpmdW5jdGlvbihlKXtyZXR1cm4gdC5pc1Byb3RvdHlwZU9mKGUpJiZ0aGlzLnNvdXJjZT09PWUuc291cmNlfSxUd2luZVNjcmlwdF9DbG9uZTpmdW5jdGlvbigpe3JldHVybiB0LmNyZWF0ZSh0aGlzLmNvZGUsdGhpcy5zb3VyY2UpfSxjcmVhdGU6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKHRoaXMpLHtjb2RlOmUsc291cmNlOnR9KX19KTtyZXR1cm4gdH0pLGRlZmluZSgiZGF0YXR5cGVzL2NvbG91ciIsWyJqcXVlcnkiXSxmdW5jdGlvbihjKXt2YXIgbD1NYXRoLm1heCx1PU1hdGgubWluLGE9TWF0aC5zaW4sbz1NYXRoLmNvcyxpPU1hdGgucG93LHA9TWF0aC5yb3VuZCxkPU1hdGguZmxvb3Iscz1NYXRoLmF0YW4yLGY9TWF0aC5jYnJ0LGg9TWF0aC5zcXJ0LG09TWF0aC5QSSxnPU9iamVjdC5hc3NpZ24seT1PYmplY3QuY3JlYXRlLGI9L14oW1xkYS1mQS1GXSkoW1xkYS1mQS1GXSkoW1xkYS1mQS1GXSkkLyx0PS9eKFtcZGEtZkEtRl0pKFtcZGEtZkEtRl0pKFtcZGEtZkEtRl0pKFtcZGEtZkEtRl0pKFtcZGEtZkEtRl0pKFtcZGEtZkEtRl0pJC8sdj15KG51bGwpO2Z1bmN0aW9uIHcoZSx0KXtmb3IodmFyIG49YXJndW1lbnRzLmxlbmd0aCxyPW5ldyBBcnJheSgyPG4/bi0yOjApLGE9MjthPG47YSsrKXJbYS0yXT1hcmd1bWVudHNbYV07aWYoMDxyLmxlbmd0aClyZXR1cm4gdy5hcHBseSh2b2lkIDAsW3coZSx0KV0uY29uY2F0KHIpKTtpZighdClyZXR1cm4gZTtmb3IodmFyIG89W10saT0wO2k8ZS5sZW5ndGg7aSsrKXtvW2ldPVtdO2Zvcih2YXIgcz0wO3M8dFswXS5sZW5ndGg7cysrKXtmb3IodmFyIGM9MCxsPTA7bDxlWzBdLmxlbmd0aDtsKyspYys9ZVtpXVtsXSp0W2xdW3NdO29baV1bc109Y319cmV0dXJuIG99ZnVuY3Rpb24gbihlKXt2YXIgdCxuPWUucixyPWUuZyxhPWUuYixlPWUuYSxvPWwobi89MjU1LHIvPTI1NSxhLz0yNTUpLGk9dShuLHIsYSkscz0obytpKS8yLGM9by1pO2lmKG89PT1pKXJldHVybntoOjAsczowLGw6c307c3dpdGNoKG8pe2Nhc2Ugbjp0PShyLWEpL2MrKHI8YT82OjApO2JyZWFrO2Nhc2Ugcjp0PShhLW4pL2MrMjticmVhaztjYXNlIGE6dD0obi1yKS9jKzR9cmV0dXJue2g6dD1wKDYwKnQpLHM6LjU8cz9jLygyLW8taSk6Yy8obytpKSxsOnMsYTplfX12YXIgaz1bLjk2NDI5NTY3NjQyOTU2NzcsMSwuODI1MTA0NjAyNTEwNDYwMl0sUz0yNDM4OS8yNyxUPTIxNi8yNDM4OSxfPWZ1bmN0aW9uKGUpe3JldHVybiBlLm1hcChmdW5jdGlvbihlKXtyZXR1cm5bZV19KX0seD1mdW5jdGlvbihlKXtyZXR1cm4gZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGVbMF19KX07ZnVuY3Rpb24gTyhlKXt2YXIgdD1lLmwsbj1lLmMscj1lLmgsZT1lLmEsbj1bdCo9MTAwLG4qbyhyKm0vMTgwKSxuKmEociptLzE4MCldLHI9W107clsxXT0oblswXSsxNikvMTE2LHJbMF09blsxXS81MDArclsxXSxyWzJdPXJbMV0tblsyXS8yMDA7bj1baShyWzBdLDMpPlQ/aShyWzBdLDMpOigxMTYqclswXS0xNikvUyxTKlQ8dD9pKCgxNit0KS8xMTYsMyk6dC9TLGkoclsyXSwzKT5UP2koclsyXSwzKTooMTE2KnJbMl0tMTYpL1NdLm1hcChmdW5jdGlvbihlLHQpe3JldHVybiBlKmtbdF19KSx0PV9zbGljZWRUb0FycmF5KHgodyhbWzMuMjQwOTY5OTQxOTA0NTIyNiwtMS41MzczODMxNzc1NzAwOTQsLS40OTg2MTA3NjAyOTMwMDM0XSxbLS45NjkyNDM2MzYyODA4Nzk2LDEuODc1OTY3NTAxNTA3NzIwMiwuMDQxNTU1MDU3NDA3MTc1NTldLFsuMDU1NjMwMDc5Njk2OTkzNjYsLS4yMDM5NzY5NTg4ODg5NzY1MiwxLjA1Njk3MTUxNDI0Mjg3ODZdXSx3KFtbLjk1NTQ3MzQ1MjcwNDIxODIsLS4wMjMwOTg1MzY4NzQyNjE0MjMsLjA2MzI1OTMwODY2MTAyMTddLFstLjAyODM2OTcwNjk2MzIwODEzNiwxLjAwOTk5NTQ1ODAwNTgyMjYsLjAyMTA0MTM5ODk2Njk0MzAwOF0sWy4wMTIzMTQwMDE2ODgzMTk4OTksLS4wMjA1MDc2OTY0MzM0Nzc5MTIsMS4zMzAzNjU5MzY2MDgwNzUzXV0sXyhuKSkpKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHUoMjU1LGwoMCwyNTUqKC4wMDMxMzA4PChlPWUpPzEuMDU1KmkoZSwxLzIuNCktLjA1NToxMi45MiplKSkpfSksMyk7cmV0dXJue3I6dFswXSxnOnRbMV0sYjp0WzJdLGE6ZX19ZnVuY3Rpb24gZShlKXtmdW5jdGlvbiB0KGUpe3JldHVybiAxZS01PD1uW2VdJiZuW2VdPD0yNTUtMWUtNX12YXIgbj1PKGUpO2lmKE9iamVjdC5rZXlzKG4pLmV2ZXJ5KHQpKXJldHVybiBuO3ZhciByPShlPV9vYmplY3RTcHJlYWQoe30sZSkpLmMsYT0wO2ZvcihlLmMvPTI7MWUtNTxyLWE7KW49TyhlKSxPYmplY3Qua2V5cyhuKS5ldmVyeSh0KT9hPWUuYzpyPWUuYyxlLmM9KHIrYSkvMjtyZXR1cm4gTyhlKX12YXIgQT1PYmplY3QuZnJlZXplKHtUd2luZVNjcmlwdF9UeXBlSUQ6ImNvbG91ciIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgY29sb3VyIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhIGNvbG91ciIsVHdpbmVTY3JpcHRfRGVidWdOYW1lOmZ1bmN0aW9uKCl7cmV0dXJuImEgY29sb3VyICIrdGhpcy5Ud2luZVNjcmlwdF9QcmludCgpfSwiVHdpbmVTY3JpcHRfKyI6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy50b1JHQkEoKSxlPWUudG9SR0JBKCk7cmV0dXJuIEEuY3JlYXRlKHtyOnUocCguNioodC5yK2UucikpLDI1NSksZzp1KHAoLjYqKHQuZytlLmcpKSwyNTUpLGI6dShwKC42Kih0LmIrZS5iKSksMjU1KSxhOih0LmErZS5hKS8yfSl9LFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy50b1JHQkEoKTtyZXR1cm4iPHR3LWNvbG91ciBzdHlsZT0nYmFja2dyb3VuZC1jb2xvcjpyZ2JhKCIrW2UucixlLmcsZS5iLGUuYV0rIik7Jz48L3R3LWNvbG91cj4ifSxUd2luZVNjcmlwdF9pczpmdW5jdGlvbihlKXt2YXIgdDtyZXR1cm4hIUEuaXNQcm90b3R5cGVPZihlKSYmKGUubGNoYSYmdGhpcy5sY2hhP2UubGNoYS5sPT09dGhpcy5sY2hhLmwmJmUubGNoYS5jPT09dGhpcy5sY2hhLmMmJmUubGNoYS5oPT09dGhpcy5sY2hhLmgmJmUuYT09PXRoaXMuYToodD10aGlzLnRvUkdCQSgpLChlPWUudG9SR0JBKCkpLnI9PT10LnImJmUuZz09PXQuZyYmZS5iPT09dC5iJiZlLmE9PT10LmEpKX0sVHdpbmVTY3JpcHRfQ2xvbmU6ZnVuY3Rpb24oKXtyZXR1cm4gQS5jcmVhdGUodGhpcyl9LHRvUkdCQVN0cmluZzpmdW5jdGlvbigpe3ZhciBlPXRoaXMudG9SR0JBKCksdD1lLnIsbj1lLmcscj1lLmIsZT1lLmE7cmV0dXJuInJnYmEoIi5jb25jYXQodCwiLCAiKS5jb25jYXQobiwiLCAiKS5jb25jYXQociwiLCAiKS5jb25jYXQoZSwiKSIpfSx0b0hTTEE6ZnVuY3Rpb24oKXtyZXR1cm4gbih0aGlzLnRvUkdCQSgpKX0sdG9SR0JBOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGNoP2UoX29iamVjdFNwcmVhZCh7YTp0aGlzLmF9LHRoaXMubGNoKSk6dGhpc30sdG9MQ0hBOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGNoP19vYmplY3RTcHJlYWQoe2E6dGhpcy5hfSx0aGlzLmxjaCk6KHQ9KGU9dGhpcykucixuPWUuZyxyPWUuYixlPWUuYSxuPVsxMTYqKHQ9eCh3KFtbMS4wNDc5Mjk4MjA4NDA1NDg4LC4wMjI5NDY3OTMzNDEwMTkwODgsLS4wNTAxOTIyMjk1NDMxMzU1N10sWy4wMjk2Mjc4MTU2ODgxNTkzNDQsLjk5MDQzNDQ4NDU3MzI0OSwtLjAxNzA3MzgyNTAyOTM4NTE0XSxbLS4wMDkyNDMwNTgxNTI1OTExNzgsLjAxNTA1NTE0NDg5NjU3Nzg5NSwuNzUxODc0Mjg5OTU4MDAwOF1dLHcoW1suNDEyMzkwNzk5MjY1OTU5MzQsLjM1NzU4NDMzOTM4Mzg3OCwuMTgwNDgwNzg4NDAxODM0M10sWy4yMTI2MzkwMDU4NzE1MTAyNywuNzE1MTY4Njc4NzY3NzU2LC4wNzIxOTIzMTUzNjA3MzM3MV0sWy4wMTkzMzA4MTg3MTU1OTE4MiwuMTE5MTk0Nzc5Nzk0NjI1OTgsLjk1MDUzMjE1MjI0OTY2MDddXSxfKFt0LzI1NSxuLzI1NSxyLzI1NV0ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlPC4wNDA0NT9lLzEyLjkyOmkoKGUrLjA1NSkvMS4wNTUsMi40KX0pKSkpKS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS9rW3RdfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBUPGU/ZihlKTooUyplKzE2KS8xMTZ9KSlbMV0tMTYsNTAwKih0WzBdLXRbMV0pLDIwMCoodFsxXS10WzJdKV0scj0xODAqcyhuWzJdLG5bMV0pL20se2w6blswXS8xMDAsYzpoKGkoblsxXSwyKStpKG5bMl0sMikpLGg6MDw9cj9yOjM2MCtyLGE6ZX0pO3ZhciBlLHQsbixyfSxMQ0hSb3RhdGU6ZnVuY3Rpb24oZSl7ZTwwJiYoZT0zNjArZSk7dmFyIHQ9dGhpcy50b0xDSEEoKTtyZXR1cm4gdC5oPSh0LmgrZSklMzYwLEEuY3JlYXRlKHQpfSxUd2luZVNjcmlwdF9HZXRQcm9wZXJ0eTpmdW5jdGlvbihlKXt2YXIgdDtyZXR1cm4ibGNoIj09PWU/KHQ9dGhpcy50b0xDSEEoKSxuZXcgTWFwKFtbImwiLHQubF0sWyJjIix0LmNdLFsiaCIsdC5oXV0pKToodD10aGlzLnRvUkdCQSgpLCJoIj09PWV8fCJzIj09PWV8fCJsIj09PWU/bih0KVtlXToiciI9PT1lfHwiZyI9PT1lfHwiYiI9PT1lfHwiYSI9PT1lP3RbZV06dm9pZCAwKX0sVHdpbmVTY3JpcHRfUHJvcGVydGllczpbImgiLCJzIiwibCIsInIiLCJnIiwiYiIsImEiLCJsY2giXSxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe2lmKDA9PT10aGlzLmEpcmV0dXJuInRyYW5zcGFyZW50Ijt2YXIgZT0hdGhpcy5sY2gmJm4odGhpcyk7aWYoMT09PWUubCYmIWUuaCYmIWUucylyZXR1cm4id2hpdGUiO2lmKDA9PT1lLmwmJiFlLmgmJiFlLnMpcmV0dXJuImJsYWNrIjtpZiguNTw9ZS5sJiZlLmw8LjUzMzQmJjA9PT1lLnMpcmV0dXJuImdyYXkiO2lmKC41PT09ZS5sJiYuODw9ZS5zJiZlLnM8LjgwNCl7dmFyIHQ9ezA6InJlZCIsMzA6Im9yYW5nZSIsNjA6InllbGxvdyIsOTA6ImxpbWUiLDEyMDoiZ3JlZW4iLDE4MDoiY3lhbiIsMjEwOiJibHVlIiwyNDA6Im5hdnkiLDI3MDoicHVycGxlIiwzMDA6Im1hZ2VudGEifVtlLmhdO2lmKHQpcmV0dXJuIHR9cmV0dXJuIigiLmNvbmNhdCh0aGlzLmxjaD8ibGNoIjoiaHNsIiwiOiIpLmNvbmNhdCh0aGlzLmxjaD9bdGhpcy5sY2gubCx0aGlzLmxjaC5jLHRoaXMubGNoLmhdOltlLmgsZS5zLGUubF0pLmNvbmNhdCgxIT09dGhpcy5hPyIsIit0aGlzLmE6IiIsIikiKX0sY3JlYXRlOmZ1bmN0aW9uKGUpe3ZhciB0LG4scixhLG8saTtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGU/dGhpcy5jcmVhdGUoKEEuaXNIZXhTdHJpbmcoZSk/ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyIhPXR5cGVvZiBlP2U6KGU9KGU9ZS5yZXBsYWNlKCIjIiwiIikpLnJlcGxhY2UoYiwiJDEkMSQyJDIkMyQzIikse3I6cGFyc2VJbnQoZS5zbGljZSgwLDIpLDE2KSxnOnBhcnNlSW50KGUuc2xpY2UoMiw0KSwxNiksYjpwYXJzZUludChlLnNsaWNlKDQsNiksMTYpfSl9OmZ1bmN0aW9uKGUpe3ZhciB0O3JldHVybiBlIGluIHY/dltlXToodD0idHJhbnNwYXJlbnQiPT09KHQ9YygiPHA+IikuY3NzKCJiYWNrZ3JvdW5kLWNvbG9yIixlKS5jc3MoImJhY2tncm91bmQtY29sb3IiKSk/e3I6MCxnOjAsYjowLGE6MH06dC5zdGFydHNXaXRoKCJyZ2IiKT90Lm1hdGNoKC9cZCsvZykucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZVsicmdiIltuXV09K3QsZX0se30pOntyOjE5MixnOjE5MixiOjE5Mn0sdltlXT10KX0pKGUpKTohKCJoImluIGUmJiJzImluIGUmJiJsImluIGUpfHwiciJpbiBlfHwiZyJpbiBlfHwiYiJpbiBlPygiYSJpbiBlJiYibnVtYmVyIj09dHlwZW9mIGUuYXx8KGUuYT0xKSwiaCJpbiBlJiYiYyJpbiBlJiYhKCJzImluIGUpJiYibCJpbiBlP2coeSh0aGlzKSx7YTplLmEsbGNoOntsOmUubCxjOmUuYyxoOmUuaH19KTpnKHkodGhpcyksZSkpOnRoaXMuY3JlYXRlKChhPSh0PWUpLmgsbz1lLnMsaT1lLmwsdD1lLmEsMD09PW8/e3I6ZT1kKDI1NSppKSxnOmUsYjplfToocj0yKmktKG49aTwuNT9pKigxK28pOmkrby1pKm8pLHtyOmQoMjU1KnMoKGEvPTM2MCkrMS8zKSksZzpkKDI1NSpzKGEpKSxiOmQoMjU1KnMoYS0xLzMpKSxhOnR9KSkpO2Z1bmN0aW9uIHMoZSl7cmV0dXJuIGU8MCYmKGUrPTEpLDE8ZSYmLS1lLGU8MS82P3IrNioobi1yKSplOmU8LjU/bjplPDIvMz9yKyhuLXIpKigyLzMtZSkqNjpyfX0saXNIZXhTdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiYiIyI9PT1lWzBdJiYoZS5zbGljZSgxKS5tYXRjaChiKXx8ZS5zbGljZSgxKS5tYXRjaCh0KSl9LGlzQ1NTM0Z1bmN0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmL14oPzpyZ2J8aHNsKWE/XChccypcZCsoPzpcLlxkKyk/XHMqLFxzKlxkKyg/OlwuXGQrKT8lP1xzKixccypcZCsoPzpcLlxkKyk/JT8oPzosXHMqXGQrKD86XC5cZCspP1xzKik/XCkkLy50ZXN0KGUpfX0pO3JldHVybiBBfSksZGVmaW5lKCJkYXRhdHlwZXMvY3VzdG9tY29tbWFuZCIsWyJpbnRlcm5hbHR5cGVzL2NoYW5nZWRlc2NyaXB0b3IiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiXSxmdW5jdGlvbihsLHUpe3ZhciBwPU9iamVjdC5hc3NpZ24sZD1PYmplY3QuY3JlYXRlO3JldHVybiBPYmplY3Quc2VhbCh7VHdpbmVTY3JpcHRfVHlwZUlEOiJjb21tYW5kIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhIGN1c3RvbSBjb21tYW5kIixUd2luZVNjcmlwdF9UeXBlTmFtZToiYSBjdXN0b20gY29tbWFuZCIsVHdpbmVTY3JpcHRfUHJpbnQ6ZnVuY3Rpb24oKXtyZXR1cm4iYFthIGN1c3RvbSBjb21tYW5kXWAifSxjcmVhdGU6ZnVuY3Rpb24oZSl7dmFyIHQsbj1lLnRvU291cmNlLHI9ZS5jaGFuZ2VyLGE9ZS5ob29rLG89ZS52YXJpYWJsZXMsaT17fTtmb3IodCBpbiBvKWlbdF09W29bdF1dO3ZhciBzLGM9bC5jcmVhdGUoe3NvdXJjZTphLGxvb3BWYXJzOml9LHIpO3JldHVybiB1LmNvbnRhaW5zRXJyb3IoYyk/YzpzPXAoZCh0aGlzKSx7VHdpbmVTY3JpcHRfQXR0YWNoOmZ1bmN0aW9uKGUsdCl7Yy5zZWN0aW9uPWU7ZT10LnJ1bihjKTtyZXR1cm4gdS5jb250YWluc0Vycm9yKGUpP2U6c30sVHdpbmVTY3JpcHRfUnVuOmZ1bmN0aW9uKGUpe2Muc2VjdGlvbj1lO2U9YztyZXR1cm4gYz1sLmNyZWF0ZSh7c291cmNlOmEsbG9vcFZhcnM6aX0sciksZX0sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4gbn0sVHdpbmVTY3JpcHRfQ3VzdG9tQ29tbWFuZDpmdW5jdGlvbigpe3JldHVybiBlfX0pfX0pfSksZGVmaW5lKCJkYXRhdHlwZXMvY3VzdG9tbWFjcm8iLFsianF1ZXJ5IiwidXRpbHMiLCJyZW5kZXJlciIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiZGF0YXR5cGVzL2N1c3RvbWNvbW1hbmQiLCJpbnRlcm5hbHR5cGVzL3ZhcnJlZiIsImludGVybmFsdHlwZXMvdmFyc2NvcGUiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJpbnRlcm5hbHR5cGVzL3R3aW5lbm90aWZpZXIiXSxmdW5jdGlvbih3LGUsayx0LFMsVCxfLHgsTyl7ZnVuY3Rpb24gbih2KXtyZXR1cm4gZnVuY3Rpb24oZSl7di5jYWxsZWQrPTE7Zm9yKHZhciB0PXYudmFyTmFtZXMsbj12LnBhcmFtcyxyPXYuYm9keSxhPUUoTihfKSx7VHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZTp7dHlwZToidGVtcCIsbmFtZTp2LlR3aW5lU2NyaXB0X09iamVjdE5hbWUrIiBjYWxsICMiK3YuY2FsbGVkfSxUd2luZVNjcmlwdF9UeXBlRGVmczpOKG51bGwpfSksbz1bXSxpPTAscz0hMSxjPWFyZ3VtZW50cy5sZW5ndGgsbD1uZXcgQXJyYXkoMTxjP2MtMTowKSx1PTE7dTxjO3UrKylsW3UtMV09YXJndW1lbnRzW3VdO2Zvcih2YXIgcD0wO3A8bC5sZW5ndGg7cCs9MSl7dmFyIGQ9bFtwXSxmPXRbaV0saD0oYS5Ud2luZVNjcmlwdF9UeXBlRGVmc1tmXT1uW2ldLmRhdGF0eXBlLnJlc3Q/bltpXS5kYXRhdHlwZS5jcmVhdGUoImFycmF5Iik6bltpXS5kYXRhdHlwZSxULmNyZWF0ZShhLGYpKTtpZih4LmNvbnRhaW5zRXJyb3IoaCkpcmV0dXJuIGg7aWYobltpXS5kYXRhdHlwZS5yZXN0KXt2YXIgcz0hMCxtPShhW2ZdfHxbXSkuY29uY2F0KFtkXSk7aWYocDxsLmxlbmd0aC0xKXthW2ZdPW07Y29udGludWV9aC5zZXQobSl9ZWxzZSBoLnNldChkKSxpKz0xO28ucHVzaChPLmNyZWF0ZShBKGgpKyIgaXMgbm93ICIrQShhW2ZdKSkpfWlmKCFzJiZudWxsIT0oZz1uW2ldKSYmZy5kYXRhdHlwZS5yZXN0KXt2YXIgZz1ULmNyZWF0ZShhLHRbaV0pO2lmKHguY29udGFpbnNFcnJvcihnKSlyZXR1cm4gZztnLnNldChbXSksYS5Ud2luZVNjcmlwdF9UeXBlRGVmc1tuYW1lXT1uW2ldLmRhdGF0eXBlLmNyZWF0ZSgiYXJyYXkiKX12YXIgeSxnPXcoIjxwPiIpLmFwcGVuZChrLmV4ZWMoci5jb2RlKSksYj1lLnN0YWNrLmxlbmd0aCxyPShlLnN0YWNrLnVuc2hpZnQoe3RlbXBWYXJpYWJsZXM6YSxkb206ZyxvdXRwdXQ6ZnVuY3Rpb24oZSl7eT1lfX0pLGUuZXZhbFJlcGxheSk7Zm9yKGUuZXZhbFJlcGxheT1udWxsLGUuZXhlY3V0ZSgpO2Uuc3RhY2subGVuZ3RoPmI7KWUuc3RhY2suc2hpZnQoKTtlLmV2YWxSZXBsYXk9cjtyPWcuZmluZCgidHctZXJyb3IiKTtyZXR1cm4gci5sZW5ndGg/KGcucHJlcGVuZChvLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5yZW5kZXIoKX0pLCI8YnI+IikseC5jcmVhdGUoInByb3BhZ2F0ZWQiLCIiLmNvbmNhdChyLmxlbmd0aCwiIGVycm9yIikuY29uY2F0KDE8ci5sZW5ndGg/InMiOiIiLCIgb2NjdXJyZWQgd2hlbiBydW5uaW5nICIpLmNvbmNhdCh2LlR3aW5lU2NyaXB0X09iamVjdE5hbWUsIi4iKSx2b2lkIDAsZykpOnZvaWQgMD09PXk/eC5jcmVhdGUoImN1c3RvbW1hY3JvIiwiIi5jb25jYXQodi5Ud2luZVNjcmlwdF9PYmplY3ROYW1lLCIgZGlkbid0IG91dHB1dCBhbnkgZGF0YSBvciBob29rcyB1c2luZyAob3V0cHV0Oikgb3IgKG91dHB1dC1kYXRhOikuIikpOiJvYmplY3QiPT09X3R5cGVvZih5KSYmImNoYW5nZXIiaW4geT9TLmNyZWF0ZShFKHkse3RvU291cmNlOiIoIi5jb25jYXQodi5Ud2luZVNjcmlwdF9Lbm93bk5hbWV8fCJ1bm5hbWVkIiwiOiIpLmNvbmNhdChsLm1hcChDKSwiKSIpfSkpOnl9fXZhciByPWUuYW5kTGlzdCxBPXQub2JqZWN0TmFtZSxhPXQudHlwZU5hbWUsbz10Lm1hdGNoZXMsQz10LnRvU291cmNlLEU9T2JqZWN0LmFzc2lnbixOPU9iamVjdC5jcmVhdGUsaT1PYmplY3Quc2VhbCh7VHdpbmVTY3JpcHRfVHlwZUlEOiJtYWNybyIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgY3VzdG9tIG1hY3JvIixUd2luZVNjcmlwdF9HZXRQcm9wZXJ0eTpmdW5jdGlvbihlKXtpZigicGFyYW1zIj09PWUpcmV0dXJuIF90b0NvbnN1bWFibGVBcnJheSh0aGlzLnBhcmFtcyl9LFR3aW5lU2NyaXB0X1Byb3BlcnRpZXM6WyJwYXJhbXMiXSxUd2luZVNjcmlwdF9QcmludDpmdW5jdGlvbigpe3JldHVybiJgWyIrdGhpcy5Ud2luZVNjcmlwdF9PYmplY3ROYW1lKyJdYCJ9LFR3aW5lU2NyaXB0X0Nsb25lOmZ1bmN0aW9uKCl7dmFyIGU9RShOKGkpLHRoaXMpO3JldHVybiBlLmZuPW4oZSksZX0sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4iKG1hY3JvOiIrdGhpcy5wYXJhbXMubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLlR3aW5lU2NyaXB0X1RvU291cmNlKCl9KS5jb25jYXQoIiIpK3RoaXMuYm9keS5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpKyIpIn0sY3JlYXRlRnJvbUZuOmZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiBFKE4oaSkse3BhcmFtczpbXSxmbjplLHR5cGVTaWduYXR1cmU6cixUd2luZVNjcmlwdF9PYmplY3ROYW1lOnQsVHdpbmVTY3JpcHRfVG9Tb3VyY2U6bixUd2luZVNjcmlwdF9Lbm93bk5hbWU6IiJ9KX0sY3JlYXRlOmZ1bmN0aW9uKGUsdCl7dD1FKE4oaSkse3BhcmFtczplLGNhbGxlZDowLHZhck5hbWVzOmUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnZhclJlZi5wcm9wZXJ0eUNoYWluWzBdfSksdHlwZVNpZ25hdHVyZTplLm1hcChmdW5jdGlvbih0KXt2YXIgZT10LmRhdGF0eXBlLnRvVHlwZVNpZ25hdHVyZU9iamVjdD90LmRhdGF0eXBlLnRvVHlwZVNpZ25hdHVyZU9iamVjdCh7cmVzdDp0LnJlc3R9KTp7cGF0dGVybjoicmFuZ2UiLHJhbmdlOmZ1bmN0aW9uKGUpe3JldHVybiBvKHQuZGF0YXR5cGUsZSl9LG5hbWU6YSh0LmRhdGF0eXBlKX07cmV0dXJuIHQucmVzdD97cGF0dGVybjoiemVybyBvciBtb3JlIixpbm5lclR5cGU6ZX06ZX0pLGJvZHk6dCxUd2luZVNjcmlwdF9Lbm93bk5hbWU6IiIsVHdpbmVTY3JpcHRfT2JqZWN0TmFtZToiYSBjdXN0b20gbWFjcm8gKHdpdGggIi5jb25jYXQoZS5sZW5ndGg/cihlLm1hcChDKSk6Im5vIHBhcmFtcyIsIikiKX0pO3JldHVybiB0LmZuPW4odCksdH19KTtyZXR1cm4gaX0pLGRlZmluZSgiZGF0YXR5cGVzL2RhdGF0eXBlIixbInV0aWxzIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJkYXRhdHlwZXMvY29sb3VyIiwiZGF0YXR5cGVzL2dyYWRpZW50IiwiZGF0YXR5cGVzL2xhbWJkYSIsImRhdGF0eXBlcy9jdXN0b21tYWNybyIsImRhdGF0eXBlcy9jb2RlaG9vayIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGUsdCxuLHIsYSxvLGkscyxjKXt2YXIgbD1lLnJlYWxXaGl0ZXNwYWNlLHU9ZS5hbnlSZWFsTGV0dGVyLHA9ZS5hbnlDYXNlZExldHRlcixkPWUuYW55TmV3bGluZSxmPXQub2JqZWN0TmFtZSxlPU9iamVjdC5zZWFsLGg9T2JqZWN0LmtleXMsbT1NYXRoLmZsb29yLGc9TWF0aC5hYnMseT17VHdpbmVTY3JpcHRfVHlwZUlEOiJkYXRhdHlwZSIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgZGF0YXR5cGUiLFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuImBbIit0aGlzLlR3aW5lU2NyaXB0X09iamVjdE5hbWUrIl1gIn0sZ2V0IFR3aW5lU2NyaXB0X09iamVjdE5hbWUoKXtyZXR1cm4idGhlICIrKHRoaXMucmVzdD8iLi4uIjoiIikrdGhpcy5uYW1lKyIgZGF0YXR5cGUifSxUd2luZVNjcmlwdF9pczpmdW5jdGlvbihlKXtyZXR1cm4geS5pc1Byb3RvdHlwZU9mKGUpJiZlLm5hbWU9PT10aGlzLm5hbWV9LFR3aW5lU2NyaXB0X0Nsb25lOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucmVzdD90aGlzOk9iamVjdC5jcmVhdGUodGhpcyl9LFR3aW5lU2NyaXB0X1RvU291cmNlOmZ1bmN0aW9uKCl7cmV0dXJuKHRoaXMucmVzdD8iLi4uIjoiIikrdGhpcy5uYW1lfSxUd2luZVNjcmlwdF9Jc1R5cGVPZjpmdW5jdGlvbihlKXt2YXIgdD10aGlzLm5hbWUsbj10aGlzLnJlc3Q7cmV0dXJuISF2W3RdJiZ2W3RdKGUsbil9LHRvVHlwZVNpZ25hdHVyZU9iamVjdDpmdW5jdGlvbigpe3ZhciBlPXRoaXMubmFtZSxlPXtwYXR0ZXJuOiJyYW5nZSIscmFuZ2U6dltlXSxuYW1lOiJhICIrKCJkbSI9PT1lPyJkYXRhbWFwIjoiZHMiPT09ZT8iZGF0YXNldCI6Im51bSI9PT1lP2UrImJlciI6InN0ciI9PT1lP2UrImluZyI6ImNvbG9yIj09PWU/ImNvbG91ciI6ImJvb2wiPT09ZT9lKyJlYW4iOiJhbG51bSI9PT1lPyJhbHBoYW51bWVyaWMgY2hhcmFjdGVyIjoiaW50Ij09PWU/ZSsiZWdlciI6ImV2ZW4iPT09ZXx8Im9kZCI9PT1lP2UrIiBudW1iZXIiOmUuZW5kc1dpdGgoImNhc2UiKXx8IndoaXRlc3BhY2UiPT09ZT9lKyIgY2hhcmFjdGVyIjoiZW1wdHkiPT09ZT9lKyIgdmFsdWUiOmUpfTtyZXR1cm4gdGhpcy5yZXN0P3twYXR0ZXJuOiJ6ZXJvIG9yIG1vcmUiLGlubmVyVHlwZTplfTplfSxjcmVhdGU6ZnVuY3Rpb24oZSl7dmFyIHQ9MTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0mJmFyZ3VtZW50c1sxXSxuPShlPSJkYXRhbWFwIj09PWU/ImRtIjoiZGF0YXNldCI9PT1lPyJkcyI6Im51bWJlciI9PT1lPyJudW0iOiJzdHJpbmciPT09ZT8ic3RyIjoiY29sb3IiPT09ZT8iY29sb3VyIjoiYm9vbGVhbiI9PT1lPyJib29sIjoiYWxwaGFudW1lcmljIj09PWU/ImFsbnVtIjoiaW50ZWdlciI9PT1lPyJpbnQiOiJuZXdsaW5lIj09PWU/ImxpbmVicmVhayI6ZSxPYmplY3QuY3JlYXRlKHRoaXMpKTtyZXR1cm4gbi5uYW1lPWUsbi5yZXN0PXQsbn0sZnJvbTpmdW5jdGlvbih0KXt2YXIgZT1oKGIpLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIGJbZV0odCl9KTtyZXR1cm4gZT95LmNyZWF0ZShlKTpjLmNyZWF0ZSgiZGF0YXR5cGUiLGYodCkrIiBkb2Vzbid0IGNvcnJlc3BvbmQgdG8gYSBkYXRhdHlwZSB2YWx1ZS4iKX19LGI9e2FycmF5OkFycmF5LmlzQXJyYXksZG06ZnVuY3Rpb24oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBNYXB9LGRzOmZ1bmN0aW9uKGUpe3JldHVybiBlIGluc3RhbmNlb2YgU2V0fSxkYXRhdHlwZTpmdW5jdGlvbihlKXtyZXR1cm4geS5pc1Byb3RvdHlwZU9mKGUpfSxjaGFuZ2VyOmZ1bmN0aW9uKGUpe3JldHVybiBuLmlzUHJvdG90eXBlT2YoZSl9LGNvbG91cjpmdW5jdGlvbihlKXtyZXR1cm4gci5pc1Byb3RvdHlwZU9mKGUpfSxncmFkaWVudDpmdW5jdGlvbihlKXtyZXR1cm4gYS5pc1Byb3RvdHlwZU9mKGUpfSxsYW1iZGE6ZnVuY3Rpb24oZSl7cmV0dXJuIG8uaXNQcm90b3R5cGVPZihlKX0sbWFjcm86ZnVuY3Rpb24oZSl7cmV0dXJuIGkuaXNQcm90b3R5cGVPZihlKX0sY29kZWhvb2s6ZnVuY3Rpb24oZSl7cmV0dXJuIHMuaXNQcm90b3R5cGVPZihlKX0sY29tbWFuZDpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImNvbW1hbmQiPT09ZS5Ud2luZVNjcmlwdF9UeXBlSUR9LHN0cjpmdW5jdGlvbihlKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGV9LG51bTpmdW5jdGlvbihlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGV9LGJvb2w6ZnVuY3Rpb24oZSl7cmV0dXJuImJvb2xlYW4iPT10eXBlb2YgZX19LHY9X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGIpLHt9LHtldmVuOmZ1bmN0aW9uKGUpe3JldHVybiFpc05hTihlKSYmbShnKGUpKSUyPT0wfSxvZGQ6ZnVuY3Rpb24oZSl7cmV0dXJuIWlzTmFOKGUpJiZtKGcoZSkpJTI9PTF9LGVtcHR5OmZ1bmN0aW9uKGUpe3JldHVybiBlIGluc3RhbmNlb2YgTWFwfHxlIGluc3RhbmNlb2YgU2V0PyFlLnNpemU6ISghQXJyYXkuaXNBcnJheShlKSYmInN0cmluZyIhPXR5cGVvZiBlfHxlLmxlbmd0aCl9LGludDpmdW5jdGlvbihlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJmU9PT0oMHxlKX0sdXBwZXJjYXNlOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmMT09PV90b0NvbnN1bWFibGVBcnJheShlKS5sZW5ndGgmJl90b0NvbnN1bWFibGVBcnJheShlKS5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gZSE9PWUudG9Mb3dlckNhc2UoKX0pfSxsb3dlcmNhc2U6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiYxPT09X3RvQ29uc3VtYWJsZUFycmF5KGUpLmxlbmd0aCYmX3RvQ29uc3VtYWJsZUFycmF5KGUpLmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiBlIT09ZS50b1VwcGVyQ2FzZSgpfSl9LHdoaXRlc3BhY2U6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiYhIWUubWF0Y2goIl4iK2wrIiQiKX0sZGlnaXQ6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiYhIWUubWF0Y2goIl5cXGQkIil9LGFsbnVtOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmISFlLm1hdGNoKCJeIit1KyIkIil9LGFueWNhc2U6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiYhIWUubWF0Y2goIl4iK3ArIiQiKX0sbGluZWJyZWFrOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmISFlLm1hdGNoKCJeIitkKyIkIil9LGFueTpmdW5jdGlvbigpe3JldHVybiEwfSxjb25zdDpmdW5jdGlvbigpe3JldHVybiEwfX0pO3JldHVybiBlKHkpfSksZGVmaW5lKCJkYXRhdHlwZXMvZ3JhZGllbnQiLFsidXRpbHMvb3BlcmF0aW9udXRpbHMiXSxmdW5jdGlvbihlKXt2YXIgdD1lLnRvU291cmNlLG49T2JqZWN0LmZyZWV6ZSh7VHdpbmVTY3JpcHRfVHlwZUlEOiJncmFkaWVudCIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgZ3JhZGllbnQiLFR3aW5lU2NyaXB0X09iamVjdE5hbWU6ImEgZ3JhZGllbnQiLFR3aW5lU2NyaXB0X0RlYnVnTmFtZTpmdW5jdGlvbigpe3JldHVybiJhIGdyYWRpZW50ICIrdGhpcy5Ud2luZVNjcmlwdF9QcmludCgpfSxUd2luZVNjcmlwdF9HZXRQcm9wZXJ0eTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO3JldHVybiJhbmdsZSI9PT1lP3RoaXMuYW5nbGU6InN0b3BzIj09PWU/dGhpcy5zdG9wcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBNYXAoW1t0LnJlcGVhdGluZz8icGl4ZWxzIjoicGVyY2VudCIsZS5zdG9wXSxbImNvbG91ciIsZS5jb2xvdXIuVHdpbmVTY3JpcHRfQ2xvbmUoKV1dKX0pOnZvaWQgMH0sVHdpbmVTY3JpcHRfUHJvcGVydGllczpbImFuZ2xlIiwic3RvcHMiXSxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe3JldHVybiIoZ3JhZGllbnQ6Iit0aGlzLmFuZ2xlKyIsIit0aGlzLnN0b3BzLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gdChlLnN0b3ApKyIsIit0KGUuY29sb3VyKX0pKyIpIn0sVHdpbmVTY3JpcHRfaXM6ZnVuY3Rpb24oZSl7dmFyIHI9dGhpcztyZXR1cm4gZS5hbmdsZT09PXRoaXMuYW5nbGUmJmUuc3RvcHMubGVuZ3RoPT09dGhpcy5zdG9wcy5sZW5ndGgmJmUuc3RvcHMuZXZlcnkoZnVuY3Rpb24oZSx0KXt2YXIgbj1lLmNvbG91cixlPWUuc3RvcDtyZXR1cm4gci5zdG9wc1t0XS5zdG9wPT09ZSYmci5zdG9wc1t0XS5jb2xvdXIuVHdpbmVTY3JpcHRfaXMobil9KX0sVHdpbmVTY3JpcHRfQ2xvbmU6ZnVuY3Rpb24oKXtyZXR1cm4gbi5jcmVhdGUodGhpcy5hbmdsZSxfdG9Db25zdW1hYmxlQXJyYXkodGhpcy5zdG9wcykpfSxUd2luZVNjcmlwdF9QcmludDpmdW5jdGlvbigpe3JldHVybiI8dHctY29sb3VyIHN0eWxlPSdiYWNrZ3JvdW5kOiIrdGhpcy50b0xpbmVhckdyYWRpZW50U3RyaW5nKCkrIic+PC90dy1jb2xvdXI+In0sY3JlYXRlOmZ1bmN0aW9uKGUsdCl7dmFyIG49Mjxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMl0mJmFyZ3VtZW50c1syXTtyZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKHRoaXMpLHthbmdsZTplLHN0b3BzOnQuc29ydChmdW5jdGlvbihlLHQpe3JldHVybiBlLnN0b3AtdC5zdG9wfSkscmVwZWF0aW5nOm59KX0sbXVsdGlwbHk6ZnVuY3Rpb24odCl7cmV0dXJuIG4uY3JlYXRlKHRoaXMuYW5nbGUsdGhpcy5zdG9wcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue2NvbG91cjplLmNvbG91cixzdG9wOmUuc3RvcCp0fX0pKX0sdG9MaW5lYXJHcmFkaWVudFN0cmluZzpmdW5jdGlvbigpe3ZhciByPXRoaXM7cmV0dXJuKHRoaXMucmVwZWF0aW5nPyJyZXBlYXRpbmctIjoiIikrImxpbmVhci1ncmFkaWVudCgiLmNvbmNhdCh0aGlzLmFuZ2xlLCJkZWcsICIpLmNvbmNhdCh0aGlzLnN0b3BzLnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuPXQuY29sb3VyLHQ9dC5zdG9wO3JldHVybiBlK24udG9SR0JBU3RyaW5nKCkrIiAiK3QqKHIucmVwZWF0aW5nPzE6MTAwKSsoci5yZXBlYXRpbmc/InB4LCI6IiUsIil9LCIiKS5zbGljZSgwLC0xKSwiKSIpfX0pO3JldHVybiBufSksZGVmaW5lKCJkYXRhdHlwZXMvaG9va3NldCIsWyJqcXVlcnkiLCJ1dGlscyIsInV0aWxzL3JlbmRlcnV0aWxzIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiXSxmdW5jdGlvbihnLHMsZSx0KXt2YXIgeT1lLnRleHROb2RlVG9DaGFycyxiPWUucmVhbFdoaXRlc3BhY2UsYz1lLmZpbmRUZXh0SW5Ob2RlcyxyPXQudG9Tb3VyY2U7ZnVuY3Rpb24gbChlKXtmdW5jdGlvbiB0KG4sZSl7aWYoQXJyYXkuaXNBcnJheShlKSlyZXR1cm4gZS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5hZGQobi5nZXQodCkpfSxnKCkpO2lmKGUmJiJvYmplY3QiPT09X3R5cGVvZihlKSYmImZpcnN0ImluIGUmJiJsYXN0ImluIGUpe2Zvcih2YXIgdD1lLmZpcnN0LHI9ZS5sYXN0LGE9bi5sZW5ndGgsbz0odDwwJiYodCs9YSkscjwwJiYocis9YSksW24uZ2V0KHQpXSk7dCE9PXI7KXQrPU1hdGguc2lnbihyLXQpLG8ucHVzaChuLmdldCh0KSk7cmV0dXJuIGcobyl9aWYoInN0cmluZyI9PXR5cGVvZiBlKXtpZigiY2hhcnMiPT09ZSl7dmFyIGkscz1bXSxjPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKG4udGV4dE5vZGVzKG0pKTt0cnl7Zm9yKGMucygpOyEoaT1jLm4oKSkuZG9uZTspe3ZhciBsLHU9aS52YWx1ZSxwPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKHkodSkpO3RyeXtmb3IocC5zKCk7IShsPXAubigpKS5kb25lOyl7dmFyIGQ9bC52YWx1ZTtkLnRleHRDb250ZW50Lm1hdGNoKGIpfHxzLnB1c2goZCl9fWNhdGNoKGUpe3AuZShlKX1maW5hbGx5e3AuZigpfX19Y2F0Y2goZSl7Yy5lKGUpfWZpbmFsbHl7Yy5mKCl9cmV0dXJuIGcocyl9aWYoImxpbmtzIj09PWUpcmV0dXJuIG4uZmluZEFuZEZpbHRlcigidHctbGluaywgLmVuY2hhbnRtZW50LWxpbmsiKTtpZigidmlzaXRlZCI9PT1lKXJldHVybiBuLmZpbmRBbmRGaWx0ZXIoInR3LWxpbmsudmlzaXRlZCIpO3ZhciBmLGg7aWYoImxpbmVzIj09PWUpcmV0dXJuIGY9bi5maW5kQW5kRmlsdGVyKCJicjpub3QodHctc2lkZWJhciAqKSx0dy1jb25zZWN1dGl2ZS1icjpub3QodHctc2lkZWJhciAqKSIpLmdldCgpLGg9W1tdXSxuLmNvbnRlbnRzKCkuZWFjaChmdW5jdGlvbiBlKHQsbil7dmFyIHI9KG4udGFnTmFtZXx8IiIpLnRvTG93ZXJDYXNlKCk7aWYoInR3LXNpZGViYXIiIT09cilpZigidHctcGFzc2FnZSI9PT1yfHwidHctdHJhbnNpdGlvbi1jb250YWluZXIiPT09cilnKG4pLmNvbnRlbnRzKCkuZWFjaChlKTtlbHNle2lmKGYubGVuZ3RoKXtpZihuPT09ZlswXSlyZXR1cm4gZi5zaGlmdCgpLHZvaWQgaC5wdXNoKFtdKTtpZigxNiZuLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKGZbMF0pKXJldHVybiBoLnB1c2goW10pLGcobikuY29udGVudHMoKS5lYWNoKGUpLHZvaWQgaC5wdXNoKFtdKX1oW2gubGVuZ3RoLTFdLnB1c2gobil9fSksZyhoLm1hcChmdW5jdGlvbihlKXtyZXR1cm4hIWUubGVuZ3RoJiZnKGUpLndyYXBBbGwoIjx0dy1wc2V1ZG8taG9vaz4iKS5wYXJlbnQoKVswXX0pLmZpbHRlcihCb29sZWFuKSl9cmV0dXJuIGcobi5nZXQoZSkpfXZhciBuLHIsYT1lLmRvbSxtPSI6bm90KHR3LWVycm9yLCB0dy1lcnJvciAqKSIsbz1nKCk7dGhpcy5uZXh0JiYobz1vLmFkZChsLmNhbGwodGhpcy5uZXh0LGUpKSk7aWYodGhpcy5zZWxlY3Rvcil7aWYoInN0cmluZyI9PT10aGlzLnNlbGVjdG9yLnR5cGUpaT10aGlzLnNlbGVjdG9yLmRhdGEsbj1jKChuPWEpLnRleHROb2RlcygpLGkpLHI9ZygpLG4uZm9yRWFjaChmdW5jdGlvbihlKXtyPXIuYWRkKGcoZSkud3JhcEFsbCgiPHR3LXBzZXVkby1ob29rPiIpLnBhcmVudCgpKX0pLGk9cjtlbHNle2lmKCJiYXNlIj09PXRoaXMuc2VsZWN0b3IudHlwZSlyZXR1cm4gby5hZGQodChsLmNhbGwodGhpcy5zZWxlY3Rvci5kYXRhLGUpLHRoaXMucHJvcGVydHkpKTtuPXRoaXMuc2VsZWN0b3IuZGF0YSxlPSd0dy1ob29rW25hbWU9IicrKG49cy5pbnNlbnNpdGl2ZU5hbWUobikucmVwbGFjZSgvIi9nLCImcXVvdDsiKSkrJyJdLHR3LWVuY2hhbnRtZW50W25hbWU9IicrbisnIl0nO3ZhciBlPWUrPXtwYWdlOiIsIHR3LXN0b3J5IixwYXNzYWdlOiIsIHR3LXBhc3NhZ2UiLHNpZGViYXI6IiwgdHctc2lkZWJhciIsbGluazoiLCB0dy1saW5rLCAuZW5jaGFudG1lbnQtbGluayJ9W25dfHwiIixpPWEuZmluZEFuZEZpbHRlcihlKS5hZGQoYS5wYXJlbnRzVW50aWwocy5zdG9yeUVsZW1lbnQucGFyZW50KCkpKS5maWx0ZXIoZSl9bz10aGlzLnByb3BlcnR5P28uYWRkKHQoaSx0aGlzLnByb3BlcnR5KSk6by5hZGQoaSl9cmV0dXJuIG89by5nZXQoKS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD1nKHQpLGUuYWRkKHQuaXMoInR3LWVuY2hhbnRtZW50IikmJnQuY29udGVudHMoKS5sZW5ndGg8PTE/dC5jb250ZW50cygpOnQpfSxnKCkpfWZ1bmN0aW9uIGEoZSl7dmFyIHQsbjtyZXR1cm4gZT8odD1lLnNlbGVjdG9yLG49ZS5wcm9wZXJ0eSxlPWUubmV4dCxbSlNPTi5zdHJpbmdpZnkoWyJiYXNlIj09PXQudHlwZT9hKHQuZGF0YSk6cy5pbnNlbnNpdGl2ZU5hbWUodC5kYXRhKSxuXSldLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoYShlKSkpLnNvcnQoKSk6W119dmFyIG89T2JqZWN0LmZyZWV6ZSh7Zm9yRWFjaDpmdW5jdGlvbihlLG4pe3ZhciB0PWwuY2FsbCh0aGlzLGUpLmVhY2goZnVuY3Rpb24oZSx0KXtyZXR1cm4gbihnKHQpLGUpfSk7cmV0dXJuIGUuZG9tLmZpbmRBbmRGaWx0ZXIoInR3LXBzZXVkby1ob29rIikuY29udGVudHMoKS51bndyYXAoKSx0fSxob29rczpmdW5jdGlvbihlKXtyZXR1cm4gbC5jYWxsKHRoaXMsZSl9LGdldCBUd2luZVNjcmlwdF9PYmplY3ROYW1lKCl7cmV0dXJuInRoZSBob29rIG5hbWUgIi5jb25jYXQodGhpcy5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpKX0sVHdpbmVTY3JpcHRfVHlwZUlEOiJob29rTmFtZSIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgaG9vayBuYW1lIChsaWtlID90aGlzKSIsVHdpbmVTY3JpcHRfVW5zdG9yYWJsZTohMCxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe3ZhciBlPSIiLHQ9dGhpcy5zZWxlY3RvcixuPXQudHlwZSx0PXQuZGF0YTtyZXR1cm4ibmFtZSI9PT1uP3QubWF0Y2goUmVnRXhwKCJeIitzLmFueVJlYWxMZXR0ZXIrIiskIikpP2UrPSI/Iit0OmUrPSIoaG9va3MtbmFtZWQ6IitKU09OLnN0cmluZ2lmeSh0KSsiKSI6InN0cmluZyI9PT1uP2UrPUpTT04uc3RyaW5naWZ5KHQpOiJiYXNlIj09PW4mJihlKz10LlR3aW5lU2NyaXB0X1RvU291cmNlKCkrIidzICIrcih0aGlzLnByb3BlcnR5LCJwcm9wZXJ0eSIpKSx0aGlzLm5leHQmJihlKz0iICsgIit0aGlzLm5leHQuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKSksZX0sIlR3aW5lU2NyaXB0XysiOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLlR3aW5lU2NyaXB0X0Nsb25lKCksbj10O24ubmV4dDspbj1uLm5leHQ7cmV0dXJuIG4ubmV4dD1lLHR9LFR3aW5lU2NyaXB0X2lzOmZ1bmN0aW9uKGUpe3JldHVybiBhKHRoaXMpKyIiPT1hKGUpKyIifSxUd2luZVNjcmlwdF9HZXRQcm9wZXJ0eTpmdW5jdGlvbihlKXtyZXR1cm4gby5jcmVhdGUoe3R5cGU6ImJhc2UiLGRhdGE6dGhpc30sZSx2b2lkIDApfSxUd2luZVNjcmlwdF9Qcm9wZXJ0aWVzOlsiY2hhcnMiLCJsaW5rcyIsImxpbmVzIiwidmlzaXRlZCJdLFR3aW5lU2NyaXB0X0Nsb25lOmZ1bmN0aW9uKCl7cmV0dXJuIG8uY3JlYXRlKHRoaXMuc2VsZWN0b3IsdGhpcy5wcm9wZXJ0eSx0aGlzLm5leHQpfSxjcmVhdGU6ZnVuY3Rpb24oZSx0KXt2YXIgbj0yPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06dm9pZCAwO3JldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUodGhpc3x8bykse3NlbGVjdG9yOk9iamVjdC5mcmVlemUoZSkscHJvcGVydHk6dCxuZXh0Om59KX0sZnJvbTpmdW5jdGlvbihlKXtyZXR1cm4gby5pc1Byb3RvdHlwZU9mKGUpfHwic3RyaW5nIj09dHlwZW9mIGV8fHMuaW1wb3NzaWJsZSgiSG9va1NldC5mcm9tKCkgd2FzIGdpdmVuIGEgbm9uLUhvb2tTZXQgbm9uLXN0cmluZy4iKSxvLmlzUHJvdG90eXBlT2YoZSk/ZTpvLmNyZWF0ZSh7dHlwZToic3RyaW5nIixkYXRhOmV9KX19KTtyZXR1cm4gb30pLGRlZmluZSgiZGF0YXR5cGVzL2xhbWJkYSIsWyJ1dGlscy9vcGVyYXRpb251dGlscyIsImludGVybmFsdHlwZXMvdmFyc2NvcGUiLCJpbnRlcm5hbHR5cGVzL3ZhcnJlZiIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGUsaCxzLG0pe3ZhciBnPWUub2JqZWN0TmFtZTt2YXIgYz1PYmplY3QuZnJlZXplKHtUd2luZVNjcmlwdF9UeXBlSUQ6ImxhbWJkYSIsVHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgbGFtYmRhIixnZXQgVHdpbmVTY3JpcHRfT2JqZWN0TmFtZSgpe3JldHVybidhICInKygibWFraW5nImluIHRoaXM/Im1ha2luZyAuLi4gIjoiIikrKCJlYWNoImluIHRoaXM/ImVhY2ggLi4uICI6IiIpKygid2hlcmUiaW4gdGhpcz8id2hlcmUgLi4uICI6IiIpKygid2hlbiJpbiB0aGlzPyJ3aGVuIC4uLiAiOiIiKSsoInZpYSJpbiB0aGlzPyJ2aWEgLi4uICI6IiIpKyciIGxhbWJkYSd9LFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuImBbQSBsYW1iZGFdYCJ9LFR3aW5lU2NyaXB0X2lzOmZ1bmN0aW9uKGUpe3JldHVybiBlPT09dGhpc30sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zb3VyY2V9LFR5cGVTaWduYXR1cmU6ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm57cGF0dGVybjoibGFtYmRhIixpbm5lclR5cGU6YyxjbGF1c2VzOnQsdHlwZU5hbWU6J2EgIicrdC5jb25jYXQoIiIpLmpvaW4oIiAuLi4iKSsnIiBsYW1iZGEnfX0sVHdpbmVTY3JpcHRfQ2xvbmU6ZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKGMpLHRoaXMpfSxjcmVhdGU6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGEsbz0idGVtcCB2YXJpYWJsZSwgb3IgdHlwZWQgdGVtcCB2YXJpYWJsZSI7ZnVuY3Rpb24gaShlKXtlPWUmJmUudmFyUmVmP2UudmFyUmVmOmU7cmV0dXJuIHZvaWQgMD09PWV8fGUmJnMuaXNQcm90b3R5cGVPZihlKSYmaC5pc1Byb3RvdHlwZU9mKGUub2JqZWN0KSYmMT09PWUucHJvcGVydHlDaGFpbi5sZW5ndGh9aWYobS5jb250YWluc0Vycm9yKG4pKXJldHVybiBuO2lmKCJtYWtpbmciPT09dCYmIWkobikpcmV0dXJuIG0uY3JlYXRlKCJzeW50YXgiLCJJIG5lZWQgYSAiK28rIiwgdG8gdGhlIHJpZ2h0IG9mICciK3QrIicsIG5vdCAiK2cobikrIi4iKTtpZihtLmNvbnRhaW5zRXJyb3IoZSkpcmV0dXJuIGU7aWYoYy5pc1Byb3RvdHlwZU9mKGUpKXtpZigid2hlbiI9PT10fHwid2hlbiJpbiBlKXJldHVybiBtLmNyZWF0ZSgic3ludGF4IiwiQSAnd2hlbicgbGFtYmRhIGNhbm5vdCBoYXZlIGFueSBvdGhlciBjbGF1c2VzLCBzdWNoIGFzICciK3QrIicuIik7aWYodCBpbiBlKXJldHVybiBtLmNyZWF0ZSgic3ludGF4IiwiVGhpcyBsYW1iZGEgaGFzIHR3byAnIit0KyInIGNsYXVzZXMuIik7YT1lfWVsc2V7aWYoIndoZW4iPT09dCYmdm9pZCAwIT09ZSlyZXR1cm4gbS5jcmVhdGUoInN5bnRheCIsIkEgJ3doZW4nIGxhbWJkYSBzaG91bGRuJ3QgYmVnaW4gd2l0aCBhIHRlbXAgdmFyaWFibGUgKGp1c3QgdXNlICd3aGVuJyBmb2xsb3dlZCBieSB0aGUgY29uZGl0aW9uKS4iKTtpZighaShlKSlyZXR1cm4gbS5jcmVhdGUoInN5bnRheCIsIlRoaXMgbGFtYmRhIG5lZWRzIHRvIHN0YXJ0IHdpdGggYSBzaW5nbGUgIitvKyIsIG5vdCAiK2coZSkrIi4iKTsoYT1PYmplY3QuY3JlYXRlKHRoaXMpKS5sb29wPWV8fCIifXJldHVybiBhLnNvdXJjZT1yLnRyaW0oKSxhW3RdPW4sYS5tYWtpbmcmJmEubWFraW5nLmdldE5hbWUoKT09PShhLmxvb3AmJmEubG9vcC5nZXROYW1lKCkpP20uY3JlYXRlKCJzeW50YXgiLCJUaGlzIGxhbWJkYSBoYXMgdHdvIHZhcmlhYmxlcyBuYW1lZCAnIithLmxvb3AuZ2V0TmFtZSgpKyInLiIsIkxhbWJkYXMgc2hvdWxkIGhhdmUgYWxsLXVuaXF1ZSBwYXJhbWV0ZXIgbmFtZXMuIik6YX0sYXBwbHk6ZnVuY3Rpb24oZSx0KXt2YXIgbj10Lmxvb3Ascj10LnBvcyxhPXQubWFraW5nLG89dC5pZ25vcmVWaWE7ZnVuY3Rpb24gaShlLHQpe2lmKGUpe3ZhciBuLHI7aWYoImRhdGF0eXBlImluIGUmJiJ2YXJSZWYiaW4gZSlyZXR1cm4gbj1lLnZhclJlZi5jcmVhdGUocyxlLnZhclJlZi5wcm9wZXJ0eUNoYWluKSxtLmNvbnRhaW5zRXJyb3Iobik/bjoocj1uLmRlZmluZVR5cGUoZS5kYXRhdHlwZSksbS5jb250YWluc0Vycm9yKHIpfHwocj1uLnNldCh0KSxtLmNvbnRhaW5zRXJyb3IocikpP3I6dm9pZCAwKTtzW2UuZ2V0TmFtZSgpXT10fX12YXIgcz0ocz10LnRlbXBWYXJpYWJsZXMpfHxPYmplY3QuY3JlYXRlKGUuc3RhY2subGVuZ3RoP2Uuc3RhY2tUb3AudGVtcFZhcmlhYmxlczpoKSx0PWkodGhpcy5sb29wLG4pfHxpKHRoaXMubWFraW5nLGEpO2lmKG0uY29udGFpbnNFcnJvcih0KSlyZXR1cm4gdDtlLnN0YWNrLnVuc2hpZnQoT2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKGUuc3RhY2tUb3B8fG51bGwpLHt0ZW1wVmFyaWFibGVzOnMsbGFtYmRhUG9zOnRoaXMud2hlbj92b2lkIDA6cn0pKSwhbnx8dGhpcy5tYWtpbmd8fHRoaXMud2hlbj9lLklkZW50aWZpZXJzLml0PW0uY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IHVzZSAnaXQnLCBvciBhbiBpbXBsaWVkICdpdCcsIGluICIrdGhpcy5Ud2luZVNjcmlwdF9PYmplY3ROYW1lKTplLklkZW50aWZpZXJzLml0PW47dmFyIGMsbCx1LHAsZCx0PSFvJiZ0aGlzLnZpYSxvPSJ3aGVyZSJpbiB0aGlzfHwid2hlbiJpbiB0aGlzLGY9ZS5ldmFsUmVwbGF5O3JldHVybiBlLmV2YWxSZXBsYXk9Zj9bXTpudWxsLG8/KGM9ZS5ldmFsKHRoaXMud2hlcmV8fHRoaXMud2hlbiksbD1lLmV2YWxSZXBsYXksZS5ldmFsUmVwbGF5PWwmJnQ/W106bnVsbCwhbnx8dGhpcy5tYWtpbmd8fHRoaXMud2hlbnx8KGUuSWRlbnRpZmllcnMuaXQ9biksdT1jLHA9IXR8fGUuZXZhbCh0KSxkPW51bGwsdT1tLmNvbnRhaW5zRXJyb3IodSl8fCgiYm9vbGVhbiIhPXR5cGVvZiB1P20uY3JlYXRlKCJvcGVyYXRpb24iLCJUaGlzIGxhbWJkYSdzICd3aGVyZScgY2xhdXNlIG11c3QgZXZhbHVhdGUgdG8gdHJ1ZSBvciBmYWxzZSwgbm90ICIrZyh1KSsiLiIpOnU/cDpkKSk6Yz11PSF0fHxlLmV2YWwodCkscD10P2UuZXZhbFJlcGxheTpudWxsLGUuc3RhY2suc2hpZnQoKSwoZS5ldmFsUmVwbGF5PWYpJiYob3x8dCkmJigoKGQ9ZltmLmxlbmd0aC0xXSl8fHt9KS5sYW1iZGEmJmQubGFtYmRhLm9iaj09PXRoaXN8fCgoZD17bGFtYmRhOntvYmo6dGhpcyxsb29wczpbXX0sY29kZTooZltmLmxlbmd0aC0xXXx8e30pLmNvZGV8fCIifSkuZnJvbUNvZGU9ZC5jb2RlLGYucHVzaChkKSksZC5sYW1iZGEubG9vcHMucHVzaChfb2JqZWN0U3ByZWFkKF9vYmplY3RTcHJlYWQoX29iamVjdFNwcmVhZCh7aXQ6bixwb3M6cn0sdm9pZCAwIT09YSYme21ha2luZzphfSksdCYme3ZpYVJlcGxheTpwLHZpYVJlc3VsdDp1fSksbyYme3doZXJlUmVwbGF5Omwsd2hlcmVSZXN1bHQ6bnVsbCE9PWMmJmN9KSkpLHV9LGZpbHRlcjpmdW5jdGlvbihyLGUpe3ZhciBhLG89dGhpcyxpPTI8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTpudWxsO3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihlLHQsbil7cmV0dXJuIGF8fChuPW8uYXBwbHkocix7bG9vcDp0LHBvczpuKzEsaWdub3JlVmlhOiEwLHRlbXBWYXJpYWJsZXM6aX0pLGE9bS5jb250YWluc0Vycm9yKG4pKXx8ZS5jb25jYXQobj9bdF06W10pfSxbXSl9fSk7cmV0dXJuIGN9KSxkZWZpbmUoImRhdGF0eXBlcy90eXBlZHZhciIsWyJ1dGlscy9vcGVyYXRpb251dGlscyIsImludGVybmFsdHlwZXMvdmFycmVmIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oZSxhLG8pe3ZhciBpPWUudHlwZU5hbWUsdD1lLm1hdGNoZXMsbj1lLnRvU291cmNlLHM9ZS51bnN0b3JhYmxlVmFsdWUsZT1PYmplY3QuZnJlZXplLGM9T2JqZWN0LmFzc2lnbixsPU9iamVjdC5jcmVhdGUsdT1lKHtUd2luZVNjcmlwdF9UeXBlTmFtZToiYSBUeXBlZFZhciAodHlwZWQgdmFyaWFibGUgbmFtZSkiLGdldCBUd2luZVNjcmlwdF9PYmplY3ROYW1lKCl7dmFyIGU9bih0aGlzLmRhdGF0eXBlKTtyZXR1cm4idGhlICIuY29uY2F0KGUubGVuZ3RoPDI0P2UrIi0iOiIiLCJ0eXBlZCB2YXJpYWJsZSBuYW1lLCAiKS5jb25jYXQodGhpcy52YXJSZWYuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKSl9LFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuImBbQSB0eXBlZCB2YXJpYWJsZSBuYW1lXWAifSxUd2luZVNjcmlwdF9VbnN0b3JhYmxlOiEwLFR3aW5lU2NyaXB0X0Nsb25lOmZ1bmN0aW9uKCl7cmV0dXJuIGMobCh1KSx7ZGF0YXR5cGU6dGhpcy5kYXRhdHlwZS5Ud2luZVNjcmlwdF9DbG9uZSgpLHZhclJlZjp0aGlzLnZhclJlZn0pfSxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe3JldHVybiBuKHRoaXMuZGF0YXR5cGUpKyItdHlwZSAiK3RoaXMudmFyUmVmLlR3aW5lU2NyaXB0X1RvU291cmNlKCl9LFR3aW5lU2NyaXB0X0dldFByb3BlcnR5OmZ1bmN0aW9uKGUpe3JldHVybiJuYW1lIj09PWU/dGhpcy5nZXROYW1lKCk6dGhpc1tlXX0sVHdpbmVTY3JpcHRfUHJvcGVydGllczpbImRhdGF0eXBlIiwibmFtZSJdLFR3aW5lU2NyaXB0X0lzVHlwZU9mOmZ1bmN0aW9uKGUpe3JldHVybiB0KHRoaXMuZGF0YXR5cGUsZSl9LGdldDpmdW5jdGlvbigpe3ZhciBlO3JldHVybihlPXRoaXMudmFyUmVmKS5nZXQuYXBwbHkoZSxhcmd1bWVudHMpfSxnZXROYW1lOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmFyUmVmLmdldE5hbWUoKX0sZGVmaW5lVHlwZTpmdW5jdGlvbigpe2lmKCJhbnkiIT09dGhpcy5kYXRhdHlwZS5uYW1lKXJldHVybiB0aGlzLnZhclJlZi5kZWZpbmVUeXBlKHRoaXMuZGF0YXR5cGUpfSxjcmVhdGU6ZnVuY3Rpb24oZSx0KXt2YXIgbixyO3JldHVybihuPW8uY29udGFpbnNFcnJvcih0KXx8by5jb250YWluc0Vycm9yKGUpfHx0LmVycm9yKXx8KGEuaXNQcm90b3R5cGVPZih0KT8obj10Lm9iamVjdCxyPXQuY29tcGlsZWRQcm9wZXJ0eUNoYWluLG4mJm4uVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSYmMT09PXIubGVuZ3RoJiZuLlR3aW5lU2NyaXB0X1R5cGVEZWZzPyhyPXMoZSkpJiYhdS5pc1Byb3RvdHlwZU9mKHIpP28uY3JlYXRlKCJzeW50YXgiLCJUaGUgLXR5cGUgc3ludGF4IGNhbid0IGhhdmUgIitpKHIpKyIgdG8gaXRzIGxlZnQuIik6YyhsKHRoaXMpLHtkYXRhdHlwZTplLHZhclJlZjp0fSk6by5jcmVhdGUoInVuaW1wbGVtZW50ZWQiLCJJIGNhbiBvbmx5IHJlc3RyaWN0IHRoZSBkYXRhdHlwZXMgb2YgdmFyaWFibGVzLCBub3QgZGF0YSBuYW1lcyBvciBhbnl0aGluZyBlbHNlLiIpKTpvLmNyZWF0ZSgic3ludGF4IiwiVGhlIC10eXBlIHN5bnRheCBtdXN0IGhhdmUgYSB2YXJpYWJsZSB0byBpdHMgcmlnaHQuIikpfX0pO3JldHVybiB1fSksZGVmaW5lKCJkYXRhdHlwZXMvdmFyYmluZCIsWyJqcXVlcnkiLCJ1dGlscyIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiaW50ZXJuYWx0eXBlcy92YXJyZWYiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiXSxmdW5jdGlvbihvLGUsdCxuLHIpe3ZhciBhPXQub2JqZWN0TmFtZTtyZXR1cm4gbi5vbigic2V0IixmdW5jdGlvbihyLGEpe3IuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSYmZS5zdG9yeUVsZW1lbnQuZmluZCgiW2RhdGEtMmJpbmRdIikuZWFjaChmdW5jdGlvbihlLHQpe3ZhciBuPSh0PW8odCkpLmRhdGEoInR3b1dheUJpbmRFdmVudCIpOyJmdW5jdGlvbiI9PXR5cGVvZiBuJiZuKHQscixhKX0pfSksT2JqZWN0LmZyZWV6ZSh7VHdpbmVTY3JpcHRfVHlwZU5hbWU6ImEgVmFyQmluZCAoYm91bmQgdmFyaWFibGUgbmFtZSkiLGdldCBUd2luZVNjcmlwdF9PYmplY3ROYW1lKCl7cmV0dXJuImEgIi5jb25jYXQodGhpcy5iaW5kLCIgYmluZCB0byAiKS5jb25jYXQodGhpcy52YXJSZWYuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKSl9LFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuImBbQSBib3VuZCB2YXJpYWJsZSBuYW1lXWAifSxUd2luZVNjcmlwdF9VbnN0b3JhYmxlOiEwLFR3aW5lU2NyaXB0X1RvU291cmNlOmZ1bmN0aW9uKCl7cmV0dXJuKCJ0d28gd2F5Ij09PXRoaXMuYmluZD8iMiI6IiIpKyJiaW5kICIrdGhpcy52YXJSZWYuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKX0sc2V0OmZ1bmN0aW9uKGUpe3ZhciBlPXRoaXMudmFyUmVmLnNldChlKTtpZihlPXIuY29udGFpbnNFcnJvcihlKSlyZXR1cm4gZX0sY3JlYXRlOmZ1bmN0aW9uKGUpe3ZhciB0PTE8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXToib25lIHdheSI7cmV0dXJuIHIuY29udGFpbnNFcnJvcihlKT9lOm4uaXNQcm90b3R5cGVPZihlKT9lLmVycm9yfHxPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUodGhpcykse3ZhclJlZjplLGJpbmQ6dH0pOnIuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbiBvbmx5ICdiaW5kJyBhIHZhcmlhYmxlLCBub3QgIithKGUpKyIuIil9fSl9KSxkZWZpbmUoImRlYnVnbW9kZS9oaWdobGlnaHQiLFsianF1ZXJ5IiwidXRpbHMiLCJ1dGlscy90eXBlY29sb3VycyIsIm1hY3JvcyIsImxleGVyIl0sZnVuY3Rpb24odSxlLHQscCxuKXt2YXIgZD1lLmluc2Vuc2l0aXZlTmFtZSxmPXQudmVyc2lvbkNsYXNzLGg9bi5sZXg7cmV0dXJuIGZ1bmN0aW9uKGUsdCxuLHIpe2lmKDk5OTk8ZS5sZW5ndGgpcmV0dXJuW3UoIjxzcGFuPiIpLnRleHQoZSldO2Zvcih2YXIgYT1oKGUsIiIsdHx8Im1hY3JvIiksbz1bXSxpPSIiLHM9YSxjPWEuc3RhcnQ7YzxhLmVuZDtjKz0xKXt2YXIgbD1hLnBhdGhBdChjKTtsWzBdIT09c1swXSYmKG8ubGVuZ3RoJiYob1tvLmxlbmd0aC0xXS50ZXh0Q29udGVudD1pKSxpPSIiLHM9bCxvLnB1c2godSgiPCIuY29uY2F0KHImJm48PWMmJmM8cj8ibWFyayI6InNwYW4iLCcgY2xhc3M9IicpLmNvbmNhdChmdW5jdGlvbihlKXtmb3IodmFyIHQ9e30sbj0iIixyPTA7cjxlLmxlbmd0aDtyKz0xKXt2YXIgYT1lW3JdLG89YS50eXBlLGk9YS50ZXh0LHM9KCJ2ZXJiYXRpbSIhPT1vJiYiY29tbWVudCIhPT1vfHwobj0iIiksZitvKTtzd2l0Y2godFtzXT0odFtzXXx8MCkrMSwxPHRbc10mJihzKz0iLSIrdFtzXSksbyl7Y2FzZSJ0ZXh0IjppLnRyaW0oKSYmZS5zbGljZShyKzEpLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiB2b2lkIDA9PT1lPyJtYWNybyI9PT10LnR5cGV8fCJob29rIiE9PXQudHlwZSYmZTplfSx2b2lkIDApJiYocys9IiAiLmNvbmNhdChmLCJlcnJvciIpKTticmVhaztjYXNlIm1hY3JvTmFtZSI6dmFyIGMsbD1lW3JdLnRleHRbMF07Il8iIT09bCYmIiQiIT09bD8oYz1kKGVbcl0udGV4dC5zbGljZSgwLC0xKSkscC5oYXMoYyk/cys9Ii0iK3AuZ2V0KGMpLnJldHVyblR5cGUudG9Mb3dlckNhc2UoKTpzKz0iICIuY29uY2F0KGYsImVycm9yIikpOnMrPSIgIi5jb25jYXQoZiwiY3VzdG9tTWFjcm8gIikuY29uY2F0KGYrKCJfIj09PWw/InRlbXBWIjoidiIpLCJhcmlhYmxlIil9bis9cysiICJ9cmV0dXJuIG59KHMpLCciPicpKVswXSkpLGkrPWEudGV4dFtjLWEuc3RhcnRdfXJldHVybiBvLmxlbmd0aCYmKG9bby5sZW5ndGgtMV0udGV4dENvbnRlbnQ9aSksb319KSxkZWZpbmUoImRlYnVnbW9kZS9tb2RlIixbImpxdWVyeSIsInV0aWxzIiwidXRpbHMvbmF0dXJhbHNvcnQiLCJzdGF0ZSIsImVuZ2luZSIsImludGVybmFsdHlwZXMvdmFycmVmIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJ1dGlscy9yZW5kZXJ1dGlscyIsInBhc3NhZ2VzIiwic2VjdGlvbiIsImRlYnVnbW9kZS9wYW5lbCIsImRlYnVnbW9kZS9oaWdobGlnaHQiLCJ1dGlscy90eXBlY29sb3VycyJdLGZ1bmN0aW9uKEksVixNLEQsRixMLEgsZSx0LHoscSxXLEIsbil7dmFyIFU9ZS5vYmplY3ROYW1lLCQ9ZS5pc09iamVjdCxHPWUudG9Tb3VyY2UsWT1lLnR5cGVJRCxKPXQuZGlhbG9nLFg9bi5DU1MsSz1mdW5jdGlvbihlLHQpe3ZhciBmPVYuZXNjYXBlLGk9Vi5udGgsbj1WLmRlYm91bmNlLHI9SShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpLGE9TSgpLG89e2RhcmtNb2RlOiEwLGZhZGVQYW5lbDohMCxldmFsUmVwbGF5OiEwLHdpZHRoOm51bGwsbWF4SGVpZ2h0OjQwMH07aWYoRC5oYXNTdG9yYWdlKXRyeXt2YXIgcz1sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgiKERlYnVnIE9wdGlvbnMgIitWLm9wdGlvbnMuaWZpZCsiKSIpO3MmJihvPUpTT04ucGFyc2UocykpfWNhdGNoKGUpe31mdW5jdGlvbiBjKCl7aWYoRC5oYXNTdG9yYWdlKXRyeXtsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgiKERlYnVnIE9wdGlvbnMgIitWLm9wdGlvbnMuaWZpZCsiKSIsSlNPTi5zdHJpbmdpZnkobykpfWNhdGNoKGUpe319Vy5kZWZhdWx0TWF4SGVpZ2h0PW8ubWF4SGVpZ2h0O2Z1bmN0aW9uIGwoZSl7cmV0dXJuIG4oZnVuY3Rpb24oKXtpZihWLm9wdGlvbnMuZGVidWcpcmV0dXJuIGUuYXBwbHkodGhpcyxhcmd1bWVudHMpfSx7bWF4V2FpdDoyZTN9KX12YXIgaD1JKCc8dHctZGVidWdnZXIgY2xhc3M9IicuY29uY2F0KFtvLmRhcmtNb2RlPyJ0aGVtZS1kYXJrIjoiIixvLmZhZGVQYW5lbD8iZmFkZS1wYW5lbCI6IiJdLmpvaW4oIiAiKSwnIiBzdHlsZT0iJykuY29uY2F0KG8ud2lkdGg/IndpZHRoOiIrby53aWR0aCsicHgiOiIiLCJcIj5cbjxkaXYgY2xhc3M9J3BhbmVsIHBhbmVsLWVycm9ycycgaGlkZGVuPjx0YWJsZT48L3RhYmxlPjwvZGl2PlxuPGRpdiBjbGFzcz0ndGFicyc+PC9kaXY+XG48bGFiZWwgc3R5bGU9J3VzZXItc2VsZWN0Om5vbmUnPlR1cm5zOiA8L2xhYmVsPjxzZWxlY3QgY2xhc3M9J3R1cm5zJyBkaXNhYmxlZD48L3NlbGVjdD5cbjxidXR0b24gY2xhc3M9J3Nob3ctaW52aXNpYmxlcyc+XHVkODNkXHVkZDBkIERlYnVnIFZpZXc8L2J1dHRvbj5cbjxidXR0b24gY2xhc3M9J3Nob3ctZG9tJz48c3BhbiBzdHlsZT1cInZlcnRpY2FsLWFsaWduOnRleHQtdG9wXCI+Jmx0Ozwvc3Bhbj48c3BhbiBzdHlsZT1cInZlcnRpY2FsLWFsaWduOnRleHQtYm90dG9tXCI+Jmd0Ozwvc3Bhbj4gRE9NIFZpZXc8L2J1dHRvbj5cbjxidXR0b24gY2xhc3M9J2Nsb3NlJz5cdTI3MTY8L2J1dHRvbj5cbjxkaXYgY2xhc3M9J3Jlc2l6ZXItaCc+XG48L3R3LWRlYnVnZ2VyPiIpKSxzPWguZmluZCgiLnRhYnMiKSx1PWguZmluZCgiLnNob3ctZG9tIikscD1oLmZpbmQoIi5zaG93LWludmlzaWJsZXMiKSxkPWguZmluZCgiLmNsb3NlIiksbT1oLmZpbmQoIi50dXJucyIpO0koZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KS5vbigiY2xpY2siLCJ0dy1leHByZXNzaW9uLCB0dy1lcnJvciwgdHctZXZhbC1leHBsYW5hdGlvbiIsbihmdW5jdGlvbihlKXt2YXIgcixhLG8saSxsLHUscCxkLHQ9SShlLnRhcmdldCkuZGF0YSgiZXZhbFJlcGxheSIpO2Z1bmN0aW9uIG4oKXt2YXIgZSxzLGM9clthXSx0PW8uZmluZCgidHctZXZhbC1leHBsYW5hdGlvbiIpLmVtcHR5KCksbj1vLmZpbmQoInR3LWV2YWwtY29kZSIpO2MudG9Db2RlfHxjLnRvRGVzY3x8Yy5lcnJvcnx8Yy5sYW1iZGE/KG8uZmluZCgidHctZXZhbC1jb2RlIikuZW1wdHkoKS5hcHBlbmQoQihjLmNvZGUsIm1hY3JvIiwwPGEmJmMuc3RhcnQsMDxhJiZjLmVuZCtjLmRpZmYpKSx0LmFwcGVuZChjLmxhbWJkYT8iIjoiPGNvZGUgY2xhc3M9JyIuY29uY2F0KDU2PGMuZnJvbUNvZGUubGVuZ3RoPyJmcm9tLWJsb2NrIjoiZnJvbS1pbmxpbmUiLCInPjwvY29kZT4iKSxjLmVycm9yPyI8c3Bhbj4gY2F1c2VkIGFuIGVycm9yOiA8L3NwYW4+IjpjLmxhbWJkYT8iPHNwYW4+VGhlIGxhbWJkYSA8Y29kZSBjbGFzcz0ndG8tbGFtYmRhJz48L2NvZGU+IHdhcyBydW4sIHByb2R1Y2luZyB0aGVzZSByZXN1bHRzLjwvc3Bhbj4iOiI8c3Bhbj4gYmVjYW1lIi5jb25jYXQoYy5Ub0Rlc2M/Ilx1MjAyNiI6IiIsIiA8L3NwYW4+IikuY29uY2F0KGMudG9EZXNjPyI8c3BhbiBjbGFzcz0ndG8tZGVzYyc+Ii5jb25jYXQoZihjLnRvRGVzYyksIi48L3NwYW4+Iik6Ijxjb2RlIGNsYXNzPSd0by1jb2RlJz48L2NvZGU+IikpLGMuZXJyb3I/dC5hcHBlbmQoYy5lcnJvcik6Yy5sYW1iZGE/KHM9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gSSgiPCIuY29uY2F0KGUsIj48Y29kZT48LyIpLmNvbmNhdChlLCI+IikpLmZpbmQoImNvZGUiKS5hcHBlbmQoQih0LCJtYWNybyIpKS5lbmQoKX0sdC5maW5kKCIudG8tbGFtYmRhIikuYXBwZW5kKEIoYy5sYW1iZGEub2JqLnNvdXJjZSwibWFjcm8iKSkuZW5kKCkuYXBwZW5kKChlPUkoIjx0YWJsZT4iKSkuYXBwZW5kLmFwcGx5KGUsW0koIjx0cj4iKS5hcHBlbmQocygidGgiLCJwb3MiKSxjLmxhbWJkYS5vYmoubG9vcD9zKCJ0aCIsIl8iK2MubGFtYmRhLm9iai5sb29wLmdldE5hbWUoKSkuYXBwZW5kKCIgLyAiLEkoIjxjb2RlPiIpLmFwcGVuZChCKCJpdCIsIm1hY3JvIikpKTpzKCJ0aCIsIml0IiksYy5sYW1iZGEub2JqLm1ha2luZyYmcygidGgiLCJfIitjLmxhbWJkYS5vYmoubWFraW5nLmdldE5hbWUoKSksYy5sYW1iZGEub2JqLndoZXJlJiZzKCJ0aCIsIndoZXJlIikuYXBwZW5kKCIgcmVzdWx0IiksYy5sYW1iZGEub2JqLnZpYSYmcygidGgiLCJ2aWEiKS5hcHBlbmQoIiByZXN1bHQiKSldLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoYy5sYW1iZGEubG9vcHMubWFwKGZ1bmN0aW9uKGUpe3ZhciB0PWUuaXQsbj1lLnBvcyxyPWUubWFraW5nLGE9ZS53aGVyZVJlc3VsdCxvPWUud2hlcmVSZXBsYXksaT1lLnZpYVJlc3VsdCxlPWUudmlhUmVwbGF5O3JldHVybiBJKCI8dHI+IikuYXBwZW5kKHMoInRkIixHKG4pKSxzKCJ0ZCIsRyh0KSksdm9pZCAwIT09ciYmcygidGQiLEcocikpLG51bGwhPWEmJihILmNvbnRhaW5zRXJyb3IoYSk/SSgiPHRkPiIpLmFwcGVuZChhLnJlbmRlcihjLmxhbWJkYS5vYmouc291cmNlLCEwKSk6cygidGQiLEcoYSkpKS5hcHBlbmQobyYmSSgiPHR3LW9wZW4tYnV0dG9uIHJlcGxheSBsYWJlbD0nXHVkODNkXHVkZDBkJz4iKS5kYXRhKCJldmFsUmVwbGF5IixvKSksbnVsbCE9aSYmKEguY29udGFpbnNFcnJvcihpKT9JKCI8dGQ+IikuYXBwZW5kKGkucmVuZGVyKGMubGFtYmRhLm9iai5zb3VyY2UsITApKTpzKCJ0ZCIsRyhpKSkpLmFwcGVuZChlJiZJKCI8dHctb3Blbi1idXR0b24gcmVwbGF5IGxhYmVsPSdcdWQ4M2RcdWRkMGQnPiIpLmRhdGEoImV2YWxSZXBsYXkiLGUpKSl9KSkpKSkpOmMudG9EZXNjfHx0LmZpbmQoIi50by1jb2RlIikuYXBwZW5kKEIoYy50b0NvZGUsIm1hY3JvIikpLHQubmV4dCgpLmh0bWwoYy5pdElkZW50aWZpZXI/JyhUaGUgPGNvZGUgY2xhc3M9ImNtLWhhcmxvd2UtMy1pZGVudGlmaWVyIj5pdDwvY29kZT4gaWRlbnRpZmllciBub3cgcmVmZXJzIHRvICcuY29uY2F0KGYoYy5pdElkZW50aWZpZXIpLCIuKSIpOiIiKS5uZXh0KCkudGV4dChjLnJlYXNvbnx8IiIpKToobi5odG1sKEIoYy5jb2RlLCJtYWNybyIpKSx0Lmh0bWwoIjxjZW50ZXI+Rmlyc3QsIHRoZXJlIHdhcyA8Y29kZT48L2NvZGU+LjwvY2VudGVyPiIpLm5leHQoKS5lbXB0eSgpLm5leHQoKS5lbXB0eSgpKSxjLmxhbWJkYXx8dC5maW5kKCJjb2RlIikuZmlyc3QoKS5hcHBlbmQoQihjLmZyb21Db2RlLCJtYWNybyIpKSxvLmZpbmQoIm1hcmsiKS5lYWNoKGZ1bmN0aW9uKGUsdCl7dC5zY3JvbGxJbnRvVmlldygpfSksaS5jc3MoInZpc2liaWxpdHkiLGE8PTk/ImhpZGRlbiI6InZpc2libGUiKSxsLmNzcygidmlzaWJpbGl0eSIsYTw9MD8iaGlkZGVuIjoidmlzaWJsZSIpLHAuY3NzKCJ2aXNpYmlsaXR5IixhPj1yLmxlbmd0aC0xPyJoaWRkZW4iOiJ2aXNpYmxlIiksZC5jc3MoInZpc2liaWxpdHkiLGE+PXIubGVuZ3RoLTEwPyJoaWRkZW4iOiJ2aXNpYmxlIiksdS5odG1sKCIoICIuY29uY2F0KGErMSwiLyIpLmNvbmNhdChyLmxlbmd0aCwiICkiKSl9dCYmKHI9dCx0PUooe2J1dHRvbnM6W3tuYW1lOiJVbmRlcnN0b29kIixjb25maXJtOiEoYT0wKSxjYWxsYmFjazpmdW5jdGlvbigpe3JldHVybiFoLmZpbmQoInR3LWJhY2tkcm9wIikubGVuZ3RoJiZoLnJlbW92ZUNsYXNzKCJzaG93LWRpYWxvZyIpfX1dfSkuYWRkQ2xhc3MoImV2YWwtcmVwbGF5Iiksbz1JKCI8dHctZXZhbC1yZXBsYXk+Ii5jb25jYXQoMT09PXIubGVuZ3RoPyIiOiI8dHctZXZhbC1jb2RlPjwvdHctZXZhbC1jb2RlPiIsIjx0dy1ldmFsLWV4cGxhbmF0aW9uPjwvdHctZXZhbC1leHBsYW5hdGlvbj48dHctZXZhbC1pdD48L3R3LWV2YWwtaXQ+PHR3LWV2YWwtcmVhc29uPjwvdHctZXZhbC1yZWFzb24+IikuY29uY2F0KDE9PT1yLmxlbmd0aD8iIjoiPHR3LWRpYWxvZy1saW5rcz48dHctbGluayBzdHlsZT0ndmlzaWJpbGl0eTpoaWRkZW4nPlx1MjE5MCAxMDwvdHctbGluaz48dHctbGluayBzdHlsZT0ndmlzaWJpbGl0eTpoaWRkZW4nPlx1MjE5MCBcdTIxOTA8L3R3LWxpbms+PGI+PC9iPjx0dy1saW5rPlx1MjE5MiBcdTIxOTI8L3R3LWxpbms+PHR3LWxpbms+MTAgXHUyMTkyPC90dy1saW5rPjwvdHctZGlhbG9nLWxpbmtzPiIsIjwvdHctZXZhbC1yZXBsYXk+IikpLHQuZmluZCgidHctZGlhbG9nIikuY3NzKHt3aWR0aDoiNzV2dyIsIm1heC13aWR0aCI6Ijc1dncifSkucHJlcGVuZChvKSxpPW8uZmluZCgidHctbGluazpmaXJzdC1vZi10eXBlIiksbD1pLm5leHQoKSx1PWwubmV4dCgpLHA9dS5uZXh0KCksZD1wLm5leHQoKSxuKCksaS5vbigiY2xpY2siLGZ1bmN0aW9uKCl7YT1NYXRoLm1heCgwLGEtMTApLG4oKX0pLGwub24oImNsaWNrIixmdW5jdGlvbigpe2E9TWF0aC5tYXgoMCxhLTEpLG4oKX0pLHAub24oImNsaWNrIixmdW5jdGlvbigpe2E9TWF0aC5taW4oci5sZW5ndGgtMSxhKzEpLG4oKX0pLGQub24oImNsaWNrIixmdW5jdGlvbigpe2E9TWF0aC5taW4oci5sZW5ndGgtMSxhKzEwKSxuKCl9KSxoLmZpbmQoInR3LWJhY2tkcm9wIikubGVuZ3RoP2guZmluZCgidHctYmFja2Ryb3AiKS5iZWZvcmUodCk6aC5hZGRDbGFzcygic2hvdy1kaWFsb2ciKS5hcHBlbmQodCkpO3ZhciBzLHQ9SShlLnRhcmdldCkuZGF0YSgiZ290byIpO3QmJihzPVYub3B0aW9ucy5pZ25vcmVHb3RvcyxWLm9wdGlvbnMuaWdub3JlR290b3M9ITEsdC5jb21tYW5kLlR3aW5lU2NyaXB0X1J1bih0LnNlY3Rpb24pLFYub3B0aW9ucy5pZ25vcmVHb3Rvcz1zKSxlLnN0b3BQcm9wYWdhdGlvbigpfSkpLGguZmluZCgiLnJlc2l6ZXItaCIpLm1vdXNlZG93bihmdW5jdGlvbihlKXtpZigxIT09ZS53aGljaClyZXR1cm4hMDtlLnN0b3BQcm9wYWdhdGlvbigpO3ZhciB0PWUucGFnZVgsbj1oLndpZHRoKCk7ci5vbigibW91c2Vtb3ZlLmRlYnVnZ2VyLXJlc2l6ZXItaCIsZnVuY3Rpb24oZSl7ZT1lLnBhZ2VYO2gud2lkdGgoIiIuY29uY2F0KG4rdC1lfDAsInB4IikpfSkub24oIm1vdXNldXAuZGVidWdnZXItcmVzaXplci1oIixmdW5jdGlvbigpe3Iub2ZmKCIuZGVidWdnZXItcmVzaXplci1oIiksby53aWR0aD1oLndpZHRoKCksYygpfSl9KSxoLm9uKCJtb3VzZWRvd24iLCIucmVzaXplci12IixmdW5jdGlvbihlKXtpZigxIT09ZS53aGljaClyZXR1cm4hMDtlLnN0b3BQcm9wYWdhdGlvbigpO3ZhciB0PWUucGFnZVksbj1JKGUudGFyZ2V0LnBhcmVudE5vZGUpLmhlaWdodCgpO3Iub24oIm1vdXNlbW92ZS5kZWJ1Z2dlci1yZXNpemVyLXYiLGZ1bmN0aW9uKGUpe2U9ZS5wYWdlWTtoLmZpbmQoIi5wYW5lbCIpLmNzcygibWF4SGVpZ2h0IiwiIi5jb25jYXQobit0LSgwfGUpLCJweCIpKX0pLm9uKCJtb3VzZXVwLmRlYnVnZ2VyLXJlc2l6ZXItdiIsZnVuY3Rpb24oKXtyLm9mZigiLmRlYnVnZ2VyLXJlc2l6ZXItdiIpLG8ubWF4SGVpZ2h0PWguZmluZCgiLnBhbmVsIikuY3NzKCJtYXhIZWlnaHQiKSxjKCl9KX0pLHAuY2xpY2soZnVuY3Rpb24oKXtyLnRvZ2dsZUNsYXNzKCJkZWJ1Zy1tb2RlIikucmVtb3ZlQ2xhc3MoImRvbS1kZWJ1Zy1tb2RlIikscC50b2dnbGVDbGFzcygiZW5hYmxlZCIpLHUucmVtb3ZlQ2xhc3MoImVuYWJsZWQiKX0pLHUuY2xpY2soZnVuY3Rpb24oKXtyLnRvZ2dsZUNsYXNzKCJkb20tZGVidWctbW9kZSIpLnJlbW92ZUNsYXNzKCJkZWJ1Zy1tb2RlIiksdS50b2dnbGVDbGFzcygiZW5hYmxlZCIpLHAucmVtb3ZlQ2xhc3MoImVuYWJsZWQiKX0pLGQuY2xpY2soZnVuY3Rpb24oKXtyLnJlbW92ZUNsYXNzKCJkZWJ1Zy1tb2RlIGRvbS1kZWJ1Zy1tb2RlIiksaC5kZXRhY2goKSxPYmplY3QuYXNzaWduKFYub3B0aW9ucyx7ZGVidWc6ITEsc3BlZWRNdWx0aXBsaWVyOjEsaWdub3JlQ2xpY2tFdmVudHM6ITEsaWdub3JlR290b3M6ITF9KX0pO2Z1bmN0aW9uIGcoZSl7KGU9ZS5wYXJlbnRzKCIudmFyaWFibGUtcm93LCAuZW5jaGFudG1lbnQtcm93LCAuc291cmNlLXJvdyIpKS5uZXh0KCIucGFuZWwtcm93LXNvdXJjZSIpLmZpbmQoInRkIikuZW1wdHkoKS5hcHBlbmQoQihlLmRhdGEoInZhbHVlIil8fEcoZS5kYXRhKCJlbmNoYW50bWVudCIpLmNoYW5nZXIpLGUuaXMoInNvdXJjZS1yb3ciKT8ibWFya3VwIjoibWFjcm8iKSl9ZnVuY3Rpb24geSgpe3JldHVybiBrPW5ldyBTZXR9ZnVuY3Rpb24gYigpe0koZG9jdW1lbnQuYm9keSkuYXBwZW5kKGgpLFYub3B0aW9ucy5kZWJ1Zz0hMCxWLm9wdGlvbnMuZXZhbFJlcGxheT1vLmV2YWxSZXBsYXksVi5vcHRpb25zLnNwZWVkTXVsdGlwbGllcj0xLFYub3B0aW9ucy5pZ25vcmVDbGlja0V2ZW50cz0hMSxWLm9wdGlvbnMuaWdub3JlR290b3M9ITEsUigpfXZhciB2LHc9bChmdW5jdGlvbigpe3ZhciByPW0uY2hpbGRyZW4oKS5nZXQoKSxlPUQudGltZWxpbmUsYT0wO2UuZm9yRWFjaChmdW5jdGlvbihlLHQpe3ZhciBuPWUudHVybnMsZT1lLnBhc3NhZ2Usbj0oYSs9MSsodm9pZCAwPT09bj8wOm4pKSsiOiAiK2U7clt0XT9yW3RdLnRleHRDb250ZW50PW46bS5hcHBlbmQoIjxvcHRpb24gdmFsdWU9JyIuY29uY2F0KHQsIic+IikuY29uY2F0KG4sIjwvb3B0aW9uPiIpKX0pLGUubGVuZ3RoPHIubGVuZ3RoJiZJKHIuc2xpY2UoZS5sZW5ndGgpKS5yZW1vdmUoKSxtWzE8PWUubGVuZ3RoPyJyZW1vdmVBdHRyIjoiYXR0ciJdKCJkaXNhYmxlZCIpLG0udmFsKEQucGFzdExlbmd0aCl9KSxrPShtLmNoYW5nZShmdW5jdGlvbihlKXtlPWUudGFyZ2V0LnZhbHVlLUQucGFzdExlbmd0aDswIT1lJiYoRFtlPDA/InJld2luZCI6ImZhc3RGb3J3YXJkIl0oTWF0aC5hYnMoZSkpLEYuc2hvd1Bhc3NhZ2UoRC5wYXNzYWdlKSl9KSx3KCksRC5vbigiZm9yd2FyZCIsdykub24oImxvYWQiLHcpLm9uKCJmb3JnZXRVbmRvcyIsZnVuY3Rpb24oKXtyZXR1cm4gd30pLm9uKCJiYWNrIixmdW5jdGlvbigpe0QucGFzdExlbmd0aDw9MSYmbS5hdHRyKCJkaXNhYmxlZCIpLG0uZmluZCgiW3NlbGVjdGVkXSIpLnJlbW92ZUF0dHIoInNlbGVjdGVkIiksbS52YWwoRC5wYXN0TGVuZ3RoKX0pLG5ldyBTZXQpLFM9Vy5jcmVhdGUoe2NsYXNzTmFtZToidmFyaWFibGVzIix0YWJOYW1lOiJWYXJpYWJsZSIscm93V3JpdGU6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPWUubmFtZSxhPWUuZGF0YXNldCxvPWUucGF0aCxpPWUudmFsdWUscz1lLnRlbXBTY29wZSxlPWUudHlwZSxjPWkmJjQ4PGkubGVuZ3RoJiYhaS5Ud2luZVNjcmlwdF9EZWJ1Z05hbWUsbD0kKGkpJiZpLlR3aW5lU2NyaXB0X0RlYnVnTmFtZT9pLlR3aW5lU2NyaXB0X0RlYnVnTmFtZSgpOmYoVShpKSksdT0iIixhPShvLmxlbmd0aCYmKHU9by5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSt0KyIncyAifSwiIikpLGEmJihyPSI/Pz8iKSxlP0coZSk6IiIpLGU9Im9iamVjdCI9PT1fdHlwZW9mKGkpfHxjO3JldHVybiB0Pyh0WzBdLmZpcnN0Q2hpbGQuaW5uZXJIVE1MPWF8fCIiLHUmJkkodFswXS5maXJzdENoaWxkKS5jaGlsZHJlbigiLnZhcmlhYmxlLXBhdGgiKS5odG1sKChzPyJfIjoiJCIpK2YodSkpLHRbMF0uY2hpbGROb2Rlc1sxXS5sYXN0Q2hpbGQudGV4dENvbnRlbnQ9KHU/IiI6cz8iXyI6IiQiKStmKHIrIiIpLHRbMF0uY2hpbGROb2Rlc1syXS50ZXh0Q29udGVudD1zfHwiIix0WzBdLmNoaWxkTm9kZXNbM10uaW5uZXJIVE1MPWwsbj0oYz1JKHRbMF0ubGFzdENoaWxkLmZpcnN0Q2hpbGQpKS5pcygiLm9wZW4iKSxjW2U/InNob3ciOiJoaWRlIl0oKSxjPXQubmV4dCgiLnBhbmVsLXJvdy1zb3VyY2UiKSxuJiZjLmZpbmQoInRkIikuZW1wdHkoKS5hcHBlbmQoQihHKGkpKSksdC5kYXRhKCJ2YWx1ZSIsRyhpKSksdC5hZGQoYykpOkkoJzxkaXYgY2xhc3M9InZhcmlhYmxlLXJvdyI+JykuYXR0cigiZGF0YS1uYW1lIixyKS5hdHRyKCJkYXRhLXBhdGgiLG8rIiIpLmF0dHIoImRhdGEtc2NvcGUiLHN8fCIiKS5jc3MoInBhZGRpbmctbGVmdCIsTWF0aC5taW4oNSxvLmxlbmd0aCkrImVtIikuYXBwZW5kKCI8dGQgY2xhc3M9J3ZhcmlhYmxlLXR5cGUnPiIuY29uY2F0KGF8fCIiLCI8L3RkPiIpLCI8dGQgY2xhc3M9J3ZhcmlhYmxlLW5hbWUgY20taGFybG93ZS0zLSIrKHM/InRlbXBWIjoidiIpKyJhcmlhYmxlJz48c3BhbiBjbGFzcz0ndmFyaWFibGUtcGF0aCc+IisodT8ocz8iXyI6IiQiKStmKHUpOiIiKSsiPC9zcGFuPiAiKyh1PyIiOnM/Il8iOiIkIikrZihyKyIiKSsiPC90ZD4iLCI8dGQgY2xhc3M9J3RlbXBvcmFyeS12YXJpYWJsZS1zY29wZSc+Ii5jb25jYXQoc3x8IiIsIjwvdGQ+IiksIjx0ZCBjbGFzcz0ndmFyaWFibGUtdmFsdWUgY20taGFybG93ZS0zLW1hY3JvTmFtZS0iK1koaSkrIic+IitsKyI8L3RkPjx0ZCBjbGFzcz0ncGFuZWwtcm93LWJ1dHRvbnMnPjx0dy1mb2xkZG93biB0YWJpbmRleD0wIHN0eWxlPSdkaXNwbGF5OiIrKGU/InZpc2libGUiOiJub25lIikrIic+KHNvdXJjZTopIDwvdHctZm9sZGRvd24+PC90ZD4iKS5kYXRhKCJ2YWx1ZSIsRyhpKSkuZmluZCgidHctZm9sZGRvd24iKS5kYXRhKCJmb2xkZG93biIsZykuZW5kKCkuYWRkKCI8dHIgY2xhc3M9J3ZhcmlhYmxlLXJvdyBwYW5lbC1yb3ctc291cmNlJyBzdHlsZT0nZGlzcGxheTpub25lJz48dGQgY29sc3Bhbj0nNSc+PC90ZD48L3RyPiIpfSxyb3dDaGVjazpmdW5jdGlvbihlLHQpe3ZhciBuPWUubmFtZSxyPWUucGF0aCxlPWUudGVtcFNjb3BlO3JldHVybiB0WzBdJiZ0WzBdLmdldEF0dHJpYnV0ZSgiZGF0YS1uYW1lIik9PT1uJiZ0WzBdLmdldEF0dHJpYnV0ZSgiZGF0YS1wYXRoIik9PT1yKyIiJiZ0WzBdLmdldEF0dHJpYnV0ZSgiZGF0YS1zY29wZSIpPT09ZX0sY29sdW1uSGVhZDpmdW5jdGlvbigpe3JldHVybic8dHIgY2xhc3M9InBhbmVsLWhlYWQiPjx0aCBkYXRhLWNvbD0idmFyaWFibGUtdHlwZSI+VHlwZTwvdGg+PHRoIGRhdGEtY29sPSJ2YXJpYWJsZS1uYW1lIj5OYW1lPC90aD48dGggZGF0YS1jb2w9InRlbXBvcmFyeS12YXJpYWJsZS1zY29wZSI+U2NvcGU8L3RoPjx0aCBkYXRhLWNvbD0idmFyaWFibGUtdmFsdWUiPlZhbHVlPC90aD48L3RyPid9LHJvd1NvcnQ6ZnVuY3Rpb24oZSx0LG4pe2lmKCJ2YXJpYWJsZS12YWx1ZSI9PT1lKXJldHVybiBhKHQuYXR0cigiY2xhc3MiKSxuLmF0dHIoImNsYXNzIikpfHxhKHQucGFyZW50KCkuZGF0YSgidmFsdWUiKSxuLnBhcmVudCgpLmRhdGEoInZhbHVlIikpfX0pLFQ9bChmdW5jdGlvbigpe3ZhciBlLHQsbz1bXSxuPUQudmFyaWFibGVzLHI9by5sZW5ndGg7Zm9yKGUgaW4gbillLnN0YXJ0c1dpdGgoIlR3aW5lU2NyaXB0Iil8fChyKz0xLGZ1bmN0aW9uIG4oZSl7dmFyIHIsdCxhOzUwMDxvLmxlbmd0aHx8KG8ucHVzaChlKSxyPWUucGF0aC5jb25jYXQoZS5uYW1lKSx0PWUudmFsdWUsYT1lLnRlbXBTY29wZSxyLmxlbmd0aDw9NCYmKEFycmF5LmlzQXJyYXkodCk/dC5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG4oe25hbWU6aSh0KzEpLHBhdGg6cix2YWx1ZTplLHRlbXBTY29wZTphfSl9KTp0IGluc3RhbmNlb2YgTWFwP190b0NvbnN1bWFibGVBcnJheSh0KS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PShlPV9zbGljZWRUb0FycmF5KGUsMikpWzBdLGU9ZVsxXTtyZXR1cm4gbih7bmFtZTp0LHBhdGg6cix2YWx1ZTplLHRlbXBTY29wZTphfSl9KTp0IGluc3RhbmNlb2YgU2V0JiZfdG9Db25zdW1hYmxlQXJyYXkodCkuZm9yRWFjaChmdW5jdGlvbihlLHQpe3JldHVybiBuKHtuYW1lOnQsZGF0YXNldDohMCxwYXRoOnIsdmFsdWU6ZSx0ZW1wU2NvcGU6YX0pfSkpKX0oe25hbWU6ZSxwYXRoOltdLHZhbHVlOm5bZV0sdGVtcFNjb3BlOiIiLHR5cGU6bnVsbD09KHQ9bi5Ud2luZVNjcmlwdF9UeXBlRGVmcyk/dm9pZCAwOnRbZV19KSk7by5wdXNoLmFwcGx5KG8sX3RvQ29uc3VtYWJsZUFycmF5KGspKSxyKz1rLnNpemUsUy51cGRhdGUobyxyKSwwPT09ciE9PVMucGFuZWxbMF0uY2xhc3NMaXN0LmNvbnRhaW5zKCJwYW5lbC12YXJpYWJsZXMtZW1wdHkiKSYmUy5wYW5lbC50b2dnbGVDbGFzcygicGFuZWwtdmFyaWFibGVzLWVtcHR5Iil9KSxfPShMLm9uKCJzZXQiLGZ1bmN0aW9uKGUsdCxuKXt2YXIgcixhO2U9PT1ELnZhcmlhYmxlc3x8InRlbXAiIT09KG51bGw9PShhPWUuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSk/dm9pZCAwOmEudHlwZSl8fG51bGwhPShhPWUuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSkmJmEubmFtZS5tYXRjaCgvI1xkKyQvKXx8KHI9bnVsbD09KGE9ZS5Ud2luZVNjcmlwdF9WYXJpYWJsZVN0b3JlKT92b2lkIDA6YS5uYW1lLGU9bnVsbD09KGE9ZS5Ud2luZVNjcmlwdF9UeXBlRGVmcyk/dm9pZCAwOmFbdF0sKGE9X3RvQ29uc3VtYWJsZUFycmF5KGspLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZT09PXQmJmUudGVtcFNjb3BlPT09cn0pKT9hLnZhbHVlPW46ay5hZGQoe25hbWU6dCxwYXRoOltdLHZhbHVlOm4sdGVtcFNjb3BlOnIsdHlwZTplfSkpLFQoKSx2KCl9KS5vbigiZGVsZXRlIixmdW5jdGlvbigpe1QoKSx2KCl9KSxTLnBhbmVsLmFwcGVuZCgiPGRpdiBjbGFzcz0ncGFuZWwtdmFyaWFibGVzLWJvdHRvbSc+XG5cdFx0XHQ8YnV0dG9uIGNsYXNzPSdwYW5lbC12YXJpYWJsZXMtY29weSc+Q29weSAkIHZhcmlhYmxlcyBhcyAoc2V0OikgY2FsbDwvYnV0dG9uPlxuXHRcdFx0PGlucHV0IGNsYXNzPSdjbGlwYm9hcmQnIHR5cGU9XCJ0ZXh0XCIgc3R5bGU9J29wYWNpdHk6MDtwb2ludGVyLWV2ZW50czpub25lO3Bvc2l0aW9uOmFic29sdXRlOyc+PC9pbnB1dD5cblx0XHQ8L2Rpdj4iKS5yZW1vdmVBdHRyKCJoaWRkZW4iKSxTLnRhYi5hZGRDbGFzcygiZW5hYmxlZCIpLFMucGFuZWwuZmluZCgiLmNsaXBib2FyZCIpKSx4PShyLm9uKCJjbGljayIsIi5wYW5lbC12YXJpYWJsZXMtY29weSIsZnVuY3Rpb24oKXt2YXIgZSx0PVtdO2ZvcihlIGluIEQudmFyaWFibGVzKWUuc3RhcnRzV2l0aCgiVHdpbmVTY3JpcHQiKXx8dC5wdXNoKCIkIitlKyIgdG8gIitHKEQudmFyaWFibGVzW2VdKSk7Xy52YWwoIihzZXQ6Iit0KyIpIilbMF0uc2VsZWN0KCksZG9jdW1lbnQuZXhlY0NvbW1hbmQoImNvcHkiKX0pLFcuY3JlYXRlKHtjbGFzc05hbWU6ImVuY2hhbnRtZW50cyIsdGFiTmFtZToiRW5jaGFudG1lbnQiLHJvd1dyaXRlOmZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5zY29wZSxyPWUuY2hhbmdlcixhPWUubGFtYmRhLG89ZS5uYW1lLGk9ZS5sb2NhbEhvb2ssYT1yP2YoVShyKSk6YT9mKEcoYSkpOiI8ZW0+ZW5jaGFudGVkIHdpdGggKCIrbysiOik8L2VtPiI7cmV0dXJuIHR8fEkoJzxkaXYgY2xhc3M9ImVuY2hhbnRtZW50LXJvdyI+JykuZGF0YSgiZW5jaGFudG1lbnQiLGUpLmFwcGVuZCgiPHRkPjxzcGFuIGNsYXNzPSdlbmNoYW50bWVudC1uYW1lJz4iK0cobikrKGk/Ijwvc3Bhbj48c3BhbiBjbGFzcz0nZW5jaGFudG1lbnQtbG9jYWwgY20taGFybG93ZS0zLWhvb2tOYW1lJz4iKygiZnVuY3Rpb24iPT10eXBlb2YgaS5Ud2luZVNjcmlwdF9Ub1NvdXJjZT9pLlR3aW5lU2NyaXB0X1RvU291cmNlKCk6aS5hdHRyKCJuYW1lIik/Ij8iK2kuYXR0cigibmFtZSIpOiJhbiB1bm5hbWVkIGhvb2siKToiIikrIjwvc3Bhbj48L3RkPjx0ZCBjbGFzcz0nZW5jaGFudG1lbnQtdmFsdWUgY20taGFybG93ZS0zLW1hY3JvTmFtZS0iKyhyPyJjaGFuZ2VyIjoiY29tbWFuZCIpKyIgJz4iK2ErIjwvdGQ+Iisocj8iPHRkIGNsYXNzPSdwYW5lbC1yb3ctYnV0dG9ucyc+PHR3LWZvbGRkb3duIHRhYmluZGV4PTA+KHNvdXJjZTopPC90dy1mb2xkZG93bj48L3RkPiI6IiIpKS5maW5kKCJ0dy1mb2xkZG93biIpLmRhdGEoImZvbGRkb3duIixnKS5lbmQoKS5hZGQocj9JKCI8dHIgY2xhc3M9J3BhbmVsLXJvdy1zb3VyY2UnIHN0eWxlPSdkaXNwbGF5Om5vbmUnPjx0ZCBjb2xzcGFuPSczJz48L3RkPjwvdHI+Iik6IiIpfSxyb3dDaGVjazpmdW5jdGlvbihlLHQpe3JldHVybiB0LmRhdGEoImVuY2hhbnRtZW50Iik9PT1lfSxjb2x1bW5IZWFkOmZ1bmN0aW9uKCl7cmV0dXJuJzx0ciBjbGFzcz0icGFuZWwtaGVhZCI+PHRoIGRhdGEtY29sPSJlbmNoYW50bWVudC1uYW1lIj5TY29wZTwvdGg+PHRoIGRhdGEtY29sPSJlbmNoYW50bWVudC12YWx1ZSI+VmFsdWU8L3RoPjwvZGl2Pid9fSkpLGQ9bChmdW5jdGlvbihlKXt4LnVwZGF0ZShlLmVuY2hhbnRtZW50cyxlLmVuY2hhbnRtZW50cy5sZW5ndGgpfSksTz0ocS5vbigiYWRkIixkKS5vbigicmVtb3ZlIixkKSxxLmNyZWF0ZSgpKSxBPVcuY3JlYXRlKHtjbGFzc05hbWU6InN0b3J5bGV0cyIsdGFiTmFtZToiU3RvcnlsZXQiLHJvd1dyaXRlOmZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5uYW1lLHI9ZS5hY3RpdmUsYT1lLnN0b3J5bGV0U291cmNlLG89ZS5leGNsdXNpdmUsZT1lLnVyZ2VudDtyZXR1cm4gdD8odC50b2dnbGVDbGFzcygic3RvcnlsZXQtY2xvc2VkIiwhciksdFswXS5maXJzdENoaWxkLnRleHRDb250ZW50PXI/Ilx1MjcxMyI6IiIpOih0PUkoJzx0ciBjbGFzcz0ic3RvcnlsZXQtcm93ICcuY29uY2F0KHI/IiI6InN0b3J5bGV0LWNsb3NlZCIsJyI+JykpLmF0dHIoImRhdGEtbmFtZSIsbikuYXBwZW5kKCI8dGQgY2xhc3M9J3N0b3J5bGV0LW9wZW4nPiIrKHI/Ilx1MjcxMyI6IiIpKyI8L3RkPjx0ZCBjbGFzcz0nc3RvcnlsZXQtbmFtZSc+IituKyI8L3RkPjx0ZCBjbGFzcz0nc3RvcnlsZXQtbGFtYmRhJz48L3RkPjx0ZCBjbGFzcz0nc3RvcnlsZXQtZXhjbHVzaXZlJz4iK28rIjwvdGQ+PHRkIGNsYXNzPSdzdG9yeWxldC11cmdlbnQnPiIrZSsiPC90ZD4iKSkuZmluZCgiLnN0b3J5bGV0LWxhbWJkYSIpLmFwcGVuZChCKGEucmVwbGFjZSgvXndoZW5ccysvaSwiIikpKSx0fSxyb3dDaGVjazpmdW5jdGlvbihlLHQpe2U9ZS5uYW1lO3JldHVybiB0WzBdLmdldEF0dHJpYnV0ZSgiZGF0YS1uYW1lIik9PT1mKGUrIiIpfSxjb2x1bW5IZWFkOmZ1bmN0aW9uKCl7cmV0dXJuJzx0ciBjbGFzcz0icGFuZWwtaGVhZCI+PHRoIGRhdGEtY29sPSJzdG9yeWxldC1vcGVuIiBkYXRhLW9yZGVyPSJkZXNjIj5PcGVuPC90aD48dGggZGF0YS1jb2w9InN0b3J5bGV0LW5hbWUiPk5hbWU8L3RoPjx0aCBkYXRhLWNvbD0ic3RvcnlsZXQtbGFtYmRhIj5Db25kaXRpb248L3RoPjx0aCBkYXRhLWNvbD0ic3RvcnlsZXQtZXhjbHVzaXZlIiBjbGFzcz1cJ3N0b3J5bGV0LWV4Y2x1c2l2ZVwnPkV4Y2x1c2l2aXR5PC90aD48dGggZGF0YS1jb2w9InN0b3J5bGV0LXVyZ2VudCIgY2xhc3M9XCdzdG9yeWxldC11cmdlbnRcJz5VcmdlbmN5PC90aD48L3RyPid9fSksQz0oQS50YWIuaGlkZSgpLHY9bChmdW5jdGlvbigpe3ZhciByLGEsbz16LmdldFN0b3J5bGV0cyhPKSxpPUguY29udGFpbnNFcnJvcihvKSxlPXouYWxsU3RvcnlsZXRzKCk7QS51cGRhdGUoZS5tYXAoZnVuY3Rpb24odCl7dmFyIGU9Im51bWJlciI9PXR5cGVvZiB0LmdldCgiZXhjbHVzaXZpdHkiKT90LmdldCgiZXhjbHVzaXZpdHkiKTowLG49Im51bWJlciI9PXR5cGVvZiB0LmdldCgidXJnZW5jeSIpP3QuZ2V0KCJ1cmdlbmN5Iik6MDtyZXR1cm4gcj1yfHxlLGE9YXx8ZSx7bmFtZTp0LmdldCgibmFtZSIpLHN0b3J5bGV0U291cmNlOnQuZ2V0KCJzdG9yeWxldCIpLlR3aW5lU2NyaXB0X1RvU291cmNlKCksYWN0aXZlOiFpJiZvLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUuZ2V0KCJuYW1lIik9PT10LmdldCgibmFtZSIpfSksZXhjbHVzaXZlOmUsdXJnZW50Om59fSksaT8wOm8ubGVuZ3RoKSxBLnBhbmVsLnRvZ2dsZUNsYXNzKCJzdG9yeWxldC1lcnJvciIsaSksQS5wYW5lbC50b2dnbGVDbGFzcygicGFuZWwtZXhjbHVzaXZlIixyKSxBLnBhbmVsLnRvZ2dsZUNsYXNzKCJwYW5lbC11cmdlbnQiLGEpLGUubGVuZ3RoJiZBLnRhYi5zaG93KCl9KSxXLmNyZWF0ZSh7Y2xhc3NOYW1lOiJzb3VyY2UiLHRhYk5hbWU6IlNvdXJjZSIsdGFiTmFtZUNvdW50ZXI6ITEscm93V3JpdGU6ZnVuY3Rpb24oZSx0KXt2YXIgbj1lLm5hbWUsZT1lLnRhZztyZXR1cm4gdD90LmFkZCh0Lm5leHQoIi5wYW5lbC1yb3ctc291cmNlIikpOih0PXouZ2V0KG4pLmdldCgic291cmNlIiksSSgnPGRpdiBjbGFzcz0ic291cmNlLXJvdyIgZGF0YS10YWc9IicuY29uY2F0KGUsJyI+JykpLmRhdGEoInZhbHVlIix0KS5hcHBlbmQoJzx0ZCBjbGFzcz0ic291cmNlLW5hbWUiPicuY29uY2F0KG4sJzwvdGQ+PHRkIGNsYXNzPSJzb3VyY2UtdGFncyI+JykuY29uY2F0KGUsIjwvdGQ+PHRkIGNsYXNzPSdwYW5lbC1yb3ctYnV0dG9ucyc+PHR3LWZvbGRkb3duIGNsYXNzPSciKS5jb25jYXQoZT8iIjoib3BlbiIsIicgdGFiaW5kZXg9MD48L3R3LWZvbGRkb3duPjwvdGQ+IikpLmZpbmQoInR3LWZvbGRkb3duIikuZGF0YSgiZm9sZGRvd24iLGcpLmVuZCgpLmFkZChJKCI8dHIgY2xhc3M9J3BhbmVsLXJvdy1zb3VyY2UnIHN0eWxlPSciLmNvbmNhdChlPyJkaXNwbGF5Om5vbmUiOiIiLCInPjx0ZCBjb2xzcGFuPSczJz48L3RkPjwvdHI+IikpLmZpbmQoInRkIikuYXBwZW5kKCFlJiZCKHQsIm1hcmt1cCIpKS5lbmQoKSkpfSxyb3dDaGVjazpmdW5jdGlvbihlLHQpe2U9ZS5uYW1lO3JldHVybiB0WzBdLmZpcnN0Q2hpbGQudGV4dENvbnRlbnQ9PT1mKGUrIiIpfSx0YWJVcGRhdGU6SS5ub29wLGNvbHVtbkhlYWQ6SS5ub29wfSkpLEU9WyJkZWJ1Zy1zdGFydHVwIiwic3RhcnR1cCIsImhlYWRlciIsImRlYnVnLWhlYWRlciIsImZvb3RlciIsImRlYnVnLWZvb3RlciJdLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlLmNvbmNhdCh6LmdldFRhZ2dlZCh0KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue25hbWU6ZS5nZXQoIm5hbWUiKSx0YWc6dH19KSl9LFtdKSxOPVcuY3JlYXRlKHtjbGFzc05hbWU6ImVycm9ycyIsdGFiTmFtZToiRXJyb3IiLHJvd1dyaXRlOkkubm9vcCxyb3dDaGVjazpJLm5vb3AsY29sdW1uSGVhZDpJLm5vb3AsdGFiVXBkYXRlOmZ1bmN0aW9uKGUpe3JldHVybiBOLnRhYi5jc3Moe2JhY2tncm91bmQ6ZT8icmdiYSgyMzAsMTAxLDIwNCwwLjMpIjoiIn0pLnRleHQoIiIuY29uY2F0KGUsIiBFcnJvciIpLmNvbmNhdCgxIT09ZT8icyI6IiIpKX19KSxkPW4oZnVuY3Rpb24oZSl7dmFyIHQ7Vi5vcHRpb25zLmRlYnVnJiYoTi5wYW5lbFJvd3MuYXBwZW5kKGUucmVkdWNlKGZ1bmN0aW9uKGUsdCl7dmFyIHQ9X3NsaWNlZFRvQXJyYXkodCwyKSxuPXRbMF0sdD10WzFdO3JldHVybiJwcm9wYWdhdGVkIj09PW4udHlwZT9lOmUrJzx0ciBjbGFzcz0iZXJyb3Itcm93Ij48dGQgY2xhc3M9ImVycm9yLXBhc3NhZ2UiPicrRC5wYXNzYWdlKyc8L3RkPjx0ZCBjbGFzcz0iZXJyb3ItbWVzc2FnZSIgdGl0bGU9IicrZih0KSsnIj4nK24ubWVzc2FnZSsiPC90ZD48L3RyPiJ9LCIiKSksNTAwPCh0PShlPU4ucGFuZWxSb3dzLmNoaWxkcmVuKCkpLmxlbmd0aCkmJkkoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoTi5wYW5lbFJvd3NbMF0uY2hpbGROb2RlcywwLHQtNTAwKSkucmVtb3ZlKCksTi50YWJVcGRhdGUoTWF0aC5taW4oNTAwLGUubGVuZ3RoKSkpfSx7YmF0Y2g6ITB9KSxqPShILm9uKGQpLE4ucGFuZWwuYXBwZW5kKCI8ZGl2IGNsYXNzPSdwYW5lbC1lcnJvcnMtYm90dG9tJz5cblx0XHRcdDxidXR0b24gY2xhc3M9J3BhbmVsLWVycm9ycy1jbGVhbic+XHVkODNlXHVkZGY5IENsZWFyIHRoaXMgcGFuZWw8L2J1dHRvbj5cblx0XHQ8L2Rpdj4iKSxyLm9uKCJjbGljayIsIi5wYW5lbC1lcnJvcnMtY2xlYW4iLGZ1bmN0aW9uKCl7Ti5wYW5lbFJvd3MuZW1wdHkoKSxOLnRhYlVwZGF0ZSgwKX0pLFcuY3JlYXRlKHtjbGFzc05hbWU6InRvb2xzIix0YWJOYW1lOiJUb29scyIsdGFiTmFtZUNvdW50ZXI6ITEscm93V3JpdGU6ZnVuY3Rpb24oZSx0KXt2YXIgbj1lLmlkLHI9ZS50eXBlLGE9ZS5sYWJlbCxvPWUuZHJvcGRvd25JdGVtcyxpPWUuZHJvcGRvd25WYWx1ZTtyZXR1cm4iY2hlY2tib3giPT09cj90P3QuZmluZCgiaW5wdXQiKS5wcm9wKCJjaGVja2VkIiwhMSk6SSgnPHNwYW4+PGlucHV0IGlkPSJkZWJ1Zy0nLmNvbmNhdChuLCciIHR5cGU9ImNoZWNrYm94Ij48L2lucHV0PjxsYWJlbCBmb3I9ImRlYnVnLScpLmNvbmNhdChuLCciPicpLmNvbmNhdChhLCI8L2xhYmVsPjwvc3Bhbj4iKSk6ImRyb3Bkb3duIj09PXI/dD90LmZpbmQoImlucHV0IikucHJvcCgiY2hlY2tlZCIsITEpOkkoIjxzcGFuPiIuY29uY2F0KGEsJzxzZWxlY3Qgc3R5bGU9IndpZHRoOjNlbSIgZGF0YS1kZWZhdWx0PSInKS5jb25jYXQoaSwnIiBpZD0iZGVidWctJykuY29uY2F0KG4sJyI+PC9zcGFuPicpKS5maW5kKCJzZWxlY3QiKS5hcHBlbmQoby5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIjxvcHRpb24gdmFsdWU9JyIuY29uY2F0KGUsIicgIikuY29uY2F0KGU9PT1pPyJzZWxlY3RlZCI6IiIsIj4iKS5jb25jYXQoZSwieDwvb3B0aW9uPiIpfSkpLmVuZCgpOnZvaWQgMH0scm93Q2hlY2s6SS5ub29wLGNvbHVtbkhlYWQ6SS5ub29wLHRhYlVwZGF0ZTpmdW5jdGlvbihlKXtyZXR1cm4gai50YWIuY3NzKHtiYWNrZ3JvdW5kOmU/ImhzbGEoMjEwLCA3MiUsIDY1JSwgLjMpIjoiIn0pfX0pKSxQPShyLm9uKCJjbGljaywgY2hhbmdlIiwnLnBhbmVsLXRvb2xzIFt0eXBlPSJjaGVja2JveCJdLCAucGFuZWwtdG9vbHMgc2VsZWN0JyxmdW5jdGlvbihlKXt2YXIgZT1lLnRhcmdldCx0PShlPUkoZSkpLmF0dHIoImlkIiksbj1lLmlzKCI6Y2hlY2tlZCIpfHxlLmlzKCJzZWxlY3QiKSYmZS52YWwoKSE9PStlLmF0dHIoImRhdGEtZGVmYXVsdCIpOyJkZWJ1Zy1wZWVrQmVoaW5kRGlhbG9ncyI9PT10JiZyLnRvZ2dsZUNsYXNzKCJkZWJ1Zy1kaWFsb2dzIixuKSwiZGVidWctaWdub3JlQ2xpY2tFdmVudHMiPT09dCYmKFYub3B0aW9ucy5pZ25vcmVDbGlja0V2ZW50cz1uKSwiZGVidWctaWdub3JlR290b3MiPT09dCYmKFYub3B0aW9ucy5pZ25vcmVHb3Rvcz1uKSwiZGVidWctc3BlZWRNdWx0aXBsaWVyIj09PXQmJihWLm9wdGlvbnMuc3BlZWRNdWx0aXBsaWVyPStlLnZhbCgpKSxqLnRhYlVwZGF0ZShuKX0pLGoudXBkYXRlKFt7aWQ6InBlZWtCZWhpbmREaWFsb2dzIix0eXBlOiJjaGVja2JveCIsbGFiZWw6IlNlZSB0aHJvdWdoIGFuZCBjbGljayB0aHJvdWdoIDxjb2RlPihkaWFsb2c6KTwvY29kZT4gYm94ZXMifSx7aWQ6Imlnbm9yZUNsaWNrRXZlbnRzIix0eXBlOiJjaGVja2JveCIsbGFiZWw6IlN0b3AgbGlua3MsIDxjb2RlPihjbGljazopPC9jb2RlPiBhbmQgPGNvZGU+KGhvdmVyLXN0eWxlOik8L2NvZGU+IGZyb20gYWN0aXZhdGluZyJ9LHtpZDoiaWdub3JlR290b3MiLHR5cGU6ImNoZWNrYm94IixsYWJlbDoiU3RvcCA8Y29kZT4oZ28tdG86KTwvY29kZT4sIDxjb2RlPih1bmRvOik8L2NvZGU+LCA8Y29kZT4ocmVkaXJlY3Q6KTwvY29kZT4gYW5kIDxjb2RlPihyZXN0YXJ0Oik8L2NvZGU+IGZyb20gYWN0aXZhdGluZzxicj48c21hbGw+KENsaWNrICdHTycgYnV0dG9ucyBpbiBEZWJ1ZyBWaWV3IHRvIGFjdGl2YXRlIGxhdGVyKTwvc21hbGw+In0se2lkOiJzcGVlZE11bHRpcGxpZXIiLGxhYmVsOiJTcGVlZCBvZiB0aW1lZCBldmVudHMgKDxjb2RlPnRpbWU8L2NvZGU+LCA8Y29kZT4obGl2ZTopPC9jb2RlPiwgPGNvZGU+KGFmdGVyOik8L2NvZGU+KTogIix0eXBlOiJkcm9wZG93biIsZHJvcGRvd25WYWx1ZToxLGRyb3Bkb3duSXRlbXM6Wy4yNSwuNSwuNzUsMSwxLjI1LDEuNSwxLjc1LDIsMyw1LDEwXX1dKSxXLmNyZWF0ZSh7Y2xhc3NOYW1lOiJvcHRpb25zIix0YWJOYW1lOiJcdTI2OTlcdWZlMGYiLHRhYk5hbWVDb3VudGVyOiExLHJvd1dyaXRlOmZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5uYW1lLGU9ZS5sYWJlbCxyPXtkYXJrTW9kZTpvLmRhcmtNb2RlLGZhZGVQYW5lbDpvLmZhZGVQYW5lbCxldmFsUmVwbGF5Om8uZXZhbFJlcGxheX1bbl07cmV0dXJuIHQ/dC5maW5kKCJpbnB1dCIpLnByb3AoImNoZWNrZWQiLHIpOkkoJzxzcGFuPjxpbnB1dCBpZD0iZGVidWctJy5jb25jYXQobiwnIiB0eXBlPSJjaGVja2JveCIgJykuY29uY2F0KHI/ImNoZWNrZWQiOiIiLCc+PC9pbnB1dD48bGFiZWwgZm9yPSJkZWJ1Zy0nKS5jb25jYXQobiwnIj4nKS5jb25jYXQoZSwiPC9sYWJlbD48L3NwYW4+IikpfSxyb3dDaGVjazpJLm5vb3AsdGFiVXBkYXRlOkkubm9vcCxjb2x1bW5IZWFkOkkubm9vcH0pKSxSPShyLm9uKCJjbGljayIsJy5wYW5lbC1vcHRpb25zIFt0eXBlPSJjaGVja2JveCJdJyxmdW5jdGlvbihlKXt2YXIgZT1lLnRhcmdldCx0PShlPUkoZSkpLmF0dHIoImlkIiksZT1lLmlzKCI6Y2hlY2tlZCIpOyJkZWJ1Zy1kYXJrTW9kZSI9PT10JiYoby5kYXJrTW9kZT1lLGgudG9nZ2xlQ2xhc3MoInRoZW1lLWRhcmsiLGUpKSwiZGVidWctZmFkZVBhbmVsIj09PXQmJihvLmZhZGVQYW5lbD1lLGgudG9nZ2xlQ2xhc3MoImZhZGUtcGFuZWwiLGUpKSwiZGVidWctZXZhbFJlcGxheSI9PT10JiYoVi5vcHRpb25zLmV2YWxSZXBsYXk9by5ldmFsUmVwbGF5PWUpLGMoKX0pLFAudXBkYXRlKFt7bmFtZToiZGFya01vZGUiLGxhYmVsOiJEZWJ1ZyBwYW5lbCBpcyBkYXJrIn0se25hbWU6ImZhZGVQYW5lbCIsbGFiZWw6IkRlYnVnIHBhbmVsIGlzIHRyYW5zcGFyZW50IHVubGVzcyB0aGUgY3Vyc29yIGlzIG92ZXIgaXQifSx7bmFtZToiZXZhbFJlcGxheSIsbGFiZWw6IlJlY29yZCBleHByZXNzaW9uIHJlcGxheXMgKHZpZXdhYmxlIHZpYSBcdWQ4M2RcdWRkMGQgYnV0dG9ucyBpbiBEZWJ1ZyBWaWV3OyBzbG93ZXIpIn1dKSxoLnByZXBlbmQoUy5wYW5lbCx4LnBhbmVsLE4ucGFuZWwsQS5wYW5lbCxDLnBhbmVsLGoucGFuZWwsUC5wYW5lbCkscy5wcmVwZW5kKFMudGFiLHgudGFiLE4udGFiLEEudGFiLEMudGFiLGoudGFiLFAudGFiKSxELm9uKCJiZWZvcmVGb3J3YXJkIix5KS5vbigiYmVmb3JlQmFjayIseSkub24oImJlZm9yZUxvYWQiLHkpLGwoZnVuY3Rpb24oKXtUKCksdigpLHgucGFuZWxSb3dzLmVtcHR5KCkseC50YWJVcGRhdGUoMCksRC5wYXNzYWdlJiZ6LmdldChELnBhc3NhZ2UpJiYoQy51cGRhdGUoRS5jb25jYXQoe25hbWU6RC5wYXNzYWdlLHRhZzoiIn0pKSxDLnBhbmVsLmZpbmQoJ1tkYXRhLXRhZz0iIl0sIFtkYXRhLXRhZz0iIl0gKyAucGFuZWwtcm93LXNvdXJjZScpLmluc2VydEJlZm9yZShDLnBhbmVsLmZpbmQoJ1tkYXRhLXRhZz0iZm9vdGVyIl0nKS5maXJzdCgpKSl9KSk7RC5vbigiZm9yd2FyZCIsUikub24oImJhY2siLFIpLm9uKCJsb2FkIixSKTtLPWIsSShkb2N1bWVudC5oZWFkKS5hcHBlbmQoSSgiPHN0eWxlPiIpLmh0bWwoWCkpLGIoKSxlJiZkKGUsdCl9O3JldHVybiBGLnJlZ2lzdGVyRGVidWdNb2RlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIVYub3B0aW9ucy5kZWJ1ZyYmSyhlLHQpfSksS30pLGRlZmluZSgiZGVidWdtb2RlL3BhbmVsIixbImpxdWVyeSIsInV0aWxzL25hdHVyYWxzb3J0Il0sZnVuY3Rpb24oZCxlKXt2YXIgaT1lKCk7cmV0dXJuIE9iamVjdC5zZWFsKHtjcmVhdGU6ZnVuY3Rpb24oZSl7dmFyIG4sdD1lLmNsYXNzTmFtZSxyPWUucm93V3JpdGUsYT1lLnJvd0NoZWNrLG89ZS5yb3dTb3J0LGk9ZS5jb2x1bW5IZWFkLHM9ZS50YWJOYW1lLGM9ZS50YWJOYW1lQ291bnRlcixsPXZvaWQgMD09PWN8fGMsYz1lLnRhYlVwZGF0ZSx1PWQoIjxkaXYgY2xhc3M9J3BhbmVsIHBhbmVsLSIuY29uY2F0KHQsIicgc3R5bGU9JyIpLmNvbmNhdCh0aGlzLmRlZmF1bHRNYXhIZWlnaHQ/Im1heC1oZWlnaHQ6Iit0aGlzLmRlZmF1bHRNYXhIZWlnaHQrInB4IjoiIiwiJyBoaWRkZW4+PGRpdiBjbGFzcz1cInJlc2l6ZXItdlwiPjwvZGl2Pjx0YWJsZSBjbGFzcz0ncGFuZWwtcm93cyc+PC90YWJsZT48L2Rpdj4iKSkscD1kKCI8YnV0dG9uIGNsYXNzPSd0YWIgdGFiLSIuY29uY2F0KHQsIic+IikuY29uY2F0KGw/IjAgIi5jb25jYXQocywicyIpOnMsIjwvYnV0dG9uPiIpKTtyZXR1cm4gcC5jbGljayhmdW5jdGlvbigpe3AudG9nZ2xlQ2xhc3MoImVuYWJsZWQiKSxwLnBhcmVudCgpLnNpYmxpbmdzKCIucGFuZWwiKS5hdHRyKCJoaWRkZW4iLCIiKSxwLmlzKCIuZW5hYmxlZCIpJiYocC5zaWJsaW5ncygiLnRhYjpub3QoLnRhYi0iK3QrIikiKS5yZW1vdmVDbGFzcygiZW5hYmxlZCIpLHUucmVtb3ZlQXR0cigiaGlkZGVuIikpfSksdS5vbigiY2xpY2siLCJ0aCIsZnVuY3Rpb24oZSl7dmFyIGU9ZS50YXJnZXQsdD0iZGVzYyI9PT0oZT1kKGUpKS5hdHRyKCJkYXRhLW9yZGVyIik/ImFzYyI6ImRlc2MiO24uc29ydChlLmF0dHIoImRhdGEtY29sIiksdCksdS5maW5kKCJ0aFtkYXRhLW9yZGVyXSIpLnJlbW92ZUF0dHIoImRhdGEtb3JkZXIiKSxlLmF0dHIoImRhdGEtb3JkZXIiLHQpfSksYz1jfHxmdW5jdGlvbihlKXtyZXR1cm4gcC50ZXh0KGw/IiIuY29uY2F0KGUsIiAiKS5jb25jYXQocykuY29uY2F0KDEhPT1lPyJzIjoiIik6cyl9LG49T2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKHRoaXMpLHt0YWJOYW1lOnMsdGFiOnAscGFuZWw6dSxwYW5lbFJvd3M6dS5maW5kKCIucGFuZWwtcm93cyIpLHJvd1dyaXRlOnIscm93U29ydDpvLHJvd0NoZWNrOmEsY29sdW1uSGVhZDppLHRhYlVwZGF0ZTpjfSl9LHNvcnQ6ZnVuY3Rpb24ocixhKXt2YXIgbz10aGlzO3RoaXMucGFuZWxSb3dzLmNoaWxkcmVuKCI6bm90KC5wYW5lbC1oZWFkLCAucGFuZWwtcm93LXNvdXJjZSkiKS5nZXQoKS5zb3J0KGZ1bmN0aW9uKGUsdCl7dmFyIG47cmV0dXJuImRlc2MiPT09YSYmKGU9KG49W3QsZV0pWzBdLHQ9blsxXSksZT1lLnF1ZXJ5U2VsZWN0b3IoIi4iK3IpLHQ9dC5xdWVyeVNlbGVjdG9yKCIuIityKSxvLnJvd1NvcnQmJm8ucm93U29ydChyLGQoZSksZCh0KSl8fGkoZS50ZXh0Q29udGVudCx0LnRleHRDb250ZW50KX0pLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9ZChlKS5uZXh0KCIucGFuZWwtcm93LXNvdXJjZSIpLmdldCgpO28ucGFuZWxSb3dzLmFwcGVuZChlLHQpfSl9LHVwZGF0ZTpmdW5jdGlvbihlLHQpe3ZhciByPXRoaXMucm93Q2hlY2ssYT10aGlzLnJvd1dyaXRlLG89dGhpcy5wYW5lbFJvd3Msbj10aGlzLmNvbHVtbkhlYWQsaT10aGlzLnBhbmVsLHM9W10sYz1vLmNoaWxkcmVuKCksZT0oZS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciBlPWMuZ2V0KCkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiByKHQsZChlKSl9KSxuPWEodCxlLmxlbmd0aCYmZChlKSk7ZS5sZW5ndGh8fG8uYXBwZW5kKG4pLHMucHVzaC5hcHBseShzLF90b0NvbnN1bWFibGVBcnJheShuLmdldCgpKSl9KSxjLmZpbHRlcihmdW5jdGlvbihlLHQpe3JldHVybiFzLmluY2x1ZGVzKHQpJiYhdC5jbGFzc05hbWUuaW5jbHVkZXMoInBhbmVsLWhlYWQiKX0pLnJlbW92ZSgpLHRoaXMudGFiVXBkYXRlKHQpLDA8dCYmIW8uZmluZCgiLnBhbmVsLWhlYWQiKS5sZW5ndGg/by5wcmVwZW5kKG4oKSk6MD09PXQmJm8uZmluZCgiLnBhbmVsLWhlYWQiKS5yZW1vdmUoKSxpLmZpbmQoInRoW2RhdGEtb3JkZXJdIikpO2UubGVuZ3RoJiZ0aGlzLnNvcnQoZS5hdHRyKCJkYXRhLWNvbCIpLGUuYXR0cigiZGF0YS1vcmRlciIpKX0sZGVmYXVsdE1heEhlaWdodDozMDB9KX0pLGRlZmluZSgiaW50ZXJuYWx0eXBlcy9jaGFuZ2VkZXNjcmlwdG9yIixbImpxdWVyeSIsInV0aWxzIiwicmVuZGVyZXIiLCJkYXRhdHlwZXMvaG9va3NldCIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGIsZSx0LHYsbil7ZnVuY3Rpb24gdyhlKXtyZXR1cm4oInN0cmluZyI9PXR5cGVvZiBlP2U6ZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudGV4dH0pLmpvaW4oIiIpKS5zcGxpdCgvXG4vZykucmVkdWNlKGZ1bmN0aW9uKGUsdCxuLHIpe3I9ci5sZW5ndGg7cmV0dXJuIGUuY29uY2F0KGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHQpLG4hPT1yLTEmJmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodC5sZW5ndGg/ImJyIjoidHctY29uc2VjdXRpdmUtYnIiKSl9LFtdKX12YXIgaz1lLmltcG9zc2libGUsUz1lLnRyYW5zaXRpb25JbixUPXQuZXhlYyxyPU9iamVjdC5hc3NpZ24scD1PYmplY3Qua2V5cyxhPU9iamVjdC5jcmVhdGUsZT1PYmplY3Quc2VhbCxfPUFycmF5LmlzQXJyYXkseD17c291cmNlOiIiLGFwcGVuZFNvdXJjZTpudWxsLGVuYWJsZWQ6ITAsZW5hYmxlcnM6bnVsbCx2ZXJiYXRpbTohMSx0YXJnZXQ6bnVsbCxhcHBlbmQ6IiIsbmV3VGFyZ2V0czpudWxsLHRyYW5zaXRpb246IiIsdHJhbnNpdGlvblRpbWU6bnVsbCx0cmFuc2l0aW9uRGVmZXJyZWQ6ITEsdHJhbnNpdGlvbkRlbGF5OjAsdHJhbnNpdGlvblNraXA6MCx0cmFuc2l0aW9uT3JpZ2luOm51bGwsbG9vcFZhcnM6bnVsbCxzdHlsZXM6bnVsbCxhdHRyOm51bGwsZGF0YTpudWxsLGlubmVyRW5jaGFudG1lbnRzOm51bGwsc2VjdGlvbjpudWxsLHRpbWVzdGFtcDowLG91dHB1dDohMSxzdW1tYXJ5OmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcztyZXR1cm5bInNvdXJjZSIsImFwcGVuZFNvdXJjZSIsImVuYWJsZWQiLCJ2ZXJiYXRpbSIsInRhcmdldCIsImFwcGVuZCIsIm5ld1RhcmdldHMiLCJ0cmFuc2l0aW9uIiwidHJhbnNpdGlvblRpbWUiLCJ0cmFuc2l0aW9uRGVmZXJyZWQiLCJ0cmFuc2l0aW9uRGVsYXkiLCJ0cmFuc2l0aW9uU2tpcCIsInRyYW5zaXRpb25PcmlnaW4iLCJpbm5lckVuY2hhbnRtZW50cyIsImVuYWJsZXJzIiwib3V0cHV0Il0uZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBoYXNPd25Qcm9wZXJ0eS5jYWxsKHQsZSl9KS5jb25jYXQoW3RoaXMuYXR0ci5sZW5ndGgmJiJhdHRyIix0aGlzLnN0eWxlcy5sZW5ndGgmJiJzdHlsZXMiLHAodGhpcy5sb29wVmFycykubGVuZ3RoJiYibG9vcFZhcnMiLHAodGhpcy5kYXRhKS5sZW5ndGgmJiJkYXRhIl0uZmlsdGVyKEJvb2xlYW4pKX0sY3JlYXRlOmZ1bmN0aW9uKGUsdCl7ZT1yKGEodGhpcykse2F0dHI6dGhpcy5hdHRyP3RoaXMuYXR0ci5zbGljZSgpOltdLHN0eWxlczp0aGlzLnN0eWxlcz90aGlzLnN0eWxlcy5zbGljZSgpOltdLGxvb3BWYXJzOnRoaXMubG9vcFZhcnN8fHt9LGRhdGE6dGhpcy5kYXRhfHx7fX0sZSk7aWYodCl7dD10LnJ1bihlKTtpZihuLmNvbnRhaW5zRXJyb3IodCkpcmV0dXJuIHR9cmV0dXJuIGV9LHVwZGF0ZTpmdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7dmFyIGUsbixyO18oYS5zdHlsZXMpJiYwPGEuc3R5bGVzLmxlbmd0aCYmKG49KGU9X3NsaWNlZFRvQXJyYXkoYS5zdHlsZXMucmVkdWNlKGZ1bmN0aW9uKG4scil7cmV0dXJuIHAocikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1yW2VdO25bKygiZnVuY3Rpb24iPT10eXBlb2YgdCldLnB1c2goX2RlZmluZVByb3BlcnR5KHt9LGUsdCkpfSksbn0sW1tdLFtdXSksMikpWzBdLHI9ZVsxXSxuLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIHQuY3NzKGUpfSksc2V0VGltZW91dChmdW5jdGlvbigpe3IuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gdC5jc3MoZSl9KX0pKSxhLmF0dHImJmEuYXR0ci5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB0LmF0dHIoZSl9KSxhLmRhdGEmJnQuZGF0YShhLmRhdGEpfXZhciBhPXRoaXMsdD10aGlzLnNlY3Rpb24sbj10aGlzLm5ld1RhcmdldHMscj10aGlzLnRyYW5zaXRpb24sbz10aGlzLnRyYW5zaXRpb25EZWZlcnJlZCxpPXRoaXMuYXBwZW5kLHM9dGhpcy50YXJnZXQ7ImZ1bmN0aW9uIj09dHlwZW9mIHMmJihzPXMoKSk7aWYoXyhuKSYmbi5sZW5ndGgmJihzPW4ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRhcmdldH0pKSxfKHMpKWZvcih2YXIgYz0wO2M8cy5sZW5ndGg7Yys9MSl2LmlzUHJvdG90eXBlT2Yoc1tjXSk/c1tjXS5mb3JFYWNoKHQsZSk6ZShzW2NdKTtlbHNlIHYuaXNQcm90b3R5cGVPZihzKT9zLmZvckVhY2godCxlKTplKHMpO2lmKHImJiFvJiYhaSl7Zm9yKHZhciBsLHU9czsobD11LmRhdGEoInRpbWVzdGFtcCIpKXx8KHU9dS5wYXJlbnQoKSksIWwmJnUubGVuZ3RoOyk7UyhzLHIsdGhpcy50cmFuc2l0aW9uVGltZSx0aGlzLnRyYW5zaXRpb25EZWxheSx0aGlzLnRyYW5zaXRpb25Ta2lwLGw/RGF0ZS5ub3coKS1sOjAsdGhpcy50cmFuc2l0aW9uT3JpZ2luKX19LHJlbmRlcjpmdW5jdGlvbigpe3ZhciBlLHI9dGhpcyx0PXRoaXMuc291cmNlLG49dGhpcy50cmFuc2l0aW9uLGE9dGhpcy50cmFuc2l0aW9uVGltZSxvPXRoaXMudHJhbnNpdGlvbkRlZmVycmVkLGk9dGhpcy5lbmFibGVkLHM9dGhpcy5lbmFibGVycyxjPXRoaXMuZGF0YSxsPXRoaXMuc2VjdGlvbix1PXRoaXMubmV3VGFyZ2V0cyxwPXRoaXMuaW5uZXJFbmNoYW50bWVudHMsZD10aGlzLmFwcGVuZFNvdXJjZSxmPXRoaXMub3V0cHV0LGg9dGhpcy50YXJnZXQsbT10aGlzLnRhcmdldCxnPXRoaXMuYXBwZW5kO2lmKCJmdW5jdGlvbiI9PXR5cGVvZiBoJiYoaD1oKCkpLCFnKXJldHVybiBrKCJDaGFuZ2VEZXNjcmlwdG9yLnJlbmRlciIsIlRoaXMgZG9lc24ndCBoYXZlIGFuICdhcHBlbmQnIG1ldGhvZCBjaG9zZW4uIiksYigpO2lmKGYpcmV0dXJuIGIoKTtpZihudWxsIT1zJiZzLmxlbmd0aClyZXR1cm4gcz0oZj1zWzBdKS5kZXNjcmlwdG9yLGY9Zi5jaGFuZ2VyLHM9cy5yZW5kZXIoKSxmJiYoZT14LmNyZWF0ZSh7c2VjdGlvbjpsLHRhcmdldDpzfSksZi5ydW4oZSksZS51cGRhdGUoKSkscztpZighaXx8dm9pZCAwIT09aC5hdHRyKCJoaWRkZW4iKSlyZXR1cm4geC5jcmVhdGUoe3RhcmdldDpoLGF0dHI6dGhpcy5hdHRyLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hKCJzdHlsZSJpbiBlKX0pLGRhdGE6X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGMpLHt9LHtvcmlnaW5hbFNvdXJjZTp0LGhpZGRlbjohMH0pfSkudXBkYXRlKCksYigpO2lmKCEoaD1fKHUpJiZ1Lmxlbmd0aD91OmgpKXJldHVybiBrKCJDaGFuZ2VEZXNjcmlwdG9yLnJlbmRlciIsIkNoYW5nZURlc2NyaXB0b3IgaGFzIHNvdXJjZSBidXQgbm90IGEgdGFyZ2V0ISIpLGIoKTt2YXIgeT1iKCk7aWYoW10uY29uY2F0KGgpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hZS5qcXVlcnl9KS5tYXAoZnVuY3Rpb24oZSl7dmFyIHQsbixyPWc7cmV0dXJuIGUudGFyZ2V0JiZlLmFwcGVuZCYmKHI9KHQ9ZSkuYXBwZW5kLG49dC5iZWZvcmUsZT1lLnRhcmdldCkse2VsZW1lbnRzOmUuaG9va3MobCxtKS5maWx0ZXIoZnVuY3Rpb24oKXtyZXR1cm4hKG4mJjEmdGhpcy5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihkb2N1bWVudCkmJjImdGhpcy5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihtWzBdKSl9KSxhcHBlbmQ6cn19LFtdKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuZWxlbWVudHMsbj1lLmFwcGVuZDt0LmVhY2goZnVuY3Rpb24oZSx0KXt0PWIodCkseT15LmFkZChyLmNyZWF0ZSh7dGFyZ2V0OnQsYXBwZW5kOm4sbmV3VGFyZ2V0czpudWxsfSkucmVuZGVyKCkpLHQuZmlsdGVyKCJ0dy1wc2V1ZG8taG9vayIpLmNvbnRlbnRzKCkudW53cmFwKCl9KX0pLCEoeS5sZW5ndGh8fF8oaCl8fHYuaXNQcm90b3R5cGVPZihoKSkpe2Y9ZztpZighKGYgaW4gaCkpe2lmKCJyZXBsYWNlIiE9PWYpcmV0dXJuIGsoIkNoYW5nZURlc2NyaXB0b3IucmVuZGVyIiwiVGhlIHRhcmdldCBkb2Vzbid0IGhhdmUgYSAnIitmKyInIG1ldGhvZC4iKSxiKCk7Zj1oWzBdaW5zdGFuY2VvZiBUZXh0PyJyZXBsYWNlV2l0aCI6KGguZW1wdHkoKSwiYXBwZW5kIil9aFswXWluc3RhbmNlb2YgVGV4dCYmInByZXBlbmQiPT09KGY9ImFwcGVuZCI9PT1mPyJhZnRlciI6ZikmJihmPSJiZWZvcmUiKSx5PWIodCYmKHRoaXMudmVyYmF0aW0/dzpUKSh0KSksXyhkKSYmZC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuc291cmNlLGU9ZS5hcHBlbmQsdD1iKChyLnZlcmJhdGltP3c6VCkodCkpO3k9ImFwcGVuZCI9PT1lP3kuYWRkKHQpOiJwcmVwZW5kIj09PWU/dC5hZGQoeSk6dH0pLGhbZl0oeS5sZW5ndGg/eTp2b2lkIDApLGguZGF0YSgidGltZXN0YW1wIixEYXRlLm5vdygpKSx0aGlzLnVwZGF0ZSgpLG4mJiFvJiZTKCJyZXBsYWNlIj09PWc/aDp5LG4sYSx0aGlzLnRyYW5zaXRpb25EZWxheSx0aGlzLnRyYW5zaXRpb25Ta2lwLHRoaXMuZXhwZWRpdGUsdGhpcy50cmFuc2l0aW9uT3JpZ2luKSxwJiZwLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZShoKX0pLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGwuYWRkRW5jaGFudG1lbnQoZSl9KX1yZXR1cm4geX19O3JldHVybiBlKHgpfSksZGVmaW5lKCJpbnRlcm5hbHR5cGVzL2VuY2hhbnRtZW50IixbImpxdWVyeSIsInV0aWxzIiwiaW50ZXJuYWx0eXBlcy9jaGFuZ2VkZXNjcmlwdG9yIiwiZGF0YXR5cGVzL2NoYW5nZXJjb21tYW5kIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJ1dGlscy9yZW5kZXJ1dGlscyJdLGZ1bmN0aW9uKGcseSxiLHYsZSx3LHQpe3ZhciBrPWUub2JqZWN0TmFtZSxTPWUudG9Tb3VyY2UsVD10LmNvbGxhcHNlO3JldHVybiBPYmplY3QuZnJlZXplKHtjcmVhdGU6ZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oT2JqZWN0LmNyZWF0ZSh0aGlzKSx7ZW5jaGFudG1lbnRzOmcoKX0sZSl9LGVuY2hhbnRTY29wZTpmdW5jdGlvbigpe3ZhciBpPXRoaXMscz10aGlzLmF0dHIsYz10aGlzLmRhdGEsbD10aGlzLmZ1bmN0aW9ucyx1PXRoaXMuc2VjdGlvbixwPXRoaXMuc2NvcGUsZD10aGlzLmxvY2FsSG9vayxmPXRoaXMubGFtYmRhLGg9W10sbT0wO3AuZm9yRWFjaCh1LGZ1bmN0aW9uKGUsdCl7aWYoZCl7ZD1kLmpxdWVyeT9kOmQuaG9va3ModSk7dmFyIG49ZS5maW5kKGQpO2lmKG4ubGVuZ3RoKWU9bjtlbHNlIGlmKCFkLmhhcyhlWzBdKS5sZW5ndGgpcmV0dXJufXZhciByLGEsbzsoIWUuaXMoIjplbXB0eSIpfHxlLmRhdGEoInNvdXJjZSIpJiZlLmRhdGEoInNvdXJjZSIpLmxlbmd0aCkmJihtKz0xLGY/KG89Zi5hcHBseSh1LHtsb29wOnAuVHdpbmVTY3JpcHRfR2V0UHJvcGVydHkodCkscG9zOm19KSx3LmNvbnRhaW5zRXJyb3Iobyk/KGUucmVwbGFjZVdpdGgoby5yZW5kZXIoKSksZj1vPW51bGwpOnYuaXNQcm90b3R5cGVPZihvKT9vLmNhbkVuY2hhbnR8fChlLnJlcGxhY2VXaXRoKHcuY3JlYXRlKCJtYWNyb2NhbGwiLCdUaGUgbGFtYmRhICInLmNvbmNhdChTKGYpLCJcIiBjYW4ndCBiZSBvciBpbmNsdWRlIGEgcmV2aXNpb24sIGVuY2hhbnRtZW50LCBvciBpbnRlcmFjdGlvbiBjaGFuZ2VyIGxpa2UgKHJlcGxhY2U6KSwgKGNsaWNrOiksIG9yIChsaW5rOikuIikpLnJlbmRlcigpKSxmPW89bnVsbCk6KGUucmVwbGFjZVdpdGgody5jcmVhdGUoIm1hY3JvY2FsbCIsJ1RoZSBsYW1iZGEgIicuY29uY2F0KFMoZiksJyIgbXVzdCByZXR1cm4gYSBjaGFuZ2VyLCBub3QgJykuY29uY2F0KGsobyksIi4iKSkucmVuZGVyKCkpLGY9bz1udWxsKSk6bz1pLmNoYW5nZXIsbj0hcyYmIWMmJighb3x8by5zdW1tYXJ5KCkuZXZlcnkoZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3RhcnRzV2l0aCgidHJhbnNpdGlvbiIpfSkpLHI9bj9lOmUud3JhcCgiPHR3LWVuY2hhbnRtZW50PiIpLnBhcmVudCgpLHMmJnIuYXR0cihzKSxjJiZyLmRhdGEoYyksbCYmbC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKHIpfSksbyYmKHQ9Yi5jcmVhdGUoe3NlY3Rpb246dSx0YXJnZXQ6cn0pLG8ucnVuKHQpLHQudXBkYXRlKCksZS5pcyh5LnN0b3J5RWxlbWVudCk/KGE9T2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbi5hcHBseShPYmplY3QsW3t9XS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KHQuc3R5bGVzKSkpKSxlLmNzcyhhLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiJiYWNrZ3JvdW5kLWNvbG9yIj09PXR8fCJiYWNrZ3JvdW5kLWltYWdlIj09PXQ/KGVbImJhY2tncm91bmQtY29sb3IiXT0idHJhbnNwYXJlbnQiLGVbImJhY2tncm91bmQtaW1hZ2UiXT0ibm9uZSIsYS5wdXNoKCJiYWNrZ3JvdW5kLSIuY29uY2F0KCJiYWNrZ3JvdW5kLWNvbG9yIj09PXQ/ImltYWdlIjoiY29sb3IiKSkpOmVbdF09ImluaGVyaXQiLGV9LHt9KSksci5kYXRhKHtlbmNoYW50ZWRQcm9wZXJ0aWVzOmF9KSk6ZS5pcygidHctcGFzc2FnZSIpJiZ0LnN0eWxlcy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiJtYXJnaW4tbGVmdCJpbiBlfHwibWFyZ2luImluIGV8fCJtYXJnaW4tcmlnaHQiaW4gZX0pJiYobz0icGFkZGluZy1yaWdodCIseS5zdG9yeUVsZW1lbnQuY3NzKHQ9InBhZGRpbmctbGVmdCIsIjBweCIpLmNzcyhvLCIwcHgiKSxyLmRhdGEoe2VuY2hhbnRlZFByb3BlcnRpZXM6W3Qsb119KSkpLGUuaXMoeS5zdG9yeUVsZW1lbnQpJiZyLmNzcyh7Im1pbi13aWR0aCI6IjEwMCUiLCJtaW4taGVpZ2h0IjoiMTAwJSJ9KSwidHJ1ZSI9PT1yLmF0dHIoImNvbGxhcHNpbmciKSYmKHIuZmluZCgiW2NvbGxhcHNpbmc9ZmFsc2VdIikuZWFjaChmdW5jdGlvbigpe2codGhpcykucmVtb3ZlQXR0cigiY29sbGFwc2luZyIpfSksVChyKSksbnx8aC5wdXNoKHIpKX0pLHRoaXMuZW5jaGFudG1lbnRzPWcoaCl9LGRpc2VuY2hhbnQ6ZnVuY3Rpb24oKXt0aGlzLmVuY2hhbnRtZW50cy5lYWNoKGZ1bmN0aW9uKGUsdCl7KHQ9Zyh0KSkuY29udGVudHMoKS51bndyYXAoKTt0PXQuZGF0YSgiZW5jaGFudGVkUHJvcGVydGllcyIpO3QmJnkuc3RvcnlFbGVtZW50LmNzcyh0LnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlW3RdPSIiLGV9LHt9KSl9KX19KX0pLGRlZmluZSgiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIixbImpxdWVyeSIsInV0aWxzIl0sZnVuY3Rpb24oaSxzKXt2YXIgYT1zLmltcG9zc2libGUsYz1zLmVzY2FwZSxsPShpKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCkub24oImNsaWNrIiwidHctZm9sZGRvd24iLGZ1bmN0aW9uKGUpe3ZhciB0PWUudGFyZ2V0LGU9KCh0PWkodCkpLnRvZ2dsZUNsYXNzKCJvcGVuIiksdC5wb3BEYXRhKCJmb2xkZG93biIpKTtmb3IoImZ1bmN0aW9uIj09dHlwZW9mIGUmJmUodCk7dCYmIXQubmV4dCgpLmxlbmd0aDspdD10LnBhcmVudCgpO251bGwhPShlPXQpJiZlLm5leHQoKS50b2dnbGUoKX0pLHtzeW50YXg6IlRoZSBtYXJrdXAgc2VlbXMgdG8gY29udGFpbiBhIG1pc3Rha2UuIixzYXZpbmc6IkkgdHJpZWQgdG8gc2F2ZSBvciBsb2FkIHRoZSBnYW1lLCBidXQgSSBjb3VsZG4ndCBkbyBpdC4iLG9wZXJhdGlvbjoiSSB0cmllZCB0byBwZXJmb3JtIGFuIG9wZXJhdGlvbiBvbiBzb21lIGRhdGEsIGJ1dCB0aGUgZGF0YSdzIHR5cGUgd2FzIGluY29ycmVjdC4iLG1hY3JvY2FsbDoiSSB0cmllZCB0byB1c2UgYSBtYWNybywgYnV0IGl0cyBjYWxsIHdhc24ndCB3cml0dGVuIGNvcnJlY3RseS4iLGRhdGF0eXBlOiJJIHRyaWVkIHRvIHVzZSBhIG1hY3JvLCBidXQgd2FzIGdpdmVuIHRoZSB3cm9uZyB0eXBlIG9mIGRhdGEgdG8gaXQuIixjdXN0b21tYWNybzoiSSB0cmllZCB0byB1c2UgYSBjdXN0b20gbWFjcm8sIGJ1dCBpdHMgY29kZSBob29rIGhhZCBhIG1pc3Rha2UgaW4gaXQuIixpbmZpbml0ZToiSSBhbG1vc3QgZW5kZWQgdXAgZG9pbmcgdGhlIHNhbWUgdGhpbmcgb3ZlciBhbmQgb3ZlciwgZm9yZXZlci4iLHByb3BlcnR5OiJJIHRyaWVkIHRvIGFjY2VzcyBhIHZhbHVlIGluIGEgc3RyaW5nL2FycmF5L2RhdGFtYXAsIGJ1dCBJIGNvdWxkbid0IGZpbmQgaXQuIix1bmltcGxlbWVudGVkOiJJIGN1cnJlbnRseSBkb24ndCBoYXZlIHRoaXMgcGFydGljdWxhciBmZWF0dXJlLiBJJ20gc29ycnkuIixwcm9wYWdhdGVkOiJDbGljayB0aGUgJ09wZW4nIGJ1dHRvbiB0byBzZWUgdGhlIGNvZGUgaG9vayBhcyBpdCB3YXMgZXhlY3V0ZWQuIix1c2VyOiJUaGlzIGlzIGEgY3VzdG9tIGVycm9yIGNyZWF0ZWQgYnkgKGVycm9yOikuIEl0IHVzdWFsbHkgbWVhbnMgeW91IHVzZWQgYSBjdXN0b20gbWFjcm8gaW5jb3JyZWN0bHkuIixhc3NlcnRpb246IlRoaXMgY29tbWFuZCBleGlzdHMgdG8gcHJvdmlkZSBhIGhlbHBmdWwgZXJyb3IgaWYgYSBjZXJ0YWluIGltcG9ydGFudCBjb25kaXRpb24gd2Fzbid0IHRydWUuIixkZWJ1Z29ubHk6IlRoaXMgbWFjcm8gaXMgbm90IG1lYW50IHRvIGJlIHVzZWQgb3V0c2lkZSBvZiBkZWJ1Z2dpbmcgeW91ciBzdG9yeS4ifSksdT1bXSxuPXtUd2luZUVycm9yOiEwLGNyZWF0ZTpmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gdCYmInN0cmluZyI9PXR5cGVvZiB0fHxhKCJUd2luZUVycm9yLmNyZWF0ZSIsImhhcyBhIGJhZCBtZXNzYWdlIHN0cmluZyIpLG58fGUgaW4gbHx8YSgiVHdpbmVFcnJvci5jcmVhdGUiLCJubyBlcnJvciBleHBsYW5hdGlvbiBnaXZlbiIpLCJ1c2VyIiE9PWUmJih0PXRbMF0udG9VcHBlckNhc2UoKSt0LnNsaWNlKDEpKSxPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUodGhpcykse3R5cGU6ZSxtZXNzYWdlOnQsZXhwbGFuYXRpb246bixzb3VyY2U6dm9pZCAwLGlubmVyRE9NOnIsYXBwZW5kVGl0bGVUZXh0OiExfSl9LGNvbnRhaW5zRXJyb3I6ZnVuY3Rpb24oKXtmb3IodmFyIGU9MDtlPGFyZ3VtZW50cy5sZW5ndGg7ZSs9MSl7dmFyIHQ9YXJndW1lbnRzW2VdO2lmKG4uaXNQcm90b3R5cGVPZih0KSlyZXR1cm4gdDtpZihBcnJheS5pc0FycmF5KHQpKXt0PW4uY29udGFpbnNFcnJvci5hcHBseShuLHQpO2lmKHQpcmV0dXJuIHR9fXJldHVybiExfSxjcmVhdGVXYXJuaW5nOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5hc3NpZ24odGhpcy5jcmVhdGUoZSx0KSx7d2FybmluZzohMH0pfSxyZW5kZXI6ZnVuY3Rpb24odCl7dmFyIG49dGhpcyxlPTE8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzFdJiZhcmd1bWVudHNbMV0scj0odD0ic3RyaW5nIj09dHlwZW9mIHQ/dDp0aGlzLnNvdXJjZXx8IiIsaSgiPHR3LWVycm9yIGNsYXNzPSciKyh0aGlzLndhcm5pbmc/Indhcm5pbmciOiJlcnJvciIpKyInIHRpdGxlPSciK2ModCkrIic+IitjKHRoaXMubWVzc2FnZSsodGhpcy5hcHBlbmRUaXRsZVRleHQ/IiAiK3Q6IiIpKSsiPC90dy1lcnJvcj4iKSksYT1pKCI8dHctZXJyb3ItZXhwbGFuYXRpb24+IikudGV4dCh0aGlzLmV4cGxhbmF0aW9ufHxsW3RoaXMudHlwZV0pLmhpZGUoKSxvPWkoIjx0dy1mb2xkZG93biB0YWJpbmRleD0wPiIpO3JldHVybiB0aGlzLmlubmVyRE9NJiZpKCI8dHctb3Blbi1idXR0b24gbGFiZWw9J09wZW4nPiIpLm9uKCJjbGljayIsZnVuY3Rpb24oKXt2YXIgZT1pKCI8dHctYmFja2Ryb3A+PHR3LWRpYWxvZz48L3R3LWJhY2tkcm9wPiIpO2UuZmluZCgidHctZGlhbG9nIikucHJlcGVuZChuLmlubmVyRE9NLGkoIjx0dy1saW5rIHRhYmluZGV4PTA+T0s8L3R3LWxpbms+Iikub24oImNsaWNrIixmdW5jdGlvbigpe24uaW5uZXJET00uZGV0YWNoKCksZS5yZW1vdmUoKX0pLndyYXAoIjx0dy1kaWFsb2ctbGlua3M+IikucGFyZW50KCkpLHMuc3RvcnlFbGVtZW50LnByZXBlbmQoZSl9KS5hcHBlbmRUbyhyKSxyLmFwcGVuZChvKS5hcHBlbmQoYSksci5kYXRhKCJUd2luZUVycm9yIix0aGlzKSxlfHx1LmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUobix0KX0pLHJ9LG9uOmZ1bmN0aW9uKGUpe3JldHVybiJmdW5jdGlvbiIhPXR5cGVvZiBlfHx1LmluY2x1ZGVzKGUpfHx1LnB1c2goZSksbn19O3JldHVybiBPYmplY3QucHJldmVudEV4dGVuc2lvbnMobil9KSxkZWZpbmUoImludGVybmFsdHlwZXMvdHdpbmVub3RpZmllciIsWyJqcXVlcnkiLCJ1dGlscyJdLGZ1bmN0aW9uKGUsdCl7dmFyIG49dC5pbXBvc3NpYmxlLHI9e2NyZWF0ZTpmdW5jdGlvbihlKXtyZXR1cm4gZXx8bigiVHdpbmVOb3RpZmllci5jcmVhdGUiLCJjYWxsZWQgd2l0aCBvbmx5IDEgc3RyaW5nLiIpLE9iamVjdC5hc3NpZ24oT2JqZWN0LmNyZWF0ZShyKSx7bWVzc2FnZTplfSl9LHJlbmRlcjpmdW5jdGlvbigpe3JldHVybiBlKCI8dHctbm90aWZpZXI+IikuYXR0cigibWVzc2FnZSIsdGhpcy5tZXNzYWdlKX19O3JldHVybiBPYmplY3QucHJldmVudEV4dGVuc2lvbnMocil9KSxkZWZpbmUoImludGVybmFsdHlwZXMvdmFycmVmIixbInN0YXRlIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIiwidXRpbHMiLCJ1dGlscy9vcGVyYXRpb251dGlscyIsImRhdGF0eXBlcy9ob29rc2V0Il0sZnVuY3Rpb24odSxwLGUsdCxpKXt2YXIgYyxuPWUuaW1wb3NzaWJsZSxzPWUuYW5kTGlzdCxyPWUubnRoLG89dC5pcyxkPXQuaXNPYmplY3QsZj10LnRvU291cmNlLGg9dC5pc1NlcXVlbnRpYWwsbT10Lm9iamVjdE5hbWUsbD10LnR5cGVOYW1lLGc9dC5jbG9uZSx5PXQuaXNWYWxpZERhdGFtYXBOYW1lLGI9dC5zdWJzZXQsdj10LmNvbGxlY3Rpb25UeXBlLHc9dC51bnN0b3JhYmxlVmFsdWUsYT10Lm1hdGNoZXMsaz1BcnJheS5pc0FycmF5LFM9e3NldDpbXSxkZWxldGU6W119LFQ9IllvdSBjYW4gb25seSBhY2Nlc3MgcG9zaXRpb24gc3RyaW5ncy9udW1iZXJzICgnNHRoJywgJ2xhc3QnLCAnMm5kbGFzdCcsICgyKSwgZXRjLiksIHNsaWNlcyAoJzFzdFRvMm5kbGFzdCcsICczcmRUbzV0aCcpLCAiLF89IllvdSBjYW4ndCBhY2Nlc3MgdGhlICcwdGgnIG9yICcwdGhsYXN0JyBwb3NpdGlvbiBvZiAiO2Z1bmN0aW9uIHgoZSx0KXtpZihwLmNvbnRhaW5zRXJyb3IodCkpcmV0dXJuIG47aWYoZSBpbnN0YW5jZW9mIE1hcCYmKG49cC5jb250YWluc0Vycm9yKHkoZSx0KSkpKXJldHVybiBuO2lmKGgoZSkpaWYoIm51bWJlciI9PXR5cGVvZiB0KXtpZigwPT09dClyZXR1cm4gcC5jcmVhdGUoInByb3BlcnR5IiwiWW91IGNhbid0IGFjY2VzcyBlbGVtZW50cyBhdCBwb3NpdGlvbiAwIG9mICIuY29uY2F0KG0oZSksIi4iKSwiT25seSBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgcG9zaXRpb24gdmFsdWVzIGV4aXN0LiIpOzA8dCYmLS10fWVsc2UgaWYoInN0cmluZyI9PXR5cGVvZiB0JiYocj0vXihcZCspKD86c3R8W25yXWR8dGgpbGFzdCQvaS5leGVjKHQpKSl7aWYoIjAiPT09clsxXSlyZXR1cm4gcC5jcmVhdGUoInByb3BlcnR5IixfK20oZSkrIi4iKTt0PS1yWzFdfWVsc2UgaWYoInN0cmluZyI9PXR5cGVvZiB0JiYocj0vXihcZCspKD86c3R8W25yXWR8dGgpJC9pLmV4ZWModCkpKXtpZigiMCI9PT1yWzFdKXJldHVybiBwLmNyZWF0ZSgicHJvcGVydHkiLF8rbShlKSsiLiIpO3Q9clsxXS0xfWVsc2UgaWYoInN0cmluZyI9PXR5cGVvZiB0JiYocj0vXig/OihcZCspKD86c3R8W25yXWR8dGgpKGxhc3QpP3xsYXN0KXRvKD86KFxkKykoPzpzdHxbbnJdZHx0aCkobGFzdCk/fGxhc3QpJC9pLmV4ZWModCkpKXt2YXIgbj1fc2xpY2VkVG9BcnJheShyLDUpLHI9blsxXSxyPXZvaWQgMD09PXI/MDpyLGE9blsyXSxvPW5bM10sbz12b2lkIDA9PT1vPzA6bzt0PXtsYXN0Om5bNF0/LW86by0xLGZpcnN0OmE/LXI6ci0xfX1lbHNlIGlmKCJsYXN0Ij09PXQpdD0tMTtlbHNlIGlmKCJyYW5kb20iPT09dCl7aWYoIWUubGVuZ3RoKXJldHVybiBwLmNyZWF0ZSgicHJvcGVydHkiLCJJIGNhbid0IGdldCBhIHJhbmRvbSB2YWx1ZSBmcm9tICIuY29uY2F0KG0oZSksIiwgYmVjYXVzZSBpdCdzIGVtcHR5LiIpKTt0PXUucmFuZG9tKCkqQXJyYXkuZnJvbShlKS5sZW5ndGh8MH1lbHNle2lmKGkuaXNQcm90b3R5cGVPZihlKSYmIWkuVHdpbmVTY3JpcHRfUHJvcGVydGllcy5pbmNsdWRlcyh0KSlyZXR1cm4gcC5jcmVhdGUoInByb3BlcnR5IiwiIi5jb25jYXQoVCtzKGkuVHdpbmVTY3JpcHRfUHJvcGVydGllcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIiciK2UrIicifSkpLCIgb2YgIikuY29uY2F0KG0oZSksIiwgbm90ICIpLmNvbmNhdCgoInN0cmluZyI9PXR5cGVvZiB0P2Y6bSkodCksIi4iKSk7aWYoIVsibGVuZ3RoIiwic29tZSIsImFueSIsImFsbCIsInN0YXJ0IiwiZW5kIiwicmFuZG9tIl0uaW5jbHVkZXModCkmJiFpLmlzUHJvdG90eXBlT2YoZSkpcmV0dXJuIHAuY3JlYXRlKCJwcm9wZXJ0eSIsIiIuY29uY2F0KFQsIidsZW5ndGgnLCAnc29tZScsICdhbnknLCAnYWxsJywgJ3N0YXJ0JywgJ2VuZCcsIGFuZCAncmFuZG9tJyBvZiAiKS5jb25jYXQobShlKSwiLCBub3QgIikuY29uY2F0KCgic3RyaW5nIj09dHlwZW9mIHQ/ZjptKSh0KSwiLiIpKX1lbHNlIGlmKGUgaW5zdGFuY2VvZiBTZXQpe2lmKCFbImxlbmd0aCIsInNvbWUiLCJhbnkiLCJhbGwiXS5pbmNsdWRlcyh0KSlyZXR1cm4gcC5jcmVhdGUoInByb3BlcnR5IiwiIi5jb25jYXQoVCwiJ2xlbmd0aCcsICdzb21lJywgJ2FueScsIGFuZCAnYWxsJyBvZiAiKS5jb25jYXQobShlKSwiLiIpLCJZb3UgY2FuJ3QgYWNjZXNzIHNwZWNpZmljIGluZGl2aWR1YWwgZGF0YSB2YWx1ZXMgZnJvbSBkYXRhc2V0cy4iKTsibGVuZ3RoIj09PXQmJih0PSJzaXplIil9ZWxzZXtpZihrKGUuVHdpbmVTY3JpcHRfUHJvcGVydGllcykmJiFlLlR3aW5lU2NyaXB0X1Byb3BlcnRpZXMuaW5jbHVkZXModCkpcmV0dXJuIHAuY3JlYXRlKCJwcm9wZXJ0eSIsIllvdSBjYW4gb25seSBnZXQgdGhlICIuY29uY2F0KHMoZS5Ud2luZVNjcmlwdF9Qcm9wZXJ0aWVzLm1hcChmdW5jdGlvbihlKXtyZXR1cm4iJyIrZSsiJyJ9KSksIiBvZiAiKS5jb25jYXQobShlKSwiLCBub3QgIikuY29uY2F0KCgic3RyaW5nIj09dHlwZW9mIHQ/ZjptKSh0KSwiLiIpKTtpZigibnVtYmVyIj09dHlwZW9mIGV8fCJib29sZWFuIj09dHlwZW9mIGUpcmV0dXJuIHAuY3JlYXRlKCJwcm9wZXJ0eSIsIllvdSBjYW4ndCBnZXQgYW55IGRhdGEgdmFsdWVzLCBsZXQgYWxvbmUgIi5jb25jYXQobSh0KSwiLCBmcm9tICIpLmNvbmNhdChtKGUpKSl9cmV0dXJuIHR9ZnVuY3Rpb24gTyhlLHQpe3JldHVybit0PDAmJk1hdGguYWJzKHQpPD1lLmxlbmd0aD9lLmxlbmd0aCsgK3Q6dH12YXIgQT0vW15cdUQ4MDEtXHVERkZGXS8sQz1uZXcgTWFwO2Z1bmN0aW9uIEUoZSx0KXt2YXIgbixyLGE7cmV0dXJuIHZvaWQgMD09PWU/ZTplIGluc3RhbmNlb2YgTWFwP2UuZ2V0KHQpOiJzb21lIiE9PXQmJiJhbnkiIT09dCYmImFsbCIhPT10JiYic3RhcnQiIT09dCYmImVuZCIhPT10fHxlLlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU/KCJzdHJpbmciPT10eXBlb2YgZSYmKEMuaGFzKGUpP2U9Qy5nZXQoZSk6QS50ZXN0KGUpPyhhPV90b0NvbnN1bWFibGVBcnJheShlKSxDLnNldChlLGEpLGU9YSk6Qy5zZXQoZSxlKSksaChlKSYmTnVtYmVyLmlzRmluaXRlKHQpJiYodD1PKGUsdCkpLGUuVHdpbmVTY3JpcHRfR2V0UHJvcGVydHk/ZS5Ud2luZVNjcmlwdF9HZXRQcm9wZXJ0eSh0KToiZnVuY3Rpb24iIT10eXBlb2YoYT1lW3RdKT9hOnZvaWQgMCk6KG49ZSxyPXQsYT0nIicuY29uY2F0KHIsIiB2YWx1ZSIpLmNvbmNhdCgiYW55Ij09PXI/IiI6InMiLCciIG9mICcpLHtkZXRlcm1pbmVyOnIsZGV0ZXJtaW5lZDpuLGFycmF5Ol90b0NvbnN1bWFibGVBcnJheShuKSxzdHJpbmc6InN0cmluZyI9PXR5cGVvZiBuJiZuLFR3aW5lU2NyaXB0X09iamVjdE5hbWU6YSttKG4pLFR3aW5lU2NyaXB0X1RvU291cmNlOmZ1bmN0aW9uKCl7cmV0dXJuIiIuY29uY2F0KHIsIiBvZiAiKS5jb25jYXQoZihuKSl9LFR3aW5lU2NyaXB0X1R5cGVOYW1lOmErImEgZGF0YSBzdHJ1Y3R1cmUiLFR3aW5lU2NyaXB0X1Vuc3RvcmFibGU6ITAsVHdpbmVTY3JpcHRfUHJpbnQ6ZnVuY3Rpb24oKXtyZXR1cm4iYFsiK3RoaXMuVHdpbmVTY3JpcHRfVHlwZU5hbWUrIl1gIn19KX1mdW5jdGlvbiBOKGUpe3ZhciB0O3JldHVybiBlLmNvbXB1dGVkPyh0PWUudmFsdWUsInN0cmluZyI9PXR5cGVvZih0PWMuaXNQcm90b3R5cGVPZih0KT90LmdldCgpOnQpPyIoJyIrdCsiJykiOiIoIit0KyIpIik6Im51bWJlciI9PXR5cGVvZiBlP3IoZSk6IiciK2UrIicifWZ1bmN0aW9uIGoodCxlLG4pe2lmKHQuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSl7aWYodC5Ud2luZVNjcmlwdF9UeXBlRGVmcyYmZSBpbiB0LlR3aW5lU2NyaXB0X1R5cGVEZWZzKXt2YXIgcj10LlR3aW5lU2NyaXB0X1R5cGVEZWZzW2VdO2lmKCJjb25zdCI9PT1yLm5hbWUpe2lmKHZvaWQgMCE9PXRbZV0pcmV0dXJuIHAuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IGFsdGVyICIuY29uY2F0KHQ9PT11LnZhcmlhYmxlcz8iJCI6Il8iKS5jb25jYXQoZSwiIGJlY2F1c2UgaXQncyBiZWVuIHJlc3RyaWN0ZWQgdG8gYSBjb25zdGFudCB2YWx1ZS4iKSwiVGhpcyB2YXJpYWJsZSBjYW4ndCBiZSBjaGFuZ2VkIGZvciB0aGUgcmVzdCBvZiB0aGUgc3RvcnkuIil9ZWxzZSBpZighYShyLG4pKXJldHVybiBwLmNyZWF0ZSgib3BlcmF0aW9uIiwiSSBjYW4ndCBzZXQgIi5jb25jYXQodD09PXUudmFyaWFibGVzPyIkIjoiXyIpLmNvbmNhdChlLCIgdG8gIikuY29uY2F0KGwobiksIiBiZWNhdXNlIGl0J3MgYmVlbiByZXN0cmljdGVkIHRvICIpLmNvbmNhdChmKHIpLCItdHlwZSBkYXRhLiIpLCJZb3UgY2FuIHJlc3RyaWN0IGEgdmFyaWFibGUgb3IgZGF0YSBuYW1lIGJ5IGdpdmluZyBhIHR5cGVkIHZhcmlhYmxlIHRvIChzZXQ6KSBvciAocHV0OikuIil9cmV0dXJuITB9cmV0dXJuIGsoZSk/ZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGoodCxlKX0pOnQgaW5zdGFuY2VvZiBNYXA/InN0cmluZyI9PXR5cGVvZiBlfHxwLmNyZWF0ZSgib3BlcmF0aW9uIiwiIi5jb25jYXQobSh0KSwiIGNhbiBvbmx5IGhhdmUgc3RyaW5nIGRhdGEgbmFtZXMsIG5vdCAiKS5jb25jYXQobShlKSwiLiIpKTpoKHQpP1sibGVuZ3RoIiwicmFuZG9tIiwic29tZSIsImFueSIsImFsbCIsInN0YXJ0IiwiZW5kIl0uaW5jbHVkZXMoZSk/cC5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgZm9yY2libHkgYWx0ZXIgdGhlICciK2UrIicgb2YgIittKHQpKyIuIiwic3RhcnQiPT09ZXx8ImVuZCI9PT1lPyJBbHRlciB0aGUgdmFsdWVzIGF0IGFjdHVhbCBwb3NpdGlvbnMsIGxpa2UgMXN0IG9yIDJuZGxhc3QsIHJhdGhlciB0aGFuIGp1c3QgdGhlICciK2UrIicuIjp2b2lkIDApOitlPT0oMHxlKXx8cC5jcmVhdGUoInByb3BlcnR5IixtKHQpKyIgY2FuIG9ubHkgaGF2ZSBwb3NpdGlvbiBrZXlzICgnM3JkJywgJzFzdCcsICg1KSwgZXRjLiksIG5vdCAiK04oZSkrIi4iKTp0LlR3aW5lU2NyaXB0X0lkZW50aWZpZXJzJiZlIGluIHQ/cC5jcmVhdGUoImtleXdvcmQiLCJJIGNhbid0IGFsdGVyIHRoZSB2YWx1ZSBvZiB0aGUgJyIrZSsiJyBpZGVudGlmaWVyLiIsIllvdSBjYW4gb25seSBhbHRlciBkYXRhIGluIHZhcmlhYmxlcywgbm90IGZpeGVkIGlkZW50aWZpZXJzLiIpOnAuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IG1vZGlmeSAiK20odCksdCBpbnN0YW5jZW9mIFNldD8iWW91IHNob3VsZCB1c2UgYW4gKGFycmF5OikgaWYgeW91IG5lZWQgdG8gbW9kaWZ5IHRoZSBkYXRhIGluc2lkZSB0aGlzIGRhdGFzZXQuIjppLmlzUHJvdG90eXBlT2YodCk/IllvdSBzaG91bGQgYWx0ZXIgaG9va3MgaW5kaXJlY3RseSB1c2luZyBtYWNyb3MgbGlrZSAocmVwbGFjZTopIG9yIChlbmNoYW50OikuIjp2b2lkIDApfWZ1bmN0aW9uIFAodCxlLG4scil7dmFyIGE9ZTt0IGluc3RhbmNlb2YgTWFwP3Quc2V0KGUsbik6KGgodCkmJihlPU8odCxlKSksdC5Ud2luZVNjcmlwdF9TZXQ/dC5Ud2luZVNjcmlwdF9TZXQoZSxuLHIpOnRbZV09biksUy5zZXQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZSh0LGEsbil9KX1mdW5jdGlvbiBSKHQsZSl7dmFyIG49ZTtoKHQpJiYoZT1PKHQsZSkpLGsodCkmJi9eKD86WzEtOV1cZCp8MCkkLy5leGVjKGUpP3Quc3BsaWNlKGUsMSk6dCBpbnN0YW5jZW9mIE1hcHx8dCBpbnN0YW5jZW9mIFNldD90LmRlbGV0ZShlKTp0LlR3aW5lU2NyaXB0X0RlbGV0ZT90LlR3aW5lU2NyaXB0X0RlbGV0ZShlKTpkZWxldGUgdFtlXSxTLmRlbGV0ZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlKHQsbil9KX1mdW5jdGlvbiBJKHQsZSl7dmFyIG4scixhPTI8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTplLG89Mzxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbM10mJmFyZ3VtZW50c1szXTtyZXR1cm4gZSYmIm9iamVjdCI9PT1fdHlwZW9mKGUpJiYibGFzdCJpbiBlJiYiZmlyc3QiaW4gZT9pLmlzUHJvdG90eXBlT2YodCk/dC5Ud2luZVNjcmlwdF9HZXRQcm9wZXJ0eShlKToobj1lLmZpcnN0LHI9ZS5sYXN0LGIodCxuKygwPD1uKSxyKygwPD1yKSkpOmsoZSk/aS5pc1Byb3RvdHlwZU9mKHQpP3QuVHdpbmVTY3JpcHRfR2V0UHJvcGVydHkoZSk6ZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIEkodCxlLGUpfSlbInN0cmluZyI9PXR5cGVvZiB0PyJqb2luIjoidmFsdWVPZiJdKCIiKTp2b2lkIDAhPT0obj1FKHQsZSkpfHxvP246dD09PXUudmFyaWFibGVzPzA6InRlbXAiPT09KG51bGw9PShyPXQuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSk/dm9pZCAwOnIudHlwZSk/cC5jcmVhdGUoInByb3BlcnR5IiwiVGhlcmUgaXNuJ3QgYSB0ZW1wIHZhcmlhYmxlIG5hbWVkIF8iLmNvbmNhdChhLCIgaW4gdGhpcyBwbGFjZS4iKSwiVGVtcCB2YXJpYWJsZXMgb25seSBleGlzdCBpbnNpZGUgdGhlIHNhbWUgcGFzc2FnZSwgaG9vaywgb3IgbGFtYmRhIGluIHdoaWNoIHRoZXkncmUgY3JlYXRlZC4iKTprKHQpJiYibnVtYmVyIj09dHlwZW9mIGU/cC5jcmVhdGUoInByb3BlcnR5IiwiVGhpcyBhcnJheSBvZiAiLmNvbmNhdCh0Lmxlbmd0aCwiIGVsZW1lbnRzIGRvZXNuJ3QgaGF2ZSBhICIpLmNvbmNhdChOKGErKCJudW1iZXIiPT10eXBlb2YgYT8xOiIiKSksIiBlbGVtZW50LiIpLHQubGVuZ3RoPyJJdCBjb250YWluczogIi5jb25jYXQocyh0Lm1hcChtKSksIi4iKToiVGhlIGFycmF5IGlzIGVtcHR5LiIpOihvPUFycmF5LmZyb20oImZ1bmN0aW9uIj09dHlwZW9mIHQua2V5cyYmdC5rZXlzKCkpLHAuY3JlYXRlKCJwcm9wZXJ0eSIsIkkgY2FuJ3QgZmluZCBhICIuY29uY2F0KE4oYSksIiBkYXRhIG5hbWUgaW4gIikuY29uY2F0KG0odCkpLHQgaW5zdGFuY2VvZiBNYXAmJm8ubGVuZ3RoPyJJdHMgbmFtZXMgaW5jbHVkZTogIi5jb25jYXQocyhvKSwiLiIpOnZvaWQgMCkpfWZ1bmN0aW9uIFYoZSx0KXt2YXIgcj10aGlzLGU9dGhpcy5jb21waWxlZFByb3BlcnR5Q2hhaW4ucmVkdWNlKGZ1bmN0aW9uKGUsdCl7dmFyIG49MD09PWUubGVuZ3RoP3Iub2JqZWN0OkkuYXBwbHkodm9pZCAwLF90b0NvbnN1bWFibGVBcnJheShlW2UubGVuZ3RoLTFdKSk7cmV0dXJuIGUucHVzaChbbix0XSkmJmV9LFtdKS5yZWR1Y2VSaWdodChlLHQpO3JldHVybiBwLmNvbnRhaW5zRXJyb3IoZSk/ZTp2b2lkIDB9cmV0dXJuIGM9T2JqZWN0LmZyZWV6ZSh7Z2V0OmZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMub2JqZWN0LHQ9MDt0PHRoaXMuY29tcGlsZWRQcm9wZXJ0eUNoYWluLmxlbmd0aC0xO3QrPTEpaWYoZT1JKGUsdGhpcy5jb21waWxlZFByb3BlcnR5Q2hhaW5bdF0pLHAuY29udGFpbnNFcnJvcihlKSlyZXR1cm4gZTtyZXR1cm4gSShlLHRoaXMuY29tcGlsZWRQcm9wZXJ0eUNoYWluLnNsaWNlKC0xKVswXSx0aGlzLnByb3BlcnR5Q2hhaW4uc2xpY2UoLTEpWzBdKX0saGFzOmZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMub2JqZWN0LHQ9MDt0PHRoaXMuY29tcGlsZWRQcm9wZXJ0eUNoYWluLmxlbmd0aC0xO3QrPTEpaWYodm9pZCAwPT09KGU9SShlLHRoaXMuY29tcGlsZWRQcm9wZXJ0eUNoYWluW3RdLHZvaWQgMCwhMCkpfHxwLmNvbnRhaW5zRXJyb3IoZSkpcmV0dXJuITE7cmV0dXJuIHZvaWQgMCE9PUkoZSx0aGlzLmNvbXBpbGVkUHJvcGVydHlDaGFpbi5zbGljZSgtMSlbMF0sdm9pZCAwLCEwKX0sc2V0OmZ1bmN0aW9uKGUsYyl7dmFyIGw9dGhpcztyZXR1cm4hdGhpcy5vYmplY3R8fHRoaXMub2JqZWN0LlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmV8fHRoaXMub2JqZWN0LlR3aW5lU2NyaXB0X0lkZW50aWZpZXJzP1YuY2FsbCh0aGlzLGZ1bmN0aW9uKG4sZSx0KXt2YXIgZT1fc2xpY2VkVG9BcnJheShlLDIpLHI9ZVswXSxhPWVbMV07aWYoZT1wLmNvbnRhaW5zRXJyb3IobixyLGEpfHxwLmNvbnRhaW5zRXJyb3IoaihyLGEsbikpKXJldHVybiBlO2lmKGU9dyhuKSlyZXR1cm4gcC5jcmVhdGUoIm9wZXJhdGlvbiIsIiIuY29uY2F0KG0obiksIiBjYW4ndCBiZSBzdG9yZWQiKS5jb25jYXQoIW4uVHdpbmVTY3JpcHRfVW5zdG9yYWJsZSYmdihuKT8iIGJlY2F1c2UgaXQgaG9sZHMgIi5jb25jYXQobShlKSk6IiIsIi4iKSk7aWYoMDx0KXI9ZyhyKTtlbHNlIGlmKCJ0ZW1wIj09PShudWxsPT0oZT1yLlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmUpP3ZvaWQgMDplLnR5cGUpJiZyIT09dS52YXJpYWJsZXMpe2Zvcih2YXIgbz1yOyJ0ZW1wIj09PShudWxsPT0oaT1vLlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmUpP3ZvaWQgMDppLnR5cGUpJiYhaGFzT3duUHJvcGVydHkuY2FsbChvLGEpOyl2YXIgaSxvPU9iamVjdC5nZXRQcm90b3R5cGVPZihvKTsidGVtcCI9PT0obnVsbD09KHQ9by5Ud2luZVNjcmlwdF9WYXJpYWJsZVN0b3JlKT92b2lkIDA6dC50eXBlKSYmKHI9byl9aWYoInN0cmluZyI9PXR5cGVvZiByKXtpZigic3RyaW5nIiE9dHlwZW9mIG4pcmV0dXJuIHAuY3JlYXRlKCJkYXRhdHlwZSIsIkkgY2FuJ3QgcHV0IHRoaXMgbm9uLXN0cmluZyB2YWx1ZSwgIi5jb25jYXQobShuKSwiLCBpbiBhIHN0cmluZy4iKSk7aWYobi5sZW5ndGghPT0oayhhKT9hLmxlbmd0aDoxKSlyZXR1cm4gcC5jcmVhdGUoImRhdGF0eXBlIiwiIi5jb25jYXQobShuKSwiaXMgbm90IHRoZSByaWdodCBsZW5ndGggdG8gZml0IGludG8gdGhpcyBzdHJpbmcgbG9jYXRpb24uIikpO3ZhciByPV90b0NvbnN1bWFibGVBcnJheShyKSxzPV90b0NvbnN1bWFibGVBcnJheShuKTtbXS5jb25jYXQoYSkuZm9yRWFjaChmdW5jdGlvbihlKXswK2U8MCYmKGU9ci5sZW5ndGgrKDArZSkpLHI9W10uY29uY2F0KF90b0NvbnN1bWFibGVBcnJheShyLnNsaWNlKDAsZSkpLFtzLnNoaWZ0KCldLF90b0NvbnN1bWFibGVBcnJheShyLnNsaWNlKGUrMSkpKX0pLHI9ci5qb2luKCIiKX1lbHNlIGQocikmJih2b2lkIDAhPT1uLlR3aW5lU2NyaXB0X0tub3duTmFtZSYmKChuPSIiIT09bi5Ud2luZVNjcmlwdF9Lbm93bk5hbWU/ZyhuKTpuKS5Ud2luZVNjcmlwdF9Lbm93bk5hbWU9ZihsKSksayhhKSYmaChuKT8oInN0cmluZyI9PXR5cGVvZiBuJiYobj1fdG9Db25zdW1hYmxlQXJyYXkobikpLGEubWFwKGZ1bmN0aW9uKGUsdCl7cmV0dXJuW2Usblt0XV19KS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciBlPV9zbGljZWRUb0FycmF5KGUsMiksdD1lWzBdLGU9ZVsxXTtyZXR1cm4gUChyLHQsZSxjKX0pKTpQKHIsYSxuLGMpKTtyZXR1cm4gcn0sZSk6cC5jcmVhdGUoIm1hY3JvY2FsbCIsIkkgY2FuJ3QgKHNldDopICIuY29uY2F0KG0odGhpcyksIiwgaWYgdGhlICIpLmNvbmNhdCgobSh0aGlzLm9iamVjdCkubWF0Y2goLyAoLiskKS8pfHxbIiIsInZhbHVlIl0pWzFdLCIgaXNuJ3Qgc3RvcmVkIGluIGEgdmFyaWFibGUuIiksIk1vZGlmeWluZyBkYXRhIHN0cnVjdHVyZXMgdGhhdCBhcmVuJ3QgaW4gdmFyaWFibGVzIHdvbid0IGNoYW5nZSB0aGUgZ2FtZSBzdGF0ZSBhdCBhbGwuIil9LGRlbGV0ZTpmdW5jdGlvbigpe3JldHVybiBWLmNhbGwodGhpcyxmdW5jdGlvbihlLHQsbil7dmFyIHIsdD1fc2xpY2VkVG9BcnJheSh0LDIpLGE9dFswXSx0PXRbMV07cmV0dXJuKHI9cC5jb250YWluc0Vycm9yKGUsYSx0KXx8cC5jb250YWluc0Vycm9yKGooYSx0KSkpfHwoMDxuJiYoYT1nKGEpKSxudWxsPT09ZT8oKHI9InN0cmluZyI9PXR5cGVvZiBhKSYmKGE9X3RvQ29uc3VtYWJsZUFycmF5KGEpKSxrKHQpPyhoKGEpJiYodD1fdG9Db25zdW1hYmxlQXJyYXkobmV3IFNldCh0KSkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gTyhhLHQpLU8oYSxlKX0pLHQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gUihhLGUpfSkpOlIoYSx0KSxyJiYoYT1hLmpvaW4oIiIpKSk6UChhLHQsZSwhMSksYSl9LG51bGwpfSxkZWZpbmVUeXBlOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMub2JqZWN0LG49dGhpcy5jb21waWxlZFByb3BlcnR5Q2hhaW5bMF0scj0oaGFzT3duUHJvcGVydHkuY2FsbCh0LCJUd2luZVNjcmlwdF9UeXBlRGVmcyIpfHwodC5Ud2luZVNjcmlwdF9UeXBlRGVmcz1PYmplY3QuY3JlYXRlKHQuVHdpbmVTY3JpcHRfVHlwZURlZnN8fG51bGwpKSx0LlR3aW5lU2NyaXB0X1R5cGVEZWZzKSxhPXJbbl07aWYoYSYmIW8oYSxlKSlyZXR1cm4gcC5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgcmVkZWZpbmUgdGhlIHR5cGUgb2YgIittKHRoaXMpKyIgdG8gIisoZS5Ud2luZVNjcmlwdF9PYmplY3ROYW1lfHxsKGUpKSsiLCBhcyBpdCBpcyBhbHJlYWR5ICIrKGEuVHdpbmVTY3JpcHRfT2JqZWN0TmFtZXx8bChhKSkrIi4iKTt0LlR3aW5lU2NyaXB0X0RlZmluZVR5cGU/dC5Ud2luZVNjcmlwdF9EZWZpbmVUeXBlKG4sZSk6cltuXT1lLCJjb25zdCI9PT1lLm5hbWUmJih0W25dPXZvaWQgMCl9LG1hdGNoZXM6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5vYmplY3Q9PT1lJiZ0aGlzLmNvbXBpbGVkUHJvcGVydHlDaGFpblswXT09PXR9LGdldE5hbWU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jb21waWxlZFByb3BlcnR5Q2hhaW5bMF19LGNyZWF0ZTpmdW5jdGlvbihlLHQpe3ZhciBuO2lmKG49cC5jb250YWluc0Vycm9yKGUpKXJldHVybiBuO0FycmF5LmlzQXJyYXkodCl8fCh0PVtdLmNvbmNhdCh0KSksYy5pc1Byb3RvdHlwZU9mKGUpJiYodD1lLnByb3BlcnR5Q2hhaW4uY29uY2F0KHQpLGU9ZS5vYmplY3QpO3ZhciByPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuLHI9W10sYT0wO2E8dC5sZW5ndGg7YSs9MSl7dmFyIG89dFthXTtpZihvLmNvbXB1dGVkJiYobz1vLnZhbHVlKSxjLmlzUHJvdG90eXBlT2YobykmJihvPW8uZ2V0KCkpLGsobykpe2Zvcih2YXIgaT1bXSxzPTA7czxvLmxlbmd0aDtzKz0xKWlbc109eChlLG9bc10pO289aX1lbHNlIG89eChlLG8pO2lmKG49cC5jb250YWluc0Vycm9yKG8pKXJldHVybiBuO2E8dC5sZW5ndGgtMSYmKGU9SShlLG8pKSxyLnB1c2gobyl9cmV0dXJuIHJ9KGUsdCk7cmV0dXJuKG49cC5jb250YWluc0Vycm9yKHIpKXx8T2JqZWN0LmFzc2lnbihPYmplY3QuY3JlYXRlKGMpLHtvYmplY3Q6ZSxwcm9wZXJ0eUNoYWluOnQsY29tcGlsZWRQcm9wZXJ0eUNoYWluOnJ9KX0sVHdpbmVTY3JpcHRfVG9Tb3VyY2U6ZnVuY3Rpb24oKXtmdW5jdGlvbiByKGUsdCl7cmV0dXJuIXQmJm4ub2JqZWN0LlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU/ZTpOKGUpfXZhciBlLG49dGhpcztyZXR1cm4odGhpcy5vYmplY3Q9PT11LnZhcmlhYmxlcz8iJCI6InRlbXAiPT09KG51bGw9PShlPXRoaXMub2JqZWN0LlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmUpP3ZvaWQgMDplLnR5cGUpPyJfIjpmKHRoaXMub2JqZWN0KSsiJ3MgIikrKDE9PT10aGlzLnByb3BlcnR5Q2hhaW4ubGVuZ3RoP3IodGhpcy5wcm9wZXJ0eUNoYWluWzBdKTp0aGlzLnByb3BlcnR5Q2hhaW4ucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsiJ3MgIityKHQsbil9KSl9LGdldCBUd2luZVNjcmlwdF9PYmplY3ROYW1lKCl7dmFyIGU7cmV0dXJuIHRoaXMub2JqZWN0LlR3aW5lU2NyaXB0X1ZhcmlhYmxlU3RvcmU/InRoZSAiLmNvbmNhdCgidGVtcCI9PT0obnVsbD09KGU9dGhpcy5vYmplY3QuVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZSk/dm9pZCAwOmUudHlwZSk/InRlbXAgIjoiIiwidmFyaWFibGUgIikuY29uY2F0KHRoaXMuVHdpbmVTY3JpcHRfVG9Tb3VyY2UoKSk6bSh0aGlzLm9iamVjdCkrIidzICIrKDE9PT10aGlzLnByb3BlcnR5Q2hhaW4ubGVuZ3RoP04odGhpcy5wcm9wZXJ0eUNoYWluWzBdKTp0aGlzLnByb3BlcnR5Q2hhaW4ucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsiJ3MgIitOKHQpfSkpfSxvbjpmdW5jdGlvbihlLHQpe2lmKGUgaW4gUylyZXR1cm4iZnVuY3Rpb24iIT10eXBlb2YgdHx8U1tlXS5pbmNsdWRlcyh0KXx8U1tlXS5wdXNoKHQpLGM7bigiVmFyUmVmLm9uIiwiaW52YWxpZCBldmVudCBuYW1lIil9fSl9KSxkZWZpbmUoImludGVybmFsdHlwZXMvdmFyc2NvcGUiLFtdLGZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5zZWFsKHtUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJ0aGUgdGVtcG9yYXJ5IHZhcmlhYmxlcyIsVHdpbmVTY3JpcHRfVmFyaWFibGVTdG9yZTp7dHlwZToidGVtcCIsbmFtZToiYW4gdW5rbm93biBzY29wZSJ9LFR3aW5lU2NyaXB0X1R5cGVEZWZzOk9iamVjdC5jcmVhdGUobnVsbCl9KX0pLGRlZmluZSgibWFjcm9saWIvY29tbWFuZHMiLFsianF1ZXJ5IiwibWFjcm9zIiwidXRpbHMiLCJzdGF0ZSIsInBhc3NhZ2VzIiwiZW5naW5lIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIiwiaW50ZXJuYWx0eXBlcy90d2luZW5vdGlmaWVyIiwiZGF0YXR5cGVzL2Fzc2lnbm1lbnRyZXF1ZXN0IiwiZGF0YXR5cGVzL2hvb2tzZXQiLCJkYXRhdHlwZXMvY29kZWhvb2siLCJkYXRhdHlwZXMvY29sb3VyIiwiZGF0YXR5cGVzL2dyYWRpZW50IiwiaW50ZXJuYWx0eXBlcy92YXJyZWYiLCJkYXRhdHlwZXMvdHlwZWR2YXIiLCJkYXRhdHlwZXMvdmFyYmluZCIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwidXRpbHMvcmVuZGVydXRpbHMiXSxmdW5jdGlvbih1LG4sYixjLGwsYSx5LE0sZSxvLHQscCxkLGkscyx2LHIsZil7dmFyIGg9ci5wcmludEJ1aWx0aW5WYWx1ZSxtPXIub2JqZWN0TmFtZSxnPXIuY2xvbmUsdz1yLnRvU291cmNlLGs9Zi5kaWFsb2csUz1mLmdlb21QYXJzZSxEPWYuZ2VvbVN0cmluZ1JlZ0V4cCxyPW4uVHlwZVNpZ25hdHVyZSxmPXIuQW55LEY9ci5FdmVyeXRoaW5nLFQ9ci5yZXN0LF89ci5laXRoZXIseD1yLm9wdGlvbmFsLE89ci56ZXJvT3JNb3JlLEw9ci5wZXJjZW50LEg9ci5ub25OZWdhdGl2ZUludGVnZXIsQT1yLnBvc2l0aXZlSW50ZWdlcixyPXIucG9zaXRpdmVOdW1iZXIsQz1PYmplY3QuYXNzaWduLEU9TWF0aC5mbG9vcixOPU1hdGguY2VpbCxqPU1hdGguYWJzLHo9TWF0aC5tYXgscT1NYXRoLm1pbixQPXUubm9vcDtmdW5jdGlvbiBSKGUpe3JldHVybiIoIi5jb25jYXQoZSwiICIpLmNvbmNhdChiLm9wdGlvbnMuaWZpZCwiKSAiKX1bInNldCIsInB1dCIsInVucGFjayJdLmZvckVhY2goZnVuY3Rpb24ocil7cmV0dXJuIG4uYWRkKHIsIkluc3RhbnQiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8KGFyZ3VtZW50cy5sZW5ndGg8PTE/MDphcmd1bWVudHMubGVuZ3RoLTEpO3QrPTEpe3ZhciBuPXQrMTwxfHxhcmd1bWVudHMubGVuZ3RoPD10KzE/dm9pZCAwOmFyZ3VtZW50c1t0KzFdO2lmKCJpbnRvIj09PW4ub3BlcmF0b3ImJiJzZXQiPT09cilyZXR1cm4geS5jcmVhdGUoIm1hY3JvY2FsbCIsIlBsZWFzZSBzYXkgJ3RvJyB3aGVuIHVzaW5nIHRoZSAoc2V0OikgbWFjcm8uIik7aWYoInRvIj09PW4ub3BlcmF0b3ImJiJzZXQiIT09cilyZXR1cm4geS5jcmVhdGUoIm1hY3JvY2FsbCIsIlBsZWFzZSBzYXkgJ2ludG8nIHdoZW4gdXNpbmcgdGhlIChwdXQ6KSBvciAodW5wYWNrOikgbWFjcm8uIik7aWYoKGkuaXNQcm90b3R5cGVPZihuLmRlc3QpfHxzLmlzUHJvdG90eXBlT2Yobi5kZXN0KSk9PT0oInVucGFjayI9PT1yKSlyZXR1cm4geS5jcmVhdGUoIm1hY3JvY2FsbCIsInVucGFjayI9PT1yPyJQbGVhc2UgdXNlIHRoZSAodW5wYWNrOikgbWFjcm8gd2l0aCBhcnJheXMsIGRhdGFtYXBzIG9yIChwOikgcGF0dGVybnMgY29udGFpbmluZyB2YXJpYWJsZXMgdG8gdGhlIHJpZ2h0IG9mICdpbnRvJy4iOiJQbGVhc2UgdXNlIHRoZSAoIi5jb25jYXQociwiOikgbWFjcm8gd2l0aCBqdXN0IHNpbmdsZSB2YXJpYWJsZXMgYW5kIHR5cGVkIHZhcmlhYmxlcyB0byB0aGUgIikuY29uY2F0KCJzZXQiPT09cj8ibGVmdCBvZiAndG8nLiI6InJpZ2h0IG9mICdpbnRvJy4iKSwiWW91IG1heSB3aXNoIHRvIGNoYW5nZSB0aGlzIHRvIHRoZSAoIi5jb25jYXQoInVucGFjayIhPT1yPyJ1bnBhY2siOiJ0byI9PT1uLm9wZXJhdG9yPyJzZXQiOiJwdXQiLCI6KSBtYWNyby4iKSk7bj1uLnNldCgpO2lmKHkuY29udGFpbnNFcnJvcihuKSlyZXR1cm4gbn1yZXR1cm57VHdpbmVTY3JpcHRfVHlwZUlEOiJpbnN0YW50IixUd2luZVNjcmlwdF9UeXBlTmFtZToiYSAoIi5jb25jYXQociwiOikgb3BlcmF0aW9uIiksVHdpbmVTY3JpcHRfT2JqZWN0TmFtZToiYSAoIi5jb25jYXQociwiOikgb3BlcmF0aW9uIiksVHdpbmVTY3JpcHRfVW5zdG9yYWJsZTohMCxUd2luZVNjcmlwdF9QcmludDpmdW5jdGlvbigpe3JldHVybiBiLm9wdGlvbnMuZGVidWcsIiJ9fX0sW1QoZSldKX0pLG4uYWRkKCJtb3ZlIiwiSW5zdGFudCIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTA7dDwoYXJndW1lbnRzLmxlbmd0aDw9MT8wOmFyZ3VtZW50cy5sZW5ndGgtMSk7dCs9MSl7dmFyIG49dCsxPDF8fGFyZ3VtZW50cy5sZW5ndGg8PXQrMT92b2lkIDA6YXJndW1lbnRzW3QrMV07aWYoImludG8iIT09bi5vcGVyYXRvcilyZXR1cm4geS5jcmVhdGUoIm1hY3JvY2FsbCIsIlBsZWFzZSBzYXkgJ2ludG8nIHdoZW4gdXNpbmcgdGhlIChtb3ZlOikgbWFjcm8uIik7bj1uLnNldCghMCk7aWYoeS5jb250YWluc0Vycm9yKG4pKXJldHVybiBufXJldHVybntUd2luZVNjcmlwdF9UeXBlSUQ6Imluc3RhbnQiLFR3aW5lU2NyaXB0X1R5cGVOYW1lOiJhIChtb3ZlOikgb3BlcmF0aW9uIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhIChtb3ZlOikgb3BlcmF0aW9uIixUd2luZVNjcmlwdF9VbnN0b3JhYmxlOiEwLFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuIGIub3B0aW9ucy5kZWJ1ZywiIn19fSxbVChlKV0pLG4uYWRkQ29tbWFuZCgiZGlzcGxheSIsZnVuY3Rpb24oZSl7aWYoIWwuaGFzVmFsaWQoZSkpcmV0dXJuIHkuY3JlYXRlKCJtYWNyb2NhbGwiLCJJIGNhbid0IChkaXNwbGF5OikgdGhlIHBhc3NhZ2UgJyIuY29uY2F0KGUsIicgYmVjYXVzZSBpdCBkb2Vzbid0IGV4aXN0LiIpKX0sZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlLnNvdXJjZT1sLmdldFRyZWUobiksZX0sW1N0cmluZ10pKCJwcmludCIsUCxmdW5jdGlvbihlLHQsbil7cmV0dXJuIEMoZSx7c291cmNlOmgobil9KX0sW2ZdKShbInZlcmJhdGltLXByaW50IiwidjZtLXByaW50Il0sUCxmdW5jdGlvbihlLHQsbil7cmV0dXJuIEMoZSx7dmVyYmF0aW06ITAsc291cmNlOmgobil9KX0sW2ZdKShbInZlcmJhdGltLXNvdXJjZSIsInY2bS1zb3VyY2UiXSxmdW5jdGlvbihlKXtpZigiY29tbWFuZCI9PT0obnVsbD09ZT92b2lkIDA6ZS5Ud2luZVNjcmlwdF9UeXBlSUQpJiYhZS5Ud2luZVNjcmlwdF9Ub1NvdXJjZSlyZXR1cm4geS5jcmVhdGUoImRhdGF0eXBlIiwiSSBjYW4ndCBjb25zdHJ1Y3QgdGhlIHNvdXJjZSBjb2RlIG9mIGEgY29tbWFuZCBjcmVhdGVkIGJ5IGEgY3VzdG9tIG1hY3JvLiIpfSxmdW5jdGlvbihlLHQsbil7cmV0dXJuIEMoZSx7dmVyYmF0aW06ITAsc291cmNlOmgodyhuKSl9KX0sW2ZdKSgiZ28tdG8iLGZ1bmN0aW9uKGUpe2lmKCFsLmhhc1ZhbGlkKGUpKXJldHVybiB5LmNyZWF0ZSgibWFjcm9jYWxsIiwiSSBjYW4ndCAoZ28tdG86KSB0byB0aGUgcGFzc2FnZSAnIi5jb25jYXQoZSwiJyBiZWNhdXNlIGl0IGRvZXNuJ3QgZXhpc3QuIiksIkNoZWNrIHRoYXQgeW91IGRpZG4ndCBtaXN0eXBlIHRoZSBwYXNzYWdlIG5hbWUsIG9yIHJlbmFtZSB0aGUgcGFzc2FnZSB0byBzb21ldGhpbmcgZWxzZS4iKX0sZnVuY3Rpb24oZSx0LG4pe2lmKCFiLm9wdGlvbnMuaWdub3JlR290b3MpcmV0dXJuIHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbigpe3JldHVybiBhLmdvVG9QYXNzYWdlKG4se3RyYW5zaXRpb246ZS5kYXRhLnBhc3NhZ2VUOG59KX0pLHtibG9ja2VkOiEwfX0sW1N0cmluZ10pKCJyZWRpcmVjdCIsZnVuY3Rpb24oZSl7aWYoIWwuaGFzVmFsaWQoZSkpcmV0dXJuIHkuY3JlYXRlKCJtYWNyb2NhbGwiLCJJIGNhbid0IChyZWRpcmVjdDopIHRvIHRoZSBwYXNzYWdlICciLmNvbmNhdChlLCInIGJlY2F1c2UgaXQgZG9lc24ndCBleGlzdC4iKSwiQ2hlY2sgdGhhdCB5b3UgZGlkbid0IG1pc3R5cGUgdGhlIHBhc3NhZ2UgbmFtZSwgb3IgcmVuYW1lIHRoZSBwYXNzYWdlIHRvIHNvbWV0aGluZyBlbHNlLiIpfSxmdW5jdGlvbihlLHQsbil7aWYoIWIub3B0aW9ucy5pZ25vcmVHb3RvcylyZXR1cm4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7cmV0dXJuIGEucmVkaXJlY3Qobix7dHJhbnNpdGlvbjplLmRhdGEucGFzc2FnZVQ4bn0pfSkse2Jsb2NrZWQ6ITB9fSxbU3RyaW5nXSkoInVuZG8iLFAsZnVuY3Rpb24oZSx0LG4pe3JldHVybiBjLnBhc3RMZW5ndGg8MT9DKGUse3NvdXJjZTpufSk6Yi5vcHRpb25zLmlnbm9yZUdvdG9zP3ZvaWQgMDoocmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7cmV0dXJuIGEuZ29CYWNrKHt0cmFuc2l0aW9uOmUuZGF0YS5wYXNzYWdlVDhufSl9KSx7YmxvY2tlZDohMH0pfSxbeChTdHJpbmcpXSkoImRlYnVnIixQLGEuZW5hYmxlRGVidWdNb2RlLFtdLCExKSxiLm9uU3RhcnR1cChmdW5jdGlvbigpe3JldHVybiBiLnN0b3J5RWxlbWVudC5vbigiY2xpY2suaWNvbiIsInR3LWljb24iLGZ1bmN0aW9uKGUpe3ZhciB0PXUodGhpcyksbj10LmRhdGEoImNsaWNrRXZlbnQiKSxyPXQuYXR0cigiYWx0Iik7biYmbih0KSwiVW5kbyI9PT1yJiYoZS5zdG9wUHJvcGFnYXRpb24oKSxhLmdvQmFjaygpKSwiUmVkbyI9PT1yJiYoZS5zdG9wUHJvcGFnYXRpb24oKSxhLmdvRm9yd2FyZCgpKSwiRnVsbHNjcmVlbiI9PT1yJiYoZS5zdG9wUHJvcGFnYXRpb24oKSxhLnRvZ2dsZUZ1bGxzY3JlZW4oKSksIlJlc3RhcnQiPT09ciYmKGMuaGFzU2Vzc2lvblN0b3JhZ2UmJnNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oIlNhdmVkIFNlc3Npb24iKSx3aW5kb3cubG9jYXRpb24ucmVsb2FkKCkpfSl9KSxbWyJVbmRvIiwiJiM4NjMwOyIsZnVuY3Rpb24oKXtyZXR1cm4gMDxjLnBhc3RMZW5ndGh9XSxbIlJlZG8iLCImIzg2MzE7IixmdW5jdGlvbigpe3JldHVybiAwPGMuZnV0dXJlTGVuZ3RofV0sWyJGdWxsc2NyZWVuIiwiJiM5OTc0OyIsZnVuY3Rpb24oKXtyZXR1cm4gZG9jdW1lbnQuZnVsbHNjcmVlbkVuYWJsZWR8fGRvY3VtZW50Lm1zRnVsbHNjcmVlbkVuYWJsZWR9XSxbIlJlc3RhcnQiLCImIzEwMjI2OyIsT2JqZWN0XV0uZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgZT1fc2xpY2VkVG9BcnJheShlLDMpLG89ZVswXSxpPWVbMV0scz1lWzJdO24uYWRkQ29tbWFuZCgiaWNvbi0iLmNvbmNhdChvLnRvTG93ZXJDYXNlKCkpLGZ1bmN0aW9uKGUsdCl7aWYoInN0cmluZyI9PXR5cGVvZiBlJiYic3RyaW5nIj09dHlwZW9mIHQpcmV0dXJuIGU9X3RvQ29uc3VtYWJsZUFycmF5KGUpLmxlbmd0aCx0PV90b0NvbnN1bWFibGVBcnJheSh0KS5sZW5ndGgsMTxlJiYxPHQ/eS5jcmVhdGUoImRhdGF0eXBlIiwiT25lIG9mIHRoZSB0d28gc3RyaW5ncyBnaXZlbiB0byAoaWNvbi0iLmNvbmNhdChvLnRvTG93ZXJDYXNlKCksIjopIHNob3VsZCBiZSAxIGNoYXJhY3RlciBsb25nLCBmb3IgaXRzIGljb24uIikpOjE9PT1lJiYxPT09dD95LmNyZWF0ZSgiZGF0YXR5cGUiLCJPbmUgb2YgdGhlIHR3byBzdHJpbmdzIGdpdmVuIHRvIChpY29uLSIuY29uY2F0KG8udG9Mb3dlckNhc2UoKSwiOikgc2hvdWxkIGJlIDIgb3IgbW9yZSBjaGFyYWN0ZXJzIGxvbmcsIGZvciBpdHMgbGFiZWwuIikpOnZvaWQgMH0sZnVuY3Rpb24odCxlLG4scil7dmFyIGE7cmV0dXJuKCJzdHJpbmciPT10eXBlb2YgciYmMT09PV90b0NvbnN1bWFibGVBcnJheShyKS5sZW5ndGh8fCJzdHJpbmciPT10eXBlb2YgbiYmMTxfdG9Db25zdW1hYmxlQXJyYXkobikubGVuZ3RoKSYmKG49KGE9W3Isbl0pWzBdLHI9YVsxXSksIlVuZG8iPT09byYmKHQuZGF0YS5mb3JnZXRVbmRvc0V2ZW50PWZ1bmN0aW9uKGUpe3Quc2VjdGlvbi53aGVuVW5ibG9ja2VkKGZ1bmN0aW9uKCl7cmV0dXJuIHUoZSkuY3NzKCJ2aXNpYmlsaXR5IiwiaGlkZGVuIil9KX0pLEModCx7c291cmNlOic8dHctaWNvbiB0YWJpbmRleD0wIGFsdD0iJy5jb25jYXQobywnIiAnKS5jb25jYXQocj8nZGF0YS1sYWJlbD0iJy5jb25jYXQoci5yZXBsYWNlKCciJywiJnF1b3Q7IiksJyInKToiIiwnIHRpdGxlPSInKS5jb25jYXQobywnIiAnKS5jb25jYXQocygpPyIiOidzdHlsZT0idmlzaWJpbGl0eTpoaWRkZW4iJywiPiIpLmNvbmNhdChufHxpLCI8L3R3LWljb24+Iil9KX0sW3goU3RyaW5nKSx4KFN0cmluZyldKX0pLG4uYWRkQ29tbWFuZCgiaWNvbi1jb3VudGVyIixmdW5jdGlvbihlLHQsbil7dmFyIHI9IiBsYWJlbCBzdHJpbmcgZ2l2ZW4gdG8gKGljb24tY291bnRlcjopIGNhbid0IGJlIGVtcHR5IG9yIG9ubHkgd2hpdGVzcGFjZS4iO3JldHVybiB0JiZ0LnRyaW0oKT8ic3RyaW5nIiE9dHlwZW9mIG58fG4udHJpbSgpP3ZvaWQgMDp5LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgMm5kICIrcik6eS5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIDFzdCAiK3IpfSxmdW5jdGlvbihyLGUsYSxvLGkpe3IuYXR0ci5wdXNoKHsiZGF0YS0yYmluZCI6ITB9KSxyLmRhdGEudHdvV2F5QmluZEV2ZW50PWZ1bmN0aW9uKGUsdCxuKXthLnZhclJlZi5tYXRjaGVzKHQsbikmJiJudW1iZXIiPT10eXBlb2YodD1hLnZhclJlZi5nZXQoKSkmJnIudGFyZ2V0LmNoaWxkcmVuKCJ0dy1pY29uIikudGV4dCgoMDx0P0U6TikodCkpLmF0dHIoImRhdGEtbGFiZWwiLDEhPT1qKHQpJiZ2b2lkIDAhPT1pP2k6byl9O3ZhciB0PWEudmFyUmVmLmdldCgpO3JldHVybiJudW1iZXIiIT10eXBlb2YgdD95LmNyZWF0ZSgiZGF0YXR5cGUiLCIoaWNvbi1jb3VudGVyOikgY2FuIG9ubHkgYmUgYm91bmQgdG8gYSB2YXJpYWJsZSBob2xkaW5nIGEgbnVtYmVyLCBub3QgIi5jb25jYXQobSh0KSwiLiIpKTpDKHIse3NvdXJjZTonPHR3LWljb24gZGF0YS1sYWJlbD0iJy5jb25jYXQoYi5lc2NhcGUoMSE9PWoodCkmJnZvaWQgMCE9PWk/aTpvKSwnIj4nKS5jb25jYXQoKDA8dD9FOk4pKHQpLCI8L3R3LWljb24+Iil9KX0sW3YsU3RyaW5nLHgoU3RyaW5nKV0pLG4uYWRkQ29tbWFuZCgibWV0ZXIiLGZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiJ0d28gd2F5Ij09PWUuYmluZD95LmNyZWF0ZSgiZGF0YXR5cGUiLCIobWV0ZXI6KSBzaG91bGRuJ3QgYmUgZ2l2ZW4gdHdvLXdheSBib3VuZCB2YXJpYWJsZXMuIiwnQ2hhbmdlIHRoZSAiMmJpbmQiIGtleXdvcmQgdG8ganVzdCAiYmluZCIuJyk6InN0cmluZyIhPXR5cGVvZiByfHxyLnRyaW0oKT8tMT09PW4uc2VhcmNoKEQpfHwhbi5pbmNsdWRlcygiPSIpJiYxPG4ubGVuZ3RoP3kuY3JlYXRlKCJkYXRhdHlwZSIsJ1RoZSAobWV0ZXI6KSBtYWNybyByZXF1aXJlcyBhIHNpemluZyBsaW5lKCI9PVg9PSIsICI9PVgiLCAiPVhYWFg9IiBldGMuKSBiZSBwcm92aWRlZCwgbm90ICcrSlNPTi5zdHJpbmdpZnkobikrIi4iKTp2b2lkIDA6eS5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIGxhYmVsIHN0cmluZyBnaXZlbiB0byAobWV0ZXI6KSBjYW4ndCBiZSBlbXB0eSBvciBvbmx5IHdoaXRlc3BhY2UuIil9LGZ1bmN0aW9uKHIsZSxhLG4sdCxvLGkpe28mJiJzdHJpbmciIT10eXBlb2YgbyYmKGk9byxvPXZvaWQgMCksaT1pfHxwLmNyZWF0ZSh7aDowLHM6MCxsOi41LGE6LjV9KSxwLmlzUHJvdG90eXBlT2YoaSkmJihpPWQuY3JlYXRlKDkwLFt7Y29sb3VyOmksc3RvcDowfSx7Y29sb3VyOmksc3RvcDoxfV0pKTtmdW5jdGlvbiBzKGUpe3ZhciB0PXooMCxxKDEsZS9uKSksZT1pLnJlcGVhdGluZz9pOmkubXVsdGlwbHkobi9lKTtyZXR1cm4iaGVpZ2h0OjEwMCU7YmFja2dyb3VuZC1yZXBlYXQ6bm8tcmVwZWF0O2JhY2tncm91bmQtaW1hZ2U6Ii5jb25jYXQoKGw/QyhlLGUucmVwZWF0aW5nP3t9OnthbmdsZToyNzB9KS50b0xpbmVhckdyYWRpZW50U3RyaW5nKCkrIiwgIjoiIikrQyhlLGUucmVwZWF0aW5nP3t9OnthbmdsZTpsfHwwPT09Yz85MDoyNzB9KS50b0xpbmVhckdyYWRpZW50U3RyaW5nKCksIjtiYWNrZ3JvdW5kLXNpemU6IikuY29uY2F0KGw/QXJyYXkoMikuZmlsbCg1MCp0KyIlIik6MTAwKnQrIiUiLCI7YmFja2dyb3VuZC1wb3NpdGlvbi14OiIpLmNvbmNhdChsPy0xMDAvKDItdCkrMTAwKyIlLCIrMTAwLygyLXQpKyIlIjowPT09Yz8ibGVmdCI6InJpZ2h0IiwiO3RleHQtYWxpZ246IikuY29uY2F0KGw/ImNlbnRlciI6MD09PWM/ImxlZnQiOiJyaWdodCIpfXZhciB0PVModCksYz10Lm1hcmdpbkxlZnQsdD10LnNpemUsbD0wPGMmJk1hdGguY2VpbChjK3QpPDEwMCx1PShyLnN0eWxlcy5wdXNoKHsibWFyZ2luLWxlZnQiOmMrIiUiLHdpZHRoOnQrIiUiLGhlaWdodDoiMS41ZW0iLGRpc3BsYXk6ImJsb2NrIn0pLHIuYXR0ci5wdXNoKHsiZGF0YS0yYmluZCI6ITB9KSxvJiZlLnN0YWNrVG9wLnRlbXBWYXJpYWJsZXMpLHQ9KHIuZGF0YS50d29XYXlCaW5kRXZlbnQ9ZnVuY3Rpb24oZSx0LG4pe2EudmFyUmVmLm1hdGNoZXModCxuKSYmIm51bWJlciI9PXR5cGVvZih0PWEudmFyUmVmLmdldCgpKSYmKChuPXIudGFyZ2V0LmNoaWxkcmVuKCJ0dy1tZXRlciIpKS5hdHRyKCJzdHlsZSIscyh0KSksbykmJnIuc2VjdGlvbi5yZW5kZXJJbnRvKCIiLG51bGwse3NvdXJjZTpvLHRhcmdldDpuLGFwcGVuZDoicmVwbGFjZSIsdHJhbnNpdGlvbkRlZmVycmVkOiExfSx1KX0sYS52YXJSZWYuZ2V0KCkpO3JldHVybiJudW1iZXIiIT10eXBlb2YgdD95LmNyZWF0ZSgiZGF0YXR5cGUiLCIobWV0ZXI6KSBjYW4gb25seSBiZSBib3VuZCB0byBhIHZhcmlhYmxlIGhvbGRpbmcgYSBudW1iZXIsIG5vdCAiLmNvbmNhdChtKHQpLCIuIikpOkMocix7c291cmNlOic8dHctbWV0ZXIgc3R5bGU9IicuY29uY2F0KHModCksJyI+JykuY29uY2F0KG98fCIiLCI8L3R3LW1ldGVyPiIpfSl9LFt2LHIsU3RyaW5nLHgoXyhTdHJpbmcscCxkKSkseChfKHAsZCkpXSksW1siY3ljbGluZy1saW5rIl0sWyJzZXEtbGluayIsInNlcXVlbmNlLWxpbmsiXV0uZm9yRWFjaChmdW5jdGlvbih0LHUpe3JldHVybiBuLmFkZENvbW1hbmQodCxmdW5jdGlvbigpe3ZhciBlO3JldHVybiIiPT09KGFyZ3VtZW50cy5sZW5ndGg8PTA/dm9pZCAwOmFyZ3VtZW50c1swXSk/eS5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIGZpcnN0IHN0cmluZyBpbiBhICgiK3RbMF0rIjopIGNhbid0IGJlIGVtcHR5LiIpOmFyZ3VtZW50cy5sZW5ndGg8PSh2LmlzUHJvdG90eXBlT2YoYXJndW1lbnRzLmxlbmd0aDw9MD92b2lkIDA6YXJndW1lbnRzWzBdKT8yOjEpP3kuY3JlYXRlKCJkYXRhdHlwZSIsIkkgbmVlZCB0d28gb3IgbW9yZSBzdHJpbmdzIHRvICIrKHU/InNlcXVlbmNlIjoiY3ljbGUiKSsiIHRocm91Z2gsIG5vdCBqdXN0ICciKygoZT1hcmd1bWVudHMubGVuZ3RoLTEpPDB8fGFyZ3VtZW50cy5sZW5ndGg8PWU/dm9pZCAwOmFyZ3VtZW50c1tlXSkrIicuIik6dm9pZCAwfSxmdW5jdGlvbihhLGUpe2Zvcih2YXIgbyx0PWFyZ3VtZW50cy5sZW5ndGgsaT1uZXcgQXJyYXkoMjx0P3QtMjowKSxuPTI7bjx0O24rKylpW24tMl09YXJndW1lbnRzW25dO3YuaXNQcm90b3R5cGVPZihpWzBdKSYmKG89aS5zaGlmdCgpKTt2YXIgcz0wLGM9KCJ0d28gd2F5Ij09PShudWxsPT0obD1vKT92b2lkIDA6bC5iaW5kKSYmKGEuYXR0ci5wdXNoKHsiZGF0YS0yYmluZCI6ITB9KSwtMTwobD1pLmluZGV4T2Yoby52YXJSZWYuZ2V0KCkpKSkmJihzPWwpLGUuc3RhY2tUb3AudGVtcFZhcmlhYmxlcyk7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXM+PWkubGVuZ3RoLTEmJnUscj0iIj09PWlbc10/IiI6bj9pW3NdOiI8dHctbGluaz4iLmNvbmNhdChpW3NdLCI8L3R3LWxpbms+Iik7aWYobiYmKGEuZGF0YS5jbGlja0V2ZW50PXZvaWQgMCksbyYmIXQpe249by5zZXQoaVtzXSk7aWYoeS5jb250YWluc0Vycm9yKG4pKXJldHVybiB2b2lkIGUucmVwbGFjZVdpdGgobi5yZW5kZXIoaVtzXSkpfXQ9X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGEpLHt9LHtzb3VyY2U6cix0cmFuc2l0aW9uRGVmZXJyZWQ6ITF9KTthLnNlY3Rpb24ucmVuZGVySW50bygiIixudWxsLHQsYyl9aVtzXSYmKGEuZGF0YS5jbGlja0V2ZW50PWZ1bmN0aW9uKGUpe3M9KHMrMSklaS5sZW5ndGgscihlLCExKX0sYS5kYXRhLnR3b1dheUJpbmRFdmVudD1mdW5jdGlvbihlLHQsbil7by52YXJSZWYubWF0Y2hlcyh0LG4pJiYodD1vLnZhclJlZi5nZXQoKSwtMTwobj1pLmluZGV4T2YodCkpKSYmbiE9PXMmJihzPW4scihlLCEwKSl9KTt2YXIgbD0iPHR3LWxpbms+Ii5jb25jYXQoaVtzXSwiPC90dy1saW5rPiIpO2lmKG8pe2U9by5zZXQoaVtzXSk7aWYoeS5jb250YWluc0Vycm9yKGUpKXJldHVybiBlfXJldHVybiBDKGEse3NvdXJjZTpsLGFwcGVuZDoicmVwbGFjZSIsdHJhbnNpdGlvbkRlZmVycmVkOiEwfSl9LFtfKHYsU3RyaW5nKSxUKFN0cmluZyldKX0pLGIub25TdGFydHVwKGZ1bmN0aW9uKCl7cmV0dXJuIGIuc3RvcnlFbGVtZW50Lm9uKCJjaGFuZ2UuZHJvcGRvd24tbWFjcm8iLCJzZWxlY3QiLGZ1bmN0aW9uKCl7dmFyIGU9dSh0aGlzKSx0PWUuY2xvc2VzdCgidHctZXhwcmVzc2lvbiwgdHctaG9vayIpLmRhdGEoImRyb3Bkb3duRXZlbnQiKTt0JiZ0KGUpfSl9KSxuLmFkZENvbW1hbmQoImRyb3Bkb3duIixmdW5jdGlvbihlKXt2YXIgdDtyZXR1cm4iIj09PShhcmd1bWVudHMubGVuZ3RoPD0xP3ZvaWQgMDphcmd1bWVudHNbMV0pfHwiIj09PSgodD0oYXJndW1lbnRzLmxlbmd0aDw9MT8wOmFyZ3VtZW50cy5sZW5ndGgtMSktMSsxKTwxfHxhcmd1bWVudHMubGVuZ3RoPD10P3ZvaWQgMDphcmd1bWVudHNbdF0pP3kuY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSBmaXJzdCBvciBsYXN0IHN0cmluZ3MgaW4gYSAoZHJvcGRvd246KSBjYW4ndCBiZSBlbXB0eS4iLCJCZWNhdXNlIGVtcHR5IHN0cmluZ3MgY3JlYXRlIHNlcGFyYXRvcnMgd2l0aGluIChkcm9wZG93bjopcywgaGF2aW5nIHRoZW0gYXQgdGhlIHN0YXJ0IG9yIGVuZCBkb2Vzbid0IG1ha2Ugc2Vuc2UuIik6KGFyZ3VtZW50cy5sZW5ndGg8PTE/MDphcmd1bWVudHMubGVuZ3RoLTEpPD0xP3kuY3JlYXRlKCJkYXRhdHlwZSIsIkkgbmVlZCB0d28gb3IgbW9yZSBzdHJpbmdzIHRvIGNyZWF0ZSBhIChkcm9wZG93bjopIG1lbnUsIG5vdCBqdXN0ICIrKGFyZ3VtZW50cy5sZW5ndGg8PTE/MDphcmd1bWVudHMubGVuZ3RoLTEpKyIuIik6dm9pZCAwfSxmdW5jdGlvbihlLHQscil7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgsYT1uZXcgQXJyYXkoMzxuP24tMzowKSxvPTM7bzxuO28rKylhW28tM109YXJndW1lbnRzW29dO3ZhciBpPTAscz0oInR3byB3YXkiPT09ci5iaW5kJiYoZS5hdHRyLnB1c2goeyJkYXRhLTJiaW5kIjohMH0pLC0xPChjPWEuaW5kZXhPZihyLnZhclJlZi5nZXQoKSkpKSYmKGk9YyksTWF0aC5tYXguYXBwbHkoTWF0aCxfdG9Db25zdW1hYmxlQXJyYXkoYS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIF90b0NvbnN1bWFibGVBcnJheShlKS5sZW5ndGh9KSkpKSxjPSI8c2VsZWN0PiIrYS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4iPG9wdGlvbiIuY29uY2F0KHQ9PT1pPyIgc2VsZWN0ZWQiOiIiKS5jb25jYXQoIiI9PT1lPyIgZGlzYWJsZWQiOiIiLCI+IikuY29uY2F0KGIuZXNjYXBlKGV8fCJcdTI1MDAiLnJlcGVhdChzKSksIjwvb3B0aW9uPiIpfSkuam9pbigiXG4iKSsiPC9zZWxlY3Q+IixsPShlLmRhdGEuZHJvcGRvd25FdmVudD1mdW5jdGlvbihlKXt2YXIgdD1lLnZhbCgpLG49ci5zZXQodCk7eS5jb250YWluc0Vycm9yKG4pJiZlLnJlcGxhY2VXaXRoKG4ucmVuZGVyKHQpKX0sZS5kYXRhLnR3b1dheUJpbmRFdmVudD1mdW5jdGlvbihlLHQsbil7ci52YXJSZWYubWF0Y2hlcyh0LG4pJiYodD1yLnZhclJlZi5nZXQoKSwtMTwobj1hLmluZGV4T2YodCkpKSYmbiE9PWkmJihlLmZpbmQoInNlbGVjdCIpLnZhbCh0KSxpPW4pfSxlLnN0eWxlcy5wdXNoKHsiYmFja2dyb3VuZC1jb2xvciI6ZnVuY3Rpb24oKXtyZXR1cm4gYi5wYXJlbnRDb2xvdXJzKHUodGhpcykpLmJhY2tncm91bmRDb2xvdXJ9fSksci5zZXQoYVtpXSkpO3JldHVybiB5LmNvbnRhaW5zRXJyb3IobCk/bDpDKGUse3NvdXJjZTpjLGFwcGVuZDoicmVwbGFjZSJ9KX0sW3YsU3RyaW5nLFQoU3RyaW5nKV0pLGIub25TdGFydHVwKGZ1bmN0aW9uKCl7cmV0dXJuIGIuc3RvcnlFbGVtZW50Lm9uKCJpbnB1dC5jaGVja2JveC1tYWNybyIsImlucHV0W3R5cGU9Y2hlY2tib3hdIixmdW5jdGlvbigpe3ZhciBlPXUodGhpcyksdD1lLmNsb3Nlc3QoInR3LWV4cHJlc3Npb24iKS5kYXRhKCJjaGVja2JveEV2ZW50Iik7dCYmdChlKX0pfSk7ZnVuY3Rpb24gSShlKXtyZXR1cm5bIkkgY2FuJ3QgdXNlIGEgZGlhbG9nIG1hY3JvIGluICIrZSsiLiIsIlBsZWFzZSByZXdyaXRlIHRoaXMgd2l0aG91dCBwdXR0aW5nIHN1Y2ggbWFjcm9zIGhlcmUuIl19dmFyIFY9MTtuLmFkZENvbW1hbmQoImNoZWNrYm94IixmdW5jdGlvbigpe30sZnVuY3Rpb24oZSx0LHIsbil7dmFyIGE9ITEsbz0iY2hlY2tib3gtIisgKytWLGk9KCJ0d28gd2F5Ij09PXIuYmluZCYmKGUuYXR0ci5wdXNoKHsiZGF0YS0yYmluZCI6ITB9KSwiYm9vbGVhbiI9PXR5cGVvZihpPXIudmFyUmVmLmdldCgpKSYmKGE9aSksZS5kYXRhLnR3b1dheUJpbmRFdmVudD1mdW5jdGlvbihlLHQsbil7ci52YXJSZWYubWF0Y2hlcyh0LG4pJiYiYm9vbGVhbiI9PXR5cGVvZih0PXIudmFyUmVmLmdldCgpKSYmZS5jaGlsZHJlbigiaW5wdXRbdHlwZT1jaGVja2JveF0iKS5wcm9wKCJjaGVja2VkIix0KX0pLGUuZGF0YS5jaGVja2JveEV2ZW50PWZ1bmN0aW9uKGUpe3ZhciB0PWUuaXMoIjpjaGVja2VkIiksdD1yLnNldCh0KTt5LmNvbnRhaW5zRXJyb3IodCkmJmUucmVwbGFjZVdpdGgodC5yZW5kZXIoIiIpKX0sci5zZXQoYSkpO3JldHVybiB5LmNvbnRhaW5zRXJyb3IoaSk/aTpDKGUse3NvdXJjZTonPGlucHV0IGlkPSInLmNvbmNhdChvLCciIHR5cGU9ImNoZWNrYm94IiAnKS5jb25jYXQoYT8iY2hlY2tlZCI6IiIsJz48bGFiZWwgZm9yPSInKS5jb25jYXQobywnIj4nKS5jb25jYXQobiwiPC9sYWJlbD4iKSxhcHBlbmQ6InJlcGxhY2UifSl9LFt2LFN0cmluZ10pLGIub25TdGFydHVwKGZ1bmN0aW9uKCl7cmV0dXJuIHUoZG9jdW1lbnQpLm9uKCJmdWxsc2NyZWVuY2hhbmdlIixmdW5jdGlvbigpe3UoImlucHV0W3R5cGU9Y2hlY2tib3hdW2lkXj1mdWxsc2NyZWVuXSIsYi5zdG9yeUVsZW1lbnQpLmVhY2goZnVuY3Rpb24oZSx0KXsodSh0KS5jbG9zZXN0KCJ0dy1leHByZXNzaW9uIikuZGF0YSgiZnVsbHNjcmVlbkV2ZW50Iil8fE9iamVjdCkodCl9KX0pfSksbi5hZGRDb21tYW5kKCJjaGVja2JveC1mdWxsc2NyZWVuIixmdW5jdGlvbigpe30sZnVuY3Rpb24oZSx0LG4pe3ZhciByPSJmdWxsc2NyZWVuQ2hlY2tib3gtIisgKytWO3JldHVybiBlLmRhdGEuZnVsbHNjcmVlbkV2ZW50PWZ1bmN0aW9uKGUpe3JldHVybiB1KGUpLnByb3AoImNoZWNrZWQiLCEoIWRvY3VtZW50LmZ1bGxzY3JlZW5FbGVtZW50JiYhZG9jdW1lbnQubXNGdWxsc2NyZWVuRWxlbWVudCkpfSxlLmRhdGEuY2hlY2tib3hFdmVudD1mdW5jdGlvbigpe3JldHVybiBhLnRvZ2dsZUZ1bGxzY3JlZW4oKX0sQyhlLHtzb3VyY2U6JzxpbnB1dCBpZD0iJy5jb25jYXQociwnIiB0eXBlPSJjaGVja2JveCIgJykuY29uY2F0KGRvY3VtZW50LmZ1bGxzY3JlZW5FbmFibGVkfHxkb2N1bWVudC5tc0Z1bGxzY3JlZW5FbmFibGVkPyIgIjoiZGlzYWJsZWQgIikuY29uY2F0KGRvY3VtZW50LmZ1bGxzY3JlZW5FbGVtZW50fHxkb2N1bWVudC5tc0Z1bGxzY3JlZW5FbGVtZW50PyJjaGVja2VkIjoiIiwnPjxsYWJlbCBmb3I9IicpLmNvbmNhdChyLCciPicpLmNvbmNhdChuLCI8L2xhYmVsPiIpLGFwcGVuZDoicmVwbGFjZSJ9KX0sW1N0cmluZ10pLGIub25TdGFydHVwKGZ1bmN0aW9uKCl7cmV0dXJuIGIuc3RvcnlFbGVtZW50Lm9uKCJpbnB1dC5pbnB1dC1ib3gtbWFjcm8iLCJ0ZXh0YXJlYSwgaW5wdXRbdHlwZT10ZXh0XSIsZnVuY3Rpb24oKXt2YXIgZT11KHRoaXMpLHQ9ZS5jbG9zZXN0KCJ0dy1leHByZXNzaW9uIikuZGF0YSgiaW5wdXRCb3hFdmVudCIpO3QmJnQoZSl9KX0pLFsiaW5wdXQiLCJmb3JjZS1pbnB1dCIsImlucHV0LWJveCIsImZvcmNlLWlucHV0LWJveCJdLmZvckVhY2goZnVuY3Rpb24oZyl7cmV0dXJuIG4uYWRkQ29tbWFuZChnLGZ1bmN0aW9uKCl7Zm9yKHZhciBlPWFyZ3VtZW50cy5sZW5ndGgsdD1uZXcgQXJyYXkoZSksbj0wO248ZTtuKyspdFtuXT1hcmd1bWVudHNbbl07dmFyIHI9Zy5lbmRzV2l0aCgiYm94IiksYT12LmlzUHJvdG90eXBlT2YodFswXSksbz0ic3RyaW5nIj09dHlwZW9mIHRbK2FdLHI9ciYmIm51bWJlciI9PXR5cGVvZiB0W28rYV0saT1vP3RbK2FdOnRbYStyXSxzPTA8UyhpKS5zaXplLG89cz90W2ErcitvXTppO3JldHVybiBnLnN0YXJ0c1dpdGgoImZvcmNlIikmJiJzdHJpbmciIT10eXBlb2Ygbz95LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgKCIuY29uY2F0KGcsIjopIG1hY3JvIHJlcXVpcmVzIGEgc3RyaW5nIG9mIHRleHQgdG8gZm9yY2libHkgaW5wdXQuIikpOnQubGVuZ3RoPmErcitzKygic3RyaW5nIj09dHlwZW9mIG8pP3kuY3JlYXRlKCJkYXRhdHlwZSIsIkFuIGluY29ycmVjdCBjb21iaW5hdGlvbiBvZiB2YWx1ZXMgd2FzIGdpdmVuIHRvIHRoaXMgKCIuY29uY2F0KGcsIjopIG1hY3JvLiIpKTp2b2lkIDB9LGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1uZXcgQXJyYXkoMjxuP24tMjowKSxhPTI7YTxuO2ErKylyW2EtMl09YXJndW1lbnRzW2FdO3ZhciBvPWcuc3RhcnRzV2l0aCgiZm9yY2UiKSxpPWcuZW5kc1dpdGgoImJveCIpLHM9di5pc1Byb3RvdHlwZU9mKHJbMF0pLGM9InN0cmluZyI9PXR5cGVvZiByWytzXSxsPWkmJiJudW1iZXIiPT10eXBlb2YgcltjK3NdLHU9cyYmclswXSxwPWw/clsxK3NdOjMsZD1jP1Moclsrc10pOnt9LGY9ZC5tYXJnaW5MZWZ0LGQ9ZC5zaXplLGg9KGQ/cltzK2wrY106YyYmclsrc10pfHwiIixsPW8/IiI6aCxjPSExO2lmKCJ0d28gd2F5Ij09PXUuYmluZCl7ZS5hdHRyLnB1c2goeyJkYXRhLTJiaW5kIjohMH0pO3M9dS52YXJSZWYuZ2V0KCk7aWYoInN0cmluZyI9PXR5cGVvZiBzKXtsPW8/aC5zbGljZSgwLHMubGVuZ3RoKTpzLHM9dS5zZXQobCksYz0hMDtpZih5LmNvbnRhaW5zRXJyb3IocykpcmV0dXJuIHN9ZS5kYXRhLnR3b1dheUJpbmRFdmVudD1mdW5jdGlvbihlLHQsbil7dS52YXJSZWYubWF0Y2hlcyh0LG4pJiYic3RyaW5nIj09dHlwZW9mKHQ9dS52YXJSZWYuZ2V0KCkpJiZlLmZpbmQoaT8idGV4dGFyZWEiOiJpbnB1dCIpLnZhbChvP2guc2xpY2UoMCx0Lmxlbmd0aCk6dCl9fWlmKHUmJiFjKXtzPXUuc2V0KG8/IiI6aCk7aWYoeS5jb250YWluc0Vycm9yKHMpKXJldHVybiBzfSFvJiZ1JiYoZS5kYXRhLmlucHV0Qm94RXZlbnQ9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS52YWwoKSx0PXUuc2V0KHQpO3kuY29udGFpbnNFcnJvcih0KSYmZS5yZXBsYWNlV2l0aCh0LnJlbmRlcigiIikpfSk7dmFyIG0sYz0iPCIuY29uY2F0KGk/InRleHRhcmVhIjoiaW5wdXQgdHlwZT10ZXh0IiwnIHN0eWxlPSJ3aWR0aDoxMDAlIiAnKS5jb25jYXQoaT8icm93cz0iLmNvbmNhdChwLCI+Iik6J3ZhbHVlPSInKS5jb25jYXQoYi5lc2NhcGUobCkpLmNvbmNhdChpPyI8L3RleHRhcmVhPiI6JyI+Jyk7cmV0dXJuIG8mJihtPUFycmF5LmZyb20oaCksZS5kYXRhLmlucHV0Qm94RXZlbnQ9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS52YWwoKS5sZW5ndGgsdD1tLnNsaWNlKDAsdCkuam9pbigiIik7cmV0dXJuIGUudmFsKHQpLHUmJih0PXUuc2V0KHQpLHkuY29udGFpbnNFcnJvcih0KSkmJmUucmVwbGFjZVdpdGgodC5yZW5kZXIoIiIpKSwhMH0pLGUuc3R5bGVzLnB1c2goe2Rpc3BsYXk6ImJsb2NrIiwibWFyZ2luLWxlZnQiOmQ/ZisiJSI6dm9pZCAwLHdpZHRoOmQ/ZCsiJSI6IjEwMCUiLCJib3JkZXItc3R5bGUiOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc3R5bGUuYm9yZGVyU3R5bGV8fCJzb2xpZCJ9fSksQyhlLHtzb3VyY2U6YyxhcHBlbmQ6InJlcGxhY2UifSl9LGcuZW5kc1dpdGgoImJveCIpP1tfKHYsU3RyaW5nKSx4KF8oQSxTdHJpbmcpKSx4KF8oQSxTdHJpbmcpKSx4KFN0cmluZyldOlt4KF8odixTdHJpbmcpKSx4KFN0cmluZykseChTdHJpbmcpXSl9KSxbInNob3ciLCJyZXJ1biJdLmZvckVhY2goZnVuY3Rpb24ocyl7cmV0dXJuIG4uYWRkQ29tbWFuZChzLGZ1bmN0aW9uKCl7Zm9yKHZhciByLGU9YXJndW1lbnRzLmxlbmd0aCx0PW5ldyBBcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm4gdC5zb21lKGZ1bmN0aW9uIGUodCl7dmFyIG49dC5zZWxlY3Rvcix0PXQubmV4dDtyZXR1cm4ibmFtZSI9PT1uLnR5cGUmJiJwYWdlIj09PW4uZGF0YT8ocj15LmNyZWF0ZSgibWFjcm9jYWxsIiwiWW91IGNhbid0IChoaWRlOikgdGhlID9wYWdlLiBTb3JyeS4iKSwhMCk6ISEoImJhc2UiPT09bi50eXBlJiZlKG4uZGF0YSl8fHQmJmUodCkpfHx2b2lkIDB9KSxyfSxmdW5jdGlvbihvLGkpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KDI8ZT9lLTI6MCksbj0yO248ZTtuKyspdFtuLTJdPWFyZ3VtZW50c1tuXTtyZXR1cm4gdC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlLmZvckVhY2goaSxmdW5jdGlvbihlKXt2YXIgdCxuLHIsYT1lLmRhdGEoImhpZGRlbiIpO3ZvaWQgMCE9PWEhPSgicmVydW4iPT09cykmJihlLnJlbW92ZURhdGEoImhpZGRlbiIpLGEgaW5zdGFuY2VvZiB1P2UuZW1wdHkoKS5hcHBlbmQoYSk6KGE9ZS5kYXRhKCJ0ZW1wVmFyaWFibGVzIiksbj0odD0idHctcGFzc2FnZSI9PT1lLnRhZygpKT9sLmdldFRyZWUoYy5wYXNzYWdlKTplLmRhdGEoIm9yaWdpbmFsU291cmNlIil8fCIiLHQmJihyPWUuZmluZCgidHctc2lkZWJhciIpLmRldGFjaCgpKSxpLnJlbmRlckludG8oIiIsbnVsbCxfb2JqZWN0U3ByZWFkKF9vYmplY3RTcHJlYWQoe30sbykse30se2FwcGVuZDoicmVwbGFjZSIsc291cmNlOm4sdGFyZ2V0OmV9KSxhJiZPYmplY3QuY3JlYXRlKGEpKSxyJiZlLnByZXBlbmQocikpKX0pfSksb30sW1QobyldKX0pO24uYWRkQ29tbWFuZCgiaGlkZSIsZnVuY3Rpb24oKXtmb3IodmFyIHIsZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3JldHVybiB0LnNvbWUoZnVuY3Rpb24gZSh0KXt2YXIgbj10LnNlbGVjdG9yLHQ9dC5uZXh0O3JldHVybiJuYW1lIj09PW4udHlwZSYmInBhZ2UiPT09bi5kYXRhPyhyPXkuY3JlYXRlKCJtYWNyb2NhbGwiLCJZb3UgY2FuJ3QgKGhpZGU6KSB0aGUgP3BhZ2UuIFNvcnJ5LiIpLCEwKTohISgiYmFzZSI9PT1uLnR5cGUmJmUobi5kYXRhKXx8dCYmZSh0KSl8fHZvaWQgMH0pLHJ9LGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtmb3IodmFyIGE9MCxvPW47YTxvLmxlbmd0aDthKyspb1thXS5mb3JFYWNoKGUsZnVuY3Rpb24oZSl7ZS5kYXRhKCJoaWRkZW4iKXx8ZS5kYXRhKCJoaWRkZW4iLGUuY29udGVudHMoKS5kZXRhY2goKSl9KX0sW1QobyldLCExKSgic2Nyb2xsIixQLGZ1bmN0aW9uKG0sZSxnKXt2YXIgeT0ibnVtYmVyIj09dHlwZW9mIGcmJmc7cmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7ZS5mb3JFYWNoKG0sZnVuY3Rpb24oZSl7aWYoITEhPT15KXt2YXIgdCxuLHI9ZVswXTtudWxsIT0odD0obj1yPXI9PT1iLnN0b3J5RWxlbWVudFswXSYmci5zY3JvbGxIZWlnaHQ9PT1yLmNsaWVudEhlaWdodD9nZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmJvZHkpLm92ZXJmbG93LmluY2x1ZGVzKCIgc2Nyb2xsIik/ZG9jdW1lbnQuYm9keTpkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ6cikuc2Nyb2xsVG8pJiZ0LmNhbGwobiwwLChyLnNjcm9sbEhlaWdodC1yLmNsaWVudEhlaWdodCkqeSl9ZWxzZXt2YXIgYSxvPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKGcuaG9va3MobSkuZ2V0KCkpO3RyeXtmb3Ioby5zKCk7IShhPW8ubigpKS5kb25lOyl7dmFyIGk9YS52YWx1ZTtpZihlLmZpbmQoaSkpe2Zvcih2YXIgcz1bXSxjPWVbMF07KGM9Yy5wYXJlbnROb2RlKSYmYyE9PWRvY3VtZW50LmJvZHk7KXMucHVzaChbYyxjLnNjcm9sbExlZnQsYy5zY3JvbGxUb3BdKTtpLnNjcm9sbEludG9WaWV3KCk7Zm9yKHZhciBsPTAsdT1zO2w8dS5sZW5ndGg7bCsrKXt2YXIgcD1fc2xpY2VkVG9BcnJheSh1W2xdLDMpLGQ9cFswXSxmPXBbMV0saD1wWzJdO2Quc2Nyb2xsTGVmdD1mLGQuc2Nyb2xsVG9wPWh9YnJlYWt9fX1jYXRjaChlKXtvLmUoZSl9ZmluYWxseXtvLmYoKX19fSl9KX0sW28sXyhMLG8pXSwhMSkoInN0b3AiLFAsUCxbXSwhMSkoImxvYWQtZ2FtZSIsUCxmdW5jdGlvbihlLHQpe3ZhciBuLHI7cmV0dXJuIGUubG9hZGVkR2FtZT95LmNyZWF0ZSgiaW5maW5pdGUiLCJJIGNhbid0IHVzZSAobG9hZC1nYW1lOikgaW1tZWRpYXRlbHkgYWZ0ZXIgbG9hZGluZyBhIGdhbWUuIik6KG49bG9jYWxTdG9yYWdlLmdldEl0ZW0oUigiU2F2ZWQgR2FtZSIpK3QpKT8obj1jLmRlc2VyaWFsaXNlKGUsbikpaW5zdGFuY2VvZiBFcnJvcj97YmxvY2tlZDpyPWsoe21lc3NhZ2U6IlNvcnJ5IHRvIGludGVycnVwdC4uLiBUaGUgc3RvcnkgdHJpZWQgdG8gbG9hZCBzYXZlZCBkYXRhLCBidXQgdGhlcmUgd2FzIGEgcHJvYmxlbS5cbiIrbi5tZXNzYWdlKyJcblxuVGhhdCBkYXRhIG1pZ2h0IGhhdmUgYmVlbiBzYXZlZCBmcm9tIGEgZGlmZmVyZW50IHZlcnNpb24gb2YgdGhpcyBzdG9yeS4gU2hvdWxkIEkgZGVsZXRlIGl0P1xuKFR5cGUgJ2RlbGV0ZScgYW5kIGNob29zZSBZZXMgdG8gZGVsZXRlIGl0LilcblxuRWl0aGVyIHdheSwgdGhlIHN0b3J5IHdpbGwgbm93IGNvbnRpbnVlIHdpdGhvdXQgbG9hZGluZyB0aGUgZGF0YS4iLGRlZmF1bHRWYWx1ZToiIixidXR0b25zOlt7bmFtZToiWWVzIixjb25maXJtOiEwLGNhbGxiYWNrOmZ1bmN0aW9uKCl7ImRlbGV0ZSI9PT1yLmZpbmQoImlucHV0IikubGFzdCgpLnZhbCgpJiZsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShSKCJTYXZlZCBHYW1lIikrdCksZS51bmJsb2NrKCIiKX19LHtuYW1lOiJObyIsY2FuY2VsOiEwLGNhbGxiYWNrOmZ1bmN0aW9uKCl7cmV0dXJuIGUudW5ibG9jaygpfX1dfSl9OnZvaWQgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGEuc2hvd1Bhc3NhZ2UuYmluZChhLGMucGFzc2FnZSx7bG9hZGVkR2FtZTohMH0pKTp5LmNyZWF0ZSgic2F2aW5nIiwiSSBjYW4ndCBmaW5kIGEgc2F2ZSBzbG90IG5hbWVkICciK3QrIichIil9LFtTdHJpbmddLCExKSgiZm9yZ2V0LXVuZG9zIixQLGZ1bmN0aW9uKGUsdCl7Yy5mdXR1cmVMZW5ndGh8fGMuZm9yZ2V0VW5kb3ModCl9LFtwYXJzZUludF0sITEpKCJmb3JnZXQtdmlzaXRzIixQLGZ1bmN0aW9uKGUsdCl7Yy5mb3JnZXRWaXNpdHModCl9LFtwYXJzZUludF0sITEpKCJtb2NrLXZpc2l0cyIsZnVuY3Rpb24oKXtpZighYi5vcHRpb25zLmRlYnVnKXJldHVybiB5LmNyZWF0ZSgiZGVidWdvbmx5IiwiKG1vY2stdmlzaXRzOikgY2Fubm90IGJlIHVzZWQgb3V0c2lkZSBvZiBkZWJ1ZyBtb2RlLiIpO2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3ZhciByPXQuZmluZChmdW5jdGlvbihlKXtyZXR1cm4hbC5oYXNWYWxpZChlKX0pO3JldHVybiByP3kuY3JlYXRlKCJkYXRhdHlwZSIsIkkgY2FuJ3QgbW9jay12aXNpdCAnIityKyInIGJlY2F1c2Ugbm8gcGFzc2FnZSB3aXRoIHRoYXQgbmFtZSBleGlzdHMuIik6dm9pZCAwfSxmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07Yy5tb2NrVmlzaXRzPWcobil9LFtUKFN0cmluZyldLCExKSgibW9jay10dXJucyIsZnVuY3Rpb24oKXtpZighYi5vcHRpb25zLmRlYnVnKXJldHVybiB5LmNyZWF0ZSgiZGVidWdvbmx5IiwiKG1vY2stdHVybnM6KSBjYW5ub3QgYmUgdXNlZCBvdXRzaWRlIG9mIGRlYnVnIG1vZGUuIil9LGZ1bmN0aW9uKGUsdCl7Yy5tb2NrVHVybnM9dH0sW0hdLCExKSgic2VlZCIsUCxmdW5jdGlvbihlLHQpe2Muc2V0U2VlZCh0KX0sW1N0cmluZ10sITEpKFsiZGlhbG9nIiwiYWxlcnQiXSxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTtpZih2LmlzUHJvdG90eXBlT2YoZSkpe2lmKCJ0d28gd2F5Ij09PWUuYmluZClyZXR1cm4geS5jcmVhdGUoImRhdGF0eXBlIiwiKGRpYWxvZzopIHNob3VsZG4ndCBiZSBnaXZlbiB0d28td2F5IGJvdW5kIHZhcmlhYmxlcy4iLCdDaGFuZ2UgdGhlICIyYmluZCIga2V5d29yZCB0byBqdXN0ICJiaW5kIi4nKTtpZih2b2lkIDA9PT10KXJldHVybiB5LmNyZWF0ZSgiZGF0YXR5cGUiLCIoZGlhbG9nOikgbmVlZHMgYSBtZXNzYWdlIHN0cmluZyBvciBjb2RlaG9vayB0byBkaXNwbGF5LiIpfWVsc2Ugdm9pZCAwIT09dCYmci51bnNoaWZ0KHQpO2U9ci5maW5kSW5kZXgoZnVuY3Rpb24oZSl7cmV0dXJuIiI9PT1lfSk7aWYoLTE8ZSlyZXR1cm4geS5jcmVhdGUoImRhdGF0eXBlIiwiKGRpYWxvZzopJ3MgIi5jb25jYXQoYi5udGgoZSsxKSwiIGxpbmsgdGV4dCBzaG91bGRuJ3QgYmUgYW4gZW1wdHkgc3RyaW5nLiIpKX0sZnVuY3Rpb24oZSxuLHIsdCl7Zm9yKHZhciBhPWFyZ3VtZW50cy5sZW5ndGgsbz1uZXcgQXJyYXkoNDxhP2EtNDowKSxpPTQ7aTxhO2krKylvW2ktNF09YXJndW1lbnRzW2ldO3JldHVybiB2LmlzUHJvdG90eXBlT2Yocil8fCh2b2lkIDAhPT10JiZvLnVuc2hpZnQodCksdD1yLHI9dm9pZCAwKSxvLmxlbmd0aHx8KG89WyJPSyJdKSx7YmxvY2tlZDprKHtzZWN0aW9uOm4sbWVzc2FnZTp0LGNkOmUsYnV0dG9uczpvLm1hcChmdW5jdGlvbih0KXtyZXR1cm57bmFtZTp0LGNhbGxiYWNrOmZ1bmN0aW9uKCl7dmFyIGU7bi51bmJsb2NrKChudWxsPT0oZT1yKT92b2lkIDA6ZS5zZXQodCkpfHwiIil9fX0pfSl9fSxbXyh2LFN0cmluZyx0KSx4KF8odCxTdHJpbmcpKSxPKFN0cmluZyldKSgib3Blbi11cmwiLFAsZnVuY3Rpb24oZSx0KXt3aW5kb3cub3Blbih0LCIiKX0sW1N0cmluZ10sITEpKFsicmVzdGFydCIsInJlbG9hZCJdLFAsZnVuY3Rpb24oKXtpZighYi5vcHRpb25zLmlnbm9yZUdvdG9zKXtpZihjLnR1cm5zPD0xKXJldHVybiB5LmNyZWF0ZSgiaW5maW5pdGUiLCJJIG11c3RuJ3QgKHJlc3RhcnQ6KSB0aGUgc3RvcnkgaW4gdGhlIHN0YXJ0aW5nIHBhc3NhZ2UuIik7Yy5oYXNTZXNzaW9uU3RvcmFnZSYmc2Vzc2lvblN0b3JhZ2UucmVtb3ZlSXRlbSgiU2F2ZWQgU2Vzc2lvbiIpLHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKX19LFtdLCExKSgiZ290by11cmwiLFAsZnVuY3Rpb24oZSx0KXt3aW5kb3cubG9jYXRpb24uYXNzaWduKHQpfSxbU3RyaW5nXSwhMSkoImlnbm9yZSIsUCxQLFtPKEYpXSkoImFzc2VydC1leGlzdHMiLGZ1bmN0aW9uKGUpe2lmKCIiPT09ZSlyZXR1cm4geS5jcmVhdGUoImRhdGF0eXBlIiwiKGFzc2VydC1leGlzdHM6KSBtdXN0bid0IGJlIGdpdmVuIGFuIGVtcHR5IHN0cmluZy4iKX0sZnVuY3Rpb24oZSx0LG4pe3ZhciByPTA7cmV0dXJuKCJzdHJpbmciPT10eXBlb2Ygbj9vLmNyZWF0ZSh7dHlwZToic3RyaW5nIixkYXRhOm59KTpuKS5mb3JFYWNoKHQsZnVuY3Rpb24oKXsrK3J9KSxyP2U6eS5jcmVhdGUoImFzc2VydGlvbiIsIkkgZGlkbid0IHNlZSBhbnkgIi5jb25jYXQoInN0cmluZyI9PXR5cGVvZiBuPyJ0ZXh0IG9jY3VycmVuY2VzIG9mIjoiaG9va3MgbWF0Y2hpbmciLCIgIikuY29uY2F0KHcobiksIiBpbiB0aGlzIHBhc3NhZ2UuIikpfSxbXyhvLFN0cmluZyldKSxuLmFkZCgiYXNzZXJ0IiwiSW5zdGFudCIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD97VHdpbmVTY3JpcHRfVHlwZUlEOiJpbnN0YW50IixUd2luZVNjcmlwdF9UeXBlTmFtZToiYW4gKGFzc2VydDopIG9wZXJhdGlvbiIsVHdpbmVTY3JpcHRfT2JqZWN0TmFtZToiYW4gKGFzc2VydDopIG9wZXJhdGlvbiIsVHdpbmVTY3JpcHRfVW5zdG9yYWJsZTohMCxUd2luZVNjcmlwdF9QcmludDpmdW5jdGlvbigpe3JldHVybiIifX06Qyh5LmNyZWF0ZSgiYXNzZXJ0aW9uIiwiQW4gYXNzZXJ0aW9uIGZhaWxlZDogIikse2FwcGVuZFRpdGxlVGV4dDohMH0pfSxbQm9vbGVhbl0pKCJzYXZlLWdhbWUiLCJCb29sZWFuIixmdW5jdGlvbihlLHQsbil7aWYobj1ufHwiIiwhYy5oYXNTdG9yYWdlKXJldHVybiExO3ZhciByPWMuc2VyaWFsaXNlKCExKS5wYXN0QW5kUHJlc2VudDtpZih5LmNvbnRhaW5zRXJyb3IocikpcmV0dXJuIHI7aWYoITE9PT1yKXJldHVybiExO3RyeXtyZXR1cm4gbG9jYWxTdG9yYWdlLnNldEl0ZW0oUigiU2F2ZWQgR2FtZSIpK3QsciksbG9jYWxTdG9yYWdlLnNldEl0ZW0oUigiU2F2ZWQgR2FtZSBGaWxlbmFtZSIpK3QsbiksITB9Y2F0Y2goZSl7cmV0dXJuITF9fSxbU3RyaW5nLHgoU3RyaW5nKV0pKCJwcm9tcHQiLCJTdHJpbmciLGZ1bmN0aW9uKGUsdCxuLHIsYSl7dmFyIG8saTtyZXR1cm4gbnVsbCE9KG89ZS5zdGFja1RvcCkmJm8uZXZhbHVhdGVPbmx5P3kuY3JlYXRlLmFwcGx5KHksWyJtYWNyb2NhbGwiXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KEkoZS5zdGFja1RvcC5ldmFsdWF0ZU9ubHkpKSkpOiIiPT09YT95LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgdGV4dCBmb3IgKHByb21wdDopJ3MgY29uZmlybSBsaW5rIGNhbid0IGJlIGJsYW5rLiIpOihpPWsoe3NlY3Rpb246ZSxtZXNzYWdlOnQsZGVmYXVsdFZhbHVlOm4sYnV0dG9uczpbe25hbWU6YXx8Ik9LIixjb25maXJtOiEwLGNhbGxiYWNrOmZ1bmN0aW9uKCl7cmV0dXJuIGUudW5ibG9jayhpLmZpbmQoImlucHV0IikubGFzdCgpLnZhbCgpKX19XS5jb25jYXQoIiI9PT1yP1tdOntuYW1lOnJ8fCJDYW5jZWwiLGNhbmNlbDohMCxjYWxsYmFjazpmdW5jdGlvbigpe3JldHVybiBlLnVuYmxvY2sobil9fSl9KSxlLnN0YWNrVG9wLmJsb2NrZWQ9aSwwKX0sW18oU3RyaW5nLHQpLFN0cmluZyx4KFN0cmluZykseChTdHJpbmcpXSkoImNvbmZpcm0iLCJCb29sZWFuIixmdW5jdGlvbihlLHQsbixyKXt2YXIgYTtyZXR1cm4gbnVsbCE9KGE9ZS5zdGFja1RvcCkmJmEuZXZhbHVhdGVPbmx5P3kuY3JlYXRlLmFwcGx5KHksWyJtYWNyb2NhbGwiXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KEkoZS5zdGFja1RvcC5ldmFsdWF0ZU9ubHkpKSkpOiIiPT09cj95LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgdGV4dCBmb3IgKGNvbmZpcm06KSdzIGNvbmZpcm0gbGluayBjYW4ndCBiZSBibGFuay4iKTooYT1rKHtzZWN0aW9uOmUsbWVzc2FnZTp0LGRlZmF1bHRWYWx1ZTohMSxidXR0b25zOlt7bmFtZTpyfHwiT0siLGNvbmZpcm06ITAsY2FsbGJhY2s6ZnVuY3Rpb24oKXtyZXR1cm4gZS51bmJsb2NrKCEwKX19XS5jb25jYXQoIiI9PT1uP1tdOntuYW1lOm58fCJDYW5jZWwiLGNhbmNlbDohMCxjYWxsYmFjazpmdW5jdGlvbigpe3JldHVybiBlLnVuYmxvY2soITEpfX0pfSksZS5zdGFja1RvcC5ibG9ja2VkPWEsMCl9LFtfKFN0cmluZyx0KSx4KFN0cmluZykseChTdHJpbmcpXSkoInBhZ2UtdXJsIiwiU3RyaW5nIixmdW5jdGlvbigpe3JldHVybiB3aW5kb3cubG9jYXRpb24uaHJlZn0sW10pfSksZGVmaW5lKCJtYWNyb2xpYi9jdXN0b21tYWNyb3MiLFsidXRpbHMiLCJtYWNyb3MiLCJzdGF0ZSIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiZGF0YXR5cGVzL2NoYW5nZXJjb21tYW5kIiwiZGF0YXR5cGVzL2N1c3RvbW1hY3JvIiwiZGF0YXR5cGVzL2NvZGVob29rIiwiZGF0YXR5cGVzL3R5cGVkdmFyIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oYyxsLHUsZSx0LHAsbixkLGYpe2Z1bmN0aW9uIHMoZSx0LG4pe2lmKCF0LnNvbWUoZnVuY3Rpb24oZSl7aWYoImZ1bmN0aW9uIj09dHlwZW9mIGUub3V0cHV0KXJldHVybiBlLm91dHB1dChuKSwhMH0pKXJldHVybiBmLmNyZWF0ZSgibWFjcm9jYWxsIiwiKCIrZSsiOikgc2hvdWxkIG9ubHkgYmUgdXNlZCBpbnNpZGUgYSBjb2RlIGhvb2sgcGFzc2VkIHRvIChtYWNybzopLiIpfXZhciBoPWUub2JqZWN0TmFtZSxtPWUudG9Tb3VyY2UsZT1sLmFkZCxyPWwuYWRkQ2hhbmdlcixhPWwuYWRkQ29tbWFuZCxvPWwuVHlwZVNpZ25hdHVyZSxpPW8ucmVzdCxnPW8uZWl0aGVyLHk9by5BbnksYj1vLkV2ZXJ5dGhpbmcsbz1vLnplcm9Pck1vcmU7ZSgibWFjcm8iLCJDdXN0b21NYWNybyIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49W10scj1hcmd1bWVudHMubGVuZ3RoLGE9bmV3IEFycmF5KDE8cj9yLTE6MCksbz0xO288cjtvKyspYVtvLTFdPWFyZ3VtZW50c1tvXTtmb3IodD0wO3Q8YS5sZW5ndGg7dCs9MSl7dmFyIGk9dD09PWEubGVuZ3RoLTE7aWYoZC5pc1Byb3RvdHlwZU9mKGFbdF0pPT09aSlyZXR1cm4gZi5jcmVhdGUoImRhdGF0eXBlIiwiVGhlICIrKGk/IiI6Yy5udGgoYS5sZW5ndGgtdCsxKSsiLSIpKyJsYXN0IHZhbHVlIGdpdmVuIHRvIChtYWNybzopIHNob3VsZCBiZSBhICIrKGk/ImNvZGUgaG9vayI6ImRhdGF0eXBlZCB2YXJpYWJsZSIpKyIsIG5vdCAiK2goYVt0XSkpO2lmKCFpKXtpPSJBIGN1c3RvbSBtYWNybyI7aWYoYVt0XS52YXJSZWYub2JqZWN0PT09dS52YXJpYWJsZXMpcmV0dXJuIGYuY3JlYXRlKCJkYXRhdHlwZSIsaSsiJ3MgdHlwZWQgdmFyaWFibGVzIG11c3QgYmUgdGVtcCB2YXJpYWJsZXMgKHdpdGggYSAnXycpLCBub3QgZ2xvYmFsIHZhcmlhYmxlcyAod2l0aCBhICckJykuIiwiV3JpdGUgdGhlbSB3aXRoIGEgXyBzeW1ib2wgYXQgdGhlIHN0YXJ0IGluc3RlYWQgb2YgYSAkIHN5bWJvbC4iKTtpZigxPGFbdF0udmFyUmVmLnByb3BlcnR5Q2hhaW4ubGVuZ3RoKXJldHVybiBmLmNyZWF0ZSgiZGF0YXR5cGUiLGkrIidzIHR5cGVkIHZhcmlhYmxlcyBjYW4ndCBiZSBwcm9wZXJ0aWVzIGluc2lkZSBhIGRhdGEgc3RydWN0dXJlLiIpO2lmKGFbdF0uZGF0YXR5cGUucmVzdCYmdCE9PWEubGVuZ3RoLTIpcmV0dXJuIGYuY3JlYXRlKCJkYXRhdHlwZSIsaSsiIGNhbiBvbmx5IGhhdmUgb25lIHNwcmVhZCB2YXJpYWJsZSwgYW5kIGl0IG11c3QgYmUgaXRzIGxhc3QgdmFyaWFibGUuIik7dmFyIHM9YVt0XS52YXJSZWYucHJvcGVydHlDaGFpblswXTtpZihuLmluY2x1ZGVzKHMpKXJldHVybiBmLmNyZWF0ZSgiZGF0YXR5cGUiLGkrIidzIHR5cGVkIHZhcmlhYmxlcyBjYW4ndCBib3RoIGJlIG5hbWVkICciK3MrIicuIik7bi5wdXNoKHMpfX1yZXR1cm4gcC5jcmVhdGUoYS5zbGljZSgwLC0xKSxhW2EubGVuZ3RoLTFdKX0sW2koZyhkLG4pKV0pO2EoWyJvdXRwdXQtZGF0YSIsIm91dC1kYXRhIl0sZnVuY3Rpb24oKXt9LGZ1bmN0aW9uKGUsdCl7ZT1lLnN0YWNrO3JldHVybiBzKCJvdXRwdXQtZGF0YSIsZSx0KXx8e2Jsb2NrZWQ6ITB9fSxbeV0sITEpLHIoWyJvdXRwdXQiLCJvdXQiXSxmdW5jdGlvbigpe3JldHVybiBPYmplY3QuYXNzaWduKHQuY3JlYXRlKCJvdXRwdXQiLFtdKSl9LGZ1bmN0aW9uKGUsdCl7aWYoZS5zZWN0aW9uKXt2YXIgbixyPWUuc2VjdGlvbixhPXIuc3RhY2ssbz1yLnN0YWNrVG9wLGk9e307Zm9yKG4gaW4gby50ZW1wVmFyaWFibGVzKW4uc3RhcnRzV2l0aCgiVHdpbmVTY3JpcHRfIil8fChpW25dPW8udGVtcFZhcmlhYmxlc1tuXSk7cygib3V0cHV0IixhLHtjaGFuZ2VyOnQsdmFyaWFibGVzOmksaG9vazpBcnJheS5pc0FycmF5KGUuc291cmNlKT8iWyIrZS5zb3VyY2UubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRleHR9KS5qb2luKCIiKSsiXSI6ZS5zb3VyY2V9KSxlLm91dHB1dD0hMCxvLmJsb2NrZWQ9ITB9fSxbXSksYSgiZXJyb3IiLGZ1bmN0aW9uKGUpe2lmKCFlKXJldHVybiBmLmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGlzIChlcnJvcjopIG1hY3JvIHdhcyBnaXZlbiBhbiBlbXB0eSBzdHJpbmcuIil9LGZ1bmN0aW9uKGUsdCl7ZT1lLnN0YWNrO3JldHVybiBzKCJlcnJvciIsZSxmLmNyZWF0ZSgidXNlciIsdCkpfHx7YmxvY2tlZDohMH19LFtTdHJpbmddLCExKSxlKCJwYXJ0aWFsIiwiQ3VzdG9tTWFjcm8iLGZ1bmN0aW9uKGUsYSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbz1uZXcgQXJyYXkoMjx0P3QtMjowKSxuPTI7bjx0O24rKylvW24tMl09YXJndW1lbnRzW25dO3ZhciByPSJzdHJpbmciIT10eXBlb2YgYSYmYSxpPSFyJiZhO2lmKCFyKXtpZighbC5oYXMoaSkpcmV0dXJuIGYuY3JlYXRlKCJtYWNyb2NhbGwiLCdUaGUgbWFjcm8gbmFtZSBnaXZlbiB0byAocGFydGlhbDopLCAiJy5jb25jYXQoYSwiXCIsIGlzbid0IHRoZSBuYW1lIG9mIGEgYnVpbHQtaW4gbWFjcm8uIikpO2lmKCJNZXRhZGF0YSI9PT1sLmdldChpKS5yZXR1cm5UeXBlKXJldHVybiBmLmNyZWF0ZSgibWFjcm9jYWxsIiwiKHBhcnRpYWw6KSBjYW4ndCBiZSB1c2VkIHdpdGggbWV0YWRhdGEgbWFjcm9zIHN1Y2ggYXMgKCIuY29uY2F0KGEsIjopIikpfXZhciBzPSIocGFydGlhbDoiLmNvbmNhdChtKGEpLCIsIikuY29uY2F0KG8ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBtKGUpfSksIikiKSxjPXAuY3JlYXRlRnJvbUZuKGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtlPWxbInN0cmluZyI9PXR5cGVvZiBhPyJydW4iOiJydW5DdXN0b20iXShhLGUsby5jb25jYXQobikpO3JldHVybiBmLmNvbnRhaW5zRXJyb3IoZSkmJihlLm1lc3NhZ2U9IkFuIGVycm9yIG9jY3VycmVkIHdoaWxlIHJ1bm5pbmcgdGhlIChwYXJ0aWFsOiktY3JlYXRlZCBtYWNybywgIi5jb25jYXQoYy5Ud2luZVNjcmlwdF9PYmplY3ROYW1lLCI6XG4iKStlLm1lc3NhZ2UpLGV9LCJhIChwYXJ0aWFsOikgY3VzdG9tIG1hY3JvIG9mICIuY29uY2F0KGl8fHIuVHdpbmVTY3JpcHRfS25vd25OYW1lPyIoIi5jb25jYXQoaXx8ci5Ud2luZVNjcmlwdF9Lbm93bk5hbWUsIjoiKS5jb25jYXQoby5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG0oZSl9KSwiKSIpOiJhbm90aGVyIHVubmFtZWQgY3VzdG9tIG1hY3JvIiksZnVuY3Rpb24oKXtyZXR1cm4gc30sKGk/bC5nZXQoaSk6cikudHlwZVNpZ25hdHVyZS5maWx0ZXIoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD49by5sZW5ndGh8fCJyZXN0Ij09PWUucGF0dGVybnx8Inplcm8gb3IgbW9yZSI9PT1lLnBhdHRlcm59KSk7cmV0dXJuIGN9LFtnKFN0cmluZyxwKSxvKGIpXSl9KSxkZWZpbmUoIm1hY3JvbGliL2RhdGFzdHJ1Y3R1cmVzIixbInV0aWxzIiwidXRpbHMvbmF0dXJhbHNvcnQiLCJtYWNyb3MiLCJ1dGlscy9vcGVyYXRpb251dGlscyIsInN0YXRlIiwiZW5naW5lIiwicGFzc2FnZXMiLCJkYXRhdHlwZXMvbGFtYmRhIiwiZGF0YXR5cGVzL3R5cGVkdmFyIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oZSxpLHQsbixzLHIsYSxjLG8sbCl7dmFyIHU9ZS5wZXJtdXRhdGlvbnMscD1lLm9wdGlvbnMsZD1uLm9iamVjdE5hbWUsZj1uLnN1YnNldCxoPW4uY29sbGVjdGlvblR5cGUsbT1uLmlzVmFsaWREYXRhbWFwTmFtZSxnPW4uaXMseT1uLnVuaXF1ZSxiPW4uY2xvbmUsdj1uLnJhbmdlLGU9dC5UeXBlU2lnbmF0dXJlLG49ZS5vcHRpb25hbCx3PWUucmVzdCxrPWUuZWl0aGVyLFM9ZS56ZXJvT3JNb3JlLFQ9ZS5BbnksZT1lLm5vbk5lZ2F0aXZlSW50ZWdlcixfPWkoImVuIik7dC5hZGQoWyJhIiwiYXJyYXkiXSwiQXJyYXkiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gbn0sUyhrKG8sVCkpKSgicmFuZ2UiLCJBcnJheSIsZnVuY3Rpb24oZSx0LG4pe3JldHVybiB2KHQsbil9LFtwYXJzZUludCxwYXJzZUludF0pKCJzdWJhcnJheSIsIkFycmF5IixmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gZih0LG4scil9LFtBcnJheSxwYXJzZUludCxwYXJzZUludF0pKCJyZXZlcnNlZCIsIkFycmF5IixmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIG4ucmV2ZXJzZSgpLm1hcChiKX0sUyhUKSkoInNodWZmbGVkIiwiQXJyYXkiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gcy5zaHVmZmxlZC5hcHBseShzLG4pLm1hcChiKX0sW1MoVCldKSgic29ydGVkIiwiQXJyYXkiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPWFyZ3VtZW50cy5sZW5ndGgscj1uZXcgQXJyYXkoMTxuP24tMTowKSxhPTE7YTxuO2ErKylyW2EtMV09YXJndW1lbnRzW2FdO2lmKCFjLmlzUHJvdG90eXBlT2YoclswXSkpcmV0dXJuKHQ9ci5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyIhPXR5cGVvZiBlJiYibnVtYmVyIiE9dHlwZW9mIGV9KSkmJnQubGVuZ3RoPzE9PT10Lmxlbmd0aCYmQXJyYXkuaXNBcnJheSh0WzBdKT9sLmNyZWF0ZSgibWFjcm9jYWxsIiwiUGxlYXNlIGdpdmUgbXVsdGlwbGUgbnVtYmVycyBvciBzdHJpbmdzIHRvIChzb3J0ZWQ6KSwgbm90IGEgc2luZ2xlIGFycmF5LiIsIllvdSBjYW4gdXNlIHRoZSBzcHJlYWQgLi4uIHN5bnRheCB0byBzcHJlYWQgb3V0IHRoZSBhcnJheSdzIHZhbHVlcyBpbnRvIChzb3J0ZWQ6KS4iKTpsLmNyZWF0ZSgiZGF0YXR5cGUiLCJJZiAoc29ydGVkOikgaXNuJ3QgZ2l2ZW4gYSAndmlhJyBsYW1iZGEsIGl0IG11c3QgYmUgZ2l2ZW4gb25seSBudW1iZXJzIGFuZCBzdHJpbmdzLCBub3QgIi5jb25jYXQoZCh0WzBdKSwiLiIpKTpyLnNvcnQoXyk7dmFyIG89ci5zaGlmdCgpO2lmKCJtYWtpbmciaW4gb3x8IndoZXJlImluIG98fCJ3aGVuImluIG98fCEoInZpYSJpbiBvKSlyZXR1cm4gbC5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIG9wdGlvbmFsIGxhbWJkYSBnaXZlbiB0byAoc29ydGVkOikgbXVzdCBiZSBhICd2aWEnIGxhbWJkYSwgbm90ICIuY29uY2F0KGQobyksIi4iKSk7Zm9yKHZhciBpPTA7aTxyLmxlbmd0aDtpKz0xKXt2YXIgcz1vLmFwcGx5KGUse2xvb3A6cltpXSxwb3M6aSsxfSk7aWYobC5jb250YWluc0Vycm9yKHMpKXJldHVybiBzO2lmKCJzdHJpbmciIT10eXBlb2YgcyYmIm51bWJlciIhPXR5cGVvZiBzKXJldHVybiBsLmNyZWF0ZSgiZGF0YXR5cGUiLCdUaGUgInZpYSIgbGFtYmRhIGdpdmVuIHRvIChzb3J0ZWQ6KSBjb3VsZG5cJ3QgY29udmVydCAnLmNvbmNhdChkKHJbaV0pLCIgaW50byBhIHN0cmluZyBvciBudW1iZXIuIikpO3JbaV09W3JbaV0sc119cmV0dXJuIHIuc29ydChmdW5jdGlvbihlLHQpe3JldHVybiBfKGVbMV0sdFsxXSl9KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGVbMF19KX0sW1MoVCldKSgicm90YXRlZCIsIkFycmF5IixmdW5jdGlvbihlLHQpe2lmKDA9PT10KXJldHVybiBsLmNyZWF0ZSgibWFjcm9jYWxsIiwiSSBjYW4ndCByb3RhdGUgdGhlc2UgdmFsdWVzIGJ5IDAgcG9zaXRpb25zLiIpO2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTt0PS0xKih0PU1hdGguYWJzKHQpJXIubGVuZ3RoKk1hdGguc2lnbih0KSk7cmV0dXJuIHIuc2xpY2UodCkuY29uY2F0KHIuc2xpY2UoMCx0KSkubWFwKGIpfSxbcGFyc2VJbnQsUyhUKV0pKCJyb3RhdGVkLXRvIiwiQXJyYXkiLGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1uZXcgQXJyYXkoMjxuP24tMjowKSxhPTI7YTxuO2ErKylyW2EtMl09YXJndW1lbnRzW2FdO3Q9dC5maWx0ZXIoZSxyKTtyZXR1cm4gbC5jb250YWluc0Vycm9yKHQpP3Q6dC5sZW5ndGg/KGU9ci5pbmRleE9mKHRbMF0pLHIuc2xpY2UoZSkuY29uY2F0KHIuc2xpY2UoMCxlKSkubWFwKGIpKTpsLmNyZWF0ZSgibWFjcm9jYWxsIiwiTm9uZSBvZiB0aGVzZSAiK3IubGVuZ3RoKyIgdmFsdWVzIG1hdGNoZWQgdGhlIGxhbWJkYSwgc28gSSBjYW4ndCByb3RhdGUgdGhlbS4iKX0sW2MuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSx3KFQpXSkoInJlcGVhdGVkIiwiQXJyYXkiLGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPVtdLHI9YXJndW1lbnRzLmxlbmd0aCxhPW5ldyBBcnJheSgyPHI/ci0yOjApLG89MjtvPHI7bysrKWFbby0yXT1hcmd1bWVudHNbb107aWYoIWEubGVuZ3RoKXJldHVybiBuO2Zvcig7MDx0LS07KW4ucHVzaC5hcHBseShuLGEpO3JldHVybiBuLm1hcChiKX0sW2UsdyhUKV0pKCJpbnRlcmxhY2VkIiwiQXJyYXkiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtmb3IodmFyIGE9TWF0aC5taW4uYXBwbHkoTWF0aCxfdG9Db25zdW1hYmxlQXJyYXkobi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUubGVuZ3RofSkpKSxvPVtdLGk9MDtpPGE7aSs9MSlmb3IodmFyIHM9MDtzPG4ubGVuZ3RoO3MrPTEpby5wdXNoKGIobltzXVtpXSkpO3JldHVybiBvfSxbQXJyYXksdyhBcnJheSldKSgicGVybXV0YXRpb25zIiwiQXJyYXkiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gbi5sZW5ndGg/dS5hcHBseSh2b2lkIDAsbik6W119LFtTKFQpXSkoInVuaXF1ZSIsIkFycmF5IixmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIG4uZmlsdGVyKHkpfSxbUyhUKV0pKCJhbHRlcmVkIiwiQXJyYXkiLGZ1bmN0aW9uKG4scil7Zm9yKHZhciBlPWFyZ3VtZW50cy5sZW5ndGgsdD1uZXcgQXJyYXkoMjxlP2UtMjowKSxhPTI7YTxlO2ErKyl0W2EtMl09YXJndW1lbnRzW2FdO3JldHVybiB0Lm1hcChmdW5jdGlvbihlLHQpe3Q9ci5hcHBseShuLHtsb29wOmUscG9zOnQrMX0pO3JldHVybiBudWxsPT09dD9lOnR9KX0sW2soYy5UeXBlU2lnbmF0dXJlKCJ2aWEiKSxjLlR5cGVTaWduYXR1cmUoIndoZXJlIiwidmlhIikpLFMoVCldKSgiZmluZCIsIkFycmF5IixmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTtyZXR1cm4gdC5maWx0ZXIoZSxyKX0sW2MuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSxTKFQpXSkoWyJhbGwtcGFzcyIsInBhc3MiXSwiQm9vbGVhbiIsZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49YXJndW1lbnRzLmxlbmd0aCxyPW5ldyBBcnJheSgyPG4/bi0yOjApLGE9MjthPG47YSsrKXJbYS0yXT1hcmd1bWVudHNbYV07dD10LmZpbHRlcihlLHIpO3JldHVybiBsLmNvbnRhaW5zRXJyb3IodCl8fHQubGVuZ3RoPT09ci5sZW5ndGh9LFtjLlR5cGVTaWduYXR1cmUoIndoZXJlIiksUyhUKV0pKCJzb21lLXBhc3MiLCJCb29sZWFuIixmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTt0PXQuZmlsdGVyKGUscik7cmV0dXJuIGwuY29udGFpbnNFcnJvcih0KXx8MDx0Lmxlbmd0aH0sW2MuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSxTKFQpXSkoIm5vbmUtcGFzcyIsIkJvb2xlYW4iLGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1uZXcgQXJyYXkoMjxuP24tMjowKSxhPTI7YTxuO2ErKylyW2EtMl09YXJndW1lbnRzW2FdO3Q9dC5maWx0ZXIoZSxyKTtyZXR1cm4gbC5jb250YWluc0Vycm9yKHQpfHwwPT09dC5sZW5ndGh9LFtjLlR5cGVTaWduYXR1cmUoIndoZXJlIiksUyhUKV0pKCJmb2xkZWQiLCJBbnkiLGZ1bmN0aW9uKHIsYSl7Zm9yKHZhciBlPWFyZ3VtZW50cy5sZW5ndGgsdD1uZXcgQXJyYXkoMjxlP2UtMjowKSxuPTI7bjxlO24rKyl0W24tMl09YXJndW1lbnRzW25dO3JldHVybiJ3aGVyZSJpbiBhJiYodD1bdFswXV0uY29uY2F0KF90b0NvbnN1bWFibGVBcnJheShhLmZpbHRlcihyLHQuc2xpY2UoMSkpKSkpLGwuY29udGFpbnNFcnJvcih0KXx8dC5yZWR1Y2UoZnVuY3Rpb24oZSx0LG4pe3JldHVybiBhLmFwcGx5KHIse21ha2luZzplLGxvb3A6dCxwb3M6bisxfSl9KX0sW2soYy5UeXBlU2lnbmF0dXJlKCJ3aGVyZSIsInZpYSIsIm1ha2luZyIpLGMuVHlwZVNpZ25hdHVyZSgidmlhIiwibWFraW5nIikpLHcoVCldKShbImRtLW5hbWVzIiwiZGF0YW1hcC1uYW1lcyIsImRhdGFuYW1lcyJdLCJBcnJheSIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gQXJyYXkuZnJvbSh0LmtleXMoKSkuc29ydChpKCJlbiIpKX0sW01hcF0pKFsiZG0tdmFsdWVzIiwiZGF0YW1hcC12YWx1ZXMiLCJkYXRhdmFsdWVzIl0sIkFycmF5IixmdW5jdGlvbihlLHQpe3JldHVybiBBcnJheS5mcm9tKHQuZW50cmllcygpKS5zb3J0KGkoImVuIixmdW5jdGlvbihlKXtyZXR1cm4gU3RyaW5nKGVbMF0pfSkpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gYihlWzFdKX0pfSxbTWFwXSkoWyJkbS1lbnRyaWVzIiwiZGF0YW1hcC1lbnRyaWVzIiwiZGF0YWVudHJpZXMiXSwiQXJyYXkiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIEFycmF5LmZyb20odC5lbnRyaWVzKCkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm5bZVswXSx0WzBdXS5zb3J0KGkoImVuIikpWzBdPT09ZVswXT8tMToxfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBuZXcgTWFwKFtbIm5hbWUiLGVbMF1dLFsidmFsdWUiLGIoZVsxXSldXSl9KX0sW01hcF0pKFsiZG0tYWx0ZXJlZCIsImRhdGFtYXAtYWx0ZXJlZCJdLCJEYXRhbWFwIixmdW5jdGlvbihhLG8sZSl7cmV0dXJuIEFycmF5LmZyb20oZS5lbnRyaWVzKCkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm5bZVswXSx0WzBdXS5zb3J0KGkoImVuIikpWzBdPT09ZVswXT8tMToxfSkucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXtpZighbC5jb250YWluc0Vycm9yKGUpKXt2YXIgcj1uZXcgTWFwKFtbIm5hbWUiLHRbMF1dLFsidmFsdWUiLGIodFsxXSldXSkscj1vLmFwcGx5KGEse2xvb3A6cixwb3M6bisxfSk7aWYobC5jb250YWluc0Vycm9yKHIpKXJldHVybiByO2Uuc2V0KHRbMF0sbnVsbD09PXI/dFsxXTpyKX1yZXR1cm4gZX0sbmV3IE1hcCl9LFtrKGMuVHlwZVNpZ25hdHVyZSgidmlhIiksYy5UeXBlU2lnbmF0dXJlKCJ3aGVyZSIsInZpYSIpKSxNYXBdKSgiaGlzdG9yeSIsIkFycmF5IixmdW5jdGlvbihlLHQpe3ZhciBuPXMuaGlzdG9yeSgpO3JldHVybiB0Pyh0PXQuZmlsdGVyKGUsbi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGEuZ2V0KGUpfSkpLGwuY29udGFpbnNFcnJvcih0KT90OnQubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLmdldCgibmFtZSIpfSkpOm59LFtuKGMuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSldKSgidmlzaXRlZCIsIkJvb2xlYW4iLGZ1bmN0aW9uKGUsdCl7dmFyIG47cmV0dXJuInN0cmluZyI9PXR5cGVvZiB0P2EuaGFzKHQpPzA8cy5wYXNzYWdlTmFtZVZpc2l0ZWQodCl8fHMucGFzc2FnZT09PXQ6bC5jcmVhdGUoIm1hY3JvY2FsbCIsIlRoZXJlJ3Mgbm8gcGFzc2FnZSBuYW1lZCAnIit0KyInIGluIHRoaXMgc3RvcnkuIik6KG49cy5oaXN0b3J5KCksbj10LmZpbHRlcihlLG4uY29uY2F0KHMucGFzc2FnZSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBhLmdldChlKX0pKSxsLmNvbnRhaW5zRXJyb3Iobik/bjowPG4ubGVuZ3RoKX0sW2soU3RyaW5nLGMuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSldKSgicGFzc2FnZSIsIkRhdGFtYXAiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGIoYS5nZXQodHx8cy5wYXNzYWdlKSl8fGwuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGVyZSdzIG5vIHBhc3NhZ2UgbmFtZWQgJyIrdCsiJyBpbiB0aGlzIHN0b3J5LiIpfSxbbihTdHJpbmcpXSkoInBhc3NhZ2VzIiwiQXJyYXkiLGZ1bmN0aW9uKGUsdCl7dmFyIG49aSgiZW4iKSxyPV90b0NvbnN1bWFibGVBcnJheShhLnZhbHVlcygpKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGIoZSl9KSx0PXQ/dC5maWx0ZXIoZSxyKTpyLGU9bC5jb250YWluc0Vycm9yKHQpO3JldHVybiBlfHx0LnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gbihlLmdldCgibmFtZSIpLHQuZ2V0KCJuYW1lIikpfSl9LFtuKGMuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSldKSgib3Blbi1zdG9yeWxldHMiLCJBcnJheSIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5zdGFja1RvcC5ldmFsdWF0ZU9ubHk/bC5jcmVhdGUoIm1hY3JvY2FsbCIsIihvcGVuLXN0b3J5bGV0czopIGNhbid0IGJlIHVzZWQgaW4gIitlLnN0YWNrVG9wLmV2YWx1YXRlT25seSsiLiIpOihlPWEuZ2V0U3RvcnlsZXRzKGUsdCksbC5jb250YWluc0Vycm9yKGUpfHxlLm1hcChiKSl9LFtuKGMuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSldKSgic2F2ZWRnYW1lcyIsIkRhdGFtYXAiLGZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXtyZXR1cm4iKCIrZSsiICIrcC5pZmlkKyIpICJ9dmFyIHQsbixyPTAsYT1uZXcgTWFwO2Rve2lmKCFzLmhhc1N0b3JhZ2UpYnJlYWs7dD1sb2NhbFN0b3JhZ2Uua2V5KHIpLHIrPTE7dmFyIG89ZSgiU2F2ZWQgR2FtZSIpfXdoaWxlKG51bGwhPShuPXQpJiZuLnN0YXJ0c1dpdGgobykmJih0PXQuc2xpY2Uoby5sZW5ndGgpLGEuc2V0KHQsbG9jYWxTdG9yYWdlLmdldEl0ZW0oZSgiU2F2ZWQgR2FtZSBGaWxlbmFtZSIpK3QpKSksdCk7cmV0dXJuIGF9LFtdKShbImRhdGFtYXAiLCJkbSJdLCJEYXRhbWFwIixmdW5jdGlvbihlKXtmb3IodmFyIHIsYT1uZXcgTWFwLHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLG89MTtvPHQ7bysrKW5bby0xXT1hcmd1bWVudHNbb107dmFyIGk9bi5yZWR1Y2UoZnVuY3Rpb24oZSx0KXt2YXIgbjtpZighbC5jb250YWluc0Vycm9yKGUpKWlmKHZvaWQgMD09PXIpcj10O2Vsc2V7aWYobj1sLmNvbnRhaW5zRXJyb3IobShhLHIpKSlyZXR1cm4gbjtpZihhLmhhcyhyKSlyZXR1cm4gbC5jcmVhdGUoIm1hY3JvY2FsbCIsIllvdSB1c2VkIHRoZSBzYW1lIGRhdGEgbmFtZSAoIitkKHIpKyIpIHR3aWNlIGluIHRoZSBzYW1lIChkYXRhbWFwOikgY2FsbC4iKTthLnNldChyLGIodCkpLHI9dm9pZCAwfXJldHVybiBlfSwhMCk7cmV0dXJuIGwuY29udGFpbnNFcnJvcihpKT9pOnZvaWQgMCE9PXI/bC5jcmVhdGUoIm1hY3JvY2FsbCIsIlRoaXMgZGF0YW1hcCBoYXMgYSBkYXRhIG5hbWUgd2l0aG91dCBhIHZhbHVlLiIpOmF9LFMoayhvLFQpKSkoWyJkYXRhc2V0IiwiZHMiXSwiRGF0YXNldCIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBuZXcgU2V0KG4uZmlsdGVyKHkpLm1hcChiKSl9LFMoVCkpKCJjb3VudCIsIk51bWJlciIsZnVuY3Rpb24gdChuLHIpe2Zvcih2YXIgZSxhPWFyZ3VtZW50cy5sZW5ndGgsbz1uZXcgQXJyYXkoMjxhP2EtMjowKSxpPTI7aTxhO2krKylvW2ktMl09YXJndW1lbnRzW2ldO2lmKDE8by5sZW5ndGgpcmV0dXJuIGU9by5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHQobixyLGUpfSksbC5jb250YWluc0Vycm9yKGUpfHxlLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlK3R9LDApO3ZhciBzPW9bMF07c3dpdGNoKGgocikpe2Nhc2UiZGF0YXNldCI6Y2FzZSJkYXRhbWFwIjpyZXR1cm4gbC5jcmVhdGUoIm1hY3JvY2FsbCIsIihjb3VudDopIHNob3VsZG4ndCBiZSBnaXZlbiBhIGRhdGFtYXAgb3IgZGF0YXNldC4iLCJZb3Ugc2hvdWxkIHVzZSB0aGUgJ2NvbnRhaW5zJyBvcGVyYXRvciBpbnN0ZWFkLiBGb3IgaW5zdGFuY2UsIHdyaXRlOiAkdmFyaWFibGUgY29udGFpbnMgJ3ZhbHVlJy4iKTtjYXNlInN0cmluZyI6cmV0dXJuInN0cmluZyIhPXR5cGVvZiBzP2wuY3JlYXRlKCJtYWNyb2NhbGwiLGQocikrIiBjYW4ndCBjb250YWluICAiK2QocykrIiBiZWNhdXNlIGl0IGlzbid0IGFsc28gYSBzdHJpbmcuIik6cz9yLnNwbGl0KHMpLmxlbmd0aC0xOjA7Y2FzZSJhcnJheSI6cmV0dXJuIHIucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUrZyh0LHMpfSwwKTtkZWZhdWx0OnJldHVybiBsLmNyZWF0ZSgibWFjcm9jYWxsIixkKHIpKyIgY2FuJ3QgY29udGFpbiB2YWx1ZXMsIGxldCBhbG9uZSAiK2QocykrIi4iKX19LFtULHcoVCldKX0pLGRlZmluZSgibWFjcm9saWIvZW5jaGFudG1lbnRzIixbImpxdWVyeSIsInV0aWxzIiwidXRpbHMvb3BlcmF0aW9udXRpbHMiLCJlbmdpbmUiLCJzdGF0ZSIsInBhc3NhZ2VzIiwibWFjcm9zIiwiZGF0YXR5cGVzL2hvb2tzZXQiLCJkYXRhdHlwZXMvY29kZWhvb2siLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJkYXRhdHlwZXMvbGFtYmRhIiwiaW50ZXJuYWx0eXBlcy9jaGFuZ2VkZXNjcmlwdG9yIiwiaW50ZXJuYWx0eXBlcy9lbmNoYW50bWVudCIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKGMscixlLGwscyxuLHUscCxhLGQsdCxpLGYsaCl7dmFyIG09ZS5pcyxlPXUuVHlwZVNpZ25hdHVyZSxnPWUuZWl0aGVyLHk9ZS5yZXN0LG89ZS5vcHRpb25hbCxiPU9iamVjdC5hc3NpZ247ZnVuY3Rpb24gdihlLHQpe2lmKGQuaXNQcm90b3R5cGVPZih0KSYmIXQuY2FuRW5jaGFudClyZXR1cm4gaC5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIGNoYW5nZXIgZ2l2ZW4gdG8gKCIuY29uY2F0KGUsIjopIGNhbid0IGluY2x1ZGUgYSByZXZpc2lvbiwgZW5jaGFudG1lbnQsIG9yIGludGVyYWN0aW9uIGNoYW5nZXIgbGlrZSAocmVwbGFjZTopLCAoY2xpY2s6KSwgb3IgKGxpbms6KS4iKSl9WyJlbmNoYW50IiwiY2hhbmdlIl0uZm9yRWFjaChmdW5jdGlvbihvKXt1LmFkZENvbW1hbmQobyxmdW5jdGlvbihlLHQpe3Q9dihvLHQpO2lmKHQpcmV0dXJuIHR9LGZ1bmN0aW9uKHQsbixlKXtuPXAuZnJvbShuKTt2YXIgcixhPVtdO3JldHVybiBkLmlzUHJvdG90eXBlT2YoZSkmJihyPWkuY3JlYXRlKHtzZWN0aW9uOnR9KSxlLnJ1bihyKSwwPChyLmlubmVyRW5jaGFudG1lbnRzfHxbXSkubGVuZ3RoKSYmKHI9ci5pbm5lckVuY2hhbnRtZW50cy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUobil9KSxhLnB1c2guYXBwbHkoYSxfdG9Db25zdW1hYmxlQXJyYXkocikpKSxhLnB1c2goZi5jcmVhdGUoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eSh7c2NvcGU6bn0sZC5pc1Byb3RvdHlwZU9mKGUpPyJjaGFuZ2VyIjoibGFtYmRhIixlKSwic2VjdGlvbiIsdCkpKSxhLmZvckVhY2goZnVuY3Rpb24oZSl7ImVuY2hhbnQiPT09bz8odC5hZGRFbmNoYW50bWVudChlKSx0LnVwZGF0ZUVuY2hhbnRtZW50cygpKTplLmVuY2hhbnRTY29wZSgpfSksIiJ9LFtnKHAsU3RyaW5nKSxnKGQsdC5UeXBlU2lnbmF0dXJlKCJ2aWEiKSldLCExKX0pLHUuYWRkQ2hhbmdlcigiZW5jaGFudC1pbiIsZnVuY3Rpb24oZSx0LG4pe3ZhciByPXYoImVuY2hhbnQtaW4iLG4pO3JldHVybiByfHxkLmNyZWF0ZSgiZW5jaGFudC1pbiIsW3Qsbl0pfSxmdW5jdGlvbih0LG4scil7cmV0dXJuIHQuaW5uZXJFbmNoYW50bWVudHM9KHQuaW5uZXJFbmNoYW50bWVudHN8fFtdKS5jb25jYXQoZnVuY3Rpb24oZSl7cmV0dXJuIGYuY3JlYXRlKF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoe3Njb3BlOnAuZnJvbShuKSxsb2NhbEhvb2s6ZX0sZC5pc1Byb3RvdHlwZU9mKHIpPyJjaGFuZ2VyIjoibGFtYmRhIixyKSwic2VjdGlvbiIsdC5zZWN0aW9uKSl9KSx0fSxbZyhwLFN0cmluZyksZyhkLHQuVHlwZVNpZ25hdHVyZSgidmlhIikpXSksW1sibGluay1zdHlsZSIscC5jcmVhdGUoe3R5cGU6Im5hbWUiLGRhdGE6ImxpbmsifSldLFsibGluZS1zdHlsZSIscC5jcmVhdGUoe3R5cGU6ImJhc2UiLGRhdGE6cC5jcmVhdGUoe3R5cGU6Im5hbWUiLGRhdGE6InBhZ2UifSl9LCJsaW5lcyIsdm9pZCAwKV0sWyJjaGFyLXN0eWxlIixwLmNyZWF0ZSh7dHlwZToiYmFzZSIsZGF0YTpwLmNyZWF0ZSh7dHlwZToibmFtZSIsZGF0YToicGFnZSJ9KX0sImNoYXJzIix2b2lkIDApXV0uZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgZT1fc2xpY2VkVG9BcnJheShlLDIpLHI9ZVswXSxhPWVbMV07dS5hZGRDaGFuZ2VyKHIsZnVuY3Rpb24oZSx0KXt2YXIgbj12KHIsdCk7cmV0dXJuIG58fGQuY3JlYXRlKHIsW3RdKX0sZnVuY3Rpb24odCxuKXtyZXR1cm4gdC5pbm5lckVuY2hhbnRtZW50cz0odC5pbm5lckVuY2hhbnRtZW50c3x8W10pLmNvbmNhdChmdW5jdGlvbihlKXtyZXR1cm4gZi5jcmVhdGUoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eSh7c2NvcGU6YSxsb2NhbEhvb2s6ZX0sZC5pc1Byb3RvdHlwZU9mKG4pPyJjaGFuZ2VyIjoibGFtYmRhIixuKSwic2VjdGlvbiIsdC5zZWN0aW9uKSl9KSx0fSxbZyhkLHQuVHlwZVNpZ25hdHVyZSgidmlhIikpXSl9KTtlPVsicmVwbGFjZSIsImFwcGVuZCIsInByZXBlbmQiXTtmdW5jdGlvbiB3KGkscyl7cmV0dXJuIHIub25TdGFydHVwKGZ1bmN0aW9uKCl7dmFyIGU9aS5jbGFzc0xpc3QucmVwbGFjZSgvIC9nLCIuIiksdD1pLmJsb2NrQ2xhc3NMaXN0P2kuYmxvY2tDbGFzc0xpc3QucmVwbGFjZSgvIC9nLCIuIik6IiIsbj0iLiIrZSsodD8iLC4iK3Q6IiIpO3Iuc3RvcnlFbGVtZW50Lm9uKGkuZXZlbnQubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlKyIuZW5jaGFudG1lbnQifSkuam9pbigiICIpLG4sZnVuY3Rpb24oKXt2YXIgZSx0PWModGhpcyk7ci5vcHRpb25zLmRlYnVnJiZyLm9wdGlvbnMuaWdub3JlQ2xpY2tFdmVudHMmJiF0LmlzKCJ0dy1iYWNrZHJvcC5ldmFsLXJlcGxheSAqLCB0dy1iYWNrZHJvcC5oYXJsb3dlLWNyYXNoICoiKXx8dC5pcygidHctb3Blbi1idXR0b24iKXx8KGU9KHQ9YyhBcnJheS5mcm9tKHQucGFyZW50cyhuKS5hZGQodGhpcykpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gOCZlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKHQpPzE6LTF9KVswXSkpLmRhdGEoImVuY2hhbnRtZW50RXZlbnQiKSkmJmUodCl9KX0pLFtmdW5jdGlvbihlLHQsbil7aWYoIXQpcmV0dXJuIGguY3JlYXRlKCJkYXRhdHlwZSIsIkEgc3RyaW5nIGdpdmVuIHRvIHRoaXMgKCIrcysiOikgbWFjcm8gd2FzIGVtcHR5LiIpO2lmKG4pe3ZhciByPXYocyxuKTtpZihyKXJldHVybiByfXJldHVybiBkLmNyZWF0ZShzLFtwLmZyb20odCldLmNvbmNhdChuP1tuXTpbXSkpfSxmdW5jdGlvbih0LGUsbil7dC5lbmFibGVkPSExLHQudHJhbnNpdGlvbkRlZmVycmVkPSEwLGkucmVyZW5kZXImJih0Lm5ld1RhcmdldHM9KHQubmV3VGFyZ2V0c3x8W10pLmNvbmNhdCh7dGFyZ2V0OmUsYXBwZW5kOmkucmVyZW5kZXJ9KSk7dmFyIHIsYT1udWxsIT0ocj10LnNlY3Rpb24pJiZyLnN0YWNrVG9wP3Quc2VjdGlvbi5zdGFja1RvcC50ZW1wVmFyaWFibGVzOk9iamVjdC5jcmVhdGUobnVsbCksbz1mLmNyZWF0ZShfZGVmaW5lUHJvcGVydHkoe2Z1bmN0aW9uczpbZnVuY3Rpb24oZSl7ZS5hdHRyKCJjbGFzcyIsZS5jaGlsZHJlbigpLmlzKCJ0dy1zdG9yeSwgdHctc2lkZWJhciwgdHctcGFzc2FnZSIpfHxbImJsb2NrIiwiZmxleCJdLmluY2x1ZGVzKGUuY2hpbGRyZW4oKS5jc3MoImRpc3BsYXkiKSk/aS5ibG9ja0NsYXNzTGlzdDppLmNsYXNzTGlzdCksZS5hdHRyKHt0YWJJbmRleDoiMCJ9KX1dLGRhdGE6e2VuY2hhbnRtZW50RXZlbnQ6ZnVuY3Rpb24oKXt2YXIgZTtudWxsIT0oZT10LnNlY3Rpb24uc3RhY2tUb3ApJiZlLmJsb2NrZWR8fChpLm9uY2UmJnQuc2VjdGlvbi5yZW1vdmVFbmNoYW50bWVudChvKSxpLmdvdG8/bC5nb1RvUGFzc2FnZShpLmdvdG8se3RyYW5zaXRpb246aS50cmFuc2l0aW9ufSk6aS51bmRvP2wuZ29CYWNrKHt0cmFuc2l0aW9uOmkudHJhbnNpdGlvbn0pOnQuc2VjdGlvbi5yZW5kZXJJbnRvKHQuc291cmNlLG51bGwsX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LHQpLHt9LHthcHBlbmQ6aS5vbmNlPyJhcHBlbmQiOiJyZXBsYWNlIixlbmFibGVkOiEwLHRyYW5zaXRpb25EZWZlcnJlZDohMX0pLGEpKX19LHNjb3BlOmUsc2VjdGlvbjp0LnNlY3Rpb24sbmFtZTpzfSxkLmlzUHJvdG90eXBlT2Yobik/ImNoYW5nZXIiOiJsYW1iZGEiLG4pKTtyZXR1cm4gdC5zZWN0aW9uJiYodC5zZWN0aW9uLmFkZEVuY2hhbnRtZW50KG8pLG8uZW5jaGFudFNjb3BlKCkpLHR9LFtnKHAsU3RyaW5nKSxvKGcoZCx0LlR5cGVTaWduYXR1cmUoInZpYSIpKSldXX1lLmZvckVhY2goZnVuY3Rpb24obyl7dS5hZGRDaGFuZ2VyKG8sZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBuLmV2ZXJ5KEJvb2xlYW4pP2QuY3JlYXRlKG8sbi5tYXAocC5mcm9tKSxudWxsLCExKTpoLmNyZWF0ZSgiZGF0YXR5cGUiLCJBIHN0cmluZyBnaXZlbiB0byB0aGlzICgiLmNvbmNhdChvLCI6KSBtYWNybyB3YXMgZW1wdHkuIikpfSxmdW5jdGlvbihlKXt2YXIgdDswPGMoZS50YXJnZXQpLnBhcmVudHMoKS5maWx0ZXIoInR3LWNvbGxhcHNlZCxbY29sbGFwc2luZz10cnVlXSIpLmxlbmd0aHx8ZS5hdHRyLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUuY29sbGFwc2luZ30pfHwoZS5hdHRyPVtdLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoZS5hdHRyKSxbe2NvbGxhcHNpbmc6ITF9XSkpLGUubmV3VGFyZ2V0cz1lLm5ld1RhcmdldHN8fFtdO2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDE8bj9uLTE6MCksYT0xO2E8bjthKyspclthLTFdPWFyZ3VtZW50c1thXTtyZXR1cm4odD1lLm5ld1RhcmdldHMpLnB1c2guYXBwbHkodCxfdG9Db25zdW1hYmxlQXJyYXkoci5maWx0ZXIoZnVuY3Rpb24obil7cmV0dXJuIWUubmV3VGFyZ2V0cy5zb21lKGZ1bmN0aW9uKGUpe3ZhciB0PWUudGFyZ2V0LGU9ZS5hcHBlbmQ7cmV0dXJuIG0obix0KSYmbz09PWV9KX0pLm1hcChmdW5jdGlvbihlKXtyZXR1cm57dGFyZ2V0OmUsYXBwZW5kOm8sYmVmb3JlOiEwfX0pKSksZX0seShnKHAsU3RyaW5nKSkpKG8rIi13aXRoIixmdW5jdGlvbihlLHQpe3JldHVybiBkLmNyZWF0ZShvKyItd2l0aCIsW3RdLG51bGwsITEpfSxmdW5jdGlvbihlLHQpe3JldHVybiBhLmlzUHJvdG90eXBlT2YodCkmJih0PXQuY29kZSksZS5hcHBlbmRTb3VyY2U9KGUuYXBwZW5kU291cmNlfHxbXSkuY29uY2F0KHtzb3VyY2U6dCxhcHBlbmQ6b30pLGV9LGcoYSxTdHJpbmcpKX0pO3ZhciBrPSJvbnRvdWNoc3RhcnQiaW4gd2luZG93fHwwPG5hdmlnYXRvci5tYXhUb3VjaFBvaW50c3x8MDxuYXZpZ2F0b3IubXNNYXhUb3VjaFBvaW50cyxTPVt7bmFtZToiY2xpY2siLGVuY2hhbnREZXNjOntldmVudDpbImNsaWNrIl0sb25jZTohMCxyZXJlbmRlcjoiIixjbGFzc0xpc3Q6ImxpbmsgZW5jaGFudG1lbnQtbGluayIsYmxvY2tDbGFzc0xpc3Q6ImVuY2hhbnRtZW50LWNsaWNrYmxvY2sifX0se25hbWU6Im1vdXNlb3ZlciIsZW5jaGFudERlc2M6e2V2ZW50OlsibW91c2VlbnRlciIsaz8iY2xpY2siOiIiXS5maWx0ZXIoQm9vbGVhbiksb25jZTohMCxyZXJlbmRlcjoiIixjbGFzc0xpc3Q6ImxpbmsgZW5jaGFudG1lbnQtbW91c2VvdmVyIixibG9ja0NsYXNzTGlzdDoiZW5jaGFudG1lbnQtbW91c2VvdmVyYmxvY2sifX0se25hbWU6Im1vdXNlb3V0IixlbmNoYW50RGVzYzp7ZXZlbnQ6WyJtb3VzZWxlYXZlIixrPyJjbGljayI6IiJdLmZpbHRlcihCb29sZWFuKSxvbmNlOiEwLHJlcmVuZGVyOiIiLGNsYXNzTGlzdDoibGluayBlbmNoYW50bWVudC1tb3VzZW91dCIsYmxvY2tDbGFzc0xpc3Q6ImVuY2hhbnRtZW50LW1vdXNlb3V0YmxvY2sifX0se25hbWU6ImRvdWJsZWNsaWNrIixlbmNoYW50RGVzYzp7ZXZlbnQ6WyJkYmxjbGljayJdLG9uY2U6ITAscmVyZW5kZXI6IiIsY2xhc3NMaXN0OiJsaW5rIGVuY2hhbnRtZW50LWRibGNsaWNrIixibG9ja0NsYXNzTGlzdDoiZW5jaGFudG1lbnQtZGJsY2xpY2tibG9jayJ9fV07Uy5mb3JFYWNoKGZ1bmN0aW9uKGUpeyJkb3VibGVjbGljayIhPT1lLm5hbWUmJih1LmFkZENoYW5nZXIuYXBwbHkodSxbZS5uYW1lXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KHcoZS5lbmNoYW50RGVzYyxlLm5hbWUpKSkpLCJjbGljayI9PT1lLm5hbWUpJiZ1LmFkZENoYW5nZXIuYXBwbHkodSxbZS5uYW1lKyItcmVydW4iXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KHcoX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGUuZW5jaGFudERlc2MpLHt9LHtvbmNlOiExfSksZS5uYW1lKyItcmVydW4iKSkpKX0pLHIub25TdGFydHVwKGZ1bmN0aW9uKCl7Uy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciBuPWUuZW5jaGFudERlc2M7bi5ibG9ja0NsYXNzTGlzdCYmci5zdG9yeUVsZW1lbnQub24obi5ldmVudC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUrIi5lbmNoYW50bWVudCJ9KS5qb2luKCIgIiksZnVuY3Rpb24oKXt2YXIgZSx0PWModGhpcyk7ci5vcHRpb25zLmRlYnVnJiZyLm9wdGlvbnMuaWdub3JlQ2xpY2tFdmVudHMmJiF0LmlzKCJ0dy1iYWNrZHJvcC5ldmFsLXJlcGxheSAqLCB0dy1iYWNrZHJvcC5oYXJsb3dlLWNyYXNoICoiKXx8dC5pcygidHctb3Blbi1idXR0b24iKXx8KGU9KHQ9YyhBcnJheS5mcm9tKHQucGFyZW50cygiLiIrbi5ibG9ja0NsYXNzTGlzdC5yZXBsYWNlKC8gL2csIi4iKSkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gOCZlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKHQpPzE6LTF9KVswXSkpLmRhdGEoImVuY2hhbnRtZW50RXZlbnQiKSkmJmUodCl9KX0pfSksZS5mb3JFYWNoKGZ1bmN0aW9uKG4pe1MuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdDsiZG91YmxlY2xpY2siIT09ZSYmKHQ9X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGUuZW5jaGFudERlc2MpLHt9LHtyZXJlbmRlcjpufSksZT1lLm5hbWUrIi0iK24sdS5hZGRDaGFuZ2VyLmFwcGx5KHUsW2VdLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkodyh0LGUpKSkpKX0pfSksUy5mb3JFYWNoKGZ1bmN0aW9uKGkpeyJkb3VibGVjbGljayIhPT1pJiZbImdvdG8iLCJ1bmRvIl0uZm9yRWFjaChmdW5jdGlvbihhKXt2YXIgbz1pLm5hbWUrIi0iK2E7dS5hZGRDb21tYW5kKG8sZnVuY3Rpb24oZSx0KXtyZXR1cm4hZXx8IXQmJiJnb3RvIj09PWE/aC5jcmVhdGUoImRhdGF0eXBlIiwiQSBzdHJpbmcgZ2l2ZW4gdG8gdGhpcyAoIitvKyI6KSBtYWNybyB3YXMgZW1wdHkuIik6ImdvdG8iIT09YXx8bi5oYXNWYWxpZCh0KT92b2lkIDA6aC5jcmVhdGUoIm1hY3JvY2FsbCIsIkkgY2FuJ3QgKCIrbysiOikgdGhlIHBhc3NhZ2UgJyIrdCsiJyBiZWNhdXNlIGl0IGRvZXNuJ3QgZXhpc3QuIil9LGZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiJ1bmRvIj09PWEmJnMucGFzdExlbmd0aDwxP2guY3JlYXRlKCJtYWNyb2NhbGwiLCJJIGNhbid0ICh1bmRvOikgb24gdGhlIGZpcnN0IHR1cm4uIik6KCgwLF9zbGljZWRUb0FycmF5KHcoX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LGkuZW5jaGFudERlc2MpLHt9LHt0cmFuc2l0aW9uOmUuZGF0YS5wYXNzYWdlVDhufSwidW5kbyI9PT1hP3t1bmRvOiEwfTp7Z290bzpyfSksbyksMilbMV0pKHtzZWN0aW9uOnR9LHAuZnJvbShuKSksYihlLHtzb3VyY2U6IiJ9KSl9LFtnKHAsU3RyaW5nKV0uY29uY2F0KCJ1bmRvIj09PWE/W106U3RyaW5nKSl9KX0pfSksZGVmaW5lKCJtYWNyb2xpYi9saW5rcyIsWyJqcXVlcnkiLCJtYWNyb3MiLCJ1dGlscyIsInN0YXRlIiwicGFzc2FnZXMiLCJlbmdpbmUiLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJpbnRlcm5hbHR5cGVzL2NoYW5nZWRlc2NyaXB0b3IiLCJkYXRhdHlwZXMvaG9va3NldCIsImRhdGF0eXBlcy9sYW1iZGEiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiXSxmdW5jdGlvbihpLGUsYyxsLHUscCxhLGQsdCxmLGgpe3ZhciBuPWUuVHlwZVNpZ25hdHVyZSxyPW4ub3B0aW9uYWwsbz1uLnJlc3Qsbj1uLmVpdGhlcixtPVsiTGlua3MgY2FuJ3QgaGF2ZSBlbXB0eSBzdHJpbmdzIGZvciB0aGVpciBkaXNwbGF5ZWQgdGV4dC4iLCJJbiB0aGUgbGluayBzeW50YXgsIGEgbGluaydzIGRpc3BsYXllZCB0ZXh0IGlzIGluc2lkZSB0aGUgW1sgYW5kIF1dLCBhbmQgb24gdGhlIG5vbi1wb2ludHkgc2lkZSBvZiB0aGUgLT4gb3IgPC0gYXJyb3cgaWYgaXQncyB0aGVyZS4iXSxnPU9iamVjdC5hc3NpZ247ZnVuY3Rpb24gcyhlLHQsbil7bj1ufHx0O3ZhciByLGE9dS5oYXNWYWxpZCh0KSYmdD09PW4sZT1lLmV2YWx1YXRlVHdpbmVNYXJrdXAoYy51bmVzY2FwZShuKSwiYSBsaW5rJ3MgcGFzc2FnZSBuYW1lIik7cmV0dXJuIGE/dD0oYT0wPGUuY2hpbGRyZW4oKS5sZW5ndGg/ImAiLnJlcGVhdCgobi5tYXRjaCgvYCsvKXx8W10pLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBNYXRoLm1heChlLHQubGVuZ3RoKzEpfSwxKSk6IiIpKyJcMCIucmVwZWF0KCEhYSkrdCsiXDAiLnJlcGVhdCghIWEpK2E6KGUuZmluZEFuZEZpbHRlcigidHctZXJyb3IiKS5sZW5ndGgmJihyPWUuZmluZEFuZEZpbHRlcigidHctZXJyb3IiKS5kYXRhKCJUd2luZUVycm9yIikpLG49ZS50ZXh0KCkpLHt0ZXh0OnQscGFzc2FnZTpuLGVycm9yOnJ9fWMub25TdGFydHVwKGZ1bmN0aW9uKCl7dmFyIGU9Im9udG91Y2hzdGFydCJpbiB3aW5kb3d8fDA8bmF2aWdhdG9yLm1heFRvdWNoUG9pbnRzfHwwPG5hdmlnYXRvci5tc01heFRvdWNoUG9pbnRzO2Z1bmN0aW9uIHQoZSl7dmFyIHQ9aSh0aGlzKSxuPXQuY2xvc2VzdCgidHctZXhwcmVzc2lvbiIpLHI9dC5jbG9zZXN0KCJ0dy1leHByZXNzaW9uLCB0dy1ob29rIiksYT1yLmRhdGEoImNsaWNrRXZlbnQiKSxyPXIuZGF0YSgic2VjdGlvbiIpO2lmKCghYy5vcHRpb25zLmRlYnVnfHwhYy5vcHRpb25zLmlnbm9yZUNsaWNrRXZlbnRzfHx0LmlzKCJ0dy1iYWNrZHJvcC5ldmFsLXJlcGxheSAqLCB0dy1iYWNrZHJvcC5oYXJsb3dlLWNyYXNoICoiKSkmJiF0LmlzKCJ0dy1vcGVuLWJ1dHRvbiIpJiYobnVsbD09cnx8IXIuc3RhY2tUb3B8fCFyLnN0YWNrVG9wLmJsb2NrZWR8fHIuc3RhY2tUb3AuYmxvY2tlZCBpbnN0YW5jZW9mIGkmJnIuc3RhY2tUb3AuYmxvY2tlZC5maW5kKHQpLmxlbmd0aCkpe2lmKGEpcmV0dXJuIDA8dC5maW5kKCJ0dy1lcnJvciIpLmxlbmd0aD92b2lkIDA6KGUuc3RvcFByb3BhZ2F0aW9uKCksdm9pZCBhKHQpKTt2YXIgcj1uLmRhdGEoImxpbmtQYXNzYWdlTmFtZSIpLG89X29iamVjdFNwcmVhZCh7fSxuLmRhdGEoInBhc3NhZ2VUOG4iKXx8e30pO24uZmluZCgidHctZW5jaGFudG1lbnQiKS5lYWNoKGZ1bmN0aW9uKGUsdCl7T2JqZWN0LmFzc2lnbihvLGkodCkuZGF0YSgicGFzc2FnZVQ4biIpfHx7fSl9KSxyPyhlLnN0b3BQcm9wYWdhdGlvbigpLHAuZ29Ub1Bhc3NhZ2Uocix7dHJhbnNpdGlvbjpvfSkpOnQuaXMoIlt1bmRvXSIpPyhlLnN0b3BQcm9wYWdhdGlvbigpLHAuZ29CYWNrKHt0cmFuc2l0aW9uOm99KSk6dC5pcygiW2Z1bGxzY3JlZW5dIikmJihlLnN0b3BQcm9wYWdhdGlvbigpLHAudG9nZ2xlRnVsbHNjcmVlbigpKX19Yy5zdG9yeUVsZW1lbnQub24oImNsaWNrLnBhc3NhZ2UtbGluayIsInR3LWxpbmsiKyhlPyIiOiI6bm90KC5lbmNoYW50bWVudC1tb3VzZW92ZXIpOm5vdCguZW5jaGFudG1lbnQtbW91c2VvdXQpOm5vdCguZW5jaGFudG1lbnQtZGJsY2xpY2spIiksdCkub24oIm1vdXNlb3Zlci5wYXNzYWdlLWxpbmsiLCJ0dy1saW5rLmVuY2hhbnRtZW50LW1vdXNlb3ZlciwgdHctZXhwcmVzc2lvbi5lbmNoYW50bWVudC1tb3VzZW92ZXIgPiB0dy1saW5rIix0KS5vbigibW91c2VvdXQucGFzc2FnZS1saW5rIiwidHctbGluay5lbmNoYW50bWVudC1tb3VzZW91dCwgdHctZXhwcmVzc2lvbi5lbmNoYW50bWVudC1tb3VzZW91dCA+IHR3LWxpbmsiLHQpLm9uKCJkYmxjbGljay5wYXNzYWdlLWxpbmsiLCJ0dy1saW5rLmVuY2hhbnRtZW50LWRibGNsaWNrLCB0dy1leHByZXNzaW9uLmVuY2hhbnRtZW50LWRibGNsaWNrID4gdHctbGluayIsdCksaShkb2N1bWVudCkub24oImZ1bGxzY3JlZW5jaGFuZ2UiLGZ1bmN0aW9uKCl7aSgidHctbGlua1tmdWxsc2NyZWVuXSIsYy5zdG9yeUVsZW1lbnQpLmVhY2goZnVuY3Rpb24oZSx0KXsoaSh0KS5jbG9zZXN0KCJ0dy1leHByZXNzaW9uLCB0dy1ob29rIikuZGF0YSgiZnVsbHNjcmVlbkV2ZW50Iil8fE9iamVjdCkodCl9KX0pfSksW1sibGluayIsImxpbmstcmVwbGFjZSJdLFsibGluay1yZXZlYWwiLCJsaW5rLWFwcGVuZCJdLFsibGluay1yZXBlYXQiXSxbImxpbmstcmVydW4iXV0uZm9yRWFjaChmdW5jdGlvbihzKXtyZXR1cm4gZS5hZGRDaGFuZ2VyKHMsZnVuY3Rpb24oZSx0LG4pe3JldHVybiB0P24mJiFuLmNhbkVuY2hhbnQ/aC5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIGNoYW5nZXIgZ2l2ZW4gdG8gKCIuY29uY2F0KHNbMF0sIjopIGNhbid0IGJlIChvciBpbmNsdWRlKSBhIHJldmlzaW9uLCBlbmNoYW50bWVudCwgb3IgaW50ZXJhY3Rpb24gY2hhbmdlciBsaWtlIChyZXBsYWNlOiksIChjbGljazopLCBvciAobGluazopLiIpKTphLmNyZWF0ZShzWzBdLFt0XS5jb25jYXQobnx8W10pLG51bGwsITApOmguY3JlYXRlKCJkYXRhdHlwZSIsbVswXSl9LGZ1bmN0aW9uKHIsZSx0KXt2YXIgbixhPXNbMF0sbz1udWxsIT0obj1yLnNlY3Rpb24pJiZuLnN0YWNrVG9wP3Iuc2VjdGlvbi5zdGFja1RvcC50ZW1wVmFyaWFibGVzOk9iamVjdC5jcmVhdGUobnVsbCksaT1kLmNyZWF0ZSh7c291cmNlOiI8dHctbGluayB0YWJpbmRleD0wPiIrZSsiPC90dy1saW5rPiIsdGFyZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIudGFyZ2V0fSxhcHBlbmQ6InJlcGxhY2UiLGRhdGE6e3NlY3Rpb246ci5zZWN0aW9uLGNsaWNrRXZlbnQ6ZnVuY3Rpb24oZSl7ci5lbmFibGVycz1yLmVuYWJsZXJzLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5kZXNjcmlwdG9yIT09aX0pLCJsaW5rLXJldmVhbCI9PT1hJiZlLmNvbnRlbnRzKCkudW53cmFwKCk7dmFyIHQsbj1lLnBhcmVudHNVbnRpbCgiOm5vdCh0dy1lbmNoYW50bWVudCkiKS5wYXJlbnQoKTtuLmxlbmd0aHx8KG49ZS5wYXJlbnQoKSksImxpbmstcmVydW4iPT09YSYmKHQ9ZS5wYXJlbnRzVW50aWwoIjpub3QodHctZW5jaGFudG1lbnQpIiksZS5kZXRhY2goKSx0LnJlbW92ZSgpKSwibGluayIhPT1hJiYibGluay1yZXJ1biIhPT1hfHxuLmVtcHR5KCksci5zZWN0aW9uLnJlbmRlckludG8oIiIsbnVsbCxyLG8pLCJsaW5rLXJlcnVuIj09PWEmJm4ucHJlcGVuZChlKX19fSk7cmV0dXJuIHIuZW5hYmxlcnM9KHIuZW5hYmxlcnN8fFtdKS5jb25jYXQoe2Rlc2NyaXB0b3I6aSxjaGFuZ2VyOnR9KSxyfSxbU3RyaW5nLHIoYSldKX0pLGUuYWRkQ29tbWFuZCgibGluay1nb3RvIixmdW5jdGlvbihlKXtpZighZSlyZXR1cm4gaC5jcmVhdGUuYXBwbHkoaCxbImRhdGF0eXBlIl0uY29uY2F0KG0pKX0sZnVuY3Rpb24oZSx0LG4scil7dmFyIGEsbz1zKHQsbixyKTtyZXR1cm4gbj1vLnRleHQscj1vLnBhc3NhZ2UsKG89by5lcnJvcil8fChlLnRyYW5zaXRpb24/aC5jcmVhdGUoImRhdGF0eXBlIiwiUGxlYXNlIGF0dGFjaCAoIisobz0idHJhbnNpdGlvbiIpKyItZGVwYXJ0Oikgb3IgKCIrbysiLWFycml2ZTopIHRvIGEgcGFzc2FnZSBsaW5rLCBub3QgKCIrbysiOikuIik6KGE9KGE9dS5oYXNWYWxpZChyKT9hOic8dHctYnJva2VuLWxpbmsgcGFzc2FnZS1uYW1lPSInK2MuZXNjYXBlKHIpKyciPicrbisiPC90dy1icm9rZW4tbGluaz4iKXx8Ijx0dy1saW5rIHRhYmluZGV4PTAgIisoMDxsLnBhc3NhZ2VOYW1lVmlzaXRlZChyKT8nY2xhc3M9InZpc2l0ZWQiICc6IiIpKyI+IituKyI8L3R3LWxpbms+IixlLmRhdGEubGlua1Bhc3NhZ2VOYW1lPXIsZS5kYXRhLnNlY3Rpb249dCxnKGUse3NvdXJjZTphLHRyYW5zaXRpb25EZWZlcnJlZDohMH0pKSl9LFtTdHJpbmcscihTdHJpbmcpXSkoImxpbmstc3RvcnlsZXQiLGZ1bmN0aW9uKCl7dmFyIGU9KGU9MT09PWFyZ3VtZW50cy5sZW5ndGh8fCJzdHJpbmciIT10eXBlb2YoYXJndW1lbnRzLmxlbmd0aDw9MD92b2lkIDA6YXJndW1lbnRzWzBdKT8wOjEpPDB8fGFyZ3VtZW50cy5sZW5ndGg8PWU/dm9pZCAwOmFyZ3VtZW50c1tlXTtpZighZXx8InN0cmluZyI9PXR5cGVvZiBlKXJldHVybiBoLmNyZWF0ZSgiZGF0YXR5cGUiLCIobGluay1zdG9yeWxldDopIHNob3VsZCBiZSBnaXZlbiBvbmUgaW5kZXggbnVtYmVyIG9yIG9uZSAnd2hlcmUnIGxhbWJkYSwgYWZ0ZXIgdGhlIG9wdGlvbmFsIGxpbmsgdGV4dCBzdHJpbmcuIil9LGZ1bmN0aW9uKGUsdCl7dmFyIG49KG49MisoInN0cmluZyI9PXR5cGVvZihhcmd1bWVudHMubGVuZ3RoPD0yP3ZvaWQgMDphcmd1bWVudHNbMl0pPzE6MCkpPDJ8fGFyZ3VtZW50cy5sZW5ndGg8PW4/dm9pZCAwOmFyZ3VtZW50c1tuXSxyPSJzdHJpbmciPT10eXBlb2YoYXJndW1lbnRzLmxlbmd0aDw9Mj92b2lkIDA6YXJndW1lbnRzWzJdKSYmKGFyZ3VtZW50cy5sZW5ndGg8PTI/dm9pZCAwOmFyZ3VtZW50c1syXSksYT0oKGE9KGFyZ3VtZW50cy5sZW5ndGg8PTI/MDphcmd1bWVudHMubGVuZ3RoLTIpLTErMik8Mnx8YXJndW1lbnRzLmxlbmd0aDw9YT92b2lkIDA6YXJndW1lbnRzW2FdKSE9PW4mJigoYT0oYXJndW1lbnRzLmxlbmd0aDw9Mj8wOmFyZ3VtZW50cy5sZW5ndGgtMiktMSsyKTwyfHxhcmd1bWVudHMubGVuZ3RoPD1hP3ZvaWQgMDphcmd1bWVudHNbYV0pO2lmKGUudHJhbnNpdGlvbilyZXR1cm4gaC5jcmVhdGUoImRhdGF0eXBlIiwiUGxlYXNlIGF0dGFjaCAoIi5jb25jYXQobz0idHJhbnNpdGlvbiIsIi1kZXBhcnQ6KSBvciAoIikuY29uY2F0KG8sIi1hcnJpdmU6KSB0byAobGluay1zdG9yeWxldDopLCBub3QgKCIpLmNvbmNhdChvLCI6KS4iKSk7dmFyIG89Zi5pc1Byb3RvdHlwZU9mKG4pLGk9dS5nZXRTdG9yeWxldHModCxvJiZuKSxzPWguY29udGFpbnNFcnJvcihpKTtpZihzKXJldHVybiBzO3ZhciBjLHM9aVtvPzA6bjwwP2kubGVuZ3RoK246bi0xXTtpZihzKXM9cy5nZXQoIm5hbWUiKSxyPXJ8fHMsYz1jfHwiPHR3LWxpbmsgdGFiaW5kZXg9MCAiKygwPGwucGFzc2FnZU5hbWVWaXNpdGVkKHMpPydjbGFzcz0idmlzaXRlZCIgJzoiIikrIj4iK3IrIjwvdHctbGluaz4iLGUuZGF0YS5saW5rUGFzc2FnZU5hbWU9cyxlLmRhdGEuc2VjdGlvbj10O2Vsc2V7aWYoIWEpcmV0dXJuIGU7Yz1hfXJldHVybiBnKGUse3NvdXJjZTpjLHRyYW5zaXRpb25EZWZlcnJlZDohMH0pfSxbbihwYXJzZUludCxTdHJpbmcsZi5UeXBlU2lnbmF0dXJlKCJ3aGVyZSIpKSxyKG4ocGFyc2VJbnQsU3RyaW5nLGYuVHlwZVNpZ25hdHVyZSgid2hlcmUiKSkpLHIoU3RyaW5nKV0pKCJsaW5rLXVuZG8iLGZ1bmN0aW9uKGUpe2lmKCFlKXJldHVybiBoLmNyZWF0ZSgiZGF0YXR5cGUiLG1bMF0pfSxmdW5jdGlvbih0LGUsbil7dmFyIHIsYT0zPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106IiI7cmV0dXJuIGwucGFzdExlbmd0aDwxP2codCx7c291cmNlOmF9KToocj0odC5kYXRhLnNlY3Rpb249ZSkuc3RhY2tUb3AudGVtcFZhcmlhYmxlcyx0LmRhdGEuZm9yZ2V0VW5kb3NFdmVudD1mdW5jdGlvbigpe3JldHVybiB0LmRhdGEuc2VjdGlvbi53aGVuVW5ibG9ja2VkKGZ1bmN0aW9uKCl7dmFyIGU9X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LHQpLHt9LHthcHBlbmQ6InJlcGxhY2UiLHNvdXJjZTphLHRyYW5zaXRpb25EZWZlcnJlZDohMX0pO3Quc2VjdGlvbi5yZW5kZXJJbnRvKCIiLG51bGwsZSxyKX0pfSxnKHQse3NvdXJjZToiPHR3LWxpbmsgdGFiaW5kZXg9MCB1bmRvPiIrbisiPC90dy1saW5rPiIsdHJhbnNpdGlvbkRlZmVycmVkOiEwfSkpfSxbU3RyaW5nLHIoU3RyaW5nKV0pKCJsaW5rLXNob3ciLGZ1bmN0aW9uKGUpe2lmKCFlKXJldHVybiBoLmNyZWF0ZSgiZGF0YXR5cGUiLG1bMF0pfSxmdW5jdGlvbihyLGEsZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMzx0P3QtMzowKSxvPTM7bzx0O28rKyluW28tM109YXJndW1lbnRzW29dO3JldHVybiByLmRhdGEuc2VjdGlvbj1hLHIuZGF0YS5jbGlja0V2ZW50PWZ1bmN0aW9uKGUpe2UuY29udGVudHMoKS51bndyYXAoKSxuLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGUuZm9yRWFjaChhLGZ1bmN0aW9uKGUpe3ZhciB0PWUuZGF0YSgib3JpZ2luYWxTb3VyY2UiKXx8IiIsbj1lLmRhdGEoImhpZGRlbiIpO24mJihlLnJlbW92ZURhdGEoImhpZGRlbiIpLG4gaW5zdGFuY2VvZiBpP2UuZW1wdHkoKS5hcHBlbmQobik6KG49ZS5kYXRhKCJ0ZW1wVmFyaWFibGVzIiksYS5yZW5kZXJJbnRvKCIiLG51bGwsX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LHIpLHt9LHtzb3VyY2U6dCx0YXJnZXQ6ZSx0cmFuc2l0aW9uRGVmZXJyZWQ6ITF9KSxuJiZPYmplY3QuY3JlYXRlKG4pKSkpfSl9KX0sZyhyLHtzb3VyY2U6Ijx0dy1saW5rIHRhYmluZGV4PTA+IitlKyI8L3R3LWxpbms+Iix0cmFuc2l0aW9uRGVmZXJyZWQ6ITB9KX0sW1N0cmluZyxvKHQpXSkoImxpbmstZnVsbHNjcmVlbiIsZnVuY3Rpb24oZSx0KXtpZighZXx8IXQpcmV0dXJuIGguY3JlYXRlKCJkYXRhdHlwZSIsbVswXSl9LGZ1bmN0aW9uKHQsZSxuLHIpe2Z1bmN0aW9uIGEoKXtyZXR1cm4gZG9jdW1lbnQuZnVsbHNjcmVlbkVuYWJsZWR8fGRvY3VtZW50Lm1zRnVsbHNjcmVlbkVuYWJsZWQ/Ijx0dy1saW5rIHRhYmluZGV4PTAgZnVsbHNjcmVlbj4iKyhkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudHx8ZG9jdW1lbnQubXNGdWxsc2NyZWVuRWxlbWVudD9yOm4pKyI8L3R3LWxpbms+IjpyPyI8dHctYnJva2VuLWxpbms+IityKyI8L3R3LWJyb2tlbi1saW5rPiI6IiJ9dmFyIG89ZS5zdGFja1RvcC50ZW1wVmFyaWFibGVzO3JldHVybiB0LmRhdGEuc2VjdGlvbj1lLHQuZGF0YS5mdWxsc2NyZWVuRXZlbnQ9ZnVuY3Rpb24oKXsoZG9jdW1lbnQuZnVsbHNjcmVlbkVuYWJsZWR8fGRvY3VtZW50Lm1zRnVsbHNjcmVlbkVuYWJsZWQpJiZ0LmRhdGEuc2VjdGlvbi53aGVuVW5ibG9ja2VkKGZ1bmN0aW9uKCl7dmFyIGU9X29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LHQpLHt9LHthcHBlbmQ6InJlcGxhY2UiLHNvdXJjZTphKCksdHJhbnNpdGlvbkRlZmVycmVkOiExfSk7dC5zZWN0aW9uLnJlbmRlckludG8oIiIsbnVsbCxlLG8pfSl9LGcodCx7c291cmNlOmEoKSx0cmFuc2l0aW9uRGVmZXJyZWQ6ITB9KX0sW1N0cmluZyxTdHJpbmcscihTdHJpbmcpXSksZS5hZGRDaGFuZ2VyKFsibGluay1yZXZlYWwtZ290byJdLGZ1bmN0aW9uKGUsdCxuLHIpe2lmKCF0KXJldHVybiBoLmNyZWF0ZS5hcHBseShoLFsiZGF0YXR5cGUiXS5jb25jYXQobSkpO2lmKGEuaXNQcm90b3R5cGVPZihuKSl7aWYoYS5pc1Byb3RvdHlwZU9mKHIpKXJldHVybiBoLmNyZWF0ZSgiZGF0YXR5cGUiLCJZb3UgbXVzdG4ndCBnaXZlIHR3byBjaGFuZ2VycyB0byAobGluay1yZXZlYWwtZ290bzopIik7cj1uLG49dm9pZCAwfXJldHVybiByJiYhci5jYW5FbmNoYW50P2guY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSBjaGFuZ2VyIGdpdmVuIHRvIChsaW5rLXJldmVhbC1nb3RvOikgY2FuJ3QgaW5jbHVkZSBhIHJldmlzaW9uLCBlbmNoYW50bWVudCwgb3IgaW50ZXJhY3Rpb24gY2hhbmdlciBsaWtlIChyZXBsYWNlOiksIChjbGljazopLCBvciAobGluazopLiIpOih0PShlPXMoZSx0LG4pKS50ZXh0LG49ZS5wYXNzYWdlLGUuZXJyb3J8fGEuY3JlYXRlKCJsaW5rLXJldmVhbC1nb3RvIixbdCxuLHJdLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gdm9pZCAwIT09ZX0pLG51bGwsITEpKX0sZnVuY3Rpb24odCxlLG4scil7dmFyIGEsbyxpLHM7aWYodS5oYXNWYWxpZChuKSlyZXR1cm4gbz1sLnBhc3NhZ2VOYW1lVmlzaXRlZChuKSxpPW51bGwhPShhPXQuc2VjdGlvbikmJmEuc3RhY2tUb3A/dC5zZWN0aW9uLnN0YWNrVG9wLnRlbXBWYXJpYWJsZXM6T2JqZWN0LmNyZWF0ZShudWxsKSxzPWQuY3JlYXRlKHtzb3VyY2U6Ijx0dy1saW5rIHRhYmluZGV4PTAgIisoMDxvPydjbGFzcz0idmlzaXRlZCIgJzoiIikrIj4iK2UrIjwvdHctbGluaz4iLHRhcmdldDp0LnRhcmdldCxhcHBlbmQ6InJlcGxhY2UiLGRhdGE6e3NlY3Rpb246dC5zZWN0aW9uLGFwcGVuZDoicmVwbGFjZSIsY2xpY2tFdmVudDpmdW5jdGlvbihlKXt0LmVuYWJsZXJzPXQuZW5hYmxlcnMuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlLmRlc2NyaXB0b3IhPT1zfSksZS5jb250ZW50cygpLnVud3JhcCgpLHQuc2VjdGlvbi5yZW5kZXJJbnRvKCIiLG51bGwsdCxpKSx0LnNlY3Rpb24ud2hlblVuYmxvY2tlZChmdW5jdGlvbigpe3JldHVybiBwLmdvVG9QYXNzYWdlKG4se3RyYW5zaXRpb246dC5kYXRhLnBhc3NhZ2VUOG59KX0pfX19KSx0LmVuYWJsZXJzPSh0LmVuYWJsZXJzfHxbXSkuY29uY2F0KHtkZXNjcmlwdG9yOnMsY2hhbmdlcjpyfSksdDt0LnNvdXJjZT0nPHR3LWJyb2tlbi1saW5rIHBhc3NhZ2UtbmFtZT0iJytjLmVzY2FwZShuKSsnIj4nK2UrIjwvdHctYnJva2VuLWxpbms+In0sW1N0cmluZyxyKG4oYSxTdHJpbmcpKSxyKGEpXSl9KSxkZWZpbmUoIm1hY3JvbGliL21ldGFkYXRhIixbIm1hY3JvcyIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiZGF0YXR5cGVzL2xhbWJkYSIsImludGVybmFsdHlwZXMvdHdpbmVlcnJvciJdLGZ1bmN0aW9uKHQsZSxuLHMpe2Z1bmN0aW9uIGMoZSl7cmV0dXJue1R3aW5lU2NyaXB0X1R5cGVOYW1lOiJhICgiK2UrIjopIG1hY3JvIixUd2luZVNjcmlwdF9PYmplY3ROYW1lOiJhICgiK2UrIjopIG1hY3JvIixUd2luZVNjcmlwdF9VbnN0b3JhYmxlOiEwLFR3aW5lU2NyaXB0X1ByaW50OmZ1bmN0aW9uKCl7cmV0dXJuIiJ9fX12YXIgbD1lLmNsb25lLHU9ZS5vYmplY3ROYW1lLHA9ZS5pc1ZhbGlkRGF0YW1hcE5hbWUsZT10LlR5cGVTaWduYXR1cmUscj1lLnplcm9Pck1vcmUsZT1lLkFueTtbWyJzdG9yeWxldCIsbi5UeXBlU2lnbmF0dXJlKCJ3aGVuIildLFsidXJnZW5jeSIsTnVtYmVyXSxbImV4Y2x1c2l2aXR5IixOdW1iZXJdXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciBlPV9zbGljZWRUb0FycmF5KGUsMiksbj1lWzBdLGU9ZVsxXTt0LmFkZChuLCJNZXRhZGF0YSIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5zdGFja1RvcC5zcGVjdWxhdGl2ZVBhc3NhZ2U/dDpjKG4pfSxlKX0pLHQuYWRkKCJtZXRhZGF0YSIsIk1ldGFkYXRhIixmdW5jdGlvbihlKXtmb3IodmFyIHIsYT1uZXcgTWFwLHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLG89MTtvPHQ7bysrKW5bby0xXT1hcmd1bWVudHNbb107dmFyIGk9bi5yZWR1Y2UoZnVuY3Rpb24oZSx0KXt2YXIgbjtpZighcy5jb250YWluc0Vycm9yKGUpKWlmKHZvaWQgMD09PXIpcj10O2Vsc2V7aWYobj1zLmNvbnRhaW5zRXJyb3IocChhLHIpKSlyZXR1cm4gbjtpZihhLmhhcyhyKSlyZXR1cm4gcy5jcmVhdGUoIm1hY3JvY2FsbCIsIllvdSB1c2VkIHRoZSBzYW1lIGRhdGEgbmFtZSAoIit1KHIpKyIpIHR3aWNlIGluIHRoZSBzYW1lIChtZXRhZGF0YTopIGNhbGwuIik7YS5zZXQocixsKHQpKSxyPXZvaWQgMH1yZXR1cm4gZX0sITApO3JldHVybiBzLmNvbnRhaW5zRXJyb3IoaSk/aTp2b2lkIDAhPT1yP3MuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGlzIChtZXRhZGF0YTopIG1hY3JvIGhhcyBhIGRhdGEgbmFtZSB3aXRob3V0IGEgdmFsdWUuIik6ZS5zdGFja1RvcC5zcGVjdWxhdGl2ZVBhc3NhZ2U/YTpjKCJtZXRhZGF0YSIpfSxyKGUpKX0pLGRlZmluZSgibWFjcm9saWIvcGF0dGVybnMiLFsibWFjcm9zIiwidXRpbHMiLCJ1dGlscy9vcGVyYXRpb251dGlscyIsImRhdGF0eXBlcy9sYW1iZGEiLCJkYXRhdHlwZXMvZGF0YXR5cGUiLCJkYXRhdHlwZXMvdHlwZWR2YXIiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJpbnRlcm5hbHR5cGVzL3ZhcnNjb3BlIl0sZnVuY3Rpb24oZSx0LG4seSxiLGgsdix3KXtmdW5jdGlvbiBrKGUpe3ZhciByLHQsYT1lLm5hbWUsbj1lLmZ1bGxBcmdzLG89ZS5hcmdzLGk9ZS5tYWtlUmVnRXhwU3RyaW5nLHM9dm9pZCAwPT09aT9mdW5jdGlvbihlKXtyZXR1cm4gZS5qb2luKCIiKX06aSxjPXZvaWQgMCE9PShpPWUuaW5zZW5zaXRpdmUpJiZpLGw9dm9pZCAwPT09KGk9ZS5jYW5Db250YWluVHlwZWRWYXJzKXx8aSx1PXZvaWQgMD09PShpPWUuY2FuQmVVc2VkQWxvbmUpfHxpLHA9dm9pZCAwPT09KGk9ZS5jYW5Db250YWluVHlwZWRHbG9iYWxzKXx8aSxkPW98fG4sZj1FKG51bGwpLGU9ZC5tYXAoZnVuY3Rpb24gZSh0KXtpZihoLmlzUHJvdG90eXBlT2YodCkpe3ZhciBuPXQudmFyUmVmO2lmKCFsKXJldHVybiB2LmNyZWF0ZSgib3BlcmF0aW9uIiwiT3B0aW9uYWwgc3RyaW5nIHBhdHRlcm5zLCBsaWtlICgiLmNvbmNhdChhLCI6KSIpLmNvbmNhdCgicC1tYW55Ij09PWE/IiB3aXRoIGEgbWluaW11bSBvZiAwIG1hdGNoZXMiOiIiLCIsIGNhbid0IGhhdmUgdHlwZWQgdmFyaWFibGVzIGluc2lkZSB0aGVtLiIpKTtpZighcCYmIXcuaXNQcm90b3R5cGVPZihuLm9iamVjdCkpcmV0dXJuIHYuY3JlYXRlKCJvcGVyYXRpb24iLCJPbmx5IHR5cGVkIHRlbXAgdmFyaWFibGVzIGNhbiBiZSB1c2VkIGluIHBhdHRlcm5zIGdpdmVuIHRvICgiLmNvbmNhdChhLCI6KSIpKTtuPW4uZ2V0TmFtZSgpO2lmKG4gaW4gZilyZXR1cm4gdi5jcmVhdGUoIm9wZXJhdGlvbiIsIlRoZXJlJ3MgYWxyZWFkeSBhIHR5cGVkIHRlbXAgdmFyaWFibGUgbmFtZWQgXyIuY29uY2F0KG4sIiBpbnNpZGUgdGhpcyAoIikuY29uY2F0KGEsIjopIGNhbGwuIikpO2Zbbl09ITA7bj1lKHQuZGF0YXR5cGUpO3JldHVybiB2LmNvbnRhaW5zRXJyb3Iobik/bjoiKCIrbisiKSJ9aWYoYi5pc1Byb3RvdHlwZU9mKHQpKXtpZighKGwmJnB8fCJmdW5jdGlvbiIhPXR5cGVvZiB0LnR5cGVkVmFycykpe249dC50eXBlZFZhcnMoKTtpZighbCYmbi5sZW5ndGgpcmV0dXJuIHYuY3JlYXRlKCJvcGVyYXRpb24iLCIoIi5jb25jYXQoYSwiOikgY2FuJ3QgaGF2ZSB0eXBlZCB2YXJpYWJsZXMgaW5zaWRlIGl0cyBwYXR0ZXJuLiIpKTtpZighcCYmbi5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiF3LmlzUHJvdG90eXBlT2YoZS52YXJSZWYub2JqZWN0KX0pKXJldHVybiB2LmNyZWF0ZSgib3BlcmF0aW9uIiwiT25seSB0eXBlZCB0ZW1wIHZhcmlhYmxlcyBjYW4gYmUgdXNlZCBpbiBwYXR0ZXJucyBnaXZlbiB0byAoIi5jb25jYXQoYSwiOikiKSl9dmFyIHI7cmV0dXJuIHQucmVnRXhwPyh0LnJlc3Q/Iig/OiI6IiIpKyhjP3QuaW5zZW5zaXRpdmUoKTp0KS5yZWdFeHArKHQucmVzdD8iKSoiOiIiKToobj10Lm5hbWUscj10LnJlc3Q/IioiOiIiLCJhbG51bSI9PT1uP20rcjoid2hpdGVzcGFjZSI9PT1uP18rcjoidXBwZXJjYXNlIj09PW4/KGM/VDpnKStyOiJsb3dlcmNhc2UiPT09bj8oYz9UOlMpK3I6ImFueWNhc2UiPT09bj9UK3I6ImRpZ2l0Ij09PW4/IlxcZCIrcjoibGluZWJyZWFrIj09PW4/Iig/OlxccnxcXG58XFxyXFxuKSIrcjoic3RyIj09PW4/Ii4qPyI6WyJldmVuIiwib2RkIiwiaW50IiwibnVtIl0uaW5jbHVkZXMobik/di5jcmVhdGUoImRhdGF0eXBlIiwiUGxlYXNlIHVzZSBzdHJpbmcgZGF0YXR5cGVzIGxpa2UgJ2RpZ2l0JyBpbiAoIi5jb25jYXQoYSwiOikgaW5zdGVhZCBvZiBudW1iZXIgZGF0YXR5cGVzLiIpKTp2LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgKCIuY29uY2F0KGEsIjopIG1hY3JvIG11c3Qgb25seSBiZSBnaXZlbiBzdHJpbmctcmVsYXRlZCBkYXRhdHlwZXMsIG5vdCAiKS5jb25jYXQoTyh0KSwiLiIpKSl9cmV0dXJuInN0cmluZyI9PXR5cGVvZiB0Pyh0PXQucmVwbGFjZSgvWy4qK1wtP14ke30oKXxbXF1cXF0vZywiXFwkJiIpLGM/dC5yZXBsYWNlKFJlZ0V4cCgiKCIuY29uY2F0KGcsInwiKS5jb25jYXQoUywiKSIpLCJnIiksZnVuY3Rpb24oZSl7cmV0dXJuIlsiK2UudG9VcHBlckNhc2UoKStlLnRvTG93ZXJDYXNlKCkrIl0ifSk6dCk6KHgoImNyZWF0ZVBhdHRlcm4iLCJtYXBwZXIoKSB3YXMgZ2l2ZW4gYSBub24tc3RyaW5nIG5vbi1kYXRhdHlwZSAiK3QpLCIiKX0pO3JldHVybihpPXYuY29udGFpbnNFcnJvcihlKSl8fChyPXMoZSksdD1DKEUoYikse25hbWU6YSxyZWdFeHA6cixpbnNlbnNpdGl2ZTpmdW5jdGlvbigpe3JldHVybiBjP3Q6ayh7bmFtZTphLGZ1bGxBcmdzOm4sYXJnczpkLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gYi5pc1Byb3RvdHlwZU9mKGUpJiYiZnVuY3Rpb24iPT10eXBlb2YgZS5pbnNlbnNpdGl2ZT9lLmluc2Vuc2l0aXZlKCk6ZX0pLG1ha2VSZWdFeHBTdHJpbmc6cyxpbnNlbnNpdGl2ZTohMCxjYW5Db250YWluVHlwZWRWYXJzOmwsY2FuQmVVc2VkQWxvbmU6dX0pfSx0eXBlZFZhcnM6ZnVuY3Rpb24oKXtyZXR1cm4gZC5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gaC5pc1Byb3RvdHlwZU9mKHQpJiYoZT1lLmNvbmNhdChjP2guY3JlYXRlKGsoe25hbWU6InAtaW5zIixmdWxsQXJnczpbdC5kYXRhdHlwZV0saW5zZW5zaXRpdmU6ITB9KSx0LnZhclJlZik6dCksdD10LmRhdGF0eXBlKSxlPWIuaXNQcm90b3R5cGVPZih0KSYmImZ1bmN0aW9uIj09dHlwZW9mIHQudHlwZWRWYXJzP2UuY29uY2F0KHQudHlwZWRWYXJzKCkpOmV9LFtdKX0sZGVzdHJ1Y3R1cmU6ZnVuY3Rpb24oZSl7dmFyIG4sdDtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIGU/W3YuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IHB1dCAiLmNvbmNhdChPKGUpLCIgaW50byAiKS5jb25jYXQodGhpcy5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpLCIgYmVjYXVzZSBpdCBpc24ndCBhIHN0cmluZy4iKSldOihuPXRoaXMudHlwZWRWYXJzKCkpLmxlbmd0aD8odD0oUmVnRXhwKCJeIisodGhpcy5yZXN0PyIoPzoiOiIiKStyKyh0aGlzLnJlc3Q/IikqIjoiIikrIiQiKS5leGVjKGUpfHxbXSkuc2xpY2UoMSkpLmxlbmd0aD90Lm1hcChmdW5jdGlvbihlLHQpe3Q9blt0XTtpZih0KXJldHVybiB0LmRhdGF0eXBlLnJlc3QmJiF0LmRhdGF0eXBlLnJlZ0V4cCYmKCh0PXQuVHdpbmVTY3JpcHRfQ2xvbmUoKSkuZGF0YXR5cGU9ayh7bmFtZToicCIsZnVsbEFyZ3M6W3QuZGF0YXR5cGVdfSkpLHtkZXN0OnQsdmFsdWU6ZXx8IiIsc3JjOnZvaWQgMH19KS5maWx0ZXIoQm9vbGVhbik6W3YuY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IHB1dCAiLmNvbmNhdChPKGUpLCIgYmVjYXVzZSBpdCBkb2Vzbid0IG1hdGNoIHRoZSBwYXR0ZXJuICIpLmNvbmNhdCh0aGlzLlR3aW5lU2NyaXB0X1RvU291cmNlKCksIi4iKSldOltdfSxUd2luZVNjcmlwdF9Jc1R5cGVPZjpmdW5jdGlvbihlKXtyZXR1cm4gdT8ic3RyaW5nIj09dHlwZW9mIGUmJiEhZS5tYXRjaCgiXiIrKHRoaXMucmVzdD8iKD86IjoiIikrcisodGhpcy5yZXN0PyIpKiI6IiIpKyIkIik6di5jcmVhdGUoIm9wZXJhdGlvbiIsIkEgKCIuY29uY2F0KGEsIjopIGRhdGF0eXBlIG11c3Qgb25seSBiZSB1c2VkIHdpdGggYSAocDopIG1hY3JvLiIpKX0sVHdpbmVTY3JpcHRfdG9UeXBlU2lnbmF0dXJlT2JqZWN0OmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcztyZXR1cm57cGF0dGVybjoicmFuZ2UiLG5hbWU6YSxyYW5nZTpmdW5jdGlvbihlKXtyZXR1cm4gdC5Ud2luZVNjcmlwdF9Jc1R5cGVPZihlKX19fSxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe3JldHVybih0aGlzLnJlc3Q/Ii4uLiI6IiIpKyIoIithKyI6IituLm1hcChBKSsiKSJ9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlR3aW5lU2NyaXB0X09iamVjdE5hbWUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4iYSAoIi5jb25jYXQoYSwiOikgZGF0YXR5cGUiKX19KSx0KX12YXIgbT10LmFueVJlYWxMZXR0ZXIsZz10LmFueVVwcGVyY2FzZSxTPXQuYW55TG93ZXJjYXNlLFQ9dC5hbnlDYXNlZExldHRlcixfPXQucmVhbFdoaXRlc3BhY2UseD10LmltcG9zc2libGUsTz1uLm9iamVjdE5hbWUsQT1uLnRvU291cmNlLHQ9ZS5UeXBlU2lnbmF0dXJlLG49dC5yZXN0LHI9dC5laXRoZXIsYT10Lm9wdGlvbmFsLHQ9dC5ub25OZWdhdGl2ZUludGVnZXIsQz1PYmplY3QuYXNzaWduLEU9T2JqZWN0LmNyZWF0ZSxvPW4ocihTdHJpbmcsYixoKSk7ZS5hZGQoWyJwIiwicGF0dGVybiJdLCJEYXRhdHlwZSIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBrKHtuYW1lOiJwIixmdWxsQXJnczpufSl9LG8pKFsicC1laXRoZXIiLCJwYXR0ZXJuLWVpdGhlciJdLCJEYXRhdHlwZSIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBrKHtuYW1lOiJwLWVpdGhlciIsZnVsbEFyZ3M6bixjYW5Db250YWluVHlwZWRWYXJzOiExLG1ha2VSZWdFeHBTdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuIig/OiIrZS5qb2luKCJ8IikrIikifX0pfSxvKShbInAtb3B0IiwicGF0dGVybi1vcHQiLCJwLW9wdGlvbmFsIiwicGF0dGVybi1vcHRpb25hbCJdLCJEYXRhdHlwZSIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBrKHtuYW1lOiJwLW9wdCIsZnVsbEFyZ3M6bixjYW5Db250YWluVHlwZWRWYXJzOiExLG1ha2VSZWdFeHBTdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuIig/OiIrZS5qb2luKCIiKSsiKT8ifX0pfSxvKShbInAtbm90IiwicGF0dGVybi1ub3QiXSwiRGF0YXR5cGUiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gbi5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZT8xIT09X3RvQ29uc3VtYWJsZUFycmF5KGUpLmxlbmd0aDplLnJlc3R8fGUucmVnRXhwfHxbInN0ciIsImVtcHR5Il0uaW5jbHVkZXMoZS5uYW1lKX0pP3YuY3JlYXRlKCJkYXRhdHlwZSIsIihwLW5vdDopIHNob3VsZCBvbmx5IGJlIGdpdmVuIHNpbmdsZSBjaGFyYWN0ZXJzLCBvciBkYXRhdHlwZXMgdGhhdCBtYXRjaCBzaW5nbGUgY2hhcmFjdGVycyIpOmsoe25hbWU6InAtbm90IixmdWxsQXJnczpuLGNhbkNvbnRhaW5UeXBlZFZhcnM6ITEsbWFrZVJlZ0V4cFN0cmluZzpmdW5jdGlvbihlKXtyZXR1cm4iW14iK2UubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnN0YXJ0c1dpdGgoIlsiKSYmZS5lbmRzV2l0aCgiXSIpP2Uuc2xpY2UoMSwtMSk6ZX0pLmpvaW4oIiIpKyJdIn19KX0sbykoWyJwLW5vdC1iZWZvcmUiLCJwYXR0ZXJuLW5vdC1iZWZvcmUiXSwiRGF0YXR5cGUiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gayh7bmFtZToicC1ub3QtYmVmb3JlIixmdWxsQXJnczpuLGNhbkNvbnRhaW5UeXBlZFZhcnM6ITEsbWFrZVJlZ0V4cFN0cmluZzpmdW5jdGlvbihlKXtyZXR1cm4iKD8hIitlLmpvaW4oIiIpKyIpIn19KX0sbykoWyJwLWJlZm9yZSIsInBhdHRlcm4tYmVmb3JlIl0sIkRhdGF0eXBlIixmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIGsoe25hbWU6InAtYmVmb3JlIixmdWxsQXJnczpuLGNhbkNvbnRhaW5UeXBlZFZhcnM6ITEsbWFrZVJlZ0V4cFN0cmluZzpmdW5jdGlvbihlKXtyZXR1cm4iKD89IitlLmpvaW4oIiIpKyIpIn19KX0sbykoWyJwLXN0YXJ0IiwicGF0dGVybi1zdGFydCJdLCJEYXRhdHlwZSIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBrKHtuYW1lOiJwLXN0YXJ0IixmdWxsQXJnczpuLG1ha2VSZWdFeHBTdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuIl4oPzoiK2Uuam9pbigiIikrIikifX0pfSxvKShbInAtZW5kIiwicGF0dGVybi1lbmQiXSwiRGF0YXR5cGUiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gayh7bmFtZToicC1lbmQiLGZ1bGxBcmdzOm4sbWFrZVJlZ0V4cFN0cmluZzpmdW5jdGlvbihlKXtyZXR1cm4iKD86IitlLmpvaW4oIiIpKyIpJCJ9fSl9LG8pKFsicC1tYW55IiwicGF0dGVybi1tYW55Il0sIkRhdGF0eXBlIixmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07dmFyIGEsbyxpLHM9bi5zbGljZSgpO3JldHVybiJudW1iZXIiPT10eXBlb2YgblswXSYmKGE9bi5zaGlmdCgpLG89Im51bWJlciI9PXR5cGVvZiBuWzBdP24uc2hpZnQoKToxLzApLCEodm9pZCAwIT09byYmbzxhKSYmbi5sZW5ndGg/KGk9bi5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciIT10eXBlb2YgZSYmIWIuaXNQcm90b3R5cGVPZihlKSYmIWguaXNQcm90b3R5cGVPZihlKX0pKT92LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGlzIChwLW1hbnk6KSBtYWNybyBjYW4gb25seSBiZSBnaXZlbiBhIG1pbiBhbmQgbWF4IG51bWJlciBmb2xsb3dlZCBieSBkYXRhdHlwZXMgb3Igc3RyaW5ncywgYnV0IHdhcyBhbHNvIGdpdmVuICIrTyhpKSsiLiIpOmsoe25hbWU6InAtbWFueSIsYXJnczpuLGZ1bGxBcmdzOnMsY2FuQ29udGFpblR5cGVkVmFyczowPGEsbWFrZVJlZ0V4cFN0cmluZzpmdW5jdGlvbihlKXtyZXR1cm4iKD86IitlLmpvaW4oIiIpKyIpIisodm9pZCAwIT09YT8ieyIrYSsobz09PTEvMD8iLCI6byE9PWE/IiwiK286IiIpKyJ9IjoiKyIpfX0pOnYuY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSAocC1tYW55OikgbWFjcm8gbmVlZHMgdG8gYmUgZ2l2ZW4gc3RyaW5nIHBhdHRlcm5zLCBub3QganVzdCBtaW4gYW5kIG1heCBudW1iZXJzLiIpfSxbbihyKHQsU3RyaW5nLGIsaCkpXSkoWyJwLWlucyIsInBhdHRlcm4taW5zIiwicC1pbnNlbnNpdGl2ZSIsInBhdHRlcm4taW5zZW5zaXRpdmUiXSwiRGF0YXR5cGUiLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gayh7bmFtZToicC1pbnMiLGZ1bGxBcmdzOm4saW5zZW5zaXRpdmU6ITB9KX0sbykoWyJzcGxpdCIsInNwbGl0dGVkIl0sIkFycmF5IixmdW5jdGlvbihlLHQsbil7aWYodD1rKHtuYW1lOiJzcGxpdCIsZnVsbEFyZ3M6W3RdLGNhbkNvbnRhaW5UeXBlZFZhcnM6ITF9KSx2LmNvbnRhaW5zRXJyb3IodCkpcmV0dXJuIHQ7aWYoIW4pcmV0dXJuWyIiXTtpZighdC5yZWdFeHApcmV0dXJuIF90b0NvbnN1bWFibGVBcnJheShuKTtmb3IodmFyIHIsYT1SZWdFeHAodC5yZWdFeHApLG89W107biYmKHI9YS5leGVjKG4pKTspe2lmKHIuaW5kZXgrclswXS5sZW5ndGg9PT0wKXJldHVybiBvO28ucHVzaChuLnNsaWNlKDAsci5pbmRleCkpLG49bi5zbGljZShyLmluZGV4K3JbMF0ubGVuZ3RoKX1yZXR1cm4gby5jb25jYXQobnx8W10pfSxbcihTdHJpbmcsYiksU3RyaW5nXSkoInRyaW1tZWQiLCJTdHJpbmciLGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdm9pZCAwPT09bnx8Yi5pc1Byb3RvdHlwZU9mKHQpJiYid2hpdGVzcGFjZSI9PT10Lm5hbWU/dC50cmltKCk6KHQ9ayh7bmFtZToidHJpbW1lZCIsZnVsbEFyZ3M6W3RdLGNhbkNvbnRhaW5UeXBlZFZhcnM6ITF9KSx2LmNvbnRhaW5zRXJyb3IodCk/dDp0LnJlZ0V4cD9uLnJlcGxhY2UoUmVnRXhwKCJeKCIrdC5yZWdFeHArIikqfCgiK3QucmVnRXhwKyIpKiQiLCJnIiksIiIpOm4pfSxbcihTdHJpbmcsYiksYShTdHJpbmcpXSkoWyJzdHItZmluZCIsInN0cmluZy1maW5kIl0sIlN0cmluZyIsZnVuY3Rpb24oZSx0LG4pe2lmKHQ9ayh7bmFtZToic3RyLWZpbmQiLGZ1bGxBcmdzOlt0XSxjYW5Db250YWluVHlwZWRHbG9iYWxzOiExfSksdi5jb250YWluc0Vycm9yKHQpKXJldHVybiB0O2Zvcih2YXIgcixhPXQudHlwZWRWYXJzKCksbz1SZWdFeHAodC5yZWdFeHAsImciKSxpPVtdLHM9by5sYXN0SW5kZXg7KHI9by5leGVjKG4pKSYmcyE9PW8ubGFzdEluZGV4OylpZihzPW8ubGFzdEluZGV4LGEubGVuZ3RoKXtmb3IodmFyIGM9bmV3IE1hcCxsPTA7bDxhLmxlbmd0aDtsKz0xKXtpZigibWF0Y2giPT09YVtsXS52YXJSZWYuZ2V0TmFtZSgpKXJldHVybiB2LmNyZWF0ZSgibWFjcm9jYWxsIiwiVGhlcmUgd2FzIGEgdHlwZWQgdGVtcCB2YXJpYWJsZSBuYW1lZCBfbWF0Y2ggaW4gdGhlIHBhdHRlcm4gZ2l2ZW4gdG8gKHN0ci1maW5kOikiLCJUaGUgdmFyaWFibGUgX21hdGNoIGlzIHJlc2VydmVkLCBhbmQgY2FuJ3QgYmUgdXNlZCBpbnNpZGUgKHN0ci1maW5kOikncyBwYXR0ZXJuLiIpO2Muc2V0KGFbbF0udmFyUmVmLmdldE5hbWUoKSxyW2wrMV0pLGMuc2V0KCJtYXRjaCIsclswXSl9aS5wdXNoKGMpfWVsc2UgaS5wdXNoKHJbMF0pO3JldHVybiBpfSxbYixTdHJpbmddKShbInN0ci1yZXBsYWNlZCIsInN0cmluZy1yZXBsYWNlZCIsInJlcGxhY2VkIl0sIlN0cmluZyIsZnVuY3Rpb24oZSx0LG4scixhKXtpZigibnVtYmVyIiE9dHlwZW9mIHQpe2lmKHZvaWQgMCE9PWEpcmV0dXJuIHYuY3JlYXRlKCJtYWNyb2NhbGwiLCIxIHRvbyBtYW55IHZhbHVlcyB3ZXJlIGdpdmVuIHRvIChzdHItcmVwbGFjZWQ6KS4iLCJJZiB0aGlzIGlzIGdpdmVuIDUgdmFsdWVzLCB0aGUgZmlyc3QgdmFsdWUgbXVzdCBiZSBhIG51bWJlciBvZiByZXBsYWNlbWVudHMuIik7YT1yLHI9bixuPXQsdD0xLzB9ZWxzZSBpZih2b2lkIDA9PT1hKXJldHVybiB2LmNyZWF0ZSgibWFjcm9jYWxsIiwiVGhlIChzdHItcmVwbGFjZWQ6KSBtYWNybyBuZWVkcyAxIG1vcmUgdmFsdWUuIiwiVGhlIGZpbmFsIHN0cmluZyBzZWVtcyB0byBiZSBtaXNzaW5nLiIpO2lmKGIuaXNQcm90b3R5cGVPZihyKSlyZXR1cm4gdi5jcmVhdGUoImRhdGF0eXBlIiwiVGhlIHJlcGxhY2VtZW50IHZhbHVlIGZvciAoc3RyLXJlcGxhY2VkOikgbXVzdCBiZSBhIHN0cmluZyBvciBsYW1iZGEsIG5vdCAiLmNvbmNhdChPKHIpKSk7aWYoeS5pc1Byb3RvdHlwZU9mKGEpfHx5LmlzUHJvdG90eXBlT2YobikpcmV0dXJuIHYuY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSAiLmNvbmNhdCh5LmlzUHJvdG90eXBlT2YoYSk/ImZpbmFsIHN0cmluZyI6InNlYXJjaCBwYXR0ZXJuIiwiIGdpdmVuIHRvIChzdHItcmVwbGFjZWQ6KSBjYW4ndCBiZSBhIGxhbWJkYS4iKSwiT25seSB0aGUgcmVwbGFjZW1lbnQgdmFsdWUgKGFmdGVyIHRoZSBzZWFyY2ggcGF0dGVybikgY2FuIGJlIGEgJ3ZpYScgbGFtYmRhLiIpO2lmKG49ayh7bmFtZToic3RyLXJlcGxhY2VkIixmdWxsQXJnczpbbl0sY2FuQ29udGFpblR5cGVkR2xvYmFsczohMX0pLHYuY29udGFpbnNFcnJvcihuKSlyZXR1cm4gbjtpZighbi5yZWdFeHApcmV0dXJuIGE7Zm9yKHZhciBvLGk9UmVnRXhwKG4ucmVnRXhwLCJnIikscz15LmlzUHJvdG90eXBlT2Yocik/bi50eXBlZFZhcnMoKTpbXSxjPTEsbD0wLHU9IiIscD1pLmxhc3RJbmRleDthJiYobz1pLmV4ZWMoYSkpJiYwPHQmJnAhPT1pLmxhc3RJbmRleDspe2Zvcih2YXIgcD1pLmxhc3RJbmRleCxkPU9iamVjdC5jcmVhdGUoZS5zdGFjay5sZW5ndGg/ZS5zdGFja1RvcC50ZW1wVmFyaWFibGVzOncpLGY9MDtmPHMubGVuZ3RoO2YrPTEpe3ZhciBoPXNbZl0sbT1oLnZhclJlZi5jcmVhdGUoZCxoLnZhclJlZi5wcm9wZXJ0eUNoYWluKTtpZih2LmNvbnRhaW5zRXJyb3IobSkpcmV0dXJuIG07aD1tLmRlZmluZVR5cGUoaC5kYXRhdHlwZSk7aWYodi5jb250YWluc0Vycm9yKGgpKXJldHVybiBoO20uc2V0KG9bZisxXSl9dmFyIGc9eS5pc1Byb3RvdHlwZU9mKHIpP3IuYXBwbHkoZSx7bG9vcDpvWzBdLHBvczpjLHRlbXBWYXJpYWJsZXM6ZH0pOnI7aWYodi5jb250YWluc0Vycm9yKGcpKXJldHVybiBnO2lmKCJzdHJpbmciIT10eXBlb2YgZylyZXR1cm4gdi5jcmVhdGUoImRhdGF0eXBlIiwiKHN0ci1yZXBsYWNlZDopJ3MgbGFtYmRhIG11c3QgcHJvZHVjZSBhIHN0cmluZywgYnV0IGl0IHByb2R1Y2VkICIuY29uY2F0KE8oZyksJyB3aGVuIGdpdmVuICInKS5jb25jYXQob1swXSwnIi4nKSk7dSs9YS5zbGljZShsLG8uaW5kZXgpK2csYys9MSwtLXQsbD1vLmluZGV4K29bMF0ubGVuZ3RofXJldHVybiB1Kz1hLnNsaWNlKGwpfSxbcih0LFN0cmluZyxiKSxyKGIsU3RyaW5nLHkuVHlwZVNpZ25hdHVyZSgidmlhIikpLHIoU3RyaW5nLHkuVHlwZVNpZ25hdHVyZSgidmlhIikpLGEoU3RyaW5nKV0pfSksZGVmaW5lKCJtYWNyb2xpYi9zdHlsZWNoYW5nZXJzIixbImpxdWVyeSIsIm1hY3JvcyIsInV0aWxzIiwidXRpbHMvcmVuZGVydXRpbHMiLCJkYXRhdHlwZXMvY29sb3VyIiwiZGF0YXR5cGVzL2hvb2tzZXQiLCJkYXRhdHlwZXMvZ3JhZGllbnQiLCJkYXRhdHlwZXMvY2hhbmdlcmNvbW1hbmQiLCJkYXRhdHlwZXMvbGFtYmRhIiwiaW50ZXJuYWx0eXBlcy9jaGFuZ2VkZXNjcmlwdG9yIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24ocyxlLGMsdCxhLG4scixvLGksbCx1KXt2YXIgcCxkLGY9dC5nZW9tUGFyc2UsaD10Lmdlb21TdHJpbmdSZWdFeHAsbT1PYmplY3QuYXNzaWduLHQ9ZS5UeXBlU2lnbmF0dXJlLGc9dC5laXRoZXIseT10LndyYXBwZWQsYj10Lm9wdGlvbmFsLHY9dC5Bbnksdz10LkV2ZXJ5dGhpbmcsaz10Lnplcm9Pck1vcmUsUz10LnJlc3QsVD10Lmluc2Vuc2l0aXZlU2V0LF89dC5wb3NpdGl2ZU51bWJlcix4PXQucG9zaXRpdmVJbnRlZ2VyLE89dC5ub25OZWdhdGl2ZU51bWJlcix0PXQucGVyY2VudCx5PVt5KEJvb2xlYW4sJ0lmIHlvdSBnYXZlIGEgbnVtYmVyLCB5b3UgbWF5IGluc3RlYWQgd2FudCB0byBjaGVjayB0aGF0IHRoZSBudW1iZXIgaXMgbm90IDAuIElmIHlvdSBnYXZlIGEgc3RyaW5nLCB5b3UgbWF5IGluc3RlYWQgd2FudCB0byBjaGVjayB0aGF0IHRoZSBzdHJpbmcgaXMgbm90ICIiLicpXSxBPShjLm9uU3RhcnR1cChmdW5jdGlvbigpe3JldHVybiBjLnN0b3J5RWxlbWVudC5vbigibW91c2VlbnRlci5ob3Zlci1tYWNybyIsIltob3Zlcj1mYWxzZV0iLGZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKSx0PWUuZGF0YSgiaG92ZXJDaGFuZ2VyIik7Yy5vcHRpb25zLmRlYnVnJiZjLm9wdGlvbnMuaWdub3JlQ2xpY2tFdmVudHMmJiFlLmlzKCJ0dy1iYWNrZHJvcC5ldmFsLXJlcGxheSAqLCB0dy1iYWNrZHJvcC5oYXJsb3dlLWNyYXNoICoiKXx8KGUuZGF0YSh7bW91c2VvdXRTdHlsZTplLmF0dHIoInN0eWxlIil8fCIifSksbC5jcmVhdGUoe3RhcmdldDplfSx0KS51cGRhdGUoKSxlLmF0dHIoImhvdmVyIiwhMCkpfSkub24oIm1vdXNlbGVhdmUuaG92ZXItbWFjcm8iLCJbaG92ZXI9dHJ1ZV0iLGZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKSx0PWUuZGF0YSgibW91c2VvdXRTdHlsZSIpO2UuYXR0cigic3R5bGUiLHQpLnJlbW92ZURhdGEoIm1vdXNlb3V0U3R5bGUiKS5hdHRyKCJob3ZlciIsITEpfSl9KSx1Lm9uKGZ1bmN0aW9uKCl7cygidHctZXhwcmVzc2lvbiwgdHctaG9vayIsYy5zdG9yeUVsZW1lbnQpLmVhY2goZnVuY3Rpb24oZSx0KXsoKHQ9cyh0KSkuZGF0YSgiZXJyb3JFdmVudCIpfHxPYmplY3QpKHQpfSl9KSxUKCJpbnN0YW50IiwiZGlzc29sdmUiLCJmYWRlIiwicnVtYmxlIiwic2h1ZGRlciIsInB1bHNlIiwiem9vbSIsImZsaWNrZXIiLCJzbGlkZWxlZnQiLCJzbGlkZXJpZ2h0Iiwic2xpZGV1cCIsInNsaWRlZG93biIsImZhZGVsZWZ0IiwiZmFkZXJpZ2h0IiwiZmFkZXVwIiwiZmFkZWRvd24iLCJibHVyIikpLEM9VCgiZG90dGVkIiwiZGFzaGVkIiwic29saWQiLCJkb3VibGUiLCJncm9vdmUiLCJyaWRnZSIsImluc2V0Iiwib3V0c2V0Iiwibm9uZSIpO2UuYWRkQ2hhbmdlcigiaWYiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlKCJpZiIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5lbmFibGVkPWUuZW5hYmxlZCYmdH0seSkoInVubGVzcyIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoInVubGVzcyIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5lbmFibGVkPWUuZW5hYmxlZCYmIXR9LHkpKCJlbHNlaWYiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuImxhc3RIb29rU2hvd24iaW4gZS5zdGFja1swXT9vLmNyZWF0ZSgiZWxzZWlmIixbITE9PT1lLnN0YWNrWzBdLmxhc3RIb29rU2hvd24mJiEhdF0pOnUuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGVyZSdzIG5vIChpZjopIG9yIHNvbWV0aGluZyBlbHNlIGJlZm9yZSB0aGlzIHRvIGRvIChlbHNlLWlmOikgd2l0aC4iKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5lbmFibGVkPWUuZW5hYmxlZCYmdH0seSkoImVsc2UiLGZ1bmN0aW9uKGUpe3JldHVybiJsYXN0SG9va1Nob3duImluIGUuc3RhY2tbMF0/by5jcmVhdGUoImVsc2UiLFshMT09PWUuc3RhY2tbMF0ubGFzdEhvb2tTaG93bl0pOnUuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGVyZSdzIG5vdGhpbmcgYmVmb3JlIHRoaXMgdG8gZG8gKGVsc2U6KSB3aXRoLiIpfSxmdW5jdGlvbihlLHQpe3JldHVybiBlLmVuYWJsZWQ9ZS5lbmFibGVkJiZ0fSxudWxsKSgiaGlkZGVuIixmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgiaGlkZGVuIil9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmVuYWJsZWQ9ITF9LG51bGwpKFsidmVyYmF0aW0iLCJ2Nm0iXSxmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgidmVyYmF0aW0iKX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudmVyYmF0aW09ITB9LG51bGwpKCJsaXZlIixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgibGl2ZSIsdD9bdF06W10pfSxmdW5jdGlvbihlLHQpe2UuZW5hYmxlZD0hMSxlLnRyYW5zaXRpb25EZWZlcnJlZD0hMCxlLmRhdGEubGl2ZT17ZGVsYXk6dH19LGIoTnVtYmVyKSkoImV2ZW50IixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgiZXZlbnQiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7ZS5lbmFibGVkPSExLGUudHJhbnNpdGlvbkRlZmVycmVkPSEwLGUuZGF0YS5saXZlPXtldmVudDp0fX0saS5UeXBlU2lnbmF0dXJlKCJ3aGVuIikpKCJtb3JlIixmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgibW9yZSIpfSxmdW5jdGlvbihlKXtlLmVuYWJsZWQ9ITEsZS50cmFuc2l0aW9uRGVmZXJyZWQ9ITAsZS5kYXRhLmxpdmU9e2V2ZW50Ont3aGVuOiEwLGZpbHRlcjpmdW5jdGlvbihlKXtyZXR1cm4gMCE9PWUuSWRlbnRpZmllcnMuZXhpdHM/W106WyEwXX19fX0sbnVsbCkoImFmdGVyIixmdW5jdGlvbihlLHQsbil7cmV0dXJuIG8uY3JlYXRlKCJhZnRlciIsW3RdLmNvbmNhdCh2b2lkIDAhPT1uP1tuXTpbXSkpfSxmdW5jdGlvbihlLHQsbil7ZS5lbmFibGVkPSExLGUudHJhbnNpdGlvbkRlZmVycmVkPSEwLGUuZGF0YS5saXZlPXtldmVudDp7d2hlbjohMCxmaWx0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGMuYW55SW5wdXREb3duKCkmJm4mJih0LT1uKSxlLklkZW50aWZpZXJzLnRpbWU+dD9bITBdOltdfX19fSxbXyxiKE8pXSkoImFmdGVyLWVycm9yIixmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgiYWZ0ZXItZXJyb3IiLFtdKX0sZnVuY3Rpb24obil7bi5lbmFibGVkPSExLG4udHJhbnNpdGlvbkRlZmVycmVkPSEwO3ZhciByPW4uc2VjdGlvbi5zdGFja1RvcC50ZW1wVmFyaWFibGVzO24uZGF0YS5lcnJvckV2ZW50PWZ1bmN0aW9uKGUpe2UucmVtb3ZlRGF0YSgiZXJyb3JFdmVudCIpO3ZhciB0PV9vYmplY3RTcHJlYWQoX29iamVjdFNwcmVhZCh7fSxuKSx7fSx7ZW5hYmxlZDohMCx0cmFuc2l0aW9uRGVmZXJyZWQ6ITF9KTt0LmRhdGEmJih0LmRhdGEuZXJyb3JFdmVudD12b2lkIDApLG4uc2VjdGlvbi53aGVuVW5ibG9ja2VkKGZ1bmN0aW9uKCl7cmV0dXJuIG4uc2VjdGlvbi5yZW5kZXJJbnRvKCIiLG51bGwsdCxyKX0pfX0sW10pKCJob29rIixmdW5jdGlvbihlLHQpe3ZhciBuO3JldHVybiB0PyhuPWMuaW5zZW5zaXRpdmVOYW1lKHQpKT9vLmNyZWF0ZSgiaG9vayIsW25dKTp1LmNyZWF0ZSgiZGF0YXR5cGUiLCdUaGUgc3RyaW5nIGdpdmVuIHRvIChob29rOiksICInLmNvbmNhdCh0LCciLCBjb250YWluZWQgb25seSBkYXNoZXMgYW5kIHVuZGVyc2NvcmVzLicpKTp1LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgc3RyaW5nIGdpdmVuIHRvIChob29rOikgd2FzIGVtcHR5LiIpfSxmdW5jdGlvbihlLHQpe3JldHVybiBlLmF0dHIucHVzaCh7bmFtZTp0fSl9LFtTdHJpbmddKShbImZvciIsImxvb3AiXSxmdW5jdGlvbihlLHQpe2lmKCF0Lmxvb3ApcmV0dXJuIHUuY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSBsYW1iZGEgcHJvdmlkZWQgdG8gKGZvcjopIG11c3QgcmVmZXIgdG8gYSB0ZW1wIHZhcmlhYmxlLCBub3QganVzdCAnaXQnLiIpO2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTtyZXR1cm4gby5jcmVhdGUoImZvciIsW3RdLmNvbmNhdChyKSl9LGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1uZXcgQXJyYXkoMjxuP24tMjowKSxhPTI7YTxuO2ErKylyW2EtMl09YXJndW1lbnRzW2FdO3ZhciBvLGk9dC5maWx0ZXIoZS5zZWN0aW9uLHIpO2lmKG89dS5jb250YWluc0Vycm9yKGkpKXJldHVybiBvO2UubG9vcFZhcnNbdC5sb29wLmdldE5hbWUoKV09aXx8W119LFtpLlR5cGVTaWduYXR1cmUoIndoZXJlIiksayh2KV0pKFsidHJhbnNpdGlvbiIsInQ4biJdLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlKCJ0cmFuc2l0aW9uIixbYy5pbnNlbnNpdGl2ZU5hbWUodCldKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4iem9vbSI9PT0oZS50cmFuc2l0aW9uPXQpJiYoZS50cmFuc2l0aW9uT3JpZ2luPWZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKS5vZmZzZXQoKSx0PWUubGVmdCxlPWUudG9wO3JldHVybiBjLm1vdXNlQ29vcmRzLngtdCsicHggIisoYy5tb3VzZUNvb3Jkcy55LWUpKyJweCJ9KSxlfSxbQV0pKFsidHJhbnNpdGlvbi10aW1lIiwidDhuLXRpbWUiXSxmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgidHJhbnNpdGlvbi10aW1lIixbdF0pfSxmdW5jdGlvbihlLHQpe3JldHVybiBlLnRyYW5zaXRpb25UaW1lPXQsZS5kYXRhLnBhc3NhZ2VUOG49bShlLmRhdGEucGFzc2FnZVQ4bnx8e30se3RpbWU6dH0pLGV9LFtfXSkoWyJ0cmFuc2l0aW9uLWRlbGF5IiwidDhuLWRlbGF5Il0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoInRyYW5zaXRpb24tZGVsYXkiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUudHJhbnNpdGlvbkRlbGF5PXQsZX0sW09dKShbInRyYW5zaXRpb24tc2tpcCIsInQ4bi1za2lwIl0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoInRyYW5zaXRpb24tc2tpcCIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS50cmFuc2l0aW9uU2tpcD10LGV9LFtfXSkoWyJ0cmFuc2l0aW9uLWRlcGFydCIsInQ4bi1kZXBhcnQiXSxmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgidHJhbnNpdGlvbi1kZXBhcnQiLFtjLmluc2Vuc2l0aXZlTmFtZSh0KV0pfSxmdW5jdGlvbihlLHQpe3JldHVybiBlLmRhdGEucGFzc2FnZVQ4bj1tKGUuZGF0YS5wYXNzYWdlVDhufHx7fSx7ZGVwYXJ0OnR9KSwiem9vbSI9PT10JiYoZS5kYXRhLnBhc3NhZ2VUOG4uZGVwYXJ0T3JpZ2luPWZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKS5vZmZzZXQoKSx0PWUubGVmdCxlPWUudG9wO3JldHVybiBjLm1vdXNlQ29vcmRzLngtdCsicHggIisoYy5tb3VzZUNvb3Jkcy55LWUpKyJweCJ9KSxlfSxbQV0pKFsidHJhbnNpdGlvbi1hcnJpdmUiLCJ0OG4tYXJyaXZlIl0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoInRyYW5zaXRpb24tYXJyaXZlIixbYy5pbnNlbnNpdGl2ZU5hbWUodCldKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5kYXRhLnBhc3NhZ2VUOG49bShlLmRhdGEucGFzc2FnZVQ4bnx8e30se2Fycml2ZTp0fSksInpvb20iPT09dCYmKGUuZGF0YS5wYXNzYWdlVDhuLmFycml2ZU9yaWdpbj1mdW5jdGlvbigpe3ZhciBlPXModGhpcyksdD1lLm9mZnNldCgpLG49dC5sZWZ0LHQ9dC50b3Ascj1lLmhlaWdodCgpO3JldHVybnsidHJhbnNmb3JtLW9yaWdpbiI6MTAwKihjLm1vdXNlQ29vcmRzLngtbikvZS53aWR0aCgpKyIlICIrMTAwKihjLm1vdXNlQ29vcmRzLnktdCkvcisiJSIsaGVpZ2h0OnIrInB4In19KSxlfSxbQV0pKCJidXR0b24iLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHZvaWQgMD09PXR8fGYodCkuc2l6ZT9vLmNyZWF0ZSgiYnV0dG9uIix0P1t0XTpbXSk6dS5jcmVhdGUoImRhdGF0eXBlIiwnVGhlIHN0cmluZyBnaXZlbiB0byAoYnV0dG9uOikgc2hvdWxkIGJlIGEgc2l6aW5nIGxpbmUgKCI9PVg9PSIsICI9PVgiLCAiPVhYWFg9IiBldGMuKSwgbm90ICcuY29uY2F0KEpTT04uc3RyaW5naWZ5KHQpLCIuIikpfSxmdW5jdGlvbihlLHQpe3ZhciB0PWYodCksbj10Lm1hcmdpbkxlZnQsdD10LnNpemU7cmV0dXJuIGUuYXR0ci5wdXNoKHtjbGFzczpmdW5jdGlvbigpe3JldHVybiB0aGlzLmNsYXNzTmFtZSsodGhpcy5jbGFzc0xpc3QuY29udGFpbnMoImVuY2hhbnRtZW50LWJ1dHRvbiIpPyIiOiIgIi5yZXBlYXQoMDx0aGlzLmNsYXNzTmFtZS5sZW5ndGgpKyJlbmNoYW50bWVudC1idXR0b24iKX19KSxlLnN0eWxlcy5wdXNoKHsibWFyZ2luLWxlZnQiOnQ/bisiJSI6dm9pZCAwLHdpZHRoOnQ/dCsiJSI6IjEwMCUifSksZX0sW2IoU3RyaW5nKV0pLmFwcGx5KHZvaWQgMCxfdG9Db25zdW1hYmxlQXJyYXkoKGQ9e2NsaWNrOntjbGFzc05hbWU6ImVuY2hhbnRtZW50LWxpbmsiLGJsb2NrQ2xhc3NOYW1lOiJlbmNoYW50bWVudC1jbGlja2Jsb2NrIn0sZG91YmxlY2xpY2s6e2NsYXNzTmFtZToiZW5jaGFudG1lbnQtZGJsY2xpY2siLGJsb2NrQ2xhc3NOYW1lOiJlbmNoYW50bWVudC1kYmxjbGlja2Jsb2NrIn0sbW91c2VvdmVyOntjbGFzc05hbWU6ImVuY2hhbnRtZW50LW1vdXNlb3ZlciIsYmxvY2tDbGFzc05hbWU6ImVuY2hhbnRtZW50LW1vdXNlb3ZlcmJsb2NrIn0sbW91c2VvdXQ6e2NsYXNzTmFtZToiZW5jaGFudG1lbnQtbW91c2VvdXQiLGJsb2NrQ2xhc3NOYW1lOiJlbmNoYW50bWVudC1tb3VzZW91dGJsb2NrIn19LFsiYWN0aW9uIixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgiYWN0aW9uIixbYy5pbnNlbnNpdGl2ZU5hbWUodCldKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5hdHRyLnB1c2goe2NsYXNzOmZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24gZSh0KXtyZXR1cm4odD1zKHQpKS5pcygidHctc3RvcnksIHR3LXNpZGViYXIsIHR3LXBhc3NhZ2UiKXx8WyJibG9jayIsImZsZXgiXS5pbmNsdWRlcyh0LmNzcygiZGlzcGxheSIpKXx8dC5jaGlsZHJlbigpLmdldCgpLnNvbWUoZSl9KHRoaXMpO3JldHVybiBBcnJheS5mcm9tKHRoaXMuY2xhc3NMaXN0KS5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIU9iamVjdC5rZXlzKGQpLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGRbZV0uY2xhc3NOYW1lPT09dHx8ZFtlXS5ibG9ja0NsYXNzTmFtZT09PXR9KX0pLmNvbmNhdChkW3RdW2U/ImJsb2NrQ2xhc3NOYW1lIjoiY2xhc3NOYW1lIl0pLmpvaW4oIiAiKX19KSxlfSxbVC5hcHBseSh2b2lkIDAsX3RvQ29uc3VtYWJsZUFycmF5KE9iamVjdC5rZXlzKGQpKSldXSkpKShbImJvcmRlciIsImI0ciJdLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gby5jcmVhdGUoImJvcmRlciIsbi5tYXAoYy5pbnNlbnNpdGl2ZU5hbWUpKX0sZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBlLnN0eWxlcy5wdXNoKHtkaXNwbGF5OmZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKS5jc3MoImRpc3BsYXkiKTtyZXR1cm4gbi5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4ibm9uZSI9PT1lfSl8fCFlLmluY2x1ZGVzKCJpbmxpbmUiKT9lOiJpbmxpbmUtYmxvY2sifSwiYm9yZGVyLXN0eWxlIjpuLmpvaW4oIiAiKSwiYm9yZGVyLXdpZHRoIjpmdW5jdGlvbigpe3JldHVybiB0aGlzLnN0eWxlLmJvcmRlcldpZHRofHwiMnB4In19KSxlfSxbQ10uY29uY2F0KF90b0NvbnN1bWFibGVBcnJheShBcnJheSgzKS5maWxsKGIoQykpKSkpKFsiYm9yZGVyLXNpemUiLCJiNHItc2l6ZSJdLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gby5jcmVhdGUoImJvcmRlci1zaXplIixuKX0sZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBlLnN0eWxlcy5wdXNoKHsiYm9yZGVyLXdpZHRoIjpuLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZSsicHgifSkuam9pbigiICIpfSksZX0sW09dLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoQXJyYXkoMykuZmlsbChiKE8pKSkpKSgiY29ybmVyLXJhZGl1cyIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBvLmNyZWF0ZSgiY29ybmVyLXJhZGl1cyIsbil9LGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gZS5zdHlsZXMucHVzaCh7ImJvcmRlci1yYWRpdXMiOm4ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlKyJweCJ9KS5qb2luKCIgIikscGFkZGluZzpmdW5jdGlvbigpe3JldHVybiB0aGlzLnN0eWxlLnBhZGRpbmd8fG4ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlKyJweCJ9KS5qb2luKCIgIil9fSksZX0sW09dLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoQXJyYXkoMykuZmlsbChiKE8pKSkpKShbImJvcmRlci1jb2xvdXIiLCJiNHItY29sb3VyIiwiYm9yZGVyLWNvbG9yIiwiYjRyLWNvbG9yIl0sZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBvLmNyZWF0ZSgiYm9yZGVyLWNvbG91ciIsbi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGEuaXNQcm90b3R5cGVPZihlKT9lLnRvUkdCQVN0cmluZyhlKTplfSkpfSxmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIGUuc3R5bGVzLnB1c2goeyJib3JkZXItY29sb3IiOm4uam9pbigiICIpfSksZX0sW2coU3RyaW5nLGEpXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KEFycmF5KDMpLmZpbGwoYihnKFN0cmluZyxhKSkpKSkpKCJvcGFjaXR5IixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgib3BhY2l0eSIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5zdHlsZXMucHVzaCh7b3BhY2l0eTp0fSl9LFt0XSkoImZvbnQiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlKCJmb250IixbdF0pfSxmdW5jdGlvbihlLHQpe3JldHVybiBlLnN0eWxlcy5wdXNoKHsiZm9udC1mYW1pbHkiOnR9KSxlfSxbU3RyaW5nXSkoImFsaWduIixmdW5jdGlvbihlLHQpe3ZhciBuPXQuaW5kZXhPZigiPjwiKTtyZXR1cm4vXig9PSs+fDw9K3w9Kz48PSt8PD09Kz4pJC8udGVzdCh0KT8oKG49fm4/X29iamVjdFNwcmVhZCh7InRleHQtYWxpZ24iOiJjZW50ZXIiLCJtYXgtd2lkdGgiOiI1MCUifSwyNT09PShuPU1hdGgucm91bmQobi8odC5sZW5ndGgtMikqNTApKT97Im1hcmdpbi1sZWZ0IjoiYXV0byIsIm1hcmdpbi1yaWdodCI6ImF1dG8ifTp7Im1hcmdpbi1sZWZ0IjpuKyIlIn0pOiI8Ij09PXRbMF0mJiI+Ij09PXQuc2xpY2UoLTEpP3sidGV4dC1hbGlnbiI6Imp1c3RpZnkiLCJtYXgtd2lkdGgiOiI1MCUifTp0LmluY2x1ZGVzKCI+Iik/eyJ0ZXh0LWFsaWduIjoicmlnaHQifTp7InRleHQtYWxpZ24iOiJsZWZ0In0pLmRpc3BsYXk9ImJsb2NrIixvLmNyZWF0ZSgiYWxpZ24iLFtuXSkpOnUuY3JlYXRlKCJkYXRhdHlwZSIsJ1RoZSAoYWxpZ246KSBtYWNybyByZXF1aXJlcyBhbiBhbGlnbm1lbnQgYXJyb3cgKCI9PT4iLCAiPD09IiwgIj09Pjw9IiBldGMuKSBiZSBwcm92aWRlZCwgbm90ICInK3QrJyInKX0sZnVuY3Rpb24oZSx0KXtlLnN0eWxlcy5wdXNoKHQpfSxbU3RyaW5nXSkoWyJ0ZXh0LWNvbG91ciIsInRleHQtY29sb3IiLCJjb2xvciIsImNvbG91ciJdLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlKCJ0ZXh0LWNvbG91ciIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gYS5pc1Byb3RvdHlwZU9mKHQpJiYodD10LnRvUkdCQVN0cmluZyh0KSksZS5zdHlsZXMucHVzaCh7Y29sb3I6dH0pLGV9LFtnKFN0cmluZyxhKV0pKFsidGV4dC1zaXplIiwic2l6ZSJdLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlKCJ0ZXh0LXNpemUiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuc3R5bGVzLnB1c2goeyJmb250LXNpemUiOjI0KnQrInB4IiwibGluZS1oZWlnaHQiOjM2KnQrInB4In0pLGV9LFtPXSkoInRleHQtaW5kZW50IixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgidGV4dC1pbmRlbnQiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuc3R5bGVzLnB1c2goeyJ0ZXh0LWluZGVudCI6dCsicHgiLGRpc3BsYXk6ImlubGluZS1ibG9jayJ9KSxlfSxbT10pKFsidGV4dC1yb3RhdGUteiIsInRleHQtcm90YXRlIl0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoInRleHQtcm90YXRlLXoiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuc3R5bGVzLnB1c2goe2Rpc3BsYXk6ImlubGluZS1ibG9jayIsdHJhbnNmb3JtOmZ1bmN0aW9uKCl7dmFyIGU9cyh0aGlzKS5jc3MoInRyYW5zZm9ybSIpfHwiIjtyZXR1cm4oZT0ibm9uZSI9PT1lPyIiOmUpKyIgcm90YXRlKCIrdCsiZGVnKSJ9fSksZX0sW051bWJlcl0pKCJ0ZXh0LXJvdGF0ZS15IixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgidGV4dC1yb3RhdGUteSIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5zdHlsZXMucHVzaCh7ZGlzcGxheToiaW5saW5lLWJsb2NrIix0cmFuc2Zvcm06ZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpLmNzcygidHJhbnNmb3JtIil8fCIiO3JldHVybihlPSJub25lIj09PWU/IiI6ZSkrIiBwZXJzcGVjdGl2ZSg1MHZ3KSByb3RhdGVZKCIrdCsiZGVnKSJ9fSksZX0sW051bWJlcl0pKCJ0ZXh0LXJvdGF0ZS14IixmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZSgidGV4dC1yb3RhdGUteCIsW3RdKX0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5zdHlsZXMucHVzaCh7ZGlzcGxheToiaW5saW5lLWJsb2NrIix0cmFuc2Zvcm06ZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpLmNzcygidHJhbnNmb3JtIil8fCIiO3JldHVybihlPSJub25lIj09PWU/IiI6ZSkrIiBwZXJzcGVjdGl2ZSg1MHZ3KSByb3RhdGVYKCIrdCsiZGVnKSJ9fSksZX0sW051bWJlcl0pKFsiYmFja2dyb3VuZCIsImJnIl0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGUoImJhY2tncm91bmQiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGEuaXNQcm90b3R5cGVPZih0KT90PXQudG9SR0JBU3RyaW5nKCk6ci5pc1Byb3RvdHlwZU9mKHQpJiYodD10LnRvTGluZWFyR3JhZGllbnRTdHJpbmcoKSksdD1hLmlzSGV4U3RyaW5nKHQpfHxhLmlzQ1NTM0Z1bmN0aW9uKHQpP3siYmFja2dyb3VuZC1jb2xvciI6dH06dC5zdGFydHNXaXRoKCJsaW5lYXItZ3JhZGllbnQoIil8fHQuc3RhcnRzV2l0aCgicmVwZWF0aW5nLWxpbmVhci1ncmFkaWVudCgiKT97ImJhY2tncm91bmQtaW1hZ2UiOnR9OnsiYmFja2dyb3VuZC1zaXplIjoiY292ZXIiLCJiYWNrZ3JvdW5kLWltYWdlIjoidXJsKCIuY29uY2F0KHQsIikiKSwiYmFja2dyb3VuZC1hdHRhY2htZW50IjoiZml4ZWQifSxlLnN0eWxlcy5wdXNoKHQse2Rpc3BsYXk6ZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpO3JldHVybiFlLmNoaWxkcmVuKCkubGVuZ3RofHxjLmNoaWxkcmVuUHJvYmFibHlJbmxpbmUoZSk/cyh0aGlzKS5jc3MoImRpc3BsYXkiKToiYmxvY2sifX0pLGV9LFtnKFN0cmluZyxhLHIpXSkuYXBwbHkodm9pZCAwLF90b0NvbnN1bWFibGVBcnJheSgoeT17Y29sb3I6ZnVuY3Rpb24oKXtyZXR1cm4idHJhbnNwYXJlbnQifX0scD1tKE9iamVjdC5jcmVhdGUobnVsbCkse25vbmU6e30sYm9sZDp7ImZvbnQtd2VpZ2h0IjoiYm9sZCJ9LGl0YWxpYzp7ImZvbnQtc3R5bGUiOiJpdGFsaWMifSx1bmRlcmxpbmU6eyJ0ZXh0LWRlY29yYXRpb24iOiJ1bmRlcmxpbmUifSxkb3VibGV1bmRlcmxpbmU6eyJ0ZXh0LWRlY29yYXRpb24iOiJ1bmRlcmxpbmUiLCJ0ZXh0LWRlY29yYXRpb24tc3R5bGUiOiJkb3VibGUifSx3YXZ5dW5kZXJsaW5lOnsidGV4dC1kZWNvcmF0aW9uIjoidW5kZXJsaW5lIiwidGV4dC1kZWNvcmF0aW9uLXN0eWxlIjoid2F2eSJ9LHN0cmlrZTp7InRleHQtZGVjb3JhdGlvbiI6ImxpbmUtdGhyb3VnaCJ9LGRvdWJsZXN0cmlrZTp7InRleHQtZGVjb3JhdGlvbiI6ImxpbmUtdGhyb3VnaCIsInRleHQtZGVjb3JhdGlvbi1zdHlsZSI6ImRvdWJsZSJ9LHdhdnlzdHJpa2U6eyJ0ZXh0LWRlY29yYXRpb24iOiJsaW5lLXRocm91Z2giLCJ0ZXh0LWRlY29yYXRpb24tc3R5bGUiOiJ3YXZ5In0sc3VwZXJzY3JpcHQ6eyJ2ZXJ0aWNhbC1hbGlnbiI6InN1cGVyIiwiZm9udC1zaXplIjoiLjgzZW0ifSxzdWJzY3JpcHQ6eyJ2ZXJ0aWNhbC1hbGlnbiI6InN1YiIsImZvbnQtc2l6ZSI6Ii44M2VtIn0sYmxpbms6e2FuaW1hdGlvbjoiZmFkZS1pbi1vdXQgMXMgc3RlcHMoMSxlbmQpIGluZmluaXRlIGFsdGVybmF0ZSJ9LHNodWRkZXI6e2FuaW1hdGlvbjoic2h1ZGRlciBsaW5lYXIgMC4xcyAwcyBpbmZpbml0ZSJ9LG1hcms6eyJiYWNrZ3JvdW5kLWNvbG9yIjoiaHNsYSg2MCwgMTAwJSwgNTAlLCAwLjYpIn0sY29uZGVuc2U6eyJsZXR0ZXItc3BhY2luZyI6Ii0wLjA4ZW0ifSxleHBhbmQ6eyJsZXR0ZXItc3BhY2luZyI6IjAuMWVtIn0sb3V0bGluZTpbeyJ0ZXh0LXNoYWRvdyI6ZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpLmNzcygiY29sb3IiKTtyZXR1cm4iLTFweCAtMXB4IDAgIitlKyIsIDFweCAtMXB4IDAgIitlKyIsLTFweCAgMXB4IDAgIitlKyIsIDFweCAgMXB4IDAgIitlfX0se2NvbG9yOmZ1bmN0aW9uKCl7cmV0dXJuIGMucGFyZW50Q29sb3VycyhzKHRoaXMpKS5iYWNrZ3JvdW5kQ29sb3VyfX1dLHNoYWRvdzp7InRleHQtc2hhZG93IjpmdW5jdGlvbigpe3JldHVybiIwLjA4ZW0gMC4wOGVtIDAuMDhlbSAiK3ModGhpcykuY3NzKCJjb2xvciIpfX0sZW1ib3NzOnsidGV4dC1zaGFkb3ciOmZ1bmN0aW9uKCl7cmV0dXJuIjAuMDRlbSAwLjA0ZW0gMGVtICIrcyh0aGlzKS5jc3MoImNvbG9yIil9fSxzbWVhcjpbeyJ0ZXh0LXNoYWRvdyI6ZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpLmNzcygiY29sb3IiKTtyZXR1cm4iMGVtICAgMGVtIDAuMDJlbSAiK2UrIiwtMC4yZW0gMGVtICAwLjVlbSAiK2UrIiwgMC4yZW0gMGVtICAwLjVlbSAiK2V9fSx5XSxibHVyOlt7InRleHQtc2hhZG93IjpmdW5jdGlvbigpe3JldHVybiIwZW0gMGVtIDAuMDhlbSAiK3ModGhpcykuY3NzKCJjb2xvciIpfX0seV0sYmx1cnJpZXI6W3sidGV4dC1zaGFkb3ciOmZ1bmN0aW9uKCl7cmV0dXJuIjBlbSAwZW0gMC4yZW0gIitzKHRoaXMpLmNzcygiY29sb3IiKX0sInVzZXItc2VsZWN0Ijoibm9uZSJ9LHldLG1pcnJvcjp7ZGlzcGxheToiaW5saW5lLWJsb2NrIix0cmFuc2Zvcm06InNjYWxlWCgtMSkifSx1cHNpZGVkb3duOntkaXNwbGF5OiJpbmxpbmUtYmxvY2siLHRyYW5zZm9ybToic2NhbGVZKC0xKSJ9LHRhbGw6e2Rpc3BsYXk6ImlubGluZS1ibG9jayIsdHJhbnNmb3JtOiJzY2FsZVkoMS41KSB0cmFuc2xhdGVZKC0wLjI1ZXgpIn0sZmxhdDp7ZGlzcGxheToiaW5saW5lLWJsb2NrIix0cmFuc2Zvcm06InNjYWxlWSgwLjUpIHRyYW5zbGF0ZVkoMC4yNWV4KSJ9LGZhZGVpbm91dDp7YW5pbWF0aW9uOiJmYWRlLWluLW91dCAycyBlYXNlLWluLW91dCBpbmZpbml0ZSBhbHRlcm5hdGUifSxydW1ibGU6e2FuaW1hdGlvbjoicnVtYmxlIGxpbmVhciAwLjFzIDBzIGluZmluaXRlIn0sc3dheTp7YW5pbWF0aW9uOiJzd2F5IGxpbmVhciAyLjVzIDBzIGluZmluaXRlIn0sYnVveTp7YW5pbWF0aW9uOiJidW95IGxpbmVhciAyLjVzIDBzIGluZmluaXRlIn0sZmlkZ2V0OnthbmltYXRpb246ZnVuY3Rpb24oKXtyZXR1cm4iZmlkZ2V0IHN0ZXAtZW5kIDYwcyAiKzYwKi1NYXRoLnJhbmRvbSgpKyJzIGluZmluaXRlIisoTWF0aC5yYW5kb20oKTwuNT8iIHJldmVyc2UiOiIiKX19fSksWyJ0ZXh0LXN0eWxlIixmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIG8uY3JlYXRlKCJ0ZXh0LXN0eWxlIixuLm1hcChjLmluc2Vuc2l0aXZlTmFtZSkpfSxmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07Zm9yKHZhciBhPTA7YTxuLmxlbmd0aDthKz0xKSJub25lIj09PW5bYV0/ZS5zdHlsZXM9W106ZS5zdHlsZXM9ZS5zdHlsZXMuY29uY2F0KHBbblthXV0pO3JldHVybiBlfSxbUyhULmFwcGx5KHZvaWQgMCxfdG9Db25zdW1hYmxlQXJyYXkoT2JqZWN0LmtleXMocCkpKSldXSkpKSgiY29sbGFwc2UiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uY3JlYXRlKCJjb2xsYXBzZSIpfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hdHRyLnB1c2goe2NvbGxhcHNpbmc6ITB9KSxlfSxbXSkoImhvdmVyLXN0eWxlIixmdW5jdGlvbihlLHQpe3ZhciBuPWwuY3JlYXRlKCkscj0odC5ydW4obiksbi5zdW1tYXJ5KCkpO3JldHVybiByKyIiPT0ic3R5bGVzInx8ci5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4ic3R5bGVzIj09PWV8fCJhdHRyIj09PWV9KSYmbi5hdHRyLmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiBPYmplY3Qua2V5cyhlKSsiIj09InN0eWxlIn0pP28uY3JlYXRlKCJob3Zlci1zdHlsZSIsW3RdKTp1LmNyZWF0ZSgiZGF0YXR5cGUiLCJUaGUgY2hhbmdlciBnaXZlbiB0byAoaG92ZXItc3R5bGU6KSBtdXN0IG9ubHkgY2hhbmdlIHRoZSBob29rJ3Mgc3R5bGUuIil9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuZGF0YS5ob3ZlckNoYW5nZXI9dCxlLmF0dHIucHVzaCh7aG92ZXI6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdm9pZCAwIT09dCYmdH19KSxlfSxbb10pKCJjc3MiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQudHJpbSgpLmVuZHNXaXRoKCI7Iil8fCh0Kz0iOyIpLG8uY3JlYXRlKCJjc3MiLFt0XSl9LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuYXR0ci5wdXNoKHtzdHlsZTpmdW5jdGlvbigpe3JldHVybihzKHRoaXMpLmF0dHIoInN0eWxlIil8fCIiKSt0fX0pLGV9LFtTdHJpbmddKSgidGVzdC10cnVlIixmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgidGVzdC10cnVlIixbXSl9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmVuYWJsZWQ9ITB9LGsodykpKCJ0ZXN0LWZhbHNlIixmdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZSgidGVzdC1mYWxzZSIsW10pfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5lbmFibGVkPSExfSxrKHcpKSxlLmFkZENvbW1hbmQoImFuaW1hdGUiLHMubm9vcCxmdW5jdGlvbihyLGUsdCxhLG8pe3QuZm9yRWFjaChlLGZ1bmN0aW9uKGUpe3ZhciB0LG47Inpvb20iPT09bmFtZSYmKG49KHQ9ZS5vZmZzZXQoKSkubGVmdCx0PXQudG9wLG49Yy5tb3VzZUNvb3Jkcy54LW4rInB4ICIrKGMubW91c2VDb29yZHMueS10KSsicHgiKSxjLnRyYW5zaXRpb25JbihlLGEsci50cmFuc2l0aW9uVGltZXx8byxyLnRyYW5zaXRpb25EZWxheSxyLnRyYW5zaXRpb25Ta2lwLDAsbil9KX0sW1MobiksVC5hcHBseSh2b2lkIDAsX3RvQ29uc3VtYWJsZUFycmF5KEEuaW5uZXJUeXBlLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iaW5zdGFudCIhPT1lfSkpKSxiKF8pXSksWyJib3giLCJmbG9hdC1ib3giXS5mb3JFYWNoKGZ1bmN0aW9uKGkpe3JldHVybiBlLmFkZENoYW5nZXIoaSxmdW5jdGlvbihlLHQsbil7dmFyIHI9LTE9PT10LnNlYXJjaChoKXx8MTx0Lmxlbmd0aCYmIXQuaW5jbHVkZXMoIj0iKSxhPSJmbG9hdC1ib3giPT09aSYmKC0xPT09bi5zZWFyY2goaCl8fDE8bi5sZW5ndGgmJiFuLmluY2x1ZGVzKCI9IikpO3JldHVybiByfHxhP3UuY3JlYXRlKCJkYXRhdHlwZSIsIlRoZSAoIitpKyc6KSBtYWNybyByZXF1aXJlcyBhIHNpemluZyBsaW5lKCI9PVg9PSIsICI9PVgiLCAiPVhYWFg9IiBldGMuKSBiZSBwcm92aWRlZCwgbm90ICInKyhyP3Q6bikrJyIuJyk6by5jcmVhdGUoaSxbdCxuXS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIHZvaWQgMCE9PWV9KSl9LGZ1bmN0aW9uKGUsdCxuKXt2YXIgcix0PWYodCksYT10Lm1hcmdpbkxlZnQsdD10LnNpemUsbz0oImZsb2F0LWJveCI9PT1pJiYocj0obz1mKG4pKS5tYXJnaW5MZWZ0LG49by5zaXplKSwiYm94Ij09PWk/IiUiOiJ2dyIpLHQ9X2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoe2Rpc3BsYXk6ImJsb2NrIix3aWR0aDp0K28sIm1heC13aWR0aCI6dCtvfSwiYm94Ij09PWk/Im1hcmdpbi1sZWZ0IjoibGVmdCIsYStvKSwib3ZlcmZsb3cteSIsImF1dG8iKSwicGFkZGluZyIsZnVuY3Rpb24oKXt2YXIgZT1zKHRoaXMpLmNzcygicGFkZGluZyIpO3JldHVybiBlJiYiMHB4IiE9PWU/ZToiMWVtIn0pO3JldHVybiB2b2lkIDAhPT1uJiYodC5oZWlnaHQ9ImJveCI9PT1pPzEuNSpuKzIrImVtIjpuKyJ2aCIpLCJmbG9hdC1ib3giPT09aSYmbSh0LHtwb3NpdGlvbjoiZml4ZWQiLHRvcDpyKyJ2aCIsImJhY2tncm91bmQtY29sb3IiOmZ1bmN0aW9uKCl7cmV0dXJuIGMucGFyZW50Q29sb3VycyhzKHRoaXMpKS5iYWNrZ3JvdW5kQ29sb3VyfX0pLGUuc3R5bGVzLnB1c2godCksZX0sW1N0cmluZywiYm94Ij09PWk/Yih4KTpTdHJpbmddKX0pfSksZGVmaW5lKCJtYWNyb2xpYi92YWx1ZXMiLFsibWFjcm9zIiwic3RhdGUiLCJ1dGlscyIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiZGF0YXR5cGVzL2NvbG91ciIsImRhdGF0eXBlcy9ncmFkaWVudCIsImRhdGF0eXBlcy9kYXRhdHlwZSIsImRhdGF0eXBlcy9ob29rc2V0IiwiZGF0YXR5cGVzL2NvZGVob29rIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24odCxyLGUsbixsLGMsYSxvLGksZil7dmFyIHM9ZS5yZWFsV2hpdGVzcGFjZSx1PWUubnRoLHA9ZS5hbnlSZWFsTGV0dGVyLGQ9ZS5wbHVyYWwsaD1uLnN1YnNldCxtPW4ub2JqZWN0TmFtZSxnPW4uY2xvbmUseT1uLnRvU291cmNlLGU9dC5UeXBlU2lnbmF0dXJlLG49ZS5yZXN0LGI9ZS56ZXJvT3JNb3JlLHY9ZS5laXRoZXIsdz1lLm9wdGlvbmFsLGs9ZS5pbnNlbnNpdGl2ZVNldCxTPWUubnVtYmVyUmFuZ2UsVD1lLnBlcmNlbnQsXz1lLm5vbk5lZ2F0aXZlSW50ZWdlcix4PWUucG9zaXRpdmVJbnRlZ2VyLGU9ZS5BbnksTz1NYXRoLm1heCxBPU1hdGgubWluLEM9TWF0aC5yb3VuZCxFPU1hdGguZmxvb3IsTj1NYXRoLmNlaWw7ZnVuY3Rpb24gaih0KXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgZT10LmFwcGx5KHZvaWQgMCxhcmd1bWVudHMpO3JldHVybiJudW1iZXIiIT10eXBlb2YgZXx8aXNOYU4oZSk/Zi5jcmVhdGUoIm1hY3JvY2FsbCIsIlRoaXMgbWF0aGVtYXRpY2FsIGV4cHJlc3Npb24gZG9lc24ndCBjb21wdXRlISIpOmV9fXQuYWRkKFsic3RyIiwic3RyaW5nIiwidGV4dCJdLCJTdHJpbmciLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49bmV3IEFycmF5KDE8dD90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gbi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGkuaXNQcm90b3R5cGVPZihlKT9lLnNvdXJjZTplfSkuam9pbigiIil9LFtiKHQuVHlwZVNpZ25hdHVyZS5laXRoZXIoU3RyaW5nLE51bWJlcixCb29sZWFuLEFycmF5LGkpKV0pKCJzb3VyY2UiLCJTdHJpbmciLGZ1bmN0aW9uKGUsdCl7cmV0dXJuImNvbW1hbmQiIT09KG51bGw9PXQ/dm9pZCAwOnQuVHdpbmVTY3JpcHRfVHlwZUlEKXx8dC5Ud2luZVNjcmlwdF9Ub1NvdXJjZT95KHQpOmYuY3JlYXRlKCJkYXRhdHlwZSIsIkkgY2FuJ3QgY29uc3RydWN0IHRoZSBzb3VyY2UgY29kZSBvZiBhIGNvbW1hbmQgY3JlYXRlZCBieSBhIGN1c3RvbSBtYWNyby4iKX0sW2VdKSgic3Vic3RyaW5nIiwiU3RyaW5nIixmdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gaCh0LG4scil9LFtTdHJpbmcscGFyc2VJbnQscGFyc2VJbnRdKSgibG93ZXJjYXNlIiwiU3RyaW5nIixmdW5jdGlvbihlLHQpe3JldHVybiB0LnRvTG93ZXJDYXNlKCl9LFtTdHJpbmddKSgidXBwZXJjYXNlIiwiU3RyaW5nIixmdW5jdGlvbihlLHQpe3JldHVybiB0LnRvVXBwZXJDYXNlKCl9LFtTdHJpbmddKSgibG93ZXJmaXJzdCIsIlN0cmluZyIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5yZXBsYWNlKFJlZ0V4cChwKyIrIiksZnVuY3Rpb24oZSl7cmV0dXJuKGU9QXJyYXkuZnJvbShlKSlbMF0udG9Mb3dlckNhc2UoKStlLnNsaWNlKDEpLmpvaW4oIiIpLnRvTG93ZXJDYXNlKCl9KX0sW1N0cmluZ10pKCJ1cHBlcmZpcnN0IiwiU3RyaW5nIixmdW5jdGlvbihlLHQpe3JldHVybiB0LnJlcGxhY2UoUmVnRXhwKHArIisiKSxmdW5jdGlvbihlKXtyZXR1cm4oZT1BcnJheS5mcm9tKGUpKVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSkuam9pbigiIikudG9Mb3dlckNhc2UoKX0pfSxbU3RyaW5nXSkoIndvcmRzIiwiQXJyYXkiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQuc3BsaXQoUmVnRXhwKHMrIisiKSkuZmlsdGVyKEJvb2xlYW4pfSxbU3RyaW5nXSkoWyJzdHItcmVwZWF0ZWQiLCJzdHJpbmctcmVwZWF0ZWQiXSwiU3RyaW5nIixmdW5jdGlvbihlLHQsbil7cmV0dXJuIDA9PT1uLmxlbmd0aD9mLmNyZWF0ZSgibWFjcm9jYWxsIiwiSSBjYW4ndCByZXBlYXQgYW4gZW1wdHkgc3RyaW5nLiIpOm4ucmVwZWF0KHQpfSxbXyxTdHJpbmddKShbInN0ci1yZXZlcnNlZCIsInN0cmluZy1yZXZlcnNlZCJdLCJTdHJpbmciLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIF90b0NvbnN1bWFibGVBcnJheSh0KS5yZXZlcnNlKCkuam9pbigiIil9LFtTdHJpbmddKSgiam9pbmVkIiwiU3RyaW5nIixmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9bmV3IEFycmF5KDI8bj9uLTI6MCksYT0yO2E8bjthKyspclthLTJdPWFyZ3VtZW50c1thXTtyZXR1cm4gci5qb2luKHQpfSxbbihTdHJpbmcpXSkoInBsdXJhbCIsIlN0cmluZyIsZnVuY3Rpb24oZSx0LG4scil7cmV0dXJuIG4mJiIiIT09cj9kKHQsbixyKTpmLmNyZWF0ZSgibWFjcm9jYWxsIiwiVGhlIChwbHVyYWw6KSBtYWNybyBjYW4ndCBiZSBnaXZlbiBlbXB0eSBzdHJpbmdzLiIpfSxbcGFyc2VJbnQsU3RyaW5nLHcoU3RyaW5nKV0pKFsic3RyLW50aCIsInN0cmluZy1udGgiXSwiU3RyaW5nIixmdW5jdGlvbihlLHQpe3JldHVybiB1KHQpfSxbcGFyc2VJbnRdKSgiZGlnaXQtZm9ybWF0IiwiU3RyaW5nIixmdW5jdGlvbihlLHQsbil7aWYoMWUyMTw9TWF0aC5hYnMobikpcmV0dXJuIGYuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGUgbnVtYmVyIGdpdmVuIHRvIChkaWdpdC1mb3JtYXQ6KSBpcyB0b28gYmlnLiIpO2Zvcih2YXIgcj0vKFteIzBdKSg/PVsjMF0qJCkvZyxhPShyLmV4ZWModCl8fFtdKVsxXSxvPSgvXlsjMF0qKFteIzBdKS9nLmV4ZWModCl8fFtdKVsxXSxpPSh0PV90b0NvbnN1bWFibGVBcnJheSh0KSkubGVuZ3RoLHM9KGEmJigiLCIhPT1hfHxvJiYiLCIhPT1vKSYmKGk9ci5sYXN0SW5kZXgtMSksTWF0aC5hYnMobikudG9GaXhlZCgxNikucmVwbGFjZSgvKFwuXGQqPykwKyQvLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR9KS5yZXBsYWNlKC9eMCsvLCIiKSksYz1zLmluY2x1ZGVzKCIuIik/cy5pbmRleE9mKCIuIik6cy5sZW5ndGgsbD0wLHU9IiIscD10Lmxlbmd0aC0xOzA8PXA7LS1wKXt2YXIgZD10W3BdOyIwIj09PWR8fCIjIj09PWQ/dT0oc1tjLWkrcCtsXXx8KCIwIj09PWQ/IjAiOiIiKSkrdTpwPHQubGVuZ3RoLTEmJjA8cCYmKHU9ZCt1LGwrPXA9PT1pPzA6MSl9cmV0dXJuKG48MD8iLSI6IiIpK3V9LFtTdHJpbmcsTnVtYmVyXSkoWyJudW0iLCJudW1iZXIiXSwiTnVtYmVyIixmdW5jdGlvbihlLHQpe3JldHVybiBOdW1iZXIuaXNOYU4oK3QpP2YuY3JlYXRlKCJtYWNyb2NhbGwiLCJJIGNvdWxkbid0IGNvbnZlcnQgIittKHQpKyIgdG8gYSBudW1iZXIuIik6K3R9LFtTdHJpbmddKSgiZGF0YXR5cGUiLCJEYXRhdHlwZSIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gYS5mcm9tKHQpfSxbZV0pKCJkYXRhcGF0dGVybiIsIkFueSIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24gbihlKXt2YXIgcjtyZXR1cm4gQXJyYXkuaXNBcnJheShlKT9yPWUubWFwKG4pOmUgaW5zdGFuY2VvZiBNYXA/KHI9bmV3IE1hcCxfdG9Db25zdW1hYmxlQXJyYXkoZSkuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgZT1fc2xpY2VkVG9BcnJheShlLDIpLHQ9ZVswXSxlPWVbMV07cmV0dXJuIHIuc2V0KHQsbihlKSl9KSk6cj1hLmZyb20oZSksKGU9Zi5jb250YWluc0Vycm9yKHIpKXx8cn0odCl9LFtlXSkoWyJyZ2IiLCJyZ2JhIl0sIkNvbG91ciIsZnVuY3Rpb24oZSl7cmV0dXJuIGwuY3JlYXRlKHtyOmFyZ3VtZW50cy5sZW5ndGg8PTE/dm9pZCAwOmFyZ3VtZW50c1sxXSxnOmFyZ3VtZW50cy5sZW5ndGg8PTI/dm9pZCAwOmFyZ3VtZW50c1syXSxiOmFyZ3VtZW50cy5sZW5ndGg8PTM/dm9pZCAwOmFyZ3VtZW50c1szXSxhOmFyZ3VtZW50cy5sZW5ndGg8PTQ/dm9pZCAwOmFyZ3VtZW50c1s0XX0pfSxbUygwLDI1NSksUygwLDI1NSksUygwLDI1NSksdyhUKV0pKFsiaHNsIiwiaHNsYSJdLCJDb2xvdXIiLGZ1bmN0aW9uKGUsdCxuLHIsYSl7cmV0dXJuKHQ9Qyh0KSUzNjApPDAmJih0Kz0zNjApLGwuY3JlYXRlKHtoOnQsczpuLGw6cixhOmF9KX0sW051bWJlcixULFQsdyhUKV0pKFsibGNoIiwibGNoYSJdLCJDb2xvdXIiLGZ1bmN0aW9uKGUsdCxuLHIsYSl7cmV0dXJuKHI9QyhyKSUzNjApPDAmJihyKz0zNjApLGwuY3JlYXRlKHtsOnQsYzpuLGg6cixhOmF9KX0sW1QsUygwLDEzMiksTnVtYmVyLHcoVCldKSgiY29tcGxlbWVudCIsIkNvbG91ciIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5MQ0hSb3RhdGUoMTgwKX0sW2xdKSgibWl4IiwiQ29sb3VyIixmdW5jdGlvbihlLHQsbixyLGEpe249bi50b0xDSEEoKSxhPWEudG9MQ0hBKCk7dmFyIG89MSxpPSh0K3IhPT0xJiYodCtyPDEmJihvPXQrciksdD0oaT1bdC8odCtyKSxyLyh0K3IpXSlbMF0scj1pWzFdKSxuLmM8Mnx8bi5sPC4wMXx8Ljk5PG4ubD9uLmg9YS5oOihhLmM8Mnx8YS5sPC4wMXx8Ljk5PGEubCkmJihhLmg9bi5oKSxuLmwqPW4uYSxuLmMqPW4uYSxhLmwqPWEuYSxhLmMqPWEuYSwxODA8YS5oLW4uaD9uLmgrPTM2MDphLmgtbi5oPC0xODAmJihhLmgrPTM2MCksbi5hKnQrYS5hKnIpLHM9KG4ubCp0K2EubCpyKS9pLGM9KG4uYyp0K2EuYypyKS9pLG49KG4uaCp0K2EuaCpyKS9pO3JldHVybiBsLmNyZWF0ZSh7bDpzLGM6YyxoOm4sYTppKm99KX0sW1QsbCxULGxdKSgicGFsZXR0ZSIsIkFycmF5IixmdW5jdGlvbihlLHQsbil7dmFyIHIsYT1uLnRvTENIQSgpLG89YS5sLGE9e2w6bzw9Ljc1Py43NStvLzM6Ljc1LTMqKDEtbyksYzo4MCxoOmEuaCxhOjF9LGk9bC5jcmVhdGUoYSk7cmV0dXJuIGEubCs9bzw9Ljc1Py0uMTouMSxhLmw8LjUmJihhLmwqPS41L2EubCkscj1sLmNyZWF0ZShhKSxhLmwrPW88PS44NT8uMTU6LS4xNSxvPWwuY3JlYXRlKGEpLCJhZGphY2VudCI9PT10PyhyPShpPWkuTENIUm90YXRlKC0zMCkpLkxDSFJvdGF0ZSgzMCksbz1pLkxDSFJvdGF0ZSg2MCkpOiJ0cmlhZCI9PT10JiYobz1pLkxDSFJvdGF0ZSgxODApLHI9aS5MQ0hSb3RhdGUoMTQwKSxpPWkuTENIUm90YXRlKC0xNDApKSxbbixpLHIsb119LFtrKCJtb25vIiwiYWRqYWNlbnQiLCJ0cmlhZCIpLGxdKSgiZ3JhZGllbnQiLCJHcmFkaWVudCIsZnVuY3Rpb24oZSx0KXsodD1DKHQpJTM2MCk8MCYmKHQrPTM2MCk7Zm9yKHZhciBuLHIsYSxvPWFyZ3VtZW50cy5sZW5ndGgsaT1uZXcgQXJyYXkoMjxvP28tMjowKSxzPTI7czxvO3MrKylpW3MtMl09YXJndW1lbnRzW3NdO3JldHVybiBpLmxlbmd0aDw0P2YuY3JlYXRlKCJkYXRhdHlwZSIsIihncmFkaWVudDopIG11c3QgYmUgZ2l2ZW4gYXQgbGVhc3QgMiBjb2xvdXItc3RvcCBwYWlycyBvZiBudW1iZXJzIGFuZCBjb2xvdXJzLiIpOihyPVtdLGE9aS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtpZighZi5jb250YWluc0Vycm9yKGUpKWlmKHZvaWQgMD09PW4pbj10O2Vsc2V7aWYoIm51bWJlciIhPXR5cGVvZiBufHwhbC5pc1Byb3RvdHlwZU9mKHQpKXJldHVybiBmLmNyZWF0ZSgiZGF0YXR5cGUiLCIoZ3JhZGllbnQ6KSBjb2xvdXItc3RvcHMgc2hvdWxkIGJlIHBhaXJzIG9mIG51bWJlcnMgYW5kIGNvbG91cnMsIG5vdCBjb2xvdXJzIGFuZCBudW1iZXJzLiIpO3IucHVzaCh7c3RvcDpuLGNvbG91cjpnKHQpfSksbj12b2lkIDB9cmV0dXJuIGV9LCEwKSxmLmNvbnRhaW5zRXJyb3IoYSk/YTp2b2lkIDAhPT1uP2YuY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGlzIGdyYWRpZW50IGhhcyBhIGNvbG91ci1zdG9wIHBlcmNlbnQgd2l0aG91dCBhIGNvbG91ci4iKTpjLmNyZWF0ZSh0LHIpKX0sW051bWJlcixuKHYoVCxsKSldKSgic3RyaXBlcyIsIkdyYWRpZW50IixmdW5jdGlvbihlLHQsbil7KHQ9Qyh0KSUzNjApPDAmJih0Kz0zNjApO2Zvcih2YXIgcj0wLGE9W10sbz1hcmd1bWVudHMubGVuZ3RoLGk9bmV3IEFycmF5KDM8bz9vLTM6MCkscz0zO3M8bztzKyspaVtzLTNdPWFyZ3VtZW50c1tzXTtyZXR1cm4gaS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2EucHVzaCh7c3RvcDpyLGNvbG91cjpnKGUpfSkscis9bixhLnB1c2goe3N0b3A6cixjb2xvdXI6ZyhlKX0pfSksYy5jcmVhdGUodCxhLCEwKX0sW051bWJlcix4LGwsbihsKV0pKCJob29rcy1uYW1lZCIsIkhvb2tOYW1lIixmdW5jdGlvbihlLHQpe3JldHVybiB0P28uY3JlYXRlKHt0eXBlOiJuYW1lIixkYXRhOnR9KTpmLmNyZWF0ZSgiZGF0YXR5cGUiLCIoaG9va3MtbmFtZWQ6KSBjYW4ndCBiZSBnaXZlbiBhbiBlbXB0eSBzdHJpbmcuIil9LFtTdHJpbmddKSgiY29uZCIsIkFueSIsZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkoMTx0P3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO2Zvcih2YXIgYT0wO2E8bi5sZW5ndGg7YSs9Mil7dmFyIG89blthXTtpZihhPT09bi5sZW5ndGgtMXx8Zi5jb250YWluc0Vycm9yKG8pKXJldHVybiBvO2lmKCJib29sZWFuIiE9dHlwZW9mIG8pcmV0dXJuIGYuY3JlYXRlKCJkYXRhdHlwZSIsIihjb25kOikncyAiK3UoYSsxKSsiIHZhbHVlIGlzICIrbShvKSsiLCBidXQgc2hvdWxkIGJlIGEgYm9vbGVhbi4iKTtpZihvKXJldHVybiBuW2ErMV19cmV0dXJuIGYuY3JlYXRlKCJtYWNyb2NhbGwiLCJBbiBvZGQgbnVtYmVyIG9mIHZhbHVlcyBtdXN0IGJlIGdpdmVuIHRvIChjb25kOiksIG5vdCAiK24ubGVuZ3RoLCIoY29uZDopIG11c3QgYmUgZ2l2ZW4gb25lIG9yIG1vcmUgcGFpcnMgb2YgYm9vbGVhbnMgYW5kIHZhbHVlcywgYXMgd2VsbCBhcyBvbmUgZmluYWwgdmFsdWUuIil9LFtCb29sZWFuLGUsbihlKV0pOyh7d2Vla2RheTpbZnVuY3Rpb24oKXtyZXR1cm5bIlN1biIsIk1vbiIsIlR1ZXMiLCJXZWRuZXMiLCJUaHVycyIsIkZyaSIsIlNhdHVyIl1bKG5ldyBEYXRlKS5nZXREYXkoKV0rImRheSJ9LG51bGxdLG1vbnRoZGF5OltmdW5jdGlvbigpe3JldHVybihuZXcgRGF0ZSkuZ2V0RGF0ZSgpfSxudWxsXSxjdXJyZW50dGltZTpbZnVuY3Rpb24oKXt2YXIgZT1uZXcgRGF0ZSx0PWUuZ2V0SG91cnMoKTwxMjtyZXR1cm4oZS5nZXRIb3VycygpJTEyfHwxMikrIjoiKygoZS5nZXRNaW51dGVzKCk8MTA/IjAiOiIiKStlLmdldE1pbnV0ZXMoKSkrIiAiKyh0PyJBIjoiUCIpKyJNIn0sbnVsbF0sY3VycmVudGRhdGU6W2Z1bmN0aW9uKCl7cmV0dXJuKG5ldyBEYXRlKS50b0RhdGVTdHJpbmcoKX0sbnVsbF0sbWluOltBLG4oTnVtYmVyKV0sbWF4OltPLG4oTnVtYmVyKV0sYWJzOltNYXRoLmFicyxOdW1iZXJdLHNpZ246W01hdGguc2lnbixOdW1iZXJdLHNpbjpbTWF0aC5zaW4sTnVtYmVyXSxjb3M6W01hdGguY29zLE51bWJlcl0sdGFuOltNYXRoLnRhbixOdW1iZXJdLGZsb29yOltFLE51bWJlcl0scm91bmQ6W0MsTnVtYmVyXSx0cnVuYzpbZnVuY3Rpb24oZSl7cmV0dXJuKDA8ZT9FOk4pKGUpfSxOdW1iZXJdLGNlaWw6W04sTnVtYmVyXSxwb3c6W2ooTWF0aC5wb3cpLFtOdW1iZXIsTnVtYmVyXV0sZXhwOltNYXRoLmV4cCxOdW1iZXJdLHNxcnQ6W2ooTWF0aC5zcXJ0KSxOdW1iZXJdLGxvZzpbaihNYXRoLmxvZyksTnVtYmVyXSxsb2cxMDpbaihNYXRoLmxvZzEwKSxOdW1iZXJdLGxvZzI6W2ooTWF0aC5sb2cyKSxOdW1iZXJdLHJhbmRvbTpbZnVuY3Rpb24oZSx0KXt2YXIgbix0PXQ/KG49QShlLHQpLE8oZSx0KSk6KG49MCxlKTtyZXR1cm4gdCs9MSx+fihyLnJhbmRvbSgpKih0LW4pKStufSxbcGFyc2VJbnQsdC5UeXBlU2lnbmF0dXJlLm9wdGlvbmFsKHBhcnNlSW50KV1dLCIiOmZ1bmN0aW9uKCl7Zm9yKHZhciBlIGluIHRoaXMpZSYmaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLGUpJiZ0LmFkZChlLCJOdW1iZXIiLGZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPW5ldyBBcnJheSgxPHQ/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIGEuYXBwbHkodm9pZCAwLG4pfX0odGhpc1tlXVswXSksdGhpc1tlXVsxXSl9fSlbIiJdKCksdC5hZGQoImVpdGhlciIsIkFueSIsZnVuY3Rpb24oZSl7dmFyIHQ9MSt+fihyLnJhbmRvbSgpKihhcmd1bWVudHMubGVuZ3RoPD0xPzA6YXJndW1lbnRzLmxlbmd0aC0xKSk7cmV0dXJuIHQ8MXx8YXJndW1lbnRzLmxlbmd0aDw9dD92b2lkIDA6YXJndW1lbnRzW3RdfSxuKGUpKSgibnRoIiwiQW55IixmdW5jdGlvbihlLHQpe3JldHVybiB0PD0wP2YuY3JlYXRlKCJkYXRhdHlwZSIsIihudGg6KSdzIGZpcnN0IHZhbHVlIHNob3VsZCBiZSBhIHBvc2l0aXZlIHdob2xlIG51bWJlciwgbm90ICIrdCk6KHQ9KHQtMSklKGFyZ3VtZW50cy5sZW5ndGg8PTI/MDphcmd1bWVudHMubGVuZ3RoLTIpKzIpPDJ8fGFyZ3VtZW50cy5sZW5ndGg8PXQ/dm9pZCAwOmFyZ3VtZW50c1t0XX0sW3BhcnNlSW50LG4oZSldKX0pLCFmdW5jdGlvbigpe3ZhciBhLGs9e307ZnVuY3Rpb24gbyhlKXtmb3IodmFyIHQgaW4gZSl0aGlzW3RdPWVbdF19ZnVuY3Rpb24gaShlLHQpe2Zvcih2YXIgbixyLGE9ZS5pbm5lclRleHQsbz1udWxsLGk9MCxzPWksYz1hLmxlbmd0aCxsPW51bGw7aTxjOyl7Zm9yKHZhciB1PWEuc2xpY2UoaSkscD0obyYmby5sZW5ndGg/b1swXTplKS5pbm5lck1vZGUsZD0wLGY9cC5sZW5ndGg7ZDxmO2QrPTEpe3ZhciBoPWtbcFtkXV07aWYoIShoLmNvbnN0cmFpbnQmJiFoLmNvbnN0cmFpbnQobCl8fGguY2Fubm90Rm9sbG93VGV4dCYmKCJ0ZXh0Ij09PShudWxsPT0odz1sKT92b2lkIDA6dy50eXBlKXx8czxpKSkmJihoLnBsYWluQ29tcGFyZT91LnN0YXJ0c1dpdGgoaC5wYXR0ZXJuKTpoLnBhdHRlcm4udGVzdCh1KSkpe3ZhciBtPWguZm4oaC5wbGFpbkNvbXBhcmU/aC5wYXR0ZXJuOmgucGF0dGVybi5leGVjKHUpKSxnPSExLHk9MDtpZihtLm1hdGNoZXMpe2Zvcig7byYmeTxvLmxlbmd0aDt5Kz0xKXt2YXIgYj1vW3ldLHY9Yi50eXBlLGI9Yi5ha2E7aWYodiBpbiBtLm1hdGNoZXMpe2c9ITA7YnJlYWt9YiYmKHY9YiksLTE8KG51bGw9PShiPW0uY2Fubm90Q3Jvc3MpP3ZvaWQgMDpiLmluZGV4T2YodikpJiYoeT1vLmxlbmd0aC0xKX1pZigoIW98fHk+PW8ubGVuZ3RoKSYmIW0uaXNGcm9udCljb250aW51ZX1zPGkmJmUuYWRkQ2hpbGQoe3R5cGU6InRleHQiLHRleHQ6YS5zbGljZShzLGkpLGlubmVyTW9kZTpwfSk7dmFyIHM9aSs9KGw9ZS5hZGRDaGlsZChtKSkudGV4dC5sZW5ndGgsdz0hMTtnJiYodCYmUyhlLGwsb1t5XSksbz1vLnNsaWNlKHkrMSksdz0hMCksIXcmJmwuaXNGcm9udCYmKG8/by51bnNoaWZ0KGwpOm89W2xdKTticmVha319ZD09PWYmJihpKz0xLG51bGw9PT1sKSYmKGw9e3R5cGU6InRleHQifSl9Zm9yKHM8aSYmZS5hZGRDaGlsZCh7dHlwZToidGV4dCIsdGV4dDphLnNsaWNlKHMsaSksaW5uZXJNb2RlOihudWxsIT0obj1vKSYmbi5sZW5ndGg/b1swXTplKS5pbm5lck1vZGV9KTswPChudWxsPT0ocj1vKT92b2lkIDA6ci5sZW5ndGgpOylvLnNoaWZ0KCkuZGVtb3RlKCk7cmV0dXJuIGV9ZnVuY3Rpb24gUyhlLHQsbil7dmFyIHI9ZS5jaGlsZHJlbi5pbmRleE9mKHQpLGE9ZS5jaGlsZHJlbi5pbmRleE9mKG4pO3QuY2hpbGRyZW49ZS5jaGlsZHJlbi5zcGxpY2UoYSsxLHItKGErMSkpLHQudHlwZT10Lm1hdGNoZXNbbi50eXBlXSx0LmlubmVyVGV4dD0iIjtmb3IodmFyIG8saT0wLHM9dC5jaGlsZHJlbi5sZW5ndGg7aTxzO2krKyl0LmlubmVyVGV4dCs9dC5jaGlsZHJlbltpXS50ZXh0O2ZvcihvIGluIHQuc3RhcnQ9bi5zdGFydCx0LnRleHQ9bi50ZXh0K3QuaW5uZXJUZXh0K3QudGV4dCxuKWhhc093blByb3BlcnR5LmNhbGwobixvKSYmIWhhc093blByb3BlcnR5LmNhbGwodCxvKSYmKHRbb109bltvXSk7dC5pc0Zyb250JiYodC5pc0Zyb250PSExKSxlLmNoaWxkcmVuLnNwbGljZShhLDEpfW8ucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpvLGFkZENoaWxkOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMubGFzdENoaWxkRW5kKCksbj1uZXcgbyhlKTtyZXR1cm4gbi5zdGFydD10LG4uZW5kPWUudGV4dCYmdCtlLnRleHQubGVuZ3RoLG4ucGxhY2U9dGhpcy5wbGFjZSxuLmNoaWxkcmVuPVtdLG4uaW5uZXJUZXh0JiZpKG4pLHRoaXMuY2hpbGRyZW4ucHVzaChuKSxufSxsYXN0Q2hpbGRFbmQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNoaWxkcmVuJiZ0aGlzLmNoaWxkcmVuW3RoaXMuY2hpbGRyZW4ubGVuZ3RoLTFdfHxudWxsO3JldHVybiBlP2UuZW5kOnRoaXMuc3RhcnQrTWF0aC5tYXgoMCx0aGlzLnRleHQuaW5kZXhPZih0aGlzLmlubmVyVGV4dCkpfSx0b2tlbkF0OmZ1bmN0aW9uKGUpe2lmKGU8dGhpcy5zdGFydHx8ZT49dGhpcy5lbmQpcmV0dXJuIG51bGw7aWYodGhpcy5jaGlsZHJlbi5sZW5ndGgpZm9yKHZhciB0PTA7dDx0aGlzLmNoaWxkcmVuLmxlbmd0aDt0Kz0xKWlmKGU+PXRoaXMuY2hpbGRyZW5bdF0uc3RhcnQmJmU8dGhpcy5jaGlsZHJlblt0XS5lbmQpe3ZhciBuPXRoaXMuY2hpbGRyZW5bdF0udG9rZW5BdChlKTtpZihuKXJldHVybiBufXJldHVybiB0aGlzfSxwYXRoQXQ6ZnVuY3Rpb24oZSl7aWYoZTx0aGlzLnN0YXJ0fHxlPj10aGlzLmVuZClyZXR1cm5bXTt2YXIgdD1bXTtpZih0aGlzLmNoaWxkcmVuLmxlbmd0aClmb3IodmFyIG49MDtuPHRoaXMuY2hpbGRyZW4ubGVuZ3RoO24rPTEpaWYoZT49dGhpcy5jaGlsZHJlbltuXS5zdGFydCYmZTx0aGlzLmNoaWxkcmVuW25dLmVuZCl7dmFyIHI9dGhpcy5jaGlsZHJlbltuXS5wYXRoQXQoZSk7aWYoci5sZW5ndGgpe3Q9dC5jb25jYXQocik7YnJlYWt9fXJldHVybiB0LmNvbmNhdCh0aGlzKX0sbmVhcmVzdFRva2VuQXQ6ZnVuY3Rpb24obil7cmV0dXJuIG48dGhpcy5zdGFydHx8bj49dGhpcy5lbmQ/bnVsbDp0aGlzLmNoaWxkcmVuP3RoaXMuY2hpbGRyZW4ucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGV8fChuPj10LnN0YXJ0JiZuPHQuZW5kP3Q6bnVsbCl9LG51bGwpOnRoaXN9LGV2ZXJ5TGVhZjpmdW5jdGlvbihuKXtyZXR1cm4gdGhpcy5jaGlsZHJlbiYmMCE9PXRoaXMuY2hpbGRyZW4ubGVuZ3RoP3RoaXMuY2hpbGRyZW4ucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJnQuZXZlcnlMZWFmKG4pfSwhMCk6ISFuKHRoaXMpfSxkZW1vdGU6ZnVuY3Rpb24oKXt0aGlzLnR5cGU9InRleHQifSxlcnJvcjpmdW5jdGlvbihlKXt0aGlzLnR5cGU9ImVycm9yIix0aGlzLm1lc3NhZ2U9ZX0sdG9TdHJpbmc6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnR5cGUrIigiK3RoaXMuc3RhcnQrIlx1MjE5MiIrdGhpcy5lbmQrIikiO3JldHVybiB0aGlzLmNoaWxkcmVuJiYwPHRoaXMuY2hpbGRyZW4ubGVuZ3RoJiYoZSs9IlsiK3RoaXMuY2hpbGRyZW4rIl0iKSxlfSxjb3B5OmZ1bmN0aW9uKCl7dmFyIGU9bmV3IG8odGhpcyk7cmV0dXJuIGUuY2hpbGRyZW49ZS5jaGlsZHJlbi5zbGljZSgpLGV9LGZvbGRDaGlsZHJlbjpmdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PXRoaXMuY2hpbGRyZW4uc2xpY2UoKSxuPTA7bjx0Lmxlbmd0aDtuKz0xKXt2YXIgcj10W25dLGE9ITE7aWYoci5tYXRjaGVzKWZvcih2YXIgbz0wO288ZS5sZW5ndGg7bys9MSllW29dLnR5cGUgaW4gci5tYXRjaGVzJiYoUyh0aGlzLHIsZVtvXSksZT1lLnNsaWNlKG8rMSksYT0hMCk7IWEmJnIuaXNGcm9udCYmZS51bnNoaWZ0KHIpfX19LGE9e2xleDpmdW5jdGlvbihlKXt2YXIgdD0xPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06IiIsbj0yPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06InN0YXJ0IixyPTM8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzNdJiZhcmd1bWVudHNbM107cmV0dXJuIGkobmV3IG8oe3R5cGU6InJvb3QiLHBsYWNlOnQsc3RhcnQ6MCxlbmQ6ZS5sZW5ndGgsdGV4dDplLGlubmVyVGV4dDplLGNoaWxkcmVuOltdLGlubmVyTW9kZTphLm1vZGVzW25dfSksIXIpfSxydWxlczprLG1vZGVzOnt9fSwib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09dHlwZW9mIG1vZHVsZT8idW5kZWZpbmVkIjpfdHlwZW9mKG1vZHVsZSkpP21vZHVsZS5leHBvcnRzPWE6ImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUoImxleGVyIixbXSxmdW5jdGlvbigpe3JldHVybiBhfSk6dGhpcyYmbnVsbCE9dGhpcyYmdGhpcy5sb2FkZWQ/KHRoaXMubW9kdWxlc3x8KHRoaXMubW9kdWxlcz17fSksdGhpcy5tb2R1bGVzLkxleGVyPWEpOnRoaXMuTGV4ZXI9YX0uY2FsbChldmFsKCJ0aGlzIil8fCgidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbD9nbG9iYWw6d2luZG93KSksIWZ1bmN0aW9uKCl7T2JqZWN0LmFzc2lnbj1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbixyPWFyZ3VtZW50c1t0XTtmb3IobiBpbiByKWhhc093blByb3BlcnR5LmNhbGwocixuKSYmKGVbbl09cltuXSl9cmV0dXJuIGV9O3ZhciBtLGc9T2JqZWN0LmtleXMseT1PYmplY3QuYXNzaWduO2Z1bmN0aW9uIHQoZSl7ZnVuY3Rpb24gdChuKXtyZXR1cm4gbj1ufHwiaW5uZXJUZXh0IixmdW5jdGlvbihlKXt2YXIgZT1lLnJlZHVjZVJpZ2h0KGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZXx8KG4/dDoiIil9LCIiKSx0PXt9O3JldHVybiB0W25dPWUsdH19ZnVuY3Rpb24gbihlLHQpe3ZhciBuPXt9O3JldHVybiBuW2VdPXQsZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMCxtYXRjaGVzOm4sY2Fubm90Q3Jvc3M6WyJ2ZXJiYXRpbU9wZW5lciJdfX19dmFyIHI9T2JqZWN0LmJpbmQoMCxudWxsKTtmdW5jdGlvbiBhKGEsZSl7cmV0dXJuIE9iamVjdC5rZXlzKGUpLmZvckVhY2goZnVuY3Rpb24obil7dmFyIHI9ZVtuXS5mbjtlW25dLmZuPWZ1bmN0aW9uKGUpe3ZhciB0PXIoZSk7cmV0dXJuIHQudGV4dHx8KHQudGV4dD0ic3RyaW5nIj09dHlwZW9mIGU/ZTplWzBdKSx0LnR5cGV8fCh0LnR5cGU9biksdC5pbm5lck1vZGV8fCh0LmlubmVyTW9kZT1hKSx0fX0pLGV9ZnVuY3Rpb24gbyhlKXtzd2l0Y2goZSYmZS50eXBlKXtjYXNlIG51bGw6Y2FzZSJiciI6Y2FzZSJociI6Y2FzZSJidWxsZXRlZCI6Y2FzZSJudW1iZXJlZCI6Y2FzZSJoZWFkaW5nIjpjYXNlImFsaWduIjpjYXNlImNvbHVtbiI6Y2FzZSJlc2NhcGVkTGluZSI6cmV0dXJuITB9cmV0dXJuITF9dmFyIGk9W10scz1bXSxjPVtdLGw9YShpLHtocjp7Zm46cn0sYnVsbGV0ZWQ6e2ZuOmZ1bmN0aW9uKGUpe3JldHVybntkZXB0aDplWzFdLmxlbmd0aH19fSxudW1iZXJlZDp7Zm46ZnVuY3Rpb24oZSl7cmV0dXJue2RlcHRoOmVbMV0ubGVuZ3RoLzJ9fX0saGVhZGluZzp7Zm46ZnVuY3Rpb24oZSl7cmV0dXJue2RlcHRoOmVbMV0ubGVuZ3RofX19LGFsaWduOntmbjpmdW5jdGlvbihlKXt2YXIgdCxlPWVbMV0sbj1lLmluZGV4T2YoIj48Iik7cmV0dXJufm4/MjU9PT0odD1NYXRoLnJvdW5kKG4vKGUubGVuZ3RoLTIpKjUwKSkmJih0PSJjZW50ZXIiKToiPCI9PT1lWzBdJiYiPiI9PT1lLnNsaWNlKC0xKT90PSJqdXN0aWZ5IjotMTxlLmluZGV4T2YoIj4iKT90PSJyaWdodCI6LTE8ZS5pbmRleE9mKCI8IikmJih0PSJsZWZ0Iikse2FsaWduOnR9fX0sY29sdW1uOntmbjpmdW5jdGlvbihlKXt2YXIgdCxlPWVbMV0sbj1lLmluZGV4T2YoInwiKTtyZXR1cm4gbiYmbjxlLmxlbmd0aC0xP3Q9ImNlbnRlciI6InwiPT09ZVswXSYmInwiPT09ZS5zbGljZSgtMSk/dD0ibm9uZSI6bj09PWUubGVuZ3RoLTE/dD0icmlnaHQiOm58fCh0PSJsZWZ0Iikse2NvbHVtbjp0LHdpZHRoOi9cfCsvLmV4ZWMoZSlbMF0ubGVuZ3RoLG1hcmdpbkxlZnQ6L149Ki8uZXhlYyhlKVswXS5sZW5ndGgsbWFyZ2luUmlnaHQ6Lz0qJC8uZXhlYyhlKVswXS5sZW5ndGh9fX19KSx1PShnKGwpLmZvckVhY2goZnVuY3Rpb24oZSl7bFtlXS5jb25zdHJhaW50PW8sbFtlXS5jYW5ub3RGb2xsb3dUZXh0PSEwfSksYShpLHt0d2luZTFNYWNybzp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57dHlwZToiZXJyb3IiLG1lc3NhZ2U6Ikhhcmxvd2UgbWFjcm9zIHVzZSBhIGRpZmZlcmVudCBzeW50YXggdG8gVHdpbmUgMSwgU3VnYXJDdWJlLCBhbmQgWWFybiBtYWNyb3MuIn19fSxlbUJhY2s6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue21hdGNoZXM6e2VtRnJvbnQ6ImVtIn0sY2Fubm90Q3Jvc3M6WyJ2ZXJiYXRpbU9wZW5lciJdfX19LHN0cm9uZ0JhY2s6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue21hdGNoZXM6e3N0cm9uZ0Zyb250OiJzdHJvbmcifSxjYW5ub3RDcm9zczpbInZlcmJhdGltT3BlbmVyIl19fX0sc3Ryb25nRnJvbnQ6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue2lzRnJvbnQ6ITB9fX0sZW1Gcm9udDp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMH19fSxib2xkT3BlbmVyOntmbjpuKCJib2xkT3BlbmVyIiwiYm9sZCIpfSxpdGFsaWNPcGVuZXI6e2ZuOm4oIml0YWxpY09wZW5lciIsIml0YWxpYyIpfSxzdHJpa2VPcGVuZXI6e2ZuOm4oInN0cmlrZU9wZW5lciIsInN0cmlrZSIpfSxzdXBPcGVuZXI6e2ZuOm4oInN1cE9wZW5lciIsInN1cCIpfSxjb21tZW50RnJvbnQ6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue2lzRnJvbnQ6ITB9fX0sY29tbWVudEJhY2s6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue21hdGNoZXM6e2NvbW1lbnRGcm9udDoiY29tbWVudCJ9fX19LHNjcmlwdFN0eWxlVGFnOntmbjpyfSx0YWc6e2ZuOnJ9LHVybDp7Zm46cn0saG9va1ByZXBlbmRlZEZyb250OntmbjpmdW5jdGlvbihlKXtyZXR1cm57bmFtZTplWzFdLGhpZGRlbjoiKSI9PT1lWzJdLGlzRnJvbnQ6ITAsdGFnUG9zaXRpb246InByZXBlbmRlZCJ9fX0saG9va0Zyb250OntmbjpmdW5jdGlvbigpe3JldHVybntpc0Zyb250OiEwfX19LGhvb2tCYWNrOntmbjpmdW5jdGlvbigpe3JldHVybnttYXRjaGVzOntob29rUHJlcGVuZGVkRnJvbnQ6Imhvb2siLGhvb2tGcm9udDoiaG9vayJ9LGNhbm5vdENyb3NzOlsidmVyYmF0aW1PcGVuZXIiXX19fSxob29rQXBwZW5kZWRCYWNrOntmbjpmdW5jdGlvbihlKXtyZXR1cm57bmFtZTplWzJdLGhpZGRlbjoiKCI9PT1lWzFdLHRhZ1Bvc2l0aW9uOiJhcHBlbmRlZCIsbWF0Y2hlczp7aG9va0Zyb250OiJob29rIn0sY2Fubm90Q3Jvc3M6WyJ2ZXJiYXRpbU9wZW5lciJdfX19LHVuY2xvc2VkSG9vazp7Zm46cn0sdW5jbG9zZWRIb29rUHJlcGVuZGVkOntmbjpmdW5jdGlvbihlKXtyZXR1cm57dHlwZToidW5jbG9zZWRIb29rIixuYW1lOmVbMV0saGlkZGVuOiIpIj09PWVbMl19fX0sdmVyYmF0aW1PcGVuZXI6e2ZuOmZ1bmN0aW9uKGUpe3ZhciBlPWVbMF0ubGVuZ3RoLHQ9e307cmV0dXJue3R5cGU6KHRbInZlcmJhdGltIitlXT0idmVyYmF0aW0iKStlLGlzRnJvbnQ6ITAsbWF0Y2hlczp0LGFrYToidmVyYmF0aW1PcGVuZXIifX19LHVuY2xvc2VkQ29sbGFwc2VkOntmbjpyfSxjb2xsYXBzZWRGcm9udDp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMH19fSxjb2xsYXBzZWRCYWNrOntmbjpmdW5jdGlvbigpe3JldHVybnttYXRjaGVzOntjb2xsYXBzZWRGcm9udDoiY29sbGFwc2VkIn0sY2Fubm90Q3Jvc3M6WyJ2ZXJiYXRpbU9wZW5lciJdfX19LGVzY2FwZWRMaW5lOntmbjpyfSxsZWdhY3lMaW5rOntmbjpmdW5jdGlvbihlKXtyZXR1cm57dHlwZToidHdpbmVMaW5rIixpbm5lclRleHQ6ZVsxXSxwYXNzYWdlOmVbMl0saW5uZXJNb2RlOml9fX0sYnI6e2ZuOnJ9fSkpLHA9eShhKHMse21hY3JvRnJvbnQ6e2ZuOmZ1bmN0aW9uKGUpe3JldHVybntpc0Zyb250OiEwLG5hbWU6ZVsxXX19fSxncm91cGluZ0JhY2s6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue21hdGNoZXM6e2dyb3VwaW5nRnJvbnQ6Imdyb3VwaW5nIixtYWNyb0Zyb250OiJtYWNybyJ9LGNhbm5vdENyb3NzOlsic2luZ2xlU3RyaW5nT3BlbmVyIiwiZG91YmxlU3RyaW5nT3BlbmVyIiwiaG9va0Zyb250Il19fX0scGFzc2FnZUxpbms6e2ZuOmZ1bmN0aW9uKGUpe3ZhciB0PWVbMV18fCIiLG49ZVsyXXx8IiIsZT1lWzNdfHwiIjtyZXR1cm57dHlwZToidHdpbmVMaW5rIixpbm5lclRleHQ6bj9lOnQscGFzc2FnZTp0P2U6bixpbm5lck1vZGU6aX19fSxzaW1wbGVMaW5rOntmbjpmdW5jdGlvbihlKXtyZXR1cm57dHlwZToidHdpbmVMaW5rIixpbm5lclRleHQ6ZVsxXXx8IiIscGFzc2FnZTplWzFdfHwiIixpbm5lck1vZGU6aX19fSx2YXJpYWJsZTp7Y29uc3RyYWludDpmdW5jdGlvbihlKXtyZXR1cm4hZXx8Im1hY3JvRnJvbnQiIT09ZS50eXBlfSxmbjp0KCJuYW1lIil9LHRlbXBWYXJpYWJsZTp7Y29uc3RyYWludDpmdW5jdGlvbihlKXtyZXR1cm4hZXx8Im1hY3JvRnJvbnQiIT09ZS50eXBlfSxmbjp0KCJuYW1lIil9fSkse2hvb2tGcm9udDp1Lmhvb2tGcm9udCxob29rQmFjazp1Lmhvb2tCYWNrfSksZD1hKHMsX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHtjb21tZW50QmFjazp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57bWF0Y2hlczp7Y29tbWVudEZyb250OiJjb21tZW50In19fX0sbWFjcm9OYW1lOntjb25zdHJhaW50OmZ1bmN0aW9uKGUpe3JldHVybiBlJiYibWFjcm9Gcm9udCI9PT1lLnR5cGV9LGZuOnQoIm5hbWUiKX0sZ3JvdXBpbmdGcm9udDp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMH19fSxwcm9wZXJ0eTp7Zm46dCgibmFtZSIpLGNvbnN0cmFpbnQ6ZnVuY3Rpb24oZSl7aWYoZSlzd2l0Y2goZS50eXBlKXtjYXNlInZhcmlhYmxlIjpjYXNlImhvb2tOYW1lIjpjYXNlInByb3BlcnR5IjpjYXNlInRlbXBWYXJpYWJsZSI6Y2FzZSJjb2xvdXIiOmNhc2UiaXRzUHJvcGVydHkiOmNhc2UiYmVsb25naW5nSXRQcm9wZXJ0eSI6Y2FzZSJtYWNybyI6Y2FzZSJncm91cGluZyI6Y2FzZSJzdHJpbmciOmNhc2UiZGF0YXR5cGUiOmNhc2UiaG9vayI6Y2FzZSJib29sZWFuIjpjYXNlIm51bWJlciI6cmV0dXJuITB9fX0scG9zc2Vzc2l2ZU9wZXJhdG9yOntmbjpyfSxpdHNQcm9wZXJ0eTp7Y2Fubm90Rm9sbG93VGV4dDohMCxmbjp0KCJuYW1lIil9LGl0c09wZXJhdG9yOntjYW5ub3RGb2xsb3dUZXh0OiEwLGZuOnJ9LGJlbG9uZ2luZ0l0UHJvcGVydHk6e2Nhbm5vdEZvbGxvd1RleHQ6ITAsZm46dCgibmFtZSIpfSxiZWxvbmdpbmdJdE9wZXJhdG9yOntjYW5ub3RGb2xsb3dUZXh0OiEwLGZuOnJ9LGJlbG9uZ2luZ1Byb3BlcnR5OntjYW5ub3RGb2xsb3dUZXh0OiEwLGZuOnQoIm5hbWUiKX0sYmVsb25naW5nT3BlcmF0b3I6e2Nhbm5vdEZvbGxvd1RleHQ6ITAsZm46cn0sZXNjYXBlZFN0cmluZ0NoYXI6e2ZuOmZ1bmN0aW9uKCl7cmV0dXJue3R5cGU6InRleHQifX19LHNpbmdsZVN0cmluZ09wZW5lcjp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMCxtYXRjaGVzOntzaW5nbGVTdHJpbmdPcGVuZXI6InN0cmluZyJ9LGlubmVyTW9kZTpjfX19LGRvdWJsZVN0cmluZ09wZW5lcjp7Zm46ZnVuY3Rpb24oKXtyZXR1cm57aXNGcm9udDohMCxtYXRjaGVzOntkb3VibGVTdHJpbmdPcGVuZXI6InN0cmluZyJ9LGlubmVyTW9kZTpjfX19LGhvb2tOYW1lOntmbjp0KCJuYW1lIil9LGNzc1RpbWU6e2ZuOmZ1bmN0aW9uKGUpe3JldHVybnt2YWx1ZTorZVsxXSooInMiPT09ZVsyXS50b0xvd2VyQ2FzZSgpPzFlMzoxKX19fSxkYXRhdHlwZTp7Y2Fubm90Rm9sbG93VGV4dDohMCxmbjpmdW5jdGlvbihlKXtyZXR1cm57bmFtZTplWzBdLnRvTG93ZXJDYXNlKCl9fX0sY29sb3VyOntjYW5ub3RGb2xsb3dUZXh0OiEwLGZuOmZ1bmN0aW9uKGUpe3ZhciBlPWVbMF0udG9Mb3dlckNhc2UoKSx0PXtyZWQ6ImU2MTkxOSIsb3JhbmdlOiJlNjgwMTkiLHllbGxvdzoiZTVlNjE5IixsaW1lOiI4MGU2MTkiLGdyZWVuOiIxOWU2MTkiLGN5YW46IjE5ZTVlNiIsYXF1YToiMTllNWU2IixibHVlOiIxOTdmZTYiLG5hdnk6IjE5MTllNiIscHVycGxlOiI3ZjE5ZTYiLGZ1Y2hzaWE6ImU2MTllNSIsbWFnZW50YToiZTYxOWU1Iix3aGl0ZToiZmZmIixibGFjazoiMDAwIixncmF5OiI4ODgiLGdyZXk6Ijg4OCJ9LHQ9aGFzT3duUHJvcGVydHkuY2FsbCh0LGUpPyIjIit0W2VdOmU7cmV0dXJue2NvbG91cjp0fX19LG51bWJlcjp7Zm46ZnVuY3Rpb24oZSl7cmV0dXJue3ZhbHVlOnBhcnNlRmxvYXQoZVswXSl9fX0saW5lcXVhbGl0eTp7Zm46ZnVuY3Rpb24oZSl7cmV0dXJue29wZXJhdG9yOmVbMl0sbmVnYXRlOi0xPGVbMV0uaW5kZXhPZigibm90Iil9fX0sYXVnbWVudGVkQXNzaWduOntmbjpmdW5jdGlvbihlKXtyZXR1cm57b3BlcmF0b3I6ZVswXVswXX19fSxpZGVudGlmaWVyOntmbjp0KCJuYW1lIiksY2Fubm90Rm9sbG93VGV4dDohMH0sd2hpdGVzcGFjZTp7Zm46cixjYW5ub3RGb2xsb3dUZXh0OiEwfSxpbmNvcnJlY3RPcGVyYXRvcjp7Zm46ZnVuY3Rpb24oZSl7dmFyIHQ9eyI9PiI6Ij49IiwiPTwiOiI8PSIsZ3RlOiI+PSIsbHRlOiI8PSIsZ3Q6Ij4iLGx0OiI8IixlcToiaXMiLGlzbm90OiJpcyBub3QiLG5lcToiaXMgbm90Iixpc2E6ImlzIGEiLGFyZToiaXMiLHg6IioiLCJvciBhIjoib3IifVtlWzBdLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvXHMrL2csIiAiKV07cmV0dXJue3R5cGU6ImVycm9yIixtZXNzYWdlOiJQbGVhc2Ugc2F5ICIrKHQ/IiciK3QrIiciOiJzb21ldGhpbmcgZWxzZSIpKyIgaW5zdGVhZCBvZiAnIitlWzBdKyInLiIsZXhwbGFuYXRpb246IkluIHRoZSBpbnRlcmVzdHMgb2YgcmVhZGFiaWxpdHksIEkgd2FudCBjZXJ0YWluIG9wZXJhdG9ycyB0byBiZSBpbiBhIHNwZWNpZmljIGZvcm0uIn19LGNhbm5vdEZvbGxvd1RleHQ6ITB9fSxbImJvb2xlYW4iLCJpcyIsInRvIiwiaW50byIsIndoZXJlIiwid2hlbiIsInZpYSIsIm1ha2luZyIsImVhY2giLCJhbmQiLCJvciIsIm5vdCIsImlzTm90IiwiY29udGFpbnMiLCJkb2VzTm90Q29udGFpbiIsImlzSW4iLCJpc0EiLCJpc05vdEEiLCJpc05vdEluIiwibWF0Y2hlcyIsImRvZXNOb3RNYXRjaCIsImJpbmQiXS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XT17Zm46cixjYW5ub3RGb2xsb3dUZXh0OiEwfSxlfSx7fSkpLFsiY29tbWEiLCJzcHJlYWQiLCJ0eXBlU2lnbmF0dXJlIiwiYWRkaXRpb24iLCJzdWJ0cmFjdGlvbiIsIm11bHRpcGxpY2F0aW9uIiwiZGl2aXNpb24iXS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XT17Zm46cn0sZX0se30pKSksZj1hKGMse3NpbmdsZVN0cmluZ0Nsb3NlcjpkLnNpbmdsZVN0cmluZ09wZW5lcixkb3VibGVTdHJpbmdDbG9zZXI6ZC5kb3VibGVTdHJpbmdPcGVuZXIsZXNjYXBlZFN0cmluZ0NoYXI6ZC5lc2NhcGVkU3RyaW5nQ2hhcn0pLGg9KGkucHVzaC5hcHBseShpLF90b0NvbnN1bWFibGVBcnJheShnKGwpKS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KGcocCkpLF90b0NvbnN1bWFibGVBcnJheShnKHUpKSkpLHMucHVzaC5hcHBseShzLF90b0NvbnN1bWFibGVBcnJheShnKHApKS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KGcoZCkpKSksYy5wdXNoLmFwcGx5KGMsX3RvQ29uc3VtYWJsZUFycmF5KGcoZikpKSxfb2JqZWN0U3ByZWFkKF9vYmplY3RTcHJlYWQoX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKF9vYmplY3RTcHJlYWQoe30sbCksdSkscCksZCksZikpLHU9KGcoaCkuZm9yRWFjaChmdW5jdGlvbihlKXttLlBsYWluQ29tcGFyZVtlXT8oaFtlXS5wYXR0ZXJuPW0uUGxhaW5Db21wYXJlW2VdLGhbZV0ucGxhaW5Db21wYXJlPSEwKTpoW2VdLnBhdHRlcm49UmVnRXhwKCJeKD86IittW2VdKyIpIiwiaSIpfSkseShlLnJ1bGVzLGgpLGUubW9kZXMpO3JldHVybiB1LnN0YXJ0PXUubWFya3VwPWksdS5tYWNybz1zLHUuc3RyaW5nPWMsZX1mdW5jdGlvbiBuKGUpe3JldHVybiBPYmplY3QuZnJlZXplKHtsZXg6dChlKS5sZXgsUGF0dGVybnM6bX0pfSJvYmplY3QiPT09KCJ1bmRlZmluZWQiPT10eXBlb2YgbW9kdWxlPyJ1bmRlZmluZWQiOl90eXBlb2YobW9kdWxlKSk/KG09cmVxdWlyZSgiLi9wYXR0ZXJucyIpLG1vZHVsZS5leHBvcnRzPW4ocmVxdWlyZSgiLi9sZXhlciIpKSk6ImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUoIm1hcmt1cCIsWyJsZXhlciIsInBhdHRlcm5zIl0sZnVuY3Rpb24oZSx0KXtyZXR1cm4gbT10LG4oZSl9KTp0aGlzJiZ0aGlzLmxvYWRlZCYmdGhpcy5tb2R1bGVzPyhtPXRoaXMubW9kdWxlcy5QYXR0ZXJucyx0aGlzLm1vZHVsZXMuTWFya3VwPW4odGhpcy5tb2R1bGVzLkxleGVyKSk6KG09dGhpcy5QYXR0ZXJucyx0aGlzLk1hcmt1cD1uKHRoaXMuTGV4ZXIpKX0uY2FsbChldmFsKCJ0aGlzIil8fCgidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbD9nbG9iYWw6d2luZG93KSksIWZ1bmN0aW9uKCl7dmFyIGU7ZnVuY3Rpb24gbih0KXtyZXR1cm4gdCYmIm9iamVjdCI9PT1fdHlwZW9mKHQpPyhPYmplY3Qua2V5cyh0KS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3RbZV09bih0W2VdKX0pLHQpOih0KyIiKS5yZXBsYWNlKC9bLVtcXS97fSgpKis/LlxcXiR8XS9nLCJcXCQmIil9ZnVuY3Rpb24gdChlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4iKCIrZStBcnJheS5hcHBseSgwLGFyZ3VtZW50cykuam9pbigifCIpKyIpIn19dmFyIHI9dCgiPzoiKSxhPXQoIj8hIiksbz10KCI/PSIpLGk9IlsgXFxmXFx0XFx2XFx1MDBhMFxcdTIwMDAtXFx1MjAwYVxcdTIwMjhcXHUyMDI5XFx1MjAyZlxcdTIwNWZcXHUzMDAwXSoiLHM9aS5yZXBsYWNlKCIqIiwiKyIpLGM9IlxcYiIsbD0iW1xcd1xcLVxcdTAwYzAtXFx1MDBkZVxcdTAwZGYtXFx1MDBmZlxcdTAxNTBcXHUwMTcwXFx1MDE1MVxcdTAxNzFcXHVEODAwLVxcdURGRkZdIix1PWwucmVwbGFjZSgiXFwtIiwiIikscD1yKCJcXG4iLCIkIiksZD1pKyIoXFwqKykiK3MsZj1pKyIoKD86MFxcLikrKSIrcyxoPWkrIi17Myx9IitpK3AsbT1pKyIoPT0rPnw8PSt8PSs+PD0rfDw9PSs+KSIraStwLHA9aSsiKD0rXFx8K3xcXHwrPSt8PStcXHwrPSt8XFx8PStcXHwpIitpK3AsZz17b3BlbmVyOiJcXFtcXFsoPyFcXFspIix0ZXh0OiIoIitmdW5jdGlvbigpe3JldHVybiJbXiIrQXJyYXkuYXBwbHkoMCxhcmd1bWVudHMpLm1hcChuKS5qb2luKCIiKSsiXSoifSgiXSIpKyIpIixyaWdodFNlcGFyYXRvcjpyKCJcXC0+IiwiXFx8IiksbGVmdFNlcGFyYXRvcjoiPFxcLSIsY2xvc2VyOiJcXF1cXF0iLGxlZ2FjeVNlcGFyYXRvcjoiXFx8IixsZWdhY3lUZXh0OiIoIityKCJbXlxcfFxcXV0iLCJcXF0iK2EoIlxcXSIpKSsiKykifSx5PXUrIioiK3UucmVwbGFjZSgiXFx3IiwiYS16QS1aIikrdSsiKiIsYj0iXFwkKCIreSsiKSIsdj0iXygiK3krIikiLHc9IidzIitzK2EoIl8iKSsiKCIreSsiKSIsaz0iKCIreSsiKSIrcysib2YiK2MrYSgiaXRcXGIiKSxTPSIncyIrcyxUPXIoIml0IiwidGltZSIsInR1cm5zPyIsInZpc2l0cz8iLCJleGl0cz8iLCJwb3MiKStjLF89Iml0cyIrcysiKCIreSsiKSIseD0iKCIreSsiKSIrcysib2YiK3MrIml0IitjLE89Im9mIitzKyJpdCIrYyxBPXtvcGVuZXI6IlxcKCIsbmFtZToiKCIrcigiXFwkIiwiXyIpKyI/IitsKyIrKToiK2EoIlxcLyIpLGNsb3NlcjoiXFwpIn0sQz1yKCI9PCIsIj0+IiwiW2dsXXRlP1xcYiIsIm4/ZXFcXGIiLCJpc25vdFxcYiIsImFyZVxcYiIsInhcXGIiLCJpc2FcXGIiLCJvciIrcysiYSIrYyksRT0iW2EtekEtWl1bXFx3XFwtXSoiLE49Iig/OlwiW15cIl0qXCJ8J1teJ10qJ3xbXidcIj5dKSo/IixqPSJcXHwoIitsKyIrKSg+fFxcKSkiLFA9Iig8fFxcKCkoIitsKyIrKVxcfCIsUj0iKCg/OlxcYlxcZCsoPzpcXC5cXGQrKT98XFwuXFxkKykoPzpbZUVdWytcXC1dP1xcZCspPykiK2EoIm0/cyIpK2M7Zy5tYWluPWcub3BlbmVyK3IoZy50ZXh0K2cucmlnaHRTZXBhcmF0b3IsZy50ZXh0LnJlcGxhY2UoIioiLCIqPyIpK2cubGVmdFNlcGFyYXRvcikrZy50ZXh0LGU9e3VwcGVyTGV0dGVyOiJbQS1aXFx1MDBjMC1cXHUwMGRlXFx1MDE1MFxcdTAxNzBdIixsb3dlckxldHRlcjoiW2EtejAtOV9cXC1cXHUwMGRmLVxcdTAwZmZcXHUwMTUxXFx1MDE3MV0iLGFueUxldHRlcjpsLGFueUxldHRlclN0cmljdDp1LHdoaXRlc3BhY2U6cy5yZXBsYWNlKCJbIiwiW1xcblxcciIpLGVzY2FwZWRMaW5lOiJcXFxcXFxuXFxcXD98XFxuXFxcXCIsYnI6Ilxcbig/IVxcXFwpIix0YWc6IjxcXC8/IitFK04rIj4iLHNjcmlwdFN0eWxlVGFnOiI8KCIrcigic2NyaXB0Iiwic3R5bGUiLCJ0ZXh0YXJlYSIpKyIpIitOKyI+W15dKj88XFwvXFwxPiIsc2NyaXB0U3R5bGVUYWdPcGVuZXI6IjwiLHVybDoiKCIrcigiaHR0cHM/IiwibWFpbHRvIiwiamF2YXNjcmlwdCIsImZ0cCIsImRhdGEiKSsiOlxcL1xcL1teXFxzPF0rW148Liw6O1wiJylcXF1cXHNdKSIsYnVsbGV0OiJcXCoiLGhyOmgsaGVhZGluZzoiWyBcXGZcXHRcXHZcXHUwMGEwXFx1MjAwMC1cXHUyMDBhXFx1MjAyOFxcdTIwMjlcXHUyMDJmXFx1MjA1ZlxcdTMwMDBdKigjezEsNn0pWyBcXGZcXHRcXHZcXHUwMGEwXFx1MjAwMC1cXHUyMDBhXFx1MjAyOFxcdTIwMjlcXHUyMDJmXFx1MjA1ZlxcdTMwMDBdKiIsYWxpZ246bSxjb2x1bW46cCxidWxsZXRlZDpkLG51bWJlcmVkOmYsdmVyYmF0aW1PcGVuZXI6ImArIixob29rQXBwZW5kZWRGcm9udDoiXFxbIithKCI9KyIpLGhvb2tQcmVwZW5kZWRGcm9udDpqKyJcXFsiK2EoIj0rIiksaG9va0Zyb250OiJcXFsiK2EoIj0rIiksaG9va0JhY2s6IlxcXSIrYShQKSxob29rQXBwZW5kZWRCYWNrOiJcXF0iK1AsdW5jbG9zZWRIb29rOiJcXFs9KyIsdW5jbG9zZWRIb29rUHJlcGVuZGVkOmorIlxcWz0rIix1bmNsb3NlZENvbGxhcHNlZDoiXFx7PSsiLHBhc3NhZ2VMaW5rOmcubWFpbitnLmNsb3NlcixsZWdhY3lMaW5rOmcub3BlbmVyK2cubGVnYWN5VGV4dCtnLmxlZ2FjeVNlcGFyYXRvcitnLmxlZ2FjeVRleHQrZy5jbG9zZXIsc2ltcGxlTGluazpnLm9wZW5lcitnLmxlZ2FjeVRleHQrZy5jbG9zZXIsbWFjcm9Gcm9udDpBLm9wZW5lcitvKEEubmFtZSksbWFjcm9OYW1lOkEubmFtZSxncm91cGluZ0Zyb250OiJcXCgiK2EoQS5uYW1lKSx0d2luZTFNYWNybzoiPDxbXj5cXHNdK1xccyooPzpcXFxcLnwnKD86W14nXFxcXF0qXFxcXC4pKlteJ1xcXFxdKid8XCIoPzpbXlwiXFxcXF0qXFxcXC4pKlteXCJcXFxcXSpcInxbXidcIlxcXFw+XXw+KD8hPikpKj4+Iix2YWxpZFByb3BlcnR5TmFtZTp5LHByb3BlcnR5OncsYmVsb25naW5nUHJvcGVydHk6ayxwb3NzZXNzaXZlT3BlcmF0b3I6UyxiZWxvbmdpbmdPcGVyYXRvcjoib2ZcXGIiLGl0c09wZXJhdG9yOiJpdHNcXGIiLGJlbG9uZ2luZ0l0T3BlcmF0b3I6Tyx2YXJpYWJsZTpiLHRlbXBWYXJpYWJsZTp2LGhvb2tOYW1lOiJcXD8oIitsKyIrKVxcYiIsY3NzVGltZToiKFxcZCtcXC4/XFxkKnxcXGQqXFwuP1xcZCspKG0/cylcXGIiLGNvbG91cjpyKHIoIlJlZCIsIk9yYW5nZSIsIlllbGxvdyIsIkxpbWUiLCJHcmVlbiIsIkN5YW4iLCJBcXVhIiwiQmx1ZSIsIk5hdnkiLCJQdXJwbGUiLCJGdWNoc2lhIiwiTWFnZW50YSIsIldoaXRlIiwiR3JheSIsIkdyZXkiLCJCbGFjayIsIlRyYW5zcGFyZW50IiksIiNbXFxkQS1GYS1mXXszfSg/OltcXGRBLUZhLWZdezN9KT8iKSxkYXRhdHlwZTpyKCJhbG51bSIsImFscGhhbnVtZXJpYyIsImFueSg/OmNhc2UpPyIsImFycmF5IiwiYm9vbCg/OmVhbik/IiwiY2hhbmdlciIsImNvZGVob29rIiwiY29sb3U/ciIsImNvbnN0IiwiY29tbWFuZCIsImRtIiwiZGF0YSIrcigibWFwIiwidHlwZSIsInNldCIpLCJkcyIsImRpZ2l0IiwiZ3JhZGllbnQiLCJlbXB0eSIsImV2ZW4iLCJpbnQiK2EoIm8iKSsiKD86ZWdlcik/IiwibGFtYmRhIiwibG93ZXJjYXNlIiwibWFjcm8iLCJsaW5lYnJlYWsiLCJuZXdsaW5lIiwibnVtKD86YmVyKT8iLCJvZGQiLCJzdHIoPzppbmcpPyIsInVwcGVyY2FzZSIsIndoaXRlc3BhY2UiKStjLG51bWJlcjpSLGJvb2xlYW46cigidHJ1ZSIsImZhbHNlIikrYyxpZGVudGlmaWVyOlQsaXRzUHJvcGVydHk6XyxiZWxvbmdpbmdJdFByb3BlcnR5OngsZXNjYXBlZFN0cmluZ0NoYXI6IlxcXFxbXlxcbl0iLHNpbmdsZVN0cmluZ09wZW5lcjoiJyIsZG91YmxlU3RyaW5nT3BlbmVyOiciJyxzaW5nbGVTdHJpbmdDbG9zZXI6IiciLGRvdWJsZVN0cmluZ0Nsb3NlcjonIicsaXM6ImlzIithKHMrIm5vdCIrYyxzKyJhbj8iK2MscysiaW4iK2MscysiPCIscysiPiIpK2MsaXNOb3Q6ImlzIitzKyJub3QiK2EocytyKCJhbj8iLCJpbiIpK2MpK2MsaXNBOiJpcyIrcysiYW4/IitjLGlzTm90QToiaXMiK3MrIm5vdCIrcysiYW4/IitjLG1hdGNoZXM6Im1hdGNoZXNcXGIiLGRvZXNOb3RNYXRjaDoiZG9lcyIrcysibm90IitzKyJtYXRjaCIrYyxhbmQ6ImFuZFxcYiIsb3I6Im9yXFxiIixub3Q6Im5vdFxcYiIsaW5lcXVhbGl0eToiKCg/OmlzKD86IitzKyJub3QpPyIraSsiKSopKCIrcigiPCg/IT0pIiwiPD0iLCI+KD8hPSkiLCI+PSIpKyIpIixpc0luOiJpcyIrcysiaW4iK2MsY29udGFpbnM6ImNvbnRhaW5zXFxiIixkb2VzTm90Q29udGFpbjoiZG9lcyIrcysibm90IitzKyJjb250YWluIitjLGlzTm90SW46ImlzIitzKyJub3QiK3MrImluIitjLGFkZGl0aW9uOm4oIisiKSthKCI9Iiksc3VidHJhY3Rpb246bigiLSIpK2EoIj0iLCJ0eXBlIiksbXVsdGlwbGljYXRpb246bigiKiIpK2EoIj0iKSxkaXZpc2lvbjpyKCIvIiwiJSIpK2EoIj0iKSxzcHJlYWQ6IlxcLlxcLlxcLiIrYSgiXFwuIiksdG86cigidG9cXGIiLCI9IiksaW50bzoiaW50b1xcYiIsbWFraW5nOiJtYWtpbmdcXGIiLHdoZXJlOiJ3aGVyZVxcYiIsd2hlbjoid2hlblxcYiIsdmlhOiJ2aWFcXGIiLGVhY2g6ImVhY2hcXGIiLGF1Z21lbnRlZEFzc2lnbjpyKCJcXCsiLCJcXC0iLCJcXCoiLCJcXC8iLCIlIikrIj0iLGJpbmQ6IjI/YmluZFxcYiIsdHlwZVNpZ25hdHVyZTpuKCItdHlwZSIpK2MsaW5jb3JyZWN0T3BlcmF0b3I6QyxQbGFpbkNvbXBhcmU6e2NvbW1hOiIsIixjb21tZW50RnJvbnQ6Ilx4M2MhLS0iLGNvbW1lbnRCYWNrOiItLVx4M2UiLHN0cmlrZU9wZW5lcjoifn4iLGl0YWxpY09wZW5lcjoiLy8iLGJvbGRPcGVuZXI6IicnIixzdXBPcGVuZXI6Il5eIixzdHJvbmdGcm9udDoiKioiLHN0cm9uZ0JhY2s6IioqIixlbUZyb250OiIqIixlbUJhY2s6IioiLGNvbGxhcHNlZEZyb250OiJ7Iixjb2xsYXBzZWRCYWNrOiJ9Iixncm91cGluZ0JhY2s6IikifX0sIm9iamVjdCI9PT0oInVuZGVmaW5lZCI9PXR5cGVvZiBtb2R1bGU/InVuZGVmaW5lZCI6X3R5cGVvZihtb2R1bGUpKT9tb2R1bGUuZXhwb3J0cz1lOiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKCJwYXR0ZXJucyIsW10sZnVuY3Rpb24oKXtyZXR1cm4gZX0pOnRoaXMmJnRoaXMubG9hZGVkPyh0aGlzLm1vZHVsZXN8fCh0aGlzLm1vZHVsZXM9e30pLHRoaXMubW9kdWxlcy5QYXR0ZXJucz1lKTp0aGlzLlBhdHRlcm5zPWV9LmNhbGwoZXZhbCgidGhpcyIpfHwoInVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWw/Z2xvYmFsOndpbmRvdykpLGRlZmluZSgidHdpbmVzY3JpcHQvb3BlcmF0aW9ucyIsWyJ1dGlscyIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiZGF0YXR5cGVzL3R5cGVkdmFyIiwiZGF0YXR5cGVzL2RhdGF0eXBlIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oZSx0LG4scixtKXt2YXIgYT1lLnBsdXJhbCxvPXQuaXNPYmplY3QsaT10LmNvbGxlY3Rpb25UeXBlLHM9dC5pcyxjPXQuaXNBLGw9dC5jbG9uZSx1PXQudW5pcXVlLHA9dC5jb250YWlucyxlPXQubWF0Y2hlcyxnPXQub2JqZWN0TmFtZSxkPXQudG9Tb3VyY2U7ZnVuY3Rpb24gZihyLGEsbyxpKXtyZXR1cm4gbz1vfHwiZG8gdGhpcyB0byIsZnVuY3Rpb24oZSx0KXt2YXIgbjtyZXR1cm4gMT09PWEubGVuZ3RoJiYodD1lKSwobj1tLmNvbnRhaW5zRXJyb3IoZSx0KSl8fChfdHlwZW9mKGUpIT09cnx8X3R5cGVvZih0KSE9PXI/bS5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuIG9ubHkgIi5jb25jYXQobywiICIpLmNvbmNhdChyLCJzLCBub3QgIikuY29uY2F0KGcoX3R5cGVvZihlKSE9PXI/ZTp0KSwiLiIpLGkpOmEoZSx0KSl9fWZ1bmN0aW9uIGgoYSl7cmV0dXJuIGZ1bmN0aW9uKGUsdCl7dmFyIG4scjtyZXR1cm4obj1tLmNvbnRhaW5zRXJyb3IoZSx0KSl8fChfdHlwZW9mKGUpIT09X3R5cGVvZih0KXx8byhlKSYmIlR3aW5lU2NyaXB0X1R5cGVOYW1lImluIGUmJm8odCkmJiJUd2luZVNjcmlwdF9UeXBlTmFtZSJpbiB0JiZlLlR3aW5lU2NyaXB0X1R5cGVOYW1lIT09dC5Ud2luZVNjcmlwdF9UeXBlTmFtZXx8aShlKSE9PWkodCk/KG49IiIuY29uY2F0KGcoZSksIiBpc24ndCB0aGUgc2FtZSB0eXBlIG9mIGRhdGEgYXMgIikuY29uY2F0KGcodCkpLF90eXBlb2YoZSkrX3R5cGVvZih0KSE9PSJzdHJpbmdudW1iZXIiJiZfdHlwZW9mKGUpK190eXBlb2YodCkhPT0ibnVtYmVyc3RyaW5nInx8KHI9IllvdSBtaWdodCB3YW50IHRvIGNvbnZlcnQgb25lIHNpZGUgdG8gYSBudW1iZXIgdXNpbmcgKG51bTopLCBvciB0byBhIHN0cmluZyB1c2luZyAoc3RyOikuIiksbS5jcmVhdGUoIm9wZXJhdGlvbiIsblswXS50b1VwcGVyQ2FzZSgpK24uc2xpY2UoMSkscikpOmEoZSx0KSl9fWZ1bmN0aW9uIHkoZCxmLGUpe3ZhciBoPTI8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09ZSYmZTtyZXR1cm4gZnVuY3Rpb24gcihhLG8pe3ZhciBlO2lmKGU9bS5jb250YWluc0Vycm9yKGEsbykpcmV0dXJuIGU7dmFyIHQ9X3NsaWNlZFRvQXJyYXkoYS5kZXRlcm1pbmVyP1thLG9dOm8uZGV0ZXJtaW5lcj9bbyxhXTpbXSwyKSxpPXRbMF0sdD10WzFdO2lmKGkpe3ZhciBuPWkscz1uLmRldGVybWluZXIsbj1uLmRldGVybWluZWQ7aWYoInN0YXJ0Ij09PXN8fCJlbmQiPT09cyl7aWYoZilyZXR1cm4gbS5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgdXNlICciLmNvbmNhdChmLCInIHdpdGggdGhlICdzdGFydCcgb3IgJ2VuZCcgb2YgIikuY29uY2F0KGcobiksIi4iKSk7aWYodC5kZXRlcm1pbmVyKXtpZigic3RhcnQiPT09dC5kZXRlcm1pbmVyfHwiZW5kIj09PXQuZGV0ZXJtaW5lcilyZXR1cm4gbS5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgY29tcGFyZSBvbmUgdmFsdWUncyAnc3RhcnQnIG9yICdlbmQnIHdpdGggYW5vdGhlciB2YWx1ZSdzICdzdGFydCcgb3IgJ2VuZCcuIiwiUGxlYXNlIGNoYW5nZSBvbmUgb2YgdGhlbSB0byB1c2UgYW4gZXhhY3QgcmFuZ2UsIHN1Y2ggYXMgJzFzdHRvNHRoJyBvciAnMm5kbGFzdHRvbGFzdCcuIik7bj1bdCxpXSxpPW5bMF19Zm9yKHZhciBjPWkuc3RyaW5nfHxpLmFycmF5LGw9MDtsPGMubGVuZ3RoKzE7bCs9MSl7dmFyIHU9bD8iZW5kIj09PXM/Yy5zbGljZSgtbCk6Yy5zbGljZSgwLGwpOmMuY29uc3RydWN0b3IoKSx1PWk9PT1hP3IodSxvKTpyKGEsdSk7aWYoZT1tLmNvbnRhaW5zRXJyb3IodSkpcmV0dXJuIGU7aWYodSE9PWgpcmV0dXJuIHV9cmV0dXJuIGh9dmFyIHA9ImFsbCI9PT1zO3JldHVybiBpLmFycmF5LnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuLHQ9aT09PWE/cih0LG8pOnIoYSx0KTtyZXR1cm4obj1tLmNvbnRhaW5zRXJyb3IoZSx0KSl8fChwP2UmJnQ6ZXx8dCl9LHApfXJldHVybiBkKGEsbyl9fWZ1bmN0aW9uIGIobixlKXtyZXR1cm4geShmdW5jdGlvbihlLHQpe2U9bihlLHQpO3JldHVybiBtLmNvbnRhaW5zRXJyb3IoZSk/ZTohZX0sZSwhMCl9dD0iSWYgb25lIG9mIHRoZXNlIHZhbHVlcyBpcyBhIG51bWJlciwgeW91IG1heSB3YW50IHRvIHdyaXRlIGEgY2hlY2sgdGhhdCBpdCAnaXMgbm90IDAnLiBBbHNvLCBpZiBvbmUgaXMgYSBzdHJpbmcsIHlvdSBtYXkgd2FudCB0byB3cml0ZSBhIGNoZWNrIHRoYXQgaXQgJ2lzIG5vdCBcIlwiICcuIix0PXthbmQ6ZigiYm9vbGVhbiIsaChmdW5jdGlvbihlLHQpe3JldHVybiBlJiZ0fSksInVzZSAnYW5kJyB0byBqb2luIix0KSxvcjpmKCJib29sZWFuIixoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGV8fHR9KSwidXNlICdvcicgdG8gam9pbiIsdCksbm90OmYoImJvb2xlYW4iLGZ1bmN0aW9uKGUpe3JldHVybiFlfSwidXNlICdub3QnIHRvIGludmVydCIsdCksIisiOmgoZnVuY3Rpb24oZSx0KXt2YXIgbjtyZXR1cm4gQXJyYXkuaXNBcnJheShlKT9bXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KGUpLF90b0NvbnN1bWFibGVBcnJheSh0KSk6ZSBpbnN0YW5jZW9mIE1hcD8obj1uZXcgTWFwKGUpLHQuZm9yRWFjaChmdW5jdGlvbihlLHQpe3JldHVybiBuLnNldCh0LGUpfSksbik6ZSBpbnN0YW5jZW9mIFNldD9uZXcgU2V0KFtdLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkoZSksX3RvQ29uc3VtYWJsZUFycmF5KHQpKS5maWx0ZXIodSkubWFwKGwpKToiZnVuY3Rpb24iPT10eXBlb2YgZVsiVHdpbmVTY3JpcHRfKyJdP2VbIlR3aW5lU2NyaXB0XysiXSh0KToic3RyaW5nfG51bWJlcnxib29sZWFuIi5pbmNsdWRlcyhfdHlwZW9mKGUpKT9lK3Q6bS5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgdXNlICsgb24gIi5jb25jYXQoZyhlKSwiLiIpKX0pLCItIjpoKGZ1bmN0aW9uKGUsbil7dmFyIHI7cmV0dXJuIEFycmF5LmlzQXJyYXkoZSk/ZS5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIW4uc29tZShmdW5jdGlvbihlKXtyZXR1cm4gcyh0LGUpfSl9KTplIGluc3RhbmNlb2YgU2V0PyhyPV90b0NvbnN1bWFibGVBcnJheShuKSxuZXcgU2V0KF90b0NvbnN1bWFibGVBcnJheShlKS5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIXIuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gcyh0LGUpfSl9KSkpOiJzdHJpbmciPT10eXBlb2YgZT9lLnNwbGl0KG4pLmpvaW4oIiIpOiJudW1iZXIiPT10eXBlb2YgZT9lLW46bS5jcmVhdGUoIm9wZXJhdGlvbiIsIkkgY2FuJ3QgdXNlIC0gb24gIi5jb25jYXQoZyhlKSwiLiIpKX0pLCIqIjpmKCJudW1iZXIiLGgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSp0fSksIm11bHRpcGx5IiksIi8iOmYoIm51bWJlciIsaChmdW5jdGlvbihlLHQpe3JldHVybiAwPT09dD9tLmNyZWF0ZSgib3BlcmF0aW9uIiwiSSBjYW4ndCBkaXZpZGUgIi5jb25jYXQoZyhlKSwiIGJ5IHplcm8uIikpOmUvdH0pLCJkaXZpZGUiKSwiJSI6ZigibnVtYmVyIixoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIDA9PT10P20uY3JlYXRlKCJvcGVyYXRpb24iLCJJIGNhbid0IG1vZHVsbyAiLmNvbmNhdChnKGUpLCIgYnkgemVyby4iKSk6ZSV0fSksIm1vZHVsdXMiKSwiPCI6eShmKCJudW1iZXIiLGgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZTx0fSksImRvIDwgdG8iKSwiPCIpLCI+Ijp5KGYoIm51bWJlciIsaChmdW5jdGlvbihlLHQpe3JldHVybiB0PGV9KSwiZG8gPiB0byIpLCI+IiksIjw9Ijp5KGYoIm51bWJlciIsaChmdW5jdGlvbihlLHQpe3JldHVybiBlPD10fSksImRvIDw9IHRvIiksIjw9IiksIj49Ijp5KGYoIm51bWJlciIsaChmdW5jdGlvbihlLHQpe3JldHVybiB0PD1lfSksImRvID49IHRvIiksIj49IiksaXM6eShzKSxpc05vdDpiKHMpLGNvbnRhaW5zOnkocCwiY29udGFpbnMiKSxkb2VzTm90Q29udGFpbjpiKHAsImRvZXMgbm90IGNvbnRhaW4iKSxpc0luOnkoZnVuY3Rpb24oZSx0KXtyZXR1cm4gcCh0LGUpfSwiaXMgaW4iKSxpc05vdEluOmIoZnVuY3Rpb24oZSx0KXtyZXR1cm4gcCh0LGUpfSwiaXMgbm90IGluIiksaXNBOnkoYywiaXMgYSIpLGlzTm90QTpiKGMsImlzIG5vdCBhIiksdHlwaWZpZXM6eShmdW5jdGlvbihlLHQpe3JldHVybiBjKHQsZSl9KSx1bnR5cGlmaWVzOmIoZnVuY3Rpb24oZSx0KXtyZXR1cm4gYyh0LGUpfSksbWF0Y2hlczp5KGUpLGRvZXNOb3RNYXRjaDpiKGUpLG1ha2VTcHJlYWRlcjpmdW5jdGlvbihlKXt2YXIgdDtyZXR1cm4gbS5jb250YWluc0Vycm9yKGUpP2U6bi5pc1Byb3RvdHlwZU9mKGUpfHxyLmlzUHJvdG90eXBlT2YoZSk/KHQ9bChlKSwobi5pc1Byb3RvdHlwZU9mKGUpP3QuZGF0YXR5cGU6dCkucmVzdD0hMCx0KTp7dmFsdWU6ZSxzcHJlYWRlcjohMCxUd2luZVNjcmlwdF9UeXBlTmFtZToiYSBzcHJlYWRlZCAnLi4uJyB2YWx1ZSIsVHdpbmVTY3JpcHRfT2JqZWN0TmFtZTphKCJzdHJpbmciPT10eXBlb2YgZXx8QXJyYXkuaXNBcnJheShlKT9fdG9Db25zdW1hYmxlQXJyYXkoZSkubGVuZ3RoOjEsInNwcmVhZGVkICcuLi4nIHZhbHVlIiksVHdpbmVTY3JpcHRfVW5zdG9yYWJsZTohMCxUd2luZVNjcmlwdF9Ub1NvdXJjZTpmdW5jdGlvbigpe3JldHVybiIiK190b0NvbnN1bWFibGVBcnJheShlKS5tYXAoZCl9fX19O3JldHVybiBPYmplY3QuZnJlZXplKHQpfSksZGVmaW5lKCJ0d2luZXNjcmlwdC9ydW5uZXIiLFsibWFjcm9zIiwic3RhdGUiLCJ1dGlscyIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwidHdpbmVzY3JpcHQvb3BlcmF0aW9ucyIsImRhdGF0eXBlcy9jb2xvdXIiLCJkYXRhdHlwZXMvaG9va3NldCIsImRhdGF0eXBlcy9sYW1iZGEiLCJkYXRhdHlwZXMvZGF0YXR5cGUiLCJkYXRhdHlwZXMvdmFyYmluZCIsImRhdGF0eXBlcy9jb2RlaG9vayIsImRhdGF0eXBlcy90eXBlZHZhciIsImRhdGF0eXBlcy9hc3NpZ25tZW50cmVxdWVzdCIsImludGVybmFsdHlwZXMvdmFycmVmIiwiaW50ZXJuYWx0eXBlcy90d2luZWVycm9yIl0sZnVuY3Rpb24oTWFjcm9zLFN0YXRlLFV0aWxzLF9yZWYxMjcsT3BlcmF0aW9ucyxDb2xvdXIsSG9va1NldCxMYW1iZGEsRGF0YXR5cGUsVmFyQmluZCxDb2RlSG9vayxUeXBlZFZhcixBc3NpZ25tZW50UmVxdWVzdCxWYXJSZWYsVHdpbmVFcnJvcil7dmFyIHRvU291cmNlPV9yZWYxMjcudG9Tb3VyY2UsdHlwZU5hbWU9X3JlZjEyNy50eXBlTmFtZSxvYmplY3ROYW1lPV9yZWYxMjcub2JqZWN0TmFtZSxpbnNlbnNpdGl2ZU5hbWU9VXRpbHMuaW5zZW5zaXRpdmVOYW1lLGltcG9zc2libGU9VXRpbHMuaW1wb3NzaWJsZSxoYXNoPVV0aWxzLmhhc2g7ZnVuY3Rpb24gYWRkRnJlZVZhcmlhYmxlKGUsdCl7dmFyIG4scj1lLmZyZWVWYXJpYWJsZXM7Im1hY3JvIj09PXQudHlwZT8iY3VycmVudC10aW1lIj09PShuPWluc2Vuc2l0aXZlTmFtZSh0Lm5hbWUpKXx8ImN1cnJlbnQtZGF0ZSI9PT1ufHwibW9udGhkYXkiPT09bnx8IndlZWtkYXkiPT09bnx8Imhpc3RvcnkiPT09bnx8InZpc2l0ZWQiPT09bnx8InBhc3NhZ2UiPT09bj9lLmZyZWVWYXJpYWJsZXM9ITA6dC5ibG9ja2VkVmFsdWUmJiFyLmJsb2NrZWRWYWx1ZXM/ci5ibG9ja2VkVmFsdWVzPWUuc3RhY2tUb3AuYmxvY2tlZFZhbHVlcy5jb25jYXQoKToicmFuZG9tIiE9PW4mJiJlaXRoZXIiIT09biYmInNodWZmbGVkIiE9PW58fHIuc2VlZHx8KHIuc2VlZD1TdGF0ZS5zZWVkLHIuc2VlZEl0ZXI9U3RhdGUuc2VlZEl0ZXIpOiJpZGVudGlmaWVyIj09PXQudHlwZT8idGltZSIhPT0obj1pbnNlbnNpdGl2ZU5hbWUodC50ZXh0KSkmJiJleGl0cyIhPT1uJiYiaXQiIT09biYmInZpc2l0cyIhPT1uJiYidHVybnMiIT09bnx8KGUuZnJlZVZhcmlhYmxlcz0hMCk6InByb3BlcnR5Ij09PXQudHlwZXx8ImJlbG9uZ2luZ1Byb3BlcnR5Ij09PXQudHlwZT8icmFuZG9tIiE9PWluc2Vuc2l0aXZlTmFtZSh0Lm5hbWUpfHxyLnNlZWR8fChyLnNlZWQ9U3RhdGUuc2VlZCxyLnNlZWRJdGVyPVN0YXRlLnNlZWRJdGVyKToidmFyaWFibGUiIT09dC50eXBlJiYidGVtcFZhcmlhYmxlIiE9PXQudHlwZXx8KGUuZnJlZVZhcmlhYmxlcz0hMCl9dmFyIHByZWNlZGVuY2VUYWJsZT1bWyJlcnJvciIsInRleHQiXSxbImNvbW1hIl0sWyJ0byIsImludG8iXSxbIndoZXJlIiwid2hlbiIsInZpYSIsIm1ha2luZyIsImVhY2giXSxbInR5cGVTaWduYXR1cmUiXSxbImF1Z21lbnRlZEFzc2lnbiJdLFsiYW5kIiwib3IiXSxbImlzIiwiaXNOb3QiXSxbImNvbnRhaW5zIiwiZG9lc05vdENvbnRhaW4iLCJpc0luIiwiaXNOb3RJbiJdLFsiaXNBIiwiaXNOb3RBIiwibWF0Y2hlcyIsImRvZXNOb3RNYXRjaCJdLFsiaW5lcXVhbGl0eSJdLFsiYWRkaXRpb24iLCJzdWJ0cmFjdGlvbiJdLFsibXVsdGlwbGljYXRpb24iLCJkaXZpc2lvbiJdLHtyaWdodEFzc29jaWF0aXZlOlsic3ByZWFkIiwiYmluZCJdfSx7cmlnaHRBc3NvY2lhdGl2ZTpbIm5vdCIsInBvc2l0aXZlIiwibmVnYXRpdmUiXX0se3JpZ2h0QXNzb2NpYXRpdmU6WyJiZWxvbmdpbmdQcm9wZXJ0eSIsImJlbG9uZ2luZ0l0UHJvcGVydHkiLCJiZWxvbmdpbmdPcGVyYXRvciIsImJlbG9uZ2luZ0l0T3BlcmF0b3IiXX0sWyJwcm9wZXJ0eSIsIml0c1Byb3BlcnR5IiwicG9zc2Vzc2l2ZU9wZXJhdG9yIiwiaXRzT3BlcmF0b3IiXSxbInR3aW5lTGluayIsIm1hY3JvIiwiaWRlbnRpZmllciIsInZhcmlhYmxlIiwidGVtcFZhcmlhYmxlIiwiaG9va05hbWUiLCJudW1iZXIiLCJjc3NUaW1lIiwiYm9vbGVhbiIsInN0cmluZyIsImhvb2siLCJjb2xvdXIiLCJkYXRhdHlwZSIsInJvb3QiXSxbImdyb3VwaW5nIl1dO2Z1bmN0aW9uIHByZWNlZGVudFRva2VuKGUsdCl7dmFyIG4scixhLG89W107aWYoZS5sZW5ndGgpZm9yKCJtb3N0Ij09PXQ/KG49cHJlY2VkZW5jZVRhYmxlLmxlbmd0aC0xLHI9YT0tMSk6KG49MCxyPXByZWNlZGVuY2VUYWJsZS5sZW5ndGgsYT0xKTtuIT09cjtuKz1hKXt2YXIgaT1wcmVjZWRlbmNlVGFibGVbbl0scz1OYU47aWYoaS5yaWdodEFzc29jaWF0aXZlKXtmb3IodmFyIGM9MDtjPGUubGVuZ3RoO2MrPTEpaWYoaS5yaWdodEFzc29jaWF0aXZlLmluY2x1ZGVzKGVbY10udHlwZSkpe3M9YzticmVha319ZWxzZSBmb3IodmFyIGw9ZS5sZW5ndGgtMTswPD1sOy0tbClpZihpLmluY2x1ZGVzKGVbbF0udHlwZSkpe3M9bDticmVha31pZighTnVtYmVyLmlzTmFOKHMpJiYtMTxzKXtvPVtlW3NdLHNdO2JyZWFrfX1yZXR1cm4gb312YXIgY29tcGFyaXNvbk9wVHlwZXM9WyJpbmVxdWFsaXR5IiwiaXMiLCJpc05vdCIsImlzSW4iLCJjb250YWlucyIsImRvZXNOb3RDb250YWluIiwiaXNOb3RJbiIsImlzQSIsInR5cGlmaWVzIiwiaXNOb3RBIiwidW50eXBpZmllcyIsIm1hdGNoZXMiLCJkb2VzTm90TWF0Y2giXSxpbmVxdWFsaXR5TmVnYXRvcj17Ij4iOiI8PSIsIjwiOiI+PSIsIj49IjoiPCIsIjw9IjoiPiJ9O2Z1bmN0aW9uIGNvbXBpbGVDb21wYXJpc29uT3BlcmF0b3IoZSl7cmV0dXJuImluZXF1YWxpdHkiPT09ZS50eXBlP2UubmVnYXRlP2luZXF1YWxpdHlOZWdhdG9yW2Uub3BlcmF0b3JdOmUub3BlcmF0b3I6ZS50eXBlfXZhciBjb21wYXJpc29uUmV2ZXJzZXI9eyI+IjoiPCIsIjwiOiI+IiwiPj0iOiI8PSIsIjw9IjoiPj0iLGNvbnRhaW5zOiJpc0luIixkb2VzTm90Q29udGFpbjoiaXNOb3RJbiIsaXNJbjoiY29udGFpbnMiLGlzQToidHlwaWZpZXMiLHR5cGlmaWVzOiJpc0EiLGlzTm90QToidW50eXBpZmllcyIsdW50eXBpZmllczoiaXNOb3RBIn07ZnVuY3Rpb24gcmV2ZXJzZUNvbXBhcmlzb25PcGVyYXRvcihlKXtlPWNvbXBpbGVDb21wYXJpc29uT3BlcmF0b3IoZSk7cmV0dXJuIGNvbXBhcmlzb25SZXZlcnNlcltlXXx8ZX12YXIgdG9rZW5TaWRlcz17ZXJyb3I6Im5laXRoZXIiLGlkZW50aWZpZXI6Im5laXRoZXIiLHZhcmlhYmxlOiJuZWl0aGVyIix0ZW1wVmFyaWFibGU6Im5laXRoZXIiLGhvb2tOYW1lOiJuZWl0aGVyIixudW1iZXI6Im5laXRoZXIiLGJvb2xlYW46Im5laXRoZXIiLHN0cmluZzoibmVpdGhlciIsaG9vazoibmVpdGhlciIsY29sb3VyOiJuZWl0aGVyIixkYXRhdHlwZToibmVpdGhlciIscm9vdDoibmVpdGhlciIsdHdpbmVMaW5rOiJuZWl0aGVyIixtYWNybzoibmVpdGhlciIsZ3JvdXBpbmc6Im5laXRoZXIiLGl0c1Byb3BlcnR5OiJuZWl0aGVyIixiZWxvbmdpbmdJdFByb3BlcnR5OiJuZWl0aGVyIix0bzoiYm90aCIsaW50bzoiYm90aCIsdHlwZVNpZ25hdHVyZToiYm90aCIsYXVnbWVudGVkQXNzaWduOiJib3RoIixhbmQ6ImJvdGgiLG9yOiJib3RoIixiZWxvbmdpbmdPcGVyYXRvcjoiYm90aCIscG9zc2Vzc2l2ZU9wZXJhdG9yOiJib3RoIixtdWx0aXBsaWNhdGlvbjoiYm90aCIsZGl2aXNpb246ImJvdGgiLHNwcmVhZDoiYWZ0ZXIiLGJpbmQ6ImFmdGVyIixub3Q6ImFmdGVyIixiZWxvbmdpbmdQcm9wZXJ0eToiYWZ0ZXIiLGVhY2g6ImFmdGVyIixpdHNPcGVyYXRvcjoiYWZ0ZXIiLHBvc2l0aXZlOiJhZnRlciIsbmVnYXRpdmU6ImFmdGVyIixiZWxvbmdpbmdJdE9wZXJhdG9yOiJiZWZvcmUiLHByb3BlcnR5OiJiZWZvcmUifTtmdW5jdGlvbiBtaXNzaW5nU2lkZUVycm9yKGUsdCxuKXtyZXR1cm4gVHdpbmVFcnJvci5jcmVhdGUoInN5bnRheCIsIkkgbmVlZCB1c2FibGUgY29kZSB0byBiZSAiLmNvbmNhdChlPyJsZWZ0ICI6IiIpLmNvbmNhdChlJiZ0PyJhbmQgIjoiIikuY29uY2F0KHQ/InJpZ2h0ICI6IiIsIm9mICIpLmNvbmNhdChuLnRleHQsIi4iKSl9ZnVuY3Rpb24gd3JvbmdTaWRlRXJyb3IoZSx0LG4pe3JldHVybiBUd2luZUVycm9yLmNyZWF0ZSgic3ludGF4IiwiVGhlcmUgY2FuJ3QgYmUgYSAiLmNvbmNhdChlJiZ0P2UubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRleHR9KS5qb2luKCIiKSsiIG9yICIrdC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudGV4dH0pLmpvaW4oIiIpOihlfHx0KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudGV4dH0pLmpvaW4oIiIpLCIgdG8gdGhlICIpLmNvbmNhdChlPyJsZWZ0ICI6IiIpLmNvbmNhdChlJiZ0PyJvciAiOiIiKS5jb25jYXQodD8icmlnaHQgIjoiIiwib2YgIikuY29uY2F0KG4udGV4dCwiLiIpLCJUaGVyZSBjb3VsZCBiZSBhIGNvbW1hIG1pc3NpbmcgYmV0d2VlbiB0aGVtLiIpfWZ1bmN0aW9uIG1ha2VFdmFsUmVwbGF5RnJhbWUoZSx0KXt2YXIgbj10LnZhbCxyPXQuZnJvbUNvZGUsYT10LnRvQ29kZSxvPXQudG9EZXNjLGk9dC5yZWFzb24scz10Lml0LGM9dC50b2tlbnMsdD10Lmk7aWYoISgyMDA8PWUubGVuZ3RoKSl7dmFyIGw9Y1t0XSx1PWMuc2xpY2UoMCx0KSx0PWMuc2xpY2UodCsxKTtpZigxPT09Yy5sZW5ndGgmJih1PXQ9ITEsbD1jWzBdKSwhZVtlLmxlbmd0aC0xXS5lcnJvcil7dmFyIHAsZCxjPVR3aW5lRXJyb3IuY29udGFpbnNFcnJvcihuKSxmPWVbZS5sZW5ndGgtMV0uY29kZSxoPWVbMF0uYmFzaXMsbT0obnVsbCE9KHA9dSkmJnAubGVuZ3RoJiZudWxsIT0ocD10KSYmcC5sZW5ndGgmJnVbMF0uc3RhcnQ+dFswXS5zdGFydCYmKHU9KHA9W3QsdV0pWzBdLHQ9cFsxXSkscD1hfHwiIi5jb25jYXQobnVsbCE9KHA9dSkmJnAubGVuZ3RoJiYid2hpdGVzcGFjZSI9PT11W3UubGVuZ3RoLTFdLnR5cGU/IiAiOiIiKS5jb25jYXQoYz8iIFx1ZDgzZFx1ZGMxZSAiOihuJiYhbi5Ud2luZVNjcmlwdF9Ub1NvdXJjZSYmbi5Ud2luZVNjcmlwdF9VbnN0b3JhYmxlP29iamVjdE5hbWU6dG9Tb3VyY2UpKG4pKS5jb25jYXQobnVsbD09KHA9dCl8fCFwLmxlbmd0aHx8IndoaXRlc3BhY2UiIT09dFswXS50eXBlJiYiYWRkaXRpb24iIT09bC50eXBlJiYic3VidHJhY3Rpb24iIT09bC50eXBlPyIiOiIgIiksKHUubGVuZ3RoP3VbMF06bCkuc3RhcnQtaCksZz0odC5sZW5ndGg/dFt0Lmxlbmd0aC0xXTpsKS5lbmQtaCx5PV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKGUpO3RyeXtmb3IoeS5zKCk7IShkPXkubigpKS5kb25lOyl7dmFyIGI9ZC52YWx1ZTtiLnN0YXJ0PG0/KG0rPWIuZGlmZixnKz1iLmRpZmYpOmIuc3RhcnQ8ZyYmKGcrPWIuZGlmZil9fWNhdGNoKGUpe3kuZShlKX1maW5hbGx5e3kuZigpfSFyJiYocj1mLnNsaWNlKG0sZyksYSkmJmEudHJpbSgpPT09ci50cmltKCl8fCh1PXAubGVuZ3RoLShnLW0pLGUucHVzaCh7Y29kZTpmLnNsaWNlKDAsbSkrcCtmLnNsaWNlKGcpLGZyb21Db2RlOnIsdG9Db2RlOiFjJiZhLHRvRGVzYzohYyYmIWEmJihvfHxvYmplY3ROYW1lKG4pKSxzdGFydDptLGVuZDpnLGRpZmY6dSxyZWFzb246aSxpdElkZW50aWZpZXI6dm9pZCAwIT09cyYmb2JqZWN0TmFtZShzKSxlcnJvcjpjJiZjLnJlbmRlcihmLnNsaWNlKG0sZyksITApfSkpfX19ZnVuY3Rpb24gc2V0SXQoZSx0KXtyZXR1cm4oVmFyUmVmLmlzUHJvdG90eXBlT2YodCl8fFR5cGVkVmFyLmlzUHJvdG90eXBlT2YodCkpJiYoZS5JZGVudGlmaWVycy5pdD10LmdldCgpKSx0fXJldHVybiBmdW5jdGlvbiBydW4oc2VjdGlvbix0b2tlbnMpe3ZhciBpc1ZhclJlZj0yPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1syXSYmYXJndW1lbnRzWzJdLGlzVHlwZWRWYXI9Mzxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbM10mJmFyZ3VtZW50c1szXSxldmFsUmVwbGF5PXNlY3Rpb24uZXZhbFJlcGxheSxoYXNFdmFsUmVwbGF5PW51bGw9PWV2YWxSZXBsYXk/dm9pZCAwOmV2YWxSZXBsYXkubGVuZ3RoLGV2YWxSZXBsYXlSZWFzb24sZXZhbFJlcGxheVNraXA9ITEsZXZhbFJlcGxheUl0LG9wcz1PcGVyYXRpb25zLHRva2VuLHJldCxpLGJlZm9yZSxhZnRlcixfcHJlY2VkZW50VG9rZW4sX3ByZWNlZGVudFRva2VuMix0b2tlbixpLGJlZm9yZSxhZnRlcjtpZihBcnJheS5pc0FycmF5KHRva2Vucyl8fCh0b2tlbnM9W3Rva2Vuc10pLCF0b2tlbnMubGVuZ3RofHwhdG9rZW5zWzBdKXJldHVybiBpbXBvc3NpYmxlKCJSdW5uZXIucnVuIiwiTm8gdG9rZW5zIHRvIHJ1biEiKSwwOzE9PT10b2tlbnMubGVuZ3RoP3Rva2VuPXRva2Vuc1swXTooX3ByZWNlZGVudFRva2VuPXByZWNlZGVudFRva2VuKHRva2VucywibGVhc3QiKSxfcHJlY2VkZW50VG9rZW4yPV9zbGljZWRUb0FycmF5KF9wcmVjZWRlbnRUb2tlbiwyKSx0b2tlbj1fcHJlY2VkZW50VG9rZW4yWzBdLGk9X3ByZWNlZGVudFRva2VuMlsxXSxiZWZvcmU9dG9rZW5zLnNsaWNlKDAsaSksYWZ0ZXI9dG9rZW5zLnNsaWNlKGkrMSksYmVmb3JlLmxlbmd0aCYmKDEhPT1iZWZvcmUubGVuZ3RofHwid2hpdGVzcGFjZSIhPT1iZWZvcmVbMF0udHlwZSl8fChiZWZvcmU9ITEpLGFmdGVyLmxlbmd0aCYmKDEhPT1hZnRlci5sZW5ndGh8fCJ3aGl0ZXNwYWNlIiE9PWFmdGVyWzBdLnR5cGUpfHwoYWZ0ZXI9ITEpKTt2YXIgdHlwZT10b2tlbi50eXBlO2lmKCF0eXBlKXJldHVybiBpbXBvc3NpYmxlKCJSdW5uZXIucnVuIiwiVG9rZW4gaGFzIG5vIHR5cGUhIiksMDt2YXIgc2lkZXM9dG9rZW5TaWRlc1t0eXBlXXx8IiIsVkFSUkVGPSgiYm90aCIhPT1zaWRlc3x8YmVmb3JlJiZhZnRlcj8ibmVpdGhlciI9PT1zaWRlcyYmKGJlZm9yZXx8YWZ0ZXIpP3JldD13cm9uZ1NpZGVFcnJvcihiZWZvcmUsYWZ0ZXIsdG9rZW4pOiJiZWZvcmUiPT09c2lkZXM/YmVmb3JlP2FmdGVyJiYocmV0PXdyb25nU2lkZUVycm9yKG51bGwsYWZ0ZXIsdG9rZW4pKTpyZXQ9bWlzc2luZ1NpZGVFcnJvcighMCwhMSx0b2tlbik6ImFmdGVyIj09PXNpZGVzJiYoYWZ0ZXI/YmVmb3JlJiYocmV0PXdyb25nU2lkZUVycm9yKGJlZm9yZSxudWxsLHRva2VuKSk6cmV0PW1pc3NpbmdTaWRlRXJyb3IoITEsITAsdG9rZW4pKTpyZXQ9bWlzc2luZ1NpZGVFcnJvcighYmVmb3JlLCFhZnRlcix0b2tlbiksc2VjdGlvbi5mcmVlVmFyaWFibGVzJiYib2JqZWN0Ij09PV90eXBlb2Yoc2VjdGlvbi5mcmVlVmFyaWFibGVzKSYmYWRkRnJlZVZhcmlhYmxlKHNlY3Rpb24sdG9rZW4pLCEwKSxUWVBFRFZBUj0hMCxfcmV0NCx2YWwsZXZhbFJlcGxheVJlYXNvbixyZXQsc291cmNlLF9zb3VyY2U0LF92YWx1ZTQsbXNnO2lmKCFyZXQpe2lmKCJjb21tYSI9PT10eXBlKXJldHVybiBpbXBvc3NpYmxlKCJTZWN0aW9uLnJ1biIsImEgY29tbWEgdG9rZW4gd2FzIHJ1bigpIHNvbWVob3cuIiksMDtpZigicm9vdCI9PT10eXBlKXJldD1ydW4oc2VjdGlvbix0b2tlbi5jaGlsZHJlbik7ZWxzZSBpZigiaWRlbnRpZmllciI9PT10eXBlKXJldD1pc1ZhclJlZj9WYXJSZWYuY3JlYXRlKHNlY3Rpb24uSWRlbnRpZmllcnMsdG9rZW4udGV4dC50b0xvd2VyQ2FzZSgpKTpzZWN0aW9uLklkZW50aWZpZXJzW3Rva2VuLnRleHQudG9Mb3dlckNhc2UoKV07ZWxzZSBpZigidmFyaWFibGUiPT09dHlwZXx8InRlbXBWYXJpYWJsZSI9PT10eXBlKXtyZXQ9VmFyUmVmLmNyZWF0ZSgidGVtcFZhcmlhYmxlIj09PXR5cGU/c2VjdGlvbi5zdGFja1RvcC50ZW1wVmFyaWFibGVzOlN0YXRlLnZhcmlhYmxlcyx0b2tlbi5uYW1lKSxpc1R5cGVkVmFyPyhyZXQ9VHlwZWRWYXIuY3JlYXRlKERhdGF0eXBlLmNyZWF0ZSgiYW55IikscmV0KSxldmFsUmVwbGF5UmVhc29uPWhhc0V2YWxSZXBsYXkmJiJWYXJpYWJsZXMgaW4gJ3RvJyBvciAnaW50bycgZXhwcmVzc2lvbnMgd2l0aCBubyAtdHlwZSB0byB0aGVpciBsZWZ0IGFyZSBjb25zaWRlcmVkIHRvIGJlICdhbnktdHlwZScgdmFyaWFibGVzIHRoYXQgY2FuIHN0b3JlIGFueSBzdG9yYWJsZSB2YWx1ZS4iKTppc1ZhclJlZnx8VHdpbmVFcnJvci5jb250YWluc0Vycm9yKHJldCk/ZXZhbFJlcGxheVNraXA9ITA6KHZhbD1yZXQuZ2V0KCksZXZhbFJlcGxheVJlYXNvbj1oYXNFdmFsUmVwbGF5JiYoKG51bGw9PShfcmV0ND1yZXQpP3ZvaWQgMDpfcmV0NC5vYmplY3QpIT09U3RhdGUudmFyaWFibGVzfHxoYXNPd25Qcm9wZXJ0eS5jYWxsKHJldC5vYmplY3QscmV0LmNvbXBpbGVkUHJvcGVydHlDaGFpblswXSk/IiI6IlRoaXMgdmFyaWFibGUgZGlkbid0IGV4aXN0OyBmb3Igc3Rvcnktd2lkZSAkIHZhcmlhYmxlcywgYSBkZWZhdWx0IHZhbHVlIG9mIDAgaXMgdXNlZCBpZiB0aGV5IGRvbid0IGV4aXN0LiIpLHJldD12YWwpfWVsc2UgaWYoImhvb2tOYW1lIj09PXR5cGUpcmV0PUhvb2tTZXQuY3JlYXRlKHt0eXBlOiJuYW1lIixkYXRhOnRva2VuLm5hbWV9KSxldmFsUmVwbGF5U2tpcD0hMDtlbHNlIGlmKCJudW1iZXIiPT09dHlwZXx8ImNzc1RpbWUiPT09dHlwZSlyZXQ9dG9rZW4udmFsdWUsZXZhbFJlcGxheVJlYXNvbj1oYXNFdmFsUmVwbGF5JiYiY3NzVGltZSI9PT10eXBlJiYodG9rZW4udGV4dC5lbmRzV2l0aCgibXMiKT8iVGhlIGxldHRlcnMgJ21zJyBhdCB0aGUgZW5kIG9mIG51bWJlcnMgYXJlIGlnbm9yZWQsIHNvIHlvdSBjYW4gdXNlIHRoZW0gdG8gaW5kaWNhdGUgdGhhdCBhIG51bWJlciByZXByZXNlbnRzIG1pbGxpc2Vjb25kcy4iOiJUaGUgbGV0dGVyICdzJyBhdCB0aGUgZW5kIG9mIG51bWJlcnMgcmVwcmVzZW50cyAnc2Vjb25kcycuIEhhcmxvd2UgY29udmVydHMgdGhlbSB0byBtaWxsaXNlY29uZHMgKG11bHRpcGxpZXMgdGhlbSBieSAxMDAwKS4iKSxldmFsUmVwbGF5U2tpcD0hZXZhbFJlcGxheVJlYXNvbjtlbHNlIGlmKCJib29sZWFuIj09PXR5cGUpcmV0PSJ0cnVlIj09PXRva2VuLnRleHQudG9Mb3dlckNhc2UoKSxldmFsUmVwbGF5U2tpcD0hMDtlbHNlIGlmKCJzdHJpbmciPT09dHlwZSl7dmFyIHQ9dG9rZW4udGV4dC5yZXBsYWNlKC8oLj8pXG4vZyxmdW5jdGlvbihlLHQpe3JldHVybigiXFwiPT09dD8iXFxcXCI6IlxuIj09PXQ/IlxcbiI6dCkrIlxcbiJ9KS5yZXBsYWNlKC8oXFwqKVxcMC9nLGZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ/IlxcIi5yZXBlYXQoMip0Lmxlbmd0aCk6IiIpKyIwIn0pO3JldD1ldmFsKHQpLGV2YWxSZXBsYXlTa2lwPSEwfWVsc2UgaWYoImhvb2siPT09dHlwZSlyZXQ9Q29kZUhvb2suY3JlYXRlKHRva2VuLmNoaWxkcmVuLHRva2VuLnRleHQpLGV2YWxSZXBsYXlTa2lwPSEwO2Vsc2UgaWYoImNvbG91ciI9PT10eXBlKXJldD1Db2xvdXIuY3JlYXRlKHRva2VuLmNvbG91ciksZXZhbFJlcGxheVNraXA9ITA7ZWxzZSBpZigiZGF0YXR5cGUiPT09dHlwZSlyZXQ9RGF0YXR5cGUuY3JlYXRlKHRva2VuLm5hbWUpLGV2YWxSZXBsYXlTa2lwPSEwO2Vsc2UgaWYoInNwcmVhZCI9PT10eXBlKXJldD1vcHMubWFrZVNwcmVhZGVyKHJ1bihzZWN0aW9uLGFmdGVyLCExLGlzVHlwZWRWYXIpKTtlbHNlIGlmKCJiaW5kIj09PXR5cGUpcmV0PVZhckJpbmQuY3JlYXRlKHJ1bihzZWN0aW9uLGFmdGVyLFZBUlJFRiksdG9rZW4udGV4dC5zdGFydHNXaXRoKCIyIik/InR3byB3YXkiOiIiKSxldmFsUmVwbGF5U2tpcD0hMDtlbHNlIGlmKCJ0byI9PT10eXBlfHwiaW50byI9PT10eXBlKXt2YXIgZGVzdD0idG8iPT09dHlwZT9zZXRJdChzZWN0aW9uLHJ1bihzZWN0aW9uLGJlZm9yZSxWQVJSRUYsVFlQRURWQVIpKTpydW4oc2VjdGlvbixhZnRlcixWQVJSRUYsVFlQRURWQVIpO2lmKFR3aW5lRXJyb3IuY29udGFpbnNFcnJvcihkZXN0KSlyZXQ9ZGVzdDtlbHNleyhWYXJSZWYuaXNQcm90b3R5cGVPZihkZXN0KSYmZGVzdC5wcm9wZXJ0eUNoYWluLmxlbmd0aDw9MXx8VHlwZWRWYXIuaXNQcm90b3R5cGVPZihkZXN0KSYmZGVzdC52YXJSZWYucHJvcGVydHlDaGFpbi5sZW5ndGg8PTEpJiYoc2VjdGlvbi5mcmVlVmFyaWFibGVzPU9iamVjdC5jcmVhdGUobnVsbCkpO3ZhciBzcmM9InRvIj09PXR5cGU/cnVuKHNlY3Rpb24sYWZ0ZXIsVkFSUkVGKTpzZXRJdChzZWN0aW9uLHJ1bihzZWN0aW9uLGJlZm9yZSxWQVJSRUYpKTtpZihUd2luZUVycm9yLmNvbnRhaW5zRXJyb3Ioc3JjKSlyZXR1cm4gc3JjO3ZhciBmcmVlVmFyaWFibGVzPXNlY3Rpb24uZnJlZVZhcmlhYmxlcyxzcmNSZWY7c2VjdGlvbi5mcmVlVmFyaWFibGVzPW51bGwsdG9rZW4ucGxhY2UmJmZyZWVWYXJpYWJsZXMmJiJvYmplY3QiPT09X3R5cGVvZihmcmVlVmFyaWFibGVzKSYmImJvb2xlYW4iIT10eXBlb2Ygc3JjJiYibnVtYmVyIiE9dHlwZW9mIHNyYyYmIVV0aWxzLm9wdGlvbnMudW5jb21wcmVzc2VkUHVyZVZhbHVlcyYmKHNyY1JlZj1mcmVlVmFyaWFibGVzLHNyY1JlZi5hdD10b2tlbi5wbGFjZSxzcmNSZWYuZnJvbT1hZnRlclswXS5zdGFydCxzcmNSZWYudG89YWZ0ZXJbYWZ0ZXIubGVuZ3RoLTFdLmVuZCxzcmNSZWYuaGFzaD1oYXNoKGFmdGVyLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlK3QudGV4dH0sIiIpKS50b1N0cmluZygxNiksSlNPTi5zdHJpbmdpZnkoc3JjUmVmKS5sZW5ndGg+PXRvU291cmNlKHNyYykubGVuZ3RoKSYmKHNyY1JlZj12b2lkIDApLHJldD1Bc3NpZ25tZW50UmVxdWVzdC5jcmVhdGUoZGVzdCxzcmMsdHlwZSxzcmNSZWYpLGV2YWxSZXBsYXlTa2lwPSEwLGV2YWxSZXBsYXlJdD1zZWN0aW9uLklkZW50aWZpZXJzLml0fX1lbHNlIGlmKCJ0eXBlU2lnbmF0dXJlIj09PXR5cGUpe3ZhciBkYXRhdHlwZT1ydW4oc2VjdGlvbixiZWZvcmUpLGZyZWU9c2VjdGlvbi5mcmVlVmFyaWFibGVzLHZhcmlhYmxlPShzZWN0aW9uLmZyZWVWYXJpYWJsZXM9bnVsbCxydW4oc2VjdGlvbixhZnRlcixWQVJSRUYpKTtzZWN0aW9uLmZyZWVWYXJpYWJsZXM9ZnJlZSxyZXQ9VHlwZWRWYXIuY3JlYXRlKGRhdGF0eXBlLHZhcmlhYmxlKSxldmFsUmVwbGF5U2tpcD0hMH1lbHNlIGlmKCJ3aGVyZSI9PT10eXBlfHwid2hlbiI9PT10eXBlfHwidmlhIj09PXR5cGUpe2FmdGVyPyhzb3VyY2U9dG9rZW5zLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS50ZXh0fSkuam9pbigiIikscmV0PUxhbWJkYS5jcmVhdGUoYmVmb3JlP3J1bihzZWN0aW9uLGJlZm9yZSxWQVJSRUYpOnZvaWQgMCx0b2tlbi50eXBlLGFmdGVyLHNvdXJjZSksZXZhbFJlcGxheVNraXA9ITApOnJldD1taXNzaW5nU2lkZUVycm9yKCExLCEwLHRva2VuKX1lbHNlIGlmKCJtYWtpbmciPT09dHlwZXx8ImVhY2giPT09dHlwZSl7YWZ0ZXI/KF9zb3VyY2U0PVtdLmNvbmNhdCh0b2tlbnMpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS50ZXh0fSkuam9pbigiIikscmV0PSJlYWNoIj09PXR5cGU/TGFtYmRhLmNyZWF0ZShydW4oc2VjdGlvbixhZnRlcixWQVJSRUYpLCJlYWNoIixudWxsLF9zb3VyY2U0KTpMYW1iZGEuY3JlYXRlKGJlZm9yZT9ydW4oc2VjdGlvbixiZWZvcmUsVkFSUkVGKTp2b2lkIDAsdG9rZW4udHlwZSxydW4oc2VjdGlvbixhZnRlcixWQVJSRUYpLF9zb3VyY2U0KSxldmFsUmVwbGF5U2tpcD0hMCk6cmV0PW1pc3NpbmdTaWRlRXJyb3IoITEsITAsdG9rZW4pfWVsc2UgaWYoImF1Z21lbnRlZEFzc2lnbiI9PT10eXBlKXJldD1vcHMubWFrZUFzc2lnbm1lbnRSZXF1ZXN0KHJ1bihzZWN0aW9uLGJlZm9yZSxWQVJSRUYpLG9wc1t0b2tlbi5vcGVyYXRvcl0ocnVuKHNlY3Rpb24sYmVmb3JlKSxydW4oc2VjdGlvbixhZnRlcikpLHRva2VuLm9wZXJhdG9yKSxldmFsUmVwbGF5U2tpcD0hMDtlbHNlIGlmKCJhbmQiPT09dHlwZXx8Im9yIj09PXR5cGUpe3ZhciBpc0NvbXBhcmlzb25PcD1mdW5jdGlvbiBlKHQpe3ZhciBuPV9zbGljZWRUb0FycmF5KHByZWNlZGVudFRva2VuKHQsImxlYXN0IiksMikscj1uWzBdLG49blsxXTtpZihyJiYid2hpdGVzcGFjZSIhPT1yLnR5cGUpcmV0dXJuIGNvbXBhcmlzb25PcFR5cGVzLmluY2x1ZGVzKHIudHlwZSk/cjpyLnR5cGU9PT10eXBlP2UodC5zbGljZSgwLG4pKXx8ZSh0LnNsaWNlKG4rMSkpOnZvaWQgMH0sbGVmdElzQ29tcGFyaXNvbj1pc0NvbXBhcmlzb25PcChiZWZvcmUpLHJpZ2h0SXNDb21wYXJpc29uPWlzQ29tcGFyaXNvbk9wKGFmdGVyKSxhbWJpZ3VpdHlFcnJvcj1Ud2luZUVycm9yLmNyZWF0ZSgib3BlcmF0aW9uIiwnVGhpcyB1c2Ugb2YgImlzIG5vdCIgYW5kICInLmNvbmNhdCh0eXBlLCciIGlzIGdyYW1tYXRpY2FsbHkgYW1iaWd1b3VzLicpLCdNYXliZSB0cnkgcmV3cml0aW5nIHRoaXMgYXMgIl9fIGlzIG5vdCBfXyAnLmNvbmNhdCh0eXBlLCcgX18gaXMgbm90IF9fIicpKSxvcGVyYXRvcixnZXRFbGlzaW9uT3BlcmFuZHM9ZnVuY3Rpb24gZSh0KXt2YXIgbixyPV9zbGljZWRUb0FycmF5KHByZWNlZGVudFRva2VuKHQsImxlYXN0IiksMiksYT1yWzBdLHI9clsxXTtyZXR1cm4gYSYmIndoaXRlc3BhY2UiIT09YS50eXBlP2EudHlwZT09PXR5cGU/W10uY29uY2F0KF90b0NvbnN1bWFibGVBcnJheShlKHQuc2xpY2UoMCxyKSkpLF90b0NvbnN1bWFibGVBcnJheShlKHQuc2xpY2UocisxKSkpKTooYT1ydW4oc2VjdGlvbix0KSxoYXNFdmFsUmVwbGF5JiYiYm9vbGVhbiIhPXR5cGVvZiBhJiYobj1vcGVyYXRvci5yZXBsYWNlKC9bQS1aXS9nLGZ1bmN0aW9uKGUpe3JldHVybiIgIitlLnRvTG93ZXJDYXNlKCl9KSxtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3RvQ29kZToiIGl0ICIuY29uY2F0KG4sIiAiKS5jb25jYXQodG9Tb3VyY2UoYSksIiAiKSxyZWFzb246IkEgbWlzc2luZyAnaXQgIi5jb25jYXQobiwiJyB3YXMgaW5mZXJyZWQgdG8gY29ycmVjdCB0aGUgJyIpLmNvbmNhdCh0eXBlLCInIG9wZXJhdGlvbi4iKSx0b2tlbnM6dCxpOnJ9KSxtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3RvQ29kZToiICIuY29uY2F0KHRvU291cmNlKHNlY3Rpb24uSWRlbnRpZmllcnMuaXQpLCIgIikuY29uY2F0KG4sIiAiKS5jb25jYXQodG9Tb3VyY2UoYSksIiAiKSx0b2tlbnM6dCxpOnJ9KSksW3t2YWw6YSx0b2tlbnM6dCxpOnJ9XSk6W119LGVsaWRlZENvbXBhcmlzb25PcGVyYXRvcj1mdW5jdGlvbigpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9bmV3IEFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3JldHVybiB0LnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuPXQudmFsLHI9dC50b2tlbnMsdD10Lmk7cmV0dXJuImJvb2xlYW4iPT10eXBlb2Ygbj9uOihlPU9wZXJhdGlvbnNbdG9rZW4udHlwZV0oZSxPcGVyYXRpb25zW29wZXJhdG9yXShzZWN0aW9uLklkZW50aWZpZXJzLml0LG4pKSxoYXNFdmFsUmVwbGF5JiZtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3ZhbDplLHRva2VuczpyLGk6dH0pLGUpfSwiYW5kIj09PXRva2VuLnR5cGUpfSxsZWZ0U2lkZSxldmFsQmVmb3JlLG9wZXJhdG9yLHJpZ2h0U2lkZSxyaWdodEluZGV4LHN3YXBwZWRTaWRlcyxldmFsQWZ0ZXI7cmV0PWxlZnRJc0NvbXBhcmlzb24mJiFyaWdodElzQ29tcGFyaXNvbj8obGVmdFNpZGU9bGVmdElzQ29tcGFyaXNvbixvcGVyYXRvcj1jb21waWxlQ29tcGFyaXNvbk9wZXJhdG9yKGxlZnRTaWRlKSwiaXNOb3QiPT09bGVmdFNpZGUudHlwZXx8ImlzTm90QSI9PT1sZWZ0U2lkZS50eXBlfHwidW50eXBpZmllcyI9PT1sZWZ0U2lkZS50eXBlP2FtYmlndWl0eUVycm9yOihldmFsQmVmb3JlPXJ1bihzZWN0aW9uLGJlZm9yZSksb3BzW3R5cGVdKGV2YWxCZWZvcmUsZWxpZGVkQ29tcGFyaXNvbk9wZXJhdG9yLmFwcGx5KHZvaWQgMCxfdG9Db25zdW1hYmxlQXJyYXkoZ2V0RWxpc2lvbk9wZXJhbmRzKGFmdGVyKSkpKSkpOiFsZWZ0SXNDb21wYXJpc29uJiZyaWdodElzQ29tcGFyaXNvbj8ocmlnaHRTaWRlPXJpZ2h0SXNDb21wYXJpc29uLHJpZ2h0SW5kZXg9dG9rZW5zLmluZGV4T2YocmlnaHRTaWRlKSxvcGVyYXRvcj1yZXZlcnNlQ29tcGFyaXNvbk9wZXJhdG9yKHJpZ2h0U2lkZSksImlzTm90Ij09PXJpZ2h0U2lkZS50eXBlfHwiaXNOb3RBIj09PXJpZ2h0U2lkZS50eXBlfHwidW50eXBpZmllcyI9PT1yaWdodFNpZGUudHlwZT9hbWJpZ3VpdHlFcnJvcjooc3dhcHBlZFNpZGVzPVtdLmNvbmNhdChfdG9Db25zdW1hYmxlQXJyYXkodG9rZW5zLnNsaWNlKHJpZ2h0SW5kZXgrMSkpLFtPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUocmlnaHRTaWRlKSxfZGVmaW5lUHJvcGVydHkoe30sImluZXF1YWxpdHkiPT09cmlnaHRTaWRlLnR5cGU/Im9wZXJhdG9yIjoidHlwZSIscmV2ZXJzZUNvbXBhcmlzb25PcGVyYXRvcihyaWdodFNpZGUpKSldLF90b0NvbnN1bWFibGVBcnJheSh0b2tlbnMuc2xpY2UoaSsxLHJpZ2h0SW5kZXgpKSksZXZhbEFmdGVyPXJ1bihzZWN0aW9uLHN3YXBwZWRTaWRlcyksb3BzW3R5cGVdKGV2YWxBZnRlcixlbGlkZWRDb21wYXJpc29uT3BlcmF0b3IuYXBwbHkodm9pZCAwLF90b0NvbnN1bWFibGVBcnJheShnZXRFbGlzaW9uT3BlcmFuZHMoYmVmb3JlKSkpKSkpOm9wc1t0eXBlXShydW4oc2VjdGlvbixiZWZvcmUpLHJ1bihzZWN0aW9uLGFmdGVyKSl9ZWxzZSBpZihjb21wYXJpc29uT3BUeXBlcy5pbmNsdWRlcyh0eXBlKSl7YWZ0ZXJ8fG1pc3NpbmdTaWRlRXJyb3IoITEsITAsdG9rZW4pO3ZhciBsZWZ0T3A9YmVmb3JlP3J1bihzZWN0aW9uLGJlZm9yZSk6c2VjdGlvbi5JZGVudGlmaWVycy5pdDtyZXQ9b3BzW2NvbXBpbGVDb21wYXJpc29uT3BlcmF0b3IodG9rZW4pXShsZWZ0T3AscnVuKHNlY3Rpb24sYWZ0ZXIpKSxzZWN0aW9uLklkZW50aWZpZXJzLml0PWxlZnRPcCxldmFsUmVwbGF5SXQ9bGVmdE9wLGV2YWxSZXBsYXlSZWFzb249aGFzRXZhbFJlcGxheSYmIWJlZm9yZSYmIkEgbWlzc2luZyAnaXQnIHdhcyBpbmZlcnJlZCB0byBjb21wbGV0ZSB0aGUgb3BlcmF0aW9uLiJ9ZWxzZSBpZigiYWRkaXRpb24iPT09dHlwZXx8InN1YnRyYWN0aW9uIj09PXR5cGUpe2FmdGVyfHxtaXNzaW5nU2lkZUVycm9yKCExLCEwLHRva2VuKTt2YXIgY29udmVydD0hYmVmb3JlLF9wcmVjZWRlbnRUb2tlbjcsX3ByZWNlZGVudFRva2VuOCxwcmV2aW91c1ByZWNlZGVudFRva2VuLF9pMTAsX3NpZGVzLHBUeXBlLGNvbnZlcnQ7YmVmb3JlJiYoX3ByZWNlZGVudFRva2VuNz1wcmVjZWRlbnRUb2tlbihiZWZvcmUsImxlYXN0IiksX3ByZWNlZGVudFRva2VuOD1fc2xpY2VkVG9BcnJheShfcHJlY2VkZW50VG9rZW43LDIpLHByZXZpb3VzUHJlY2VkZW50VG9rZW49X3ByZWNlZGVudFRva2VuOFswXSxfaTEwPV9wcmVjZWRlbnRUb2tlbjhbMV0sX3NpZGVzPXRva2VuU2lkZXNbcHJldmlvdXNQcmVjZWRlbnRUb2tlbi50eXBlXSxwVHlwZT1wcmV2aW91c1ByZWNlZGVudFRva2VuLnR5cGUsY29udmVydD0oImJvdGgiPT09X3NpZGVzfHwiYWZ0ZXIiPT09X3NpZGVzfHwiYWRkaXRpb24iPT09cFR5cGV8fCJzdWJ0cmFjdGlvbiI9PT1wVHlwZSkmJihfaTEwPT09YmVmb3JlLmxlbmd0aC0xfHxfaTEwPT09YmVmb3JlLmxlbmd0aC0yJiYid2hpdGVzcGFjZSI9PT1iZWZvcmVbYmVmb3JlLmxlbmd0aC0xXS50eXBlKSksY29udmVydD8odG9rZW4udHlwZT0iYWRkaXRpb24iPT09dHlwZT8icG9zaXRpdmUiOiJuZWdhdGl2ZSIscmV0PXJ1bihzZWN0aW9uLHRva2VucyksdG9rZW4udHlwZT10eXBlLGV2YWxSZXBsYXlTa2lwPSEwKTpyZXQ9b3BzW3Rva2VuLnRleHRdKHJ1bihzZWN0aW9uLGJlZm9yZSkscnVuKHNlY3Rpb24sYWZ0ZXIpKX1lbHNlIGlmKCJtdWx0aXBsaWNhdGlvbiI9PT10eXBlfHwiZGl2aXNpb24iPT09dHlwZSlyZXQ9b3BzW3Rva2VuLnRleHRdKHJ1bihzZWN0aW9uLGJlZm9yZSkscnVuKHNlY3Rpb24sYWZ0ZXIpKTtlbHNlIGlmKCJwb3NpdGl2ZSI9PT10eXBlfHwibmVnYXRpdmUiPT09dHlwZSlyZXQ9b3BzWyIqIl0oIm5lZ2F0aXZlIj09PXR5cGU/LTE6MSxydW4oc2VjdGlvbixhZnRlcikpLGV2YWxSZXBsYXlTa2lwPSEwO2Vsc2UgaWYoIm5vdCI9PT10eXBlKXJldD1vcHMubm90KHJ1bihzZWN0aW9uLGFmdGVyKSk7ZWxzZSBpZigiYmVsb25naW5nUHJvcGVydHkiPT09dHlwZSl7dmFyIGNvbnRhaW5lcj1ydW4oc2VjdGlvbixhZnRlcixpc1ZhclJlZiksaXNSZWY9KHJldD1WYXJSZWYuY3JlYXRlKGNvbnRhaW5lcix0b2tlbi5uYW1lKSxpc1ZhclJlZnx8VHdpbmVFcnJvci5jb250YWluc0Vycm9yKHJldCkpO3JldD1pc1JlZj9yZXQ6cmV0LmdldCgpLGlzUmVmPWlzVmFyUmVmfHxUd2luZUVycm9yLmNvbnRhaW5zRXJyb3IocmV0KSxoYXNFdmFsUmVwbGF5JiYhaXNSZWY/bWFrZUV2YWxSZXBsYXlGcmFtZShldmFsUmVwbGF5LHt0b0NvZGU6IiAiLmNvbmNhdCh0b2tlbi5uYW1lLCIgb2YgIikuY29uY2F0KHRvU291cmNlKFZhclJlZi5pc1Byb3RvdHlwZU9mKGNvbnRhaW5lcik/Y29udGFpbmVyLmdldCgpOmNvbnRhaW5lciksIiAiKSx0b2tlbnM6dG9rZW5zLGk6aX0pOmlzUmVmfHwoZXZhbFJlcGxheVJlYXNvbj0iVGhlIHZhbHVlIHRvIHRoZSByaWdodCBvZiAnb2YnLCAiLmNvbmNhdCh0eXBlTmFtZShjb250YWluZXIpLCcsIGhhZCBhICInKS5jb25jYXQodG9rZW4ubmFtZSwnIiBkYXRhIG5hbWUgY29ycmVzcG9uZGluZyB0byB0aGF0IGRhdGEgdmFsdWUuJykpfWVsc2UgaWYoImJlbG9uZ2luZ09wZXJhdG9yIj09PXR5cGV8fCJiZWxvbmdpbmdJdE9wZXJhdG9yIj09PXR5cGUpe3ZhciB2YWx1ZT1ydW4oc2VjdGlvbixiZWZvcmUpOyJyYW5kb20iPT09dmFsdWUmJnNlY3Rpb24uZnJlZVZhcmlhYmxlcyYmIm9iamVjdCI9PT1fdHlwZW9mKHNlY3Rpb24uZnJlZVZhcmlhYmxlcykmJiFzZWN0aW9uLmZyZWVWYXJpYWJsZXMuc2VlZCYmKHNlY3Rpb24uZnJlZVZhcmlhYmxlcy5zZWVkPVN0YXRlLnNlZWQsc2VjdGlvbi5mcmVlVmFyaWFibGVzLnNlZWRJdGVyPVN0YXRlLnNlZWRJdGVyKSxyZXQ9VmFyUmVmLmNyZWF0ZSgiYmVsb25naW5nSXRPcGVyYXRvciI9PT10eXBlP3NlY3Rpb24uSWRlbnRpZmllcnMuaXQ6cnVuKHNlY3Rpb24sYWZ0ZXIsaXNWYXJSZWYpLHtjb21wdXRlZDohMCx2YWx1ZTp2YWx1ZX0pLHJldD1pc1ZhclJlZnx8VHdpbmVFcnJvci5jb250YWluc0Vycm9yKHJldCk/cmV0OnJldC5nZXQoKSwiYmVsb25naW5nSXRPcGVyYXRvciI9PT10eXBlJiZoYXNFdmFsUmVwbGF5JiZtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3RvQ29kZToiICIuY29uY2F0KHRvU291cmNlKHZhbHVlKSwiIG9mICIpLmNvbmNhdCh0b1NvdXJjZShzZWN0aW9uLklkZW50aWZpZXJzLml0KSwiICIpLHRva2Vuczp0b2tlbnMsaTppfSl9ZWxzZSBpZigicHJvcGVydHkiPT09dHlwZSl7dmFyIF9jb250YWluZXI9cnVuKHNlY3Rpb24sYmVmb3JlLFZBUlJFRiksX2lzUmVmPShyZXQ9VmFyUmVmLmNyZWF0ZShfY29udGFpbmVyLHRva2VuLm5hbWUpLGlzVmFyUmVmfHxUd2luZUVycm9yLmNvbnRhaW5zRXJyb3IocmV0KSk7cmV0PV9pc1JlZj9yZXQ6cmV0LmdldCgpLF9pc1JlZj1pc1ZhclJlZnx8VHdpbmVFcnJvci5jb250YWluc0Vycm9yKHJldCksaGFzRXZhbFJlcGxheSYmVmFyUmVmLmlzUHJvdG90eXBlT2YoX2NvbnRhaW5lcikmJiFfaXNSZWY/bWFrZUV2YWxSZXBsYXlGcmFtZShldmFsUmVwbGF5LHt0b0NvZGU6IiAiLmNvbmNhdCh0b1NvdXJjZShfY29udGFpbmVyLmdldCgpKSwiJ3MgIikuY29uY2F0KHRva2VuLm5hbWUsIiAiKSx0b2tlbnM6dG9rZW5zLGk6aX0pOl9pc1JlZnx8KGV2YWxSZXBsYXlSZWFzb249IlRoZSB2YWx1ZSB0byB0aGUgbGVmdCBvZiAncywgIi5jb25jYXQodHlwZU5hbWUoX2NvbnRhaW5lciksJywgaGFkIGEgIicpLmNvbmNhdCh0b2tlbi5uYW1lLCciIGRhdGEgbmFtZSBjb3JyZXNwb25kaW5nIHRvIHRoYXQgZGF0YSB2YWx1ZS4nKSl9ZWxzZSBpZigiaXRzUHJvcGVydHkiPT09dHlwZXx8ImJlbG9uZ2luZ0l0UHJvcGVydHkiPT09dHlwZSlyZXQ9VmFyUmVmLmNyZWF0ZShzZWN0aW9uLklkZW50aWZpZXJzLml0LHRva2VuLm5hbWUpLHJldD1pc1ZhclJlZnx8VHdpbmVFcnJvci5jb250YWluc0Vycm9yKHJldCk/cmV0OnJldC5nZXQoKSxoYXNFdmFsUmVwbGF5JiZtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3RvQ29kZToiaXRzUHJvcGVydHkiPT09dHlwZT8iICIuY29uY2F0KHRvU291cmNlKHNlY3Rpb24uSWRlbnRpZmllcnMuaXQpLCIncyAiKS5jb25jYXQodG9rZW4ubmFtZSwiICIpOiIgIi5jb25jYXQodG9rZW4ubmFtZSwiIG9mICIpLmNvbmNhdCh0b1NvdXJjZShzZWN0aW9uLklkZW50aWZpZXJzLml0KSwiICIpLHRva2Vuczp0b2tlbnMsaTppfSk7ZWxzZSBpZigicG9zc2Vzc2l2ZU9wZXJhdG9yIj09PXR5cGV8fCJpdHNPcGVyYXRvciI9PT10eXBlKXshYWZ0ZXJ8fCFiZWZvcmUmJiJpdHNPcGVyYXRvciIhPT10b2tlbi50eXBlP3JldD1taXNzaW5nU2lkZUVycm9yKCFiZWZvcmUsIWFmdGVyLHRva2VuKTooX3ZhbHVlND1ydW4oc2VjdGlvbixhZnRlciksInJhbmRvbSI9PT1fdmFsdWU0JiZzZWN0aW9uLmZyZWVWYXJpYWJsZXMmJiJvYmplY3QiPT09X3R5cGVvZihzZWN0aW9uLmZyZWVWYXJpYWJsZXMpJiYhc2VjdGlvbi5mcmVlVmFyaWFibGVzLnNlZWQmJihzZWN0aW9uLmZyZWVWYXJpYWJsZXMuc2VlZD1TdGF0ZS5zZWVkLHNlY3Rpb24uZnJlZVZhcmlhYmxlcy5zZWVkSXRlcj1TdGF0ZS5zZWVkSXRlcikscmV0PVZhclJlZi5jcmVhdGUoIml0c09wZXJhdG9yIj09PXRva2VuLnR5cGU/c2VjdGlvbi5JZGVudGlmaWVycy5pdDpydW4oc2VjdGlvbixiZWZvcmUsaXNWYXJSZWYpLHtjb21wdXRlZDohMCx2YWx1ZTpfdmFsdWU0fSkscmV0PWlzVmFyUmVmfHxUd2luZUVycm9yLmNvbnRhaW5zRXJyb3IocmV0KT9yZXQ6cmV0LmdldCgpLCJpdHNPcGVyYXRvciI9PT10eXBlJiZoYXNFdmFsUmVwbGF5JiZtYWtlRXZhbFJlcGxheUZyYW1lKGV2YWxSZXBsYXkse3RvQ29kZToiICIuY29uY2F0KHRvU291cmNlKHNlY3Rpb24uSWRlbnRpZmllcnMuaXQpLCIncyAiKS5jb25jYXQodG9Tb3VyY2UoX3ZhbHVlNCksIiAiKSx0b2tlbnM6dG9rZW5zLGk6aX0pKX1lbHNlIGlmKCJ0d2luZUxpbmsiPT09dHlwZSlyZXQ9TWFjcm9zLnJ1bigibGluay1nb3RvIixzZWN0aW9uLFt0b2tlbi5pbm5lclRleHQsdG9rZW4ucGFzc2FnZV0pLGV2YWxSZXBsYXlSZWFzb249aGFzRXZhbFJlcGxheSYmIlBhc3NhZ2UgbGlua3MgYXJlIHRoZSBzYW1lIGFzIChsaW5rLWdvdG86KSBtYWNybyBjYWxscy4iO2Vsc2UgaWYoIm1hY3JvIj09PXR5cGUpaWYodG9rZW4uYmxvY2tlZFZhbHVlJiYhc2VjdGlvbi5ibG9ja2VkKXtpZihyZXQ9c2VjdGlvbi5ibG9ja2VkVmFsdWUoKSx2b2lkIDA9PT1yZXQpcmV0dXJuIGltcG9zc2libGUoIlJ1bm5lci5ydW4iLCJzZWN0aW9uLmJsb2NrZWRWYWx1ZSgpIHJldHVybmVkIHVuZGVmaW5lZCIpLDB9ZWxzZXt2YXIgbWFjcm9OYW1lVG9rZW49dG9rZW4uY2hpbGRyZW5bMF0sdmFyaWFibGVDYWxsPSIkIj09PW1hY3JvTmFtZVRva2VuLnRleHRbMF18fCJfIj09PW1hY3JvTmFtZVRva2VuLnRleHRbMF0sbWFjcm9SZWY7aWYoIm1hY3JvTmFtZSIhPT1tYWNyb05hbWVUb2tlbi50eXBlJiYhdmFyaWFibGVDYWxsKXJldHVybiBpbXBvc3NpYmxlKCJSdW5uZXIucnVuIiwibWFjcm8gdG9rZW4gaGFkIG5vIG1hY3JvTmFtZSBjaGlsZCB0b2tlbiIpLDA7dmFyaWFibGVDYWxsPyhtYWNyb1JlZj1WYXJSZWYuY3JlYXRlKCJfIj09PW1hY3JvTmFtZVRva2VuLnRleHRbMF0/c2VjdGlvbi5zdGFja1RvcC50ZW1wVmFyaWFibGVzOlN0YXRlLnZhcmlhYmxlcyxtYWNyb05hbWVUb2tlbi50ZXh0LnRyaW0oKS5zbGljZSgxLC0xKSksVHdpbmVFcnJvci5jb250YWluc0Vycm9yKG1hY3JvUmVmKXx8KG1hY3JvUmVmPW1hY3JvUmVmLmdldCgpKSk6bWFjcm9SZWY9dG9rZW4ubmFtZSxyZXQ9TWFjcm9zW3ZhcmlhYmxlQ2FsbD8icnVuQ3VzdG9tIjoicnVuIl0obWFjcm9SZWYsc2VjdGlvbix0b2tlbi5jaGlsZHJlbi5zbGljZSgxKS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4iY29tbWEiPT09dC50eXBlP2UucHVzaChbXSk6ZVtlLmxlbmd0aC0xXS5wdXNoKHQpLGV9LFtbXV0pLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5sZW5ndGgmJigxPGUubGVuZ3RofHwid2hpdGVzcGFjZSIhPT1lWzBdLnR5cGUpfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBydW4oc2VjdGlvbixlLCExLGlzVHlwZWRWYXIpfSkpLGV2YWxSZXBsYXlSZWFzb249aGFzRXZhbFJlcGxheSYmdmFyaWFibGVDYWxsJiYiSSBjYWxsZWQgIi5jb25jYXQob2JqZWN0TmFtZShtYWNyb1JlZiksIi4iKX1lbHNlIGlmKCJncm91cGluZyI9PT10eXBlKXJldD1ydW4oc2VjdGlvbix0b2tlbi5jaGlsZHJlbixpc1ZhclJlZiksZXZhbFJlcGxheVNraXA9ITA7ZWxzZSBpZigiZXJyb3IiPT09dHlwZSlyZXQ9VHdpbmVFcnJvci5jcmVhdGUoInN5bnRheCIsdG9rZW4ubWVzc2FnZSx0b2tlbi5leHBsYW5hdGlvbnx8IiIpO2Vsc2V7aWYoInRleHQiIT09dHlwZSlyZXR1cm4gaW1wb3NzaWJsZSgiU2VjdGlvbi5ydW4iLCJ1bmtub3duIHN5bnRheCB0b2tlbiB0eXBlOiAiLmNvbmNhdCh0eXBlLCIhISIpKSwwO3Rva2VuLnRleHQudHJpbSgpLm1hdGNoKC9eXGQrKD86dGh8bmR8c3R8cmQpKD86bGFzdCk/KD86dG9cZCsoPzpudGh8bmR8c3R8cmQpKD86bGFzdCk/KT8kL2cpJiYobXNnPSdQb3NpdGlvbiBkYXRhIG5hbWVzIGxpa2UgIicuY29uY2F0KHRva2VuLnRleHQsJyIgbmVlZCB0byBiZSBlaXRoZXIgbGVmdCBvZiAib2YiIG9yIHJpZ2h0IG9mICJcJ3MiLicpKSxyZXQ9VHdpbmVFcnJvci5jcmVhdGUoInN5bnRheCIsbXNnfHwnIicuY29uY2F0KHRva2VuLnRleHQsIlwiIGlzbid0IHZhbGlkIEhhcmxvd2Ugc3ludGF4IGZvciB0aGUgaW5zaWRlIG9mIGEgbWFjcm8gY2FsbC4iKSwiTWF5YmUgeW91IG1pc3NwZWxsZWQgc29tZXRoaW5nPyBBbHNvLCBhcyBvZiAzLjMuMCwgSmF2YXNjcmlwdCBzeW50YXggaXMgbm90IGFsbG93ZWQgaW5zaWRlIG1hY3JvIGNhbGxzLiIpfX1yZXR1cm4gdm9pZCAwPT09cmV0PyhpbXBvc3NpYmxlKCJTZWN0aW9uLnJ1biIsInRva2VuICIuY29uY2F0KHR5cGUpLmNvbmNhdCh0b2tlbi5uYW1lPyIgKCIuY29uY2F0KHRva2VuLm5hbWUsIjopIik6IiIsIiBwcm9kdWNlZCB1bmRlZmluZWQiKSksMCk6cmV0PT09c2VjdGlvbj8oaW1wb3NzaWJsZSgiU2VjdGlvbi5ydW4iLCJ0b2tlbiAiLmNvbmNhdCh0eXBlKS5jb25jYXQodG9rZW4ubmFtZT8iICgiLmNvbmNhdCh0b2tlbi5uYW1lLCI6KSIpOiIiLCIgcHJvZHVjZWQgdGhlIHNlY3Rpb24iKSksMCk6KGhhc0V2YWxSZXBsYXkmJiFldmFsUmVwbGF5U2tpcCYmbWFrZUV2YWxSZXBsYXlGcmFtZShldmFsUmVwbGF5LHt2YWw6cmV0LHJlYXNvbjpldmFsUmVwbGF5UmVhc29uLGl0OmV2YWxSZXBsYXlJdCx0b2tlbnM6dG9rZW5zLGk6aX0pLHJldCl9fSksZGVmaW5lKCJ1dGlscy9qcXVlcnlwbHVnaW5zIixbImpxdWVyeSJdLGZ1bmN0aW9uKGUpe2UucHJvdG90eXBlLmV4dGVuZCh7cG9wQXR0cjpmdW5jdGlvbihlKXt2YXIgdD10aGlzLmF0dHIoZSk7cmV0dXJuIHRoaXMucmVtb3ZlQXR0cihlKSx0fSxwb3BEYXRhOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuZGF0YShlKTtyZXR1cm4gdGhpcy5yZW1vdmVEYXRhKGUpLHR9LHRhZzpmdW5jdGlvbigpe3JldHVybiB0aGlzWzBdJiZ0aGlzWzBdLnRhZ05hbWUmJnRoaXNbMF0udGFnTmFtZS50b0xvd2VyQ2FzZSgpfSx0ZXh0Tm9kZXM6ZnVuY3Rpb24oKXt2YXIgZT0wPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1swXT9hcmd1bWVudHNbMF06IioiO3JldHVybiAxPT09dGhpcy5sZW5ndGgmJnRoaXNbMF0mJnRoaXNbMF0ubm9kZVR5cGU9PT1Ob2RlLlRFWFRfTk9ERT9bdGhpc1swXV06dGhpcy5nZXQoKS5jb25jYXQodGhpcy5jb250ZW50cygpLmdldCgpLHRoaXMuZmluZChlKS5jb250ZW50cygpLmdldCgpKS5maWx0ZXIoZnVuY3Rpb24oZSx0LG4pe3JldHVybihudWxsPT1lP3ZvaWQgMDplLm5vZGVUeXBlKT09PU5vZGUuVEVYVF9OT0RFJiZuLmluZGV4T2YoZSk9PT10fSkuc29ydChmdW5jdGlvbihlLHQpe3JldHVybiAyJmUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odCk/MTotMX0pfSxmaW5kQW5kRmlsdGVyOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuZmluZChlKSxlPXRoaXMuZmlsdGVyKGUpO3JldHVybiBlLmxlbmd0aD90LmFkZChlKTp0fX0pfSksZGVmaW5lKCJ1dGlscy9uYXR1cmFsc29ydCIsW10sZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24oaCl7dmFyIG09MTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOlN0cmluZztyZXR1cm4gZnVuY3Rpb24oZSx0KXt2YXIgbixyLGEsbyxpPS8oXi0/WzAtOV0rKFwuP1swLTldKilbZGZdP2U/WzAtOV0/JHxeMHhbMC05YS1mXSskfFswLTldKykvZ2kscz0vKF4oW1x3IF0rLD9bXHcgXSspP1tcdyBdKyw/W1x3IF0rXGQrOlxkKyg6XGQrKT9bXHcgXT98XlxkezEsNH1bLy1dXGR7MSw0fVsvLV1cZHsxLDR9fF5cdyssIFx3KyBcZCssIFxkezR9KS8sYz0vXjB4WzAtOWEtZl0rJC9pLGw9L14wLyxlPW0oZSkudHJpbSgpLHQ9bSh0KS50cmltKCksdT1lLnJlcGxhY2UoaSwiXDAkMVwwIikucmVwbGFjZSgvXDAkLywiIikucmVwbGFjZSgvXlwwLywiIikuc3BsaXQoIlwwIikscD10LnJlcGxhY2UoaSwiXDAkMVwwIikucmVwbGFjZSgvXDAkLywiIikucmVwbGFjZSgvXlwwLywiIikuc3BsaXQoIlwwIiksaT1wYXJzZUludChlLm1hdGNoKGMpKXx8MSE9PXUubGVuZ3RoJiZlLm1hdGNoKHMpJiZEYXRlLnBhcnNlKGUpLGU9cGFyc2VJbnQodC5tYXRjaChjKSl8fGkmJnQubWF0Y2gocykmJkRhdGUucGFyc2UodCl8fG51bGw7aWYoaCYmd2luZG93LkludGwmJndpbmRvdy5JbnRsLkNvbGxhdG9yJiYoYT13aW5kb3cuSW50bC5Db2xsYXRvcihoKSksZSl7aWYoaTxlKXJldHVybi0xO2lmKGU8aSlyZXR1cm4gMX1mb3IodmFyIGQ9MCxmPU1hdGgubWF4KHUubGVuZ3RoLHAubGVuZ3RoKTtkPGY7ZCsrKXtpZihuPSEodVtkXXx8IiIpLm1hdGNoKGwpJiZwYXJzZUZsb2F0KHVbZF0pfHx1W2RdfHwwLHI9IShwW2RdfHwiIikubWF0Y2gobCkmJnBhcnNlRmxvYXQocFtkXSl8fHBbZF18fDAsaXNOYU4obikhPT1pc05hTihyKSlyZXR1cm4gaXNOYU4obik/MTotMTtpZihfdHlwZW9mKG4pIT09X3R5cGVvZihyKSluKz0iIixyKz0iIjtlbHNlIGlmKCJzdHJpbmciPT10eXBlb2YgbiYmYSYmMCE9PShvPWEuY29tcGFyZShuLHIpKSlyZXR1cm4gbztpZihuPHIpcmV0dXJuLTE7aWYocjxuKXJldHVybiAxfXJldHVybiAwfX19KSxkZWZpbmUoInV0aWxzL29wZXJhdGlvbnV0aWxzIixbInV0aWxzL25hdHVyYWxzb3J0IiwidXRpbHMiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiLCJwYXR0ZXJucyJdLGZ1bmN0aW9uKGYsZSxoLHQpe3ZhciBtPWUuaW1wb3NzaWJsZSxnPWUubnRoLHU9ZS5wZXJtdXRhdGlvbnMscz1lLnBsdXJhbCx5PXQudmFsaWRQcm9wZXJ0eU5hbWUscj0ib2JqZWN0IixuPSJib29sZWFuIixiPSJzdHJpbmciLHY9Im51bWJlciIsdz0iZnVuY3Rpb24iO2Z1bmN0aW9uIGEoZSl7cmV0dXJuISFlJiYoX3R5cGVvZihlKT09PXJ8fF90eXBlb2YoZSk9PT13KX12YXIgaz1BcnJheS5pc0FycmF5O2Z1bmN0aW9uIFMoZSl7cmV0dXJuIGUmJk9iamVjdC5nZXRQcm90b3R5cGVPZihlKT09PU9iamVjdC5wcm90b3R5cGV9ZnVuY3Rpb24gaShlKXtyZXR1cm4gayhlKT8iYXJyYXkiOmUgaW5zdGFuY2VvZiBNYXA/ImRhdGFtYXAiOmUgaW5zdGFuY2VvZiBTZXQ/ImRhdGFzZXQiOl90eXBlb2YoZSk9PT1iP2I6ZSYmX3R5cGVvZihlKT09PXI/cjoiIn1mdW5jdGlvbiBjKGUpe2lmKGEoZSkpe2lmKF90eXBlb2YoZS5Ud2luZVNjcmlwdF9DbG9uZSk9PT13KXJldHVybiBlLlR3aW5lU2NyaXB0X0Nsb25lKCk7aWYoayhlKSlyZXR1cm4gX3RvQ29uc3VtYWJsZUFycmF5KGUpO2lmKGUgaW5zdGFuY2VvZiBNYXApcmV0dXJuIG5ldyBNYXAoZSk7aWYoZSBpbnN0YW5jZW9mIFNldClyZXR1cm4gbmV3IFNldChlKTtpZihfdHlwZW9mKGUpPT09dylyZXR1cm4gT2JqZWN0LmFzc2lnbihlLmJpbmQoKSxlKTtzd2l0Y2goT2JqZWN0LmdldFByb3RvdHlwZU9mKGUpKXtjYXNlIE9iamVjdC5wcm90b3R5cGU6cmV0dXJuIF9vYmplY3RTcHJlYWQoe30sZSk7Y2FzZSBudWxsOnJldHVybiBPYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUobnVsbCksZSl9bSgiT3BlcmF0aW9uVXRpbHMuY2xvbmUiLCJUaGUgdmFsdWUgIitlKyIgY2Fubm90IGJlIGNsb25lZCEiKX1yZXR1cm4gZX1mdW5jdGlvbiBvKGUsdCxuLHIpe2Zvcih2YXIgYT0iIixvPTA7YS5sZW5ndGg8PXQmJm88ZS5sZW5ndGg7KXt2YXIgaT1yKGVbb10pO2lmKCEoaS5sZW5ndGgrYS5sZW5ndGg8PXQpKXthKz0oMDxvPyIgYW5kICI6IiIpK3MoZS5sZW5ndGgtbywoMDxvPyJvdGhlciAiOiIiKStuKTticmVha31hKz0oMDxvJiZvPT09ZS5sZW5ndGgtMT8iIGFuZCAiOiIiKStpKyhvPGUubGVuZ3RoLTE/IiwgIjoiIiksbys9MX1yZXR1cm4gYX1mdW5jdGlvbiBsKGUpe3ZhciB0O3JldHVybiBhKGUpJiYiVHdpbmVTY3JpcHRfT2JqZWN0TmFtZSJpbiBlP2UuVHdpbmVTY3JpcHRfT2JqZWN0TmFtZTprKGUpPzA9PT1lLmxlbmd0aD8iYW4gZW1wdHkgYXJyYXkiOiJhbiBhcnJheSAod2l0aCAiK28oZSw0OCwiaXRlbSIsbCkrIikiOmUgaW5zdGFuY2VvZiBNYXA/MD09PWUuc2l6ZT8iYW4gZW1wdHkgZGF0YW1hcCI6ImEgZGF0YW1hcCAod2l0aCAiK28oX3RvQ29uc3VtYWJsZUFycmF5KGUua2V5cygpKSw0OCwiZGF0YW5hbWUiLF8pKyIpIjplIGluc3RhbmNlb2YgU2V0PzA9PT1lLnNpemU/ImFuIGVtcHR5IGRhdGFzZXQiOiJhIGRhdGFzZXQgKHdpdGggIitvKF90b0NvbnN1bWFibGVBcnJheShlLnZhbHVlcygpKSw0OCwiaXRlbSIsbCkrIikiOl90eXBlb2YoZSk9PT1iPzA9PT1lLmxlbmd0aD8iYW4gZW1wdHkgc3RyaW5nIjo0ODwodD1fdG9Db25zdW1hYmxlQXJyYXkoZSkpLmxlbmd0aD8iYSAiLmNvbmNhdCh0Lmxlbmd0aCwiLWNoYXJhY3RlciBzdHJpbmcgc3RhcnRpbmcgd2l0aCAiKS5jb25jYXQoSlNPTi5zdHJpbmdpZnkodC5zbGljZSgwLDQ4KS5qb2luKCIiKSkpOiJ0aGUgc3RyaW5nICIuY29uY2F0KEpTT04uc3RyaW5naWZ5KGUpKTpfdHlwZW9mKGUpPT09bj8idGhlIGJvb2xlYW4gdmFsdWUgJyIrZSsiJyI6X3R5cGVvZihlKT09PXY/InRoZSBudW1iZXIgIitKU09OLnN0cmluZ2lmeShlKTp2b2lkIDA9PT1lPyJhbiBlbXB0eSB2YXJpYWJsZSI6Ii4uLndoYXRldmVyIHRoaXMgaXMifWZ1bmN0aW9uIFQoZSx0KXtyZXR1cm5bZVswXSx0WzBdXS5zb3J0KGYoImVuIikpWzBdPT09ZVswXT8tMToxfWZ1bmN0aW9uIF8oZSx0KXt2YXIgbj1oLmNvbnRhaW5zRXJyb3IoZSk7aWYobiYmbSgidG9Tb3VyY2UiLCJyZWNlaXZlZCBhIFR3aW5lRXJyb3I6ICIrbi5tZXNzYWdlKSxfdHlwZW9mKGUuVHdpbmVTY3JpcHRfVG9Tb3VyY2UpPT09dylyZXR1cm4gZS5Ud2luZVNjcmlwdF9Ub1NvdXJjZSgpO2lmKFMoZSkmJiJmaXJzdCJpbiBlJiYibGFzdCJpbiBlKXJldHVybihlLmZpcnN0PDA/KC0xIT09ZS5maXJzdD9nKC1lLmZpcnN0KToiIikrImxhc3QiOmcoZS5maXJzdCsxKSkrInRvIisoZS5sYXN0PDA/KC0xIT09ZS5sYXN0P2coLWUubGFzdCk6IiIpKyJsYXN0IjpnKGUubGFzdCsxKSk7aWYoayhlKSl7dmFyIHIsYT0iIixvPV9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyKGUpO3RyeXtmb3Ioby5zKCk7IShyPW8ubigpKS5kb25lOyl2YXIgaT1yLnZhbHVlLGE9KGErPWE/IiwiOiIoYToiKSsoInByb3BlcnR5Ij09PXQ/aSsoMDxpKTpfKGkpKX1jYXRjaChlKXtvLmUoZSl9ZmluYWxseXtvLmYoKX1yZXR1cm4gYSsoYT8iKSI6IihhOikiKX1pZihlIGluc3RhbmNlb2YgTWFwKXt2YXIgcyxjPSIiLGw9X2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIoQXJyYXkuZnJvbShlLmVudHJpZXMoKSkuc29ydChUKSk7dHJ5e2ZvcihsLnMoKTshKHM9bC5uKCkpLmRvbmU7KXt2YXIgdT1fc2xpY2VkVG9BcnJheShzLnZhbHVlLDIpLHA9dVswXSxkPXVbMV07Yys9KGM/IiwiOiIoZG06IikrXyhwKSsiLCIrXyhkKX19Y2F0Y2goZSl7bC5lKGUpfWZpbmFsbHl7bC5mKCl9cmV0dXJuIGMrKGM/IikiOiIoZG06KSIpfXJldHVybiBlIGluc3RhbmNlb2YgU2V0PyIoZHM6IitBcnJheS5mcm9tKGUpLnNvcnQoZigiZW4iKSkubWFwKF8pKyIpIjpfdHlwZW9mKGUpPT09diYmInByb3BlcnR5Ij09PXQ/ZTwwPy0xPT09ZT8ibGFzdCI6ZygtZSkrImxhc3QiOmcoZSsxKTpfdHlwZW9mKGUpPT09YiYmInByb3BlcnR5Ij09PXQ/UmVnRXhwKHkpLnRlc3QoZSk/ZToiKCIrSlNPTi5zdHJpbmdpZnkoZSkrIikiOkpTT04uc3RyaW5naWZ5KGUpfWZ1bmN0aW9uIHAodCxuKXtyZXR1cm4gX3R5cGVvZih0KSE9PXImJl90eXBlb2YobikhPT1yP3Q9PT1uOmsodCkmJmsobik/dC5sZW5ndGg9PT1uLmxlbmd0aCYmdC5ldmVyeShmdW5jdGlvbihlLHQpe3JldHVybiBwKG5bdF0sZSl9KTp0IGluc3RhbmNlb2YgTWFwJiZuIGluc3RhbmNlb2YgTWFwP3AoQXJyYXkuZnJvbSh0LmVudHJpZXMoKSkuc29ydCgpLEFycmF5LmZyb20obi5lbnRyaWVzKCkpLnNvcnQoKSk6dCBpbnN0YW5jZW9mIFNldCYmbiBpbnN0YW5jZW9mIFNldD9wKF90b0NvbnN1bWFibGVBcnJheSh0KSxfdG9Db25zdW1hYmxlQXJyYXkobikpOnQmJl90eXBlb2YodC5Ud2luZVNjcmlwdF9pcyk9PT13P3QuVHdpbmVTY3JpcHRfaXMobik6dCYmX3R5cGVvZih0KT09PXImJm4mJl90eXBlb2Yobik9PT1yJiZTKHQpJiZTKG4pP3AoT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModCkubWFwKGZ1bmN0aW9uKGUpe3JldHVybltlLHRbZV1dfSksT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobikubWFwKGZ1bmN0aW9uKGUpe3JldHVybltlLG5bZV1dfSkpOk9iamVjdC5pcyh0LG4pfXJldHVybiBPYmplY3QuZnJlZXplKHtpc09iamVjdDphLGlzVmFsaWREYXRhbWFwTmFtZTpmdW5jdGlvbihlLHQpe3ZhciBuO3JldHVybiBlIGluc3RhbmNlb2YgTWFwfHxtKCJpc1ZhbGlkRGF0YW1hcE5hbWUiLCJjYWxsZWQgd2l0aCBub24tTWFwIiksaC5jb250YWluc0Vycm9yKHQpP3Q6X3R5cGVvZih0KSE9PWImJl90eXBlb2YodCkhPT12P2guY3JlYXRlKCJwcm9wZXJ0eSIsIk9ubHkgc3RyaW5ncyBhbmQgbnVtYmVycyBjYW4gYmUgdXNlZCBhcyBkYXRhIG5hbWVzIGZvciAiK2woZSkrIiwgbm90ICIrbCh0KSsiLiIpOihuPV90eXBlb2YodCk9PT1iPyt0OiIiK3QsISghTnVtYmVyLmlzTmFOKG4pJiZlLmhhcyhuKSl8fGguY3JlYXRlKCJwcm9wZXJ0eSIsIllvdSBtdXN0bid0IHVzZSBib3RoICIrbCh0KSsiIGFuZCAiK2wobikrIiBhcyBkYXRhIG5hbWVzIGluIHRoZSBzYW1lIGRhdGFtYXAuIikpfSxjb2xsZWN0aW9uVHlwZTppLGlzU2VxdWVudGlhbDpmdW5jdGlvbihlKXtyZXR1cm4gX3R5cGVvZihlKT09PWJ8fGsoZSl8fF90eXBlb2YoZS5ob29rcyk9PT13fSx1bnN0b3JhYmxlVmFsdWU6ZnVuY3Rpb24gZSh0KXtyZXR1cm4obnVsbD09dD92b2lkIDA6dC5Ud2luZVNjcmlwdF9VbnN0b3JhYmxlKSYmdHx8ayh0KSYmdC5maW5kKGUpfHx0IGluc3RhbmNlb2YgTWFwJiZfdG9Db25zdW1hYmxlQXJyYXkodC52YWx1ZXMoKSkuZmluZChlKXx8dCBpbnN0YW5jZW9mIFNldCYmX3RvQ29uc3VtYWJsZUFycmF5KHQpLmZpbmQoZSl9LGlzSGFybG93ZUpTVmFsdWU6ZnVuY3Rpb24gZSh0KXtyZXR1cm4gX3R5cGVvZih0KT09PWJ8fF90eXBlb2YodCk9PT1ufHxfdHlwZW9mKHQpPT09diYmIU51bWJlci5pc05hTih0KSYmTWF0aC5hYnModCkhPT0xLzB8fEFycmF5LmlzQXJyYXkodCkmJnQuZXZlcnkoZSl8fHQgaW5zdGFuY2VvZiBTZXQmJl90b0NvbnN1bWFibGVBcnJheSh0KS5ldmVyeShlKXx8dCBpbnN0YW5jZW9mIE1hcCYmX3RvQ29uc3VtYWJsZUFycmF5KHQudmFsdWVzKCkpLmV2ZXJ5KGUpJiZfdG9Db25zdW1hYmxlQXJyYXkodC5rZXlzKCkpLmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiBfdHlwZW9mKGUpPT09Yn0pfSxjbG9uZTpjLG9iamVjdE5hbWU6bCx0eXBlTmFtZTpmdW5jdGlvbiBlKHQpe3ZhciBuLHI9Uyh0KTtyZXR1cm4gciYmdC5pbm5lclR5cGU/dC50eXBlTmFtZXx8KCJpbnNlbnNpdGl2ZSBzZXQiPT09dC5wYXR0ZXJuPyJhIGNhc2UtaW5zZW5zaXRpdmUgc3RyaW5nIG5hbWUiOiJlaXRoZXIiPT09dC5wYXR0ZXJuPyhrKHQuaW5uZXJUeXBlKXx8bSgidHlwZU5hbWUiLCciZWl0aGVyIiBwYXR0ZXJuIGhhZCBub24tYXJyYXkgaW5uZXIgdHlwZScpLHQuaW5uZXJUeXBlLm1hcChlKS5qb2luKCIgb3IgIikpOiJvcHRpb25hbCI9PT10LnBhdHRlcm4/IihvcHRpb25hbCkgIitlKHQuaW5uZXJUeXBlKTplKHQuaW5uZXJUeXBlKSk6ciYmInJhbmdlIj09PXQucGF0dGVybj90Lm5hbWV8fChyPXQubWluLG49dC5tYXgsImEiKygwPHI/IiBwb3NpdGl2ZSI6IiIpKyh0LmludGVnZXI/IiB3aG9sZSI6IiIpKyIgbnVtYmVyIisoMD09PXI/IiBiZXR3ZWVuIDAgYW5kICIrbjpuPDEvMD8iIHVwIHRvICIrbjoiIikpOnQ9PT1TdHJpbmd8fHQ9PT1OdW1iZXJ8fHQ9PT1Cb29sZWFuPyJhICIrX3R5cGVvZih0KCkpOnQ9PT1wYXJzZUludD8iYSB3aG9sZSBudW1iZXIiOnQ9PT1NYXA/ImEgZGF0YW1hcCI6dD09PVNldD8iYSBkYXRhc2V0Ijp0PT09QXJyYXk/ImFuIGFycmF5IjphKHQpJiYiVHdpbmVTY3JpcHRfVHlwZU5hbWUiaW4gdD90LlR3aW5lU2NyaXB0X1R5cGVOYW1lOmwodCl9LHR5cGVJRDpmdW5jdGlvbihlKXt2YXIgdD1fdHlwZW9mKGUpO3JldHVybltuLGIsdl0uaW5jbHVkZXModCk/dDprKGUpPyJhcnJheSI6ZSBpbnN0YW5jZW9mIE1hcD8iZGF0YW1hcCI6ZSBpbnN0YW5jZW9mIFNldD8iZGF0YXNldCI6ZS5Ud2luZVNjcmlwdF9UeXBlSUR8fCIifSx0b1NvdXJjZTpfLGlzOnAsY29udGFpbnM6ZnVuY3Rpb24oZSx0KXtpZihlfHwiIj09PWUpe2lmKF90eXBlb2YoZSk9PT1iKXJldHVybiBfdHlwZW9mKHQpIT09Yj9oLmNyZWF0ZSgib3BlcmF0aW9uIixsKGUpKyIgY2FuIG9ubHkgY29udGFpbiBzdHJpbmdzLCBub3QgIitsKHQpKyIuIik6ZS5pbmNsdWRlcyh0KTtpZihrKGUpKXJldHVybiBlLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIHAoZSx0KX0pO2lmKGUgaW5zdGFuY2VvZiBTZXR8fGUgaW5zdGFuY2VvZiBNYXApcmV0dXJuIEFycmF5LmZyb20oZS5rZXlzKCkpLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIHAoZSx0KX0pfXJldHVybiBoLmNyZWF0ZSgib3BlcmF0aW9uIixsKGUpKyIgY2Fubm90IGNvbnRhaW4gYW55IHZhbHVlcywgbGV0IGFsb25lICIrbCh0KSl9LGlzQTpmdW5jdGlvbihlLHQpe3JldHVybiBfdHlwZW9mKHQuVHdpbmVTY3JpcHRfSXNUeXBlT2YpPT09dz90LlR3aW5lU2NyaXB0X0lzVHlwZU9mKGUpOmguY3JlYXRlKCJvcGVyYXRpb24iLCciaXMgYSIgc2hvdWxkIG9ubHkgYmUgdXNlZCB0byBjb21wYXJlIHR5cGUgbmFtZXMsIG5vdCAnK2wodCkrIi4iKX0sbWF0Y2hlczpmdW5jdGlvbiB0KG4sZSl7dmFyIHI9ITE7aWYobiYmX3R5cGVvZihuLlR3aW5lU2NyaXB0X0lzVHlwZU9mKT09PXcpe3ZhciBhPW4uVHdpbmVTY3JpcHRfSXNUeXBlT2YoZSk7aWYoaC5jb250YWluc0Vycm9yKGEpKXJldHVybiBhO3J8PWF9aWYoZSYmX3R5cGVvZihlLlR3aW5lU2NyaXB0X0lzVHlwZU9mKT09PXcpe2lmKGE9ZS5Ud2luZVNjcmlwdF9Jc1R5cGVPZihuKSxoLmNvbnRhaW5zRXJyb3IoYSkpcmV0dXJuIGE7cnw9YX1pZihyKXJldHVybiEwO2lmKGsobikmJmsoZSkpe2Zvcih2YXIgbz0wLGk9MCxzPSEwO3MmJm88bi5sZW5ndGgmJmk8ZS5sZW5ndGg7KXt2YXIgYz1uW29dLGw9ZVtpXTtpZihjLnJlc3Qpe2Zvcig7aTxlLmxlbmd0aCYmdChjLGwpOylsPWVbaSs9MV07bys9MX1lbHNlIGlmKGwucmVzdCl7Zm9yKDtvPG4ubGVuZ3RoJiZ0KGMsbCk7KWM9bltvKz0xXTtpKz0xfWVsc2UgdChjLGwpPyhvKz0xLGkrPTEpOnM9ITF9cmV0dXJuIHMmJm8+PW4ubGVuZ3RoJiZpPj1lLmxlbmd0aH1yZXR1cm4gbiBpbnN0YW5jZW9mIE1hcCYmZSBpbnN0YW5jZW9mIE1hcD90KEFycmF5LmZyb20obi5lbnRyaWVzKCkpLnNvcnQoKSxBcnJheS5mcm9tKGUuZW50cmllcygpKS5zb3J0KCkpOm4gaW5zdGFuY2VvZiBTZXQmJmUgaW5zdGFuY2VvZiBTZXQ/KG49X3RvQ29uc3VtYWJsZUFycmF5KG4pLHUuYXBwbHkodm9pZCAwLF90b0NvbnN1bWFibGVBcnJheShlKSkuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gdChuLGUpfSkpOnAobixlKX0sc3Vic2V0OmZ1bmN0aW9uIGUodCxuLHIpe3ZhciBhLG87cmV0dXJuIG4mJnI/KChhPV90eXBlb2YodCk9PT1iKSYmKHQ9QXJyYXkuZnJvbSh0KSksbjwwJiYobj1NYXRoLm1heCgwLHQubGVuZ3RoK24rMSkpLChyPXI8MD9NYXRoLm1heCgwLHQubGVuZ3RoK3IrMSk6cik8bj9lKGFyZ3VtZW50c1swXSxyLG4pOihvPXQuc2xpY2UoMDxuP24tMTpuLHIpLm1hcChjKSxhP28uam9pbigiIik6bykpOmguY3JlYXRlKCJtYWNyb2NhbGwiLCJUaGUgc3ViIitpKHQpKyIgaW5kZXggdmFsdWUgbXVzdCBub3QgYmUgIisobiYmcikrIi4iKX0scmFuZ2U6ZnVuY3Rpb24gZSh0LG4pe2lmKG48dClyZXR1cm4gZShuLHQpO3ZhciByPVt0XTtmb3Iobi09dDswPG4tLTspci5wdXNoKCsrdCk7cmV0dXJuIHJ9LHByaW50QnVpbHRpblZhbHVlOmZ1bmN0aW9uIHIoZSl7cmV0dXJuIGguY29udGFpbnNFcnJvcihlKT9lOmUmJl90eXBlb2YoZS5Ud2luZVNjcmlwdF9QcmludCk9PT13P2UuVHdpbmVTY3JpcHRfUHJpbnQoKTplIGluc3RhbmNlb2YgTWFwPyhlPUFycmF5LmZyb20oZS5lbnRyaWVzKCkpLGguY29udGFpbnNFcnJvcihlKT9lOmUucmVkdWNlKGZ1bmN0aW9uKGUsdCl7dmFyIG49KHQ9X3NsaWNlZFRvQXJyYXkodCwyKSlbMF0sdD10WzFdO3JldHVybiBlKyI8dHI+PHRkPmAiK3IobikrImA8L3RkPjx0ZD5gIityKHQpKyJgPC90ZD48L3RyPiJ9LCI8dGFibGUgY2xhc3M9ZGF0YW1hcD4iKSsiPC90YWJsZT4iKTplIGluc3RhbmNlb2YgU2V0P0FycmF5LmZyb20oZS52YWx1ZXMoKSkubWFwKHIpKyIiOmsoZSk/ZS5tYXAocikrIiI6ZSYmX3R5cGVvZihlLmpxdWVyeSk9PT1iP2U6YShlKT9oLmNyZWF0ZSgidW5pbXBsZW1lbnRlZCIsIkkgZG9uJ3Qga25vdyBob3cgdG8gcHJpbnQgdGhpcyB2YWx1ZSB5ZXQuIik6ZSsiIn0sdW5pcXVlOmZ1bmN0aW9uKHQsZSxuKXtyZXR1cm4gbi5maW5kSW5kZXgoZnVuY3Rpb24oZSl7cmV0dXJuIHAodCxlKX0pPT09ZX19KX0pLGRlZmluZSgidXRpbHMvcG9seWZpbGxzIixbXSxmdW5jdGlvbigpe3ZhciBvPUFycmF5LnByb3RvdHlwZTsiZnVuY3Rpb24iIT10eXBlb2Ygby5pbmNsdWRlcyYmKG8uaW5jbHVkZXM9ZnVuY3Rpb24oZSl7dmFyIHQ9MTxhcmd1bWVudHMubGVuZ3RoJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOjA7aWYoIU51bWJlci5pc05hTihlKSYmTnVtYmVyLmlzRmluaXRlKHQpJiZ2b2lkIDAhPT1lKXJldHVybi0xPG8uaW5kZXhPZi5jYWxsKHRoaXMsZSx0KTt2YXIgbj1PYmplY3QodGhpcykscj1wYXJzZUludChuLmxlbmd0aCk7aWYoIShyPD0wKSlmb3IodmFyIGE9MDw9dD90Ok1hdGgubWF4KDAscit0KTthPHI7KXtpZihPYmplY3QuaXMoZSxuW2FdKSlyZXR1cm4hMDthKz0xfXJldHVybiExfSksd2luZG93LlN5bWJvbHx8KHdpbmRvdy5TeW1ib2w9e2l0ZXJhdG9yOiJfZXM2LXNoaW0gaXRlcmF0b3JfIn0pfSksZGVmaW5lKCJ1dGlscy9yZW5kZXJ1dGlscyIsWyJqcXVlcnkiLCJ1dGlscyIsInJlbmRlcmVyIl0sZnVuY3Rpb24obCx1LHApe3ZhciBuPVJlZ0V4cCh1LnJlYWxXaGl0ZXNwYWNlKyIrIikscz1SZWdFeHAodS5yZWFsV2hpdGVzcGFjZSsiKyIsImciKTtmdW5jdGlvbiBkKGUsdCxuKXt2YXIgcixhPWUudGV4dENvbnRlbnQubGVuZ3RoO2lmKCEoYTw9dCkpcmV0dXJuIHI9W2U9MD09PXQ/ZTplLnNwbGl0VGV4dCh0KV0sbiYmKG49bjw9MD9hLW46bik8YSYmci5wdXNoKGUuc3BsaXRUZXh0KG4tdCkpLHJ9dmFyIHQsYz1mdW5jdGlvbigpe3ZhciBlO3JldHVybiB2b2lkIDAhPT10P3Q6KGU9bCgiPHA+IiksdD0hIWVbMF0ubm9ybWFsaXplJiYoZS5hcHBlbmQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIjAtIiksZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIjIiKSxkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgiIikpWzBdLm5vcm1hbGl6ZSgpLDE9PT1lLmNvbnRlbnRzKCkubGVuZ3RoKSl9O3ZhciBmPSJ0dy1jb2xsYXBzZWQsW2NvbGxhcHNpbmc9dHJ1ZV0iO3ZhciBvPS9eKD0qKShbXj1dKyk9KiQvO3JldHVybiBPYmplY3QuZnJlZXplKHtkaWFsb2c6ZnVuY3Rpb24oKXt2YXIgZSx0PShjPTA8YXJndW1lbnRzLmxlbmd0aCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTp7fSkuc2VjdGlvbixuPXZvaWQgMD09PShuPWMucGFyZW50KT91LnN0b3J5RWxlbWVudDpuLHI9Yy5jZCxhPXZvaWQgMD09PShhPWMubWVzc2FnZSk/IiI6YSxvPWMuZGVmYXVsdFZhbHVlLGk9dm9pZCAwPT09KGM9Yy5idXR0b25zKT9be25hbWU6Ik9LIixjb25maXJtOiEwLGNhbGxiYWNrOk9iamVjdH1dOmMscz0oImEgY29kZSBob29rIj09PWEuVHdpbmVTY3JpcHRfVHlwZU5hbWUmJihhPWEuY29kZSksbCgiPHR3LWJhY2tkcm9wPjx0dy1kaWFsb2c+Iisob3x8IiI9PT1vPyI8aW5wdXQgdHlwZT10ZXh0IHN0eWxlPSdkaXNwbGF5OmJsb2NrO21hcmdpbjowIGF1dG8nPjwvaW5wdXQ+XG4iOiIiKSsiPHR3LWRpYWxvZy1saW5rcz4iKyhpLmxlbmd0aD9pLnJlZHVjZShmdW5jdGlvbihlLHQsbil7dD10Lm5hbWU7cmV0dXJuIGUrIjx0dy1saW5rIHN0eWxlPSdtYXJnaW46MCAiKyhuPT09aS5sZW5ndGgtMT8iMCAwIDAuNWVtIjowPT09bj8iMC41ZW0gMCAwIjoiMC41ZW0iKSsiJyB0YWJpbmRleD0wPiIrdCsiPC90dy1saW5rPiJ9LCIiKToiPHR3LWxpbmsgdGFiaW5kZXg9MD4iK2lbMF0ubmFtZSsiPC90dy1saW5rPiIpKyI8L3R3LWRpYWxvZy1saW5rcz48L3R3LWRpYWxvZz48L3R3LWJhY2tkcm9wPiIpKSxjPXMuZmluZCgidHctZGlhbG9nIik7cmV0dXJuIG4uYXBwZW5kKHMpLHQ/KHQucmVuZGVySW50byhhLGMsX29iamVjdFNwcmVhZChfb2JqZWN0U3ByZWFkKHt9LHIpLHt9LHthcHBlbmQ6InByZXBlbmQifSkpLG51bGwhPShuPShudWxsPT1yP3ZvaWQgMDpyLnRyYW5zaXRpb24pJiZzLmZpbmQoInR3LWRpYWxvZyA+IHR3LXRyYW5zaXRpb24tY29udGFpbmVyIikpJiZuLmxlbmd0aCYmbi5hcHBlbmRUbyhzKS5hcHBlbmQoYy5wcmVwZW5kKG4uY29udGVudHMoKS5kZXRhY2goKSkpKTpjLnByZXBlbmQocC5leGVjKGEpKSxvJiYoKGU9cy5maW5kKCJpbnB1dCIpLmxhc3QoKSkudmFsKG8pLm9uKCJrZXlwcmVzcyIsZnVuY3Rpb24oZSl7MTM9PT1lLndoaWNoJiYocy5yZW1vdmUoKSxpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5jb25maXJtfSkuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZS5jYWxsYmFjaygpfSkpfSksc2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiBlLmZvY3VzKCl9LDEwMCkpLGkucmV2ZXJzZSgpLmZvckVhY2goZnVuY3Rpb24oZSx0KXtsKHMuZmluZCgidHctbGluayIpLmdldCgtdC0xKSkub24oImNsaWNrIixmdW5jdGlvbigpe3Uub3B0aW9ucy5kZWJ1ZyYmdS5vcHRpb25zLmlnbm9yZUNsaWNrRXZlbnRzJiYhbChzKS5pcygiLmV2YWwtcmVwbGF5LCAuaGFybG93ZS1jcmFzaCIpfHwocy5yZW1vdmUoKSxlLmNhbGxiYWNrKCkpfSl9KSxzfSxyZWFsV2hpdGVzcGFjZTpuLHRleHROb2RlVG9DaGFyczpmdW5jdGlvbihyKXt2YXIgZT1fdG9Db25zdW1hYmxlQXJyYXkoci50ZXh0Q29udGVudCk7cmV0dXJuIDE9PT1lLmxlbmd0aD9bcl06ZS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5tYXRjaChuKSYmZS5sZW5ndGgmJmVbZS5sZW5ndGgtMV0ubWF0Y2gobik/ZVtlLmxlbmd0aC0xXSs9dDplLnB1c2godCksZX0sW10pLnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuPXI7cmV0dXJuIHQubGVuZ3RoPHIudGV4dENvbnRlbnQubGVuZ3RoJiYocj1yLnNwbGl0VGV4dCh0Lmxlbmd0aCkpLGUuY29uY2F0KG4pfSxbXSl9LGZpbmRUZXh0SW5Ob2RlczpmdW5jdGlvbiBlKHQsbil7dmFyIHI9W10sYT0iIixvPVtdO2lmKCF0Lmxlbmd0aHx8IW4pcmV0dXJuIG87Zm9yKDswPHQubGVuZ3RoOyl7ci5wdXNoKHRbMF0pLGErPXRbMF0udGV4dENvbnRlbnQsdC5zaGlmdCgpO3ZhciBpPWEuaW5kZXhPZihuKTtpZigtMTxpKXtmb3IodmFyIHM9YS5sZW5ndGgtKGkrbi5sZW5ndGgpO2k+PXJbMF0udGV4dENvbnRlbnQubGVuZ3RoOylpLT1yWzBdLnRleHRDb250ZW50Lmxlbmd0aCxyLnNoaWZ0KCk7aWYoMT09PXIubGVuZ3RoKXt2YXIgYz1kKHJbMF0saSxpK24ubGVuZ3RoKTtvLnB1c2goY1swXSksY1sxXSYmdC51bnNoaWZ0KGNbMV0pO2JyZWFrfW8ucHVzaChkKHJbMF0saSxyWzBdLmxlbmd0aClbMF0pLG8ucHVzaC5hcHBseShvLF90b0NvbnN1bWFibGVBcnJheShyLnNsaWNlKDEsLTEpKSksYz1kKHJbci5sZW5ndGgtMV0sMCxyW3IubGVuZ3RoLTFdLnRleHRDb250ZW50Lmxlbmd0aC1zKSxvLnB1c2goY1swXSksY1sxXSYmdC51bnNoaWZ0KGNbMV0pLG89by5maWx0ZXIoQm9vbGVhbik7YnJlYWt9fXJldHVybltvXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KGUodCxuKSkpfSxjb2xsYXBzZTpmdW5jdGlvbihlKXtmdW5jdGlvbiBuKGUpe3JldHVybiAwPT09bCh0aGlzfHxlKS5wYXJlbnRzVW50aWwoZikuZmlsdGVyKCJ0dy12ZXJiYXRpbSwgdHctZXhwcmVzc2lvbiwgW2NvbGxhcHNpbmc9ZmFsc2VdIikubGVuZ3RofXZhciB0PWZ1bmN0aW9uIGUodCl7dmFyIG49dFswXSxyPXQucGFyZW50KCk7cmV0dXJuIXIubGVuZ3RofHx0LmZpbmRBbmRGaWx0ZXIoInR3LXN0b3J5IikubGVuZ3RoP251bGw6KHQ9KHQ9ci50ZXh0Tm9kZXMoKS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIDQmKGU9ZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihuKSkmJiEoOCZlKX0pKVt0Lmxlbmd0aC0xXSl8fGUocil9KGUpLHI9KGwodCkucGFyZW50cyhmKS5sZW5ndGh8fCh0PW51bGwpLGZ1bmN0aW9uIGUodCl7dmFyIG49dFswXSxyPXQucGFyZW50KCk7cmV0dXJuIXIubGVuZ3RofHx0LmZpbmRBbmRGaWx0ZXIoInR3LXN0b3J5IikubGVuZ3RoP251bGw6ci50ZXh0Tm9kZXMoKS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIDImKGU9ZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihuKSkmJiEoOCZlKX0pWzBdfHxlKHIpfShlKSksYT0obChyKS5wYXJlbnRzKGYpLmxlbmd0aHx8KHI9bnVsbCksImJyOm5vdChbZGF0YS1yYXddKSx0dy1jb25zZWN1dGl2ZS1icjpub3QoW2RhdGEtcmF3XSkiKSxvPShlLmZpbmQoYSkuZmlsdGVyKG4pLnJlcGxhY2VXaXRoKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCIgIikpLChlPWwoZS5nZXQoKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGwoZSkuZmlsdGVyKG4pLmlzKGEpP2woZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIiAiKSkucmVwbGFjZUFsbChlKVswXTplfSkpKS50ZXh0Tm9kZXMoKSksaT0wO28ucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG4odCk/KHQudGV4dENvbnRlbnQ9dC50ZXh0Q29udGVudC5yZXBsYWNlKHMsIiAiKSwiICIhPT10LnRleHRDb250ZW50WzBdfHxlJiZlLnRleHRDb250ZW50JiYhKC0xPGUudGV4dENvbnRlbnQuc2VhcmNoKC9ccyQvKSl8fCh0LnRleHRDb250ZW50PXQudGV4dENvbnRlbnQuc2xpY2UoMSkpLHQpOmRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCJBIil9LHQpLF90b0NvbnN1bWFibGVBcnJheShvKS5yZXZlcnNlKCkuZXZlcnkoZnVuY3Rpb24oZSl7cmV0dXJuISghbihlKXx8KGUudGV4dENvbnRlbnQubWF0Y2goL15ccyokLyk/KGkrPWUudGV4dENvbnRlbnQubGVuZ3RoLGUudGV4dENvbnRlbnQ9IiIpOihlLnRleHRDb250ZW50PWUudGV4dENvbnRlbnQucmVwbGFjZSgvXHMrJC8sZnVuY3Rpb24oZSl7cmV0dXJuIGkrPWUubGVuZ3RoLCIifSksMSkpKX0pLDA8aSYmciYmKG9bby5sZW5ndGgtMV0udGV4dENvbnRlbnQrPSIgIiksZVswXSYmYygpJiZlWzBdLm5vcm1hbGl6ZSgpfSxnZW9tU3RyaW5nUmVnRXhwOm8sZ2VvbVBhcnNlOmZ1bmN0aW9uKGUpe3ZhciB0LG4scixhO3JldHVybiFlfHwodD1lLmxlbmd0aCxuPShhPV9zbGljZWRUb0FycmF5KG8uZXhlYyhlKXx8W10sMykpWzBdLHI9YVsxXSxhPWFbMl0sIW4pfHxhPT09ZSYmMTxhLmxlbmd0aD97bWFyZ2luTGVmdDowLHNpemU6MH06e21hcmdpbkxlZnQ6ci5sZW5ndGgvdCoxMDAsc2l6ZTphLmxlbmd0aC90KjEwMH19fSl9KSxkZWZpbmUoInV0aWxzL3NjcmlwdHRhZyIsWyJzdGF0ZSIsInV0aWxzL29wZXJhdGlvbnV0aWxzIiwiaW50ZXJuYWx0eXBlcy92YXJyZWYiLCJpbnRlcm5hbHR5cGVzL3R3aW5lZXJyb3IiXSxmdW5jdGlvbihhLG8saSxzKXtyZXR1cm4gZnVuY3Rpb24oZSxyKXtGdW5jdGlvbigic2NyaXB0Iiwic2NvcGUiLCJ3aXRoKHNjb3BlKXt2YXIgc2NvcGU9dm9pZCAwLGFyZ3VtZW50cz12b2lkIDA7ZXZhbChbc2NyaXB0LHNjcmlwdD12b2lkIDBdWzBdKTt9IikoZSxPYmplY3QuY3JlYXRlKG51bGwsT2JqZWN0LmtleXMoYS52YXJpYWJsZXMpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4hZS5zdGFydHNXaXRoKCJUd2luZVNjcmlwdF8iKSYmIiQiK2V9KS5jb25jYXQoT2JqZWN0LmtleXMocikubWFwKGZ1bmN0aW9uKGUpe3JldHVybiFlLnN0YXJ0c1dpdGgoIlR3aW5lU2NyaXB0XyIpJiYiXyIrZX0pKS5yZWR1Y2UoZnVuY3Rpb24oZSxuKXtyZXR1cm4gbiYmKGVbbl09e2dldDpmdW5jdGlvbigpe3ZhciBlPSgiJCI9PT1uWzBdP2EudmFyaWFibGVzOnIpW24uc2xpY2UoMSldO2lmKG8uaXNIYXJsb3dlSlNWYWx1ZShlKSlyZXR1cm4gby5jbG9uZShlKTt0aHJvdyBzLmNyZWF0ZSgiIiwiVGhlIGNvbnRlbnRzIG9mIHRoZSB2YXJpYWJsZSAiLmNvbmNhdChuLCIsICIpLmNvbmNhdChvLm9iamVjdE5hbWUoZSksIiwgY291bGRuJ3QgYmUgY29udmVydGVkIHRvIGEgSmF2YXNjcmlwdCB2YWx1ZS4iKSwiT25seSBib29sZWFucywgc3RyaW5ncywgbnVtYmVycywgZGF0YW1hcHMsIGRhdGFzZXRzIGFuZCBhcnJheXMgY2FuIGJlIGNvbnZlcnRlZCB0byBKYXZhc2NyaXB0IHZhbHVlcy4iKX0sc2V0OmZ1bmN0aW9uKGUpe3ZhciB0PSIkIj09PW5bMF0/YS52YXJpYWJsZXM6cjtpZighby5pc0hhcmxvd2VKU1ZhbHVlKGUpKXRocm93IHMuY3JlYXRlKCIiLCJUaGUgSmF2YXNjcmlwdCB2YWx1ZSwgIi5jb25jYXQoZSwiLCBjb3VsZG4ndCBiZSBjb252ZXJ0ZWQgdG8gYSBIYXJsb3dlIHZhbHVlIGFuZCBhc3NpZ25lZCB0byB0aGUgdmFyaWFibGUgIikuY29uY2F0KG4sIi4iKSwiT25seSBib29sZWFucywgc3RyaW5ncywgbnVtYmVycyAoZXhjZXB0IE5hTiBhbmQgSW5maW5pdHkpLCBNYXBzLCBTZXRzIGFuZCBBcnJheXMgY2FuIGJlIGNvbnZlcnRlZCB0byBIYXJsb3dlIHZhbHVlcy4iKTtlPW8uY2xvbmUoZSk7dD1pLmNyZWF0ZSh0LG4uc2xpY2UoMSkpLnNldChlKTtpZihzLmNvbnRhaW5zRXJyb3IodCkpdGhyb3cgdH19KSxlfSx7fSkpKX19KSwhZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQsbixyKXtyZXR1cm4gZnVuY3Rpb24oZSl7cmV0dXJuImJhY2tncm91bmQtY29sb3I6IGhzbGEoIi5jb25jYXQodCwiLCIpLmNvbmNhdChuLCIlLCIpLmNvbmNhdChyLCIlLCIpLmNvbmNhdChlLCIpOyIpfX12YXIgdD17Ym9vbGVhbjoiY29sb3I6aHNsYSgwLDAlLDMwJSwxLjApIixhcnJheToiY29sb3I6aHNsYSgwLDEwMCUsMzAlLDEuMCkiLGRhdGFzZXQ6ImNvbG9yOmhzbGEoMzAsMTAwJSw0MCUsMS4wKSIsbnVtYmVyOiJjb2xvcjpoc2xhKDMwLDEwMCUsMzAlLDEuMCkiLGRhdGFtYXA6ImNvbG9yOmhzbGEoNjAsMTAwJSwzMCUsMS4wKSIsY2hhbmdlcjoiY29sb3I6aHNsYSg5MCwxMDAlLDMwJSwxLjApIixsYW1iZGE6ImNvbG9yOmhzbGEoMTIwLDEwMCUsNDAlLDEuMCkiLGhvb2tOYW1lOiJjb2xvcjpoc2xhKDE2MCwxMDAlLDMwJSwxLjApIixzdHJpbmc6ImNvbG9yOmhzbGEoMTgwLDEwMCUsMzAlLDEuMCkiLGlkZW50aWZpZXI6ImNvbG9yOmhzbGEoMjAwLDgwJSw0MCUsMS4wKSIsdmFyaWFibGU6ImNvbG9yOmhzbGEoMjAwLDEwMCUsMzAlLDEuMCkiLHRlbXBWYXJpYWJsZToiY29sb3I6aHNsYSgyMDAsNzAlLDIwJSwxLjApIixkYXRhdHlwZToiY29sb3I6aHNsYSgyMjAsMTAwJSwzMCUsMS4wKSIsY29sb3VyOiJjb2xvcjpoc2xhKDI4MCwxMDAlLDMwJSwxLjApIixtYWNybzoiY29sb3I6aHNsYSgzMjAsODAlLDMwJSwxLjApIix0d2luZUxpbms6ImNvbG9yOmhzbGEoMjQwLDEwMCUsMjAlLDEuMCkifSxvPSh0LmdyYWRpZW50PXQuY29sb3VyLHQuY29tbWFuZD10LnR3aW5lTGluayx0Lmluc3RhbnQ9dC5tZXRhZGF0YT10LmFueT10LmN1c3RvbU1hY3JvPXQubWFjcm8sTWF0aC5taW4pLG49ZSg0MCwxMDAsNTApLHI9ZSgyMjAsMTAwLDUwKSxpPS9oc2xhXCgoXGQrKSxccyooXGQrKSUsXHMqKFxkKyklLFxzKihcZCtcLlxkKylcKS9nLHM9ImNtLWhhcmxvd2UtMy0iLGE9KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShuPXtyb290OiJib3gtc2l6aW5nOmJvcmRlci1ib3g7Iixob29rOm4oLjA1KSwiaG9vay0yIjpuKC4xKSwiaG9vay0zIjpuKC4xNSksImhvb2stNCI6biguMiksImhvb2stNSI6biguMjUpLCJob29rLTYiOm4oLjMpLCJob29rLTciOm4oLjM1KSwiaG9vay04IjpuKC40KSwiXj1ob29rICwgXj1ob29rLSI6ImZvbnQtd2VpZ2h0OmJvbGQ7Iix1bmNsb3NlZEhvb2s6biguMDUpKyJmb250LXdlaWdodDpib2xkOyJ9LCJlcnJvcjpub3QoW2NsYXNzKj0nIitzKyJzdHJpbmcnXSkiLCJiYWNrZ3JvdW5kLWNvbG9yOiBoc2xhKDE3LDEwMCUsNTAlLDAuNSkgIWltcG9ydGFudDsiKSwiXj1tYWNyb05hbWUiLCJmb250LXN0eWxlOml0YWxpYzsiKSwibWFjcm9OYW1lLWJvb2xlYW4iLHQuYm9vbGVhbiksIm1hY3JvTmFtZS1hcnJheSIsdC5hcnJheSksIm1hY3JvTmFtZS1kYXRhc2V0Iix0LmRhdGFzZXQpLCJtYWNyb05hbWUtZGF0YXR5cGUiLHQuZGF0YXR5cGUpLCJtYWNyb05hbWUtbnVtYmVyIix0Lm51bWJlciksIm1hY3JvTmFtZS1kYXRhbWFwIix0LmRhdGFtYXApLCJtYWNyb05hbWUtY2hhbmdlciIsdC5jaGFuZ2VyKSwibWFjcm9OYW1lLXN0cmluZyIsdC5zdHJpbmcpLF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShuLCJtYWNyb05hbWUtY29sb3VyLCBtYWNyb05hbWUtZ3JhZGllbnQiLHQuY29sb3VyKSwibWFjcm9OYW1lLWNvbW1hbmQsIG1hY3JvTmFtZS1pbnN0YW50LCBtYWNyb05hbWUtbWV0YWRhdGEiLHQuY29tbWFuZCksIm1hY3JvTmFtZS1jdXN0b21tYWNybywgbWFjcm9OYW1lLW1hY3JvLCBtYWNyb05hbWUtYW55Iix0Lm1hY3JvKSwiXj1tYWNybyAiLCJmb250LXdlaWdodDpib2xkOyIrdC5tYWNybyksImNvbW1hLCBzcHJlYWQiLHQubWFjcm8pLCJhZGRpdGlvbiIsdC5hbnkpLCJzdWJ0cmFjdGlvbiwgbXVsdGlwbGljYXRpb24sIGRpdmlzaW9uIix0Lm51bWJlciksImlzLCBhbmQsIG9yLCBub3QsIGlzTm90LCBjb250YWlucywgZG9lc05vdENvbnRhaW4sIGlzSW4sIGlzQSwgaXNOb3RBLCBpc05vdEluLCBtYXRjaGVzLCBkb2VzTm90TWF0Y2giLHQuYm9vbGVhbiksImJvbGQsIHN0cm9uZyIsImZvbnQtd2VpZ2h0OmJvbGQ7IiksIml0YWxpYywgZW0iLCJmb250LXN0eWxlOml0YWxpYzsiKSxfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkobiwic3VwIiwidmVydGljYWwtYWxpZ246IHN1cGVyO2ZvbnQtc2l6ZTowLjhlbTsiKSwic3RyaWtlIiwidGV4dC1kZWNvcmF0aW9uOiBsaW5lLXRocm91Z2g7IiksInZlcmJhdGltIiwiYmFja2dyb3VuZC1jb2xvcjogaHNsYSgwLDAlLDUwJSwwLjEpO2ZvbnQ6dmFyKC0tZm9udC1tb25vc3BhY2VkKSIpLCJePWJvbGQsIF49c3Ryb25nLCBePWl0YWxpYywgXj1lbSwgXj1zdXAsIF49dmVyYmF0aW0sIF49c3RyaWtlIiwiZm9udC13ZWlnaHQ6MTAwOyBjb2xvcjogaHNsYSgwLDAlLDAlLDAuNSkiKSwiXj1jb2xsYXBzZWQiLCJmb250LXdlaWdodDpib2xkOyBjb2xvcjogaHNsYSgyMDEsMTAwJSwzMCUsMS4wKTsiKSwidW5jbG9zZWRDb2xsYXBzZWQiLHIoLjAyNSkrImZvbnQtd2VpZ2h0OmJvbGQ7IGNvbG9yOiBoc2xhKDIwMSwxMDAlLDMwJSwxLjApOyIpLCJjb2xsYXBzZWQiLHIoLjAyNSkpLCJjb2xsYXBzZWQuaG9vayIsciguMDUpKSwiY29sbGFwc2VkLmhvb2stMiIsciguMSkpLCJjb2xsYXBzZWQuaG9vay0zIixyKC4xNSkpLF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShuLCJjb2xsYXBzZWQuaG9vay00IixyKC4yKSksImNvbGxhcHNlZC5ob29rLTUiLHIoLjI1KSksImNvbGxhcHNlZC5ob29rLTYiLHIoLjMpKSwiY29sbGFwc2VkLmhvb2stNyIsciguMzUpKSwiY29sbGFwc2VkLmhvb2stOCIsciguNCkpLCJ0d2luZUxpbms6bm90KC50ZXh0KSIsdC50d2luZUxpbmspLCJ0YWcsIHNjcmlwdFN0eWxlVGFnLCBjb21tZW50IiwiY29sb3I6IGhzbGEoMjQwLDM0JSwyNSUsMS4wKTsiKSwiYm9vbGVhbiIsdC5ib29sZWFuKSwic3RyaW5nIix0LnN0cmluZyksIm51bWJlciIsdC5udW1iZXIpLF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShuLCJ2YXJpYWJsZSIsdC52YXJpYWJsZSksInRlbXBWYXJpYWJsZSIsdC50ZW1wVmFyaWFibGUpLCJob29rTmFtZSIsdC5ob29rTmFtZSksImRhdGF0eXBlIix0LmRhdGF0eXBlKSwiY29sb3VyIix0LmNvbG91ciksImNzc1RpbWUiLHQubnVtYmVyKSwicGFzc2FnZVN0cmluZyIsdC52YXJpYWJsZSsiO3RleHQtZGVjb3JhdGlvbjp1bmRlcmxpbmUgMXB4OyIpLCJ0YWdTdHJpbmciLHQudmFyaWFibGUrIjt0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lIDFweCBkb3R0ZWQ7IiksInZhcmlhYmxlT2NjdXJyZW5jZSwgaG9va09jY3VycmVuY2UiLCJiYWNrZ3JvdW5kOiBoc2xhKDE1OSw1MCUsNzUlLDEuMCkgIWltcG9ydGFudDsiKSwiXj13aGVyZSwgXj12aWEsIF49d2l0aCwgXj1tYWtpbmcsIF49ZWFjaCwgXj13aGVuIix0LmxhbWJkYSsiOyBmb250LXN0eWxlOml0YWxpYzsiKSxfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkoX2RlZmluZVByb3BlcnR5KF9kZWZpbmVQcm9wZXJ0eShfZGVmaW5lUHJvcGVydHkobiwiaGVhZGluZyIsImZvbnQtd2VpZ2h0OmJvbGQ7IiksImhyIiwiYmFja2dyb3VuZC1pbWFnZTogbGluZWFyLWdyYWRpZW50KDBkZWcsIHRyYW5zcGFyZW50LCB0cmFuc3BhcmVudCA0NSUsIGhzbGEoMCwwJSw3NSUsMS4wKSA0NSUsIHRyYW5zcGFyZW50IDU1JSwgdHJhbnNwYXJlbnQpOyIpLCJhbGlnbiIsImNvbG9yOiBoc2xhKDE0LDk5JSwzNyUsMS4wKTsgYmFja2dyb3VuZC1jb2xvcjogaHNsYSgxNCw5OSUsODclLDAuMSk7IiksImNvbHVtbiIsImNvbG9yOiBoc2xhKDIwNCw5OSUsMzclLDEuMCk7IGJhY2tncm91bmQtY29sb3I6IGhzbGEoMjA0LDk5JSw4NyUsMC4xKTsiKSwiZXNjYXBlZExpbmUiLCJmb250LXdlaWdodDpib2xkOyBjb2xvcjogaHNsYSg1MSwxMDAlLDMwJSwxLjApOyIpLCJpZGVudGlmaWVyLCBwcm9wZXJ0eSwgYmVsb25naW5nUHJvcGVydHksIGl0c1Byb3BlcnR5LCBiZWxvbmdpbmdJdFByb3BlcnR5LCBiZWxvbmdpbmdJdE9wZXJhdG9yLCBwb3NzZXNzaXZlT3BlcmF0b3IsIGJlbG9uZ2luZ09wZXJhdG9yIix0LmlkZW50aWZpZXIpLCJ0b1N0cmluZyIsZnVuY3Rpb24oKXt2YXIgYT10aGlzO3JldHVybiBPYmplY3Qua2V5cyh0aGlzKS5yZWR1Y2UoZnVuY3Rpb24oZSxuKXt2YXIgcjtyZXR1cm4idG9TdHJpbmciIT09biYmKHI9bi5zcGxpdCgiLCAiKS5tYXAoZnVuY3Rpb24gZSh0KXtyZXR1cm4tMTx0LmluZGV4T2YoIi4iKT90LnNwbGl0KC9cLi9nKS5tYXAoZSkuam9pbigiIik6MD09PXQuaW5kZXhPZigiXj0iKT8iW2NsYXNzXj0nIitzK3Quc2xpY2UoMikrIiddIjoiLiIrcyt0fSksZSs9ci5qb2luKCIsICIpKyJ7IithW25dKyJ9IixhW25dLm1hdGNoKGkpKSYmWyIudGhlbWUtZGFyayIsIltkYXRhLWFwcC10aGVtZT1kYXJrXSJdLmZvckVhY2goZnVuY3Rpb24odCl7ZSs9ci5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHQrIiAiK2V9KS5qb2luKCIsICIpKyJ7IithW25dLnJlcGxhY2UoaSxmdW5jdGlvbihlLHQsbixyLGEpe3JldHVybiJoc2xhKCIrdCsiLCIrbygxMDAsMS41KituKSsiJSwiKygxMDAtcikrIiUsIithKyIpIn0pKyJ9In0pLGV9LCIiKX0pKyIiKTsib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09dHlwZW9mIG1vZHVsZT8idW5kZWZpbmVkIjpfdHlwZW9mKG1vZHVsZSkpP21vZHVsZS5leHBvcnRzPXtDb2xvdXJzOnQsQ1NTOmEsdmVyc2lvbkNsYXNzOnN9OiJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQmJmRlZmluZSgidXRpbHMvdHlwZWNvbG91cnMiLFtdLGZ1bmN0aW9uKCl7cmV0dXJue0NvbG91cnM6dCxDU1M6YSx2ZXJzaW9uQ2xhc3M6c319KX0uY2FsbCh2b2lkIDApOwo7cmVxdWlyZSgiaGFybG93ZSIpfSgpKTsKPC9zY3JpcHQ+Cgo8L2JvZHk+CjwvaHRtbD4K diff --git a/twine_b64.txt b/twine_b64.txt new file mode 100644 index 000000000..e69de29bb From 784bd943f4c5be73d39855e416891e2bd3c3883d Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Wed, 21 May 2025 16:39:26 -0500 Subject: [PATCH 28/37] resolve merge conflict --- .../migrations/0003_alter_livechatmessagereaction_content.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py b/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py index bd49b76a8..6e7d6dbdc 100644 --- a/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py +++ b/src/chigame/chat/migrations/0003_alter_livechatmessagereaction_content.py @@ -1,6 +1,5 @@ from django.db import migrations, models - class Migration(migrations.Migration): dependencies = [ ("chat", "0002_livechatmessagereaction"), From 490eb2055cb6f05cf7ffc18b3775eb78c5df2b44 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 01:57:25 -0500 Subject: [PATCH 29/37] [IF] Run pre-commit hooks and finalize test fixes --- src/chigame/api/tests/test_api.py | 5 +++++ .../migrations/0046_auto_20250521_1607.py | 18 +++++++++++++++--- src/chigame/games/tests.py | 12 +++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/chigame/api/tests/test_api.py b/src/chigame/api/tests/test_api.py index 75bd0a1e6..3dea11eb3 100644 --- a/src/chigame/api/tests/test_api.py +++ b/src/chigame/api/tests/test_api.py @@ -27,6 +27,11 @@ class GameTests(APITestCase): + # for IF games migration resetting + def setUp(self): + super().setUp() + Game.objects.all().delete() + def check_equal(self, obj, expected: dict): """ Helper function to check that the object data matches the expected data. diff --git a/src/chigame/games/migrations/0046_auto_20250521_1607.py b/src/chigame/games/migrations/0046_auto_20250521_1607.py index 0b1aaec7c..4725c9fe5 100644 --- a/src/chigame/games/migrations/0046_auto_20250521_1607.py +++ b/src/chigame/games/migrations/0046_auto_20250521_1607.py @@ -1,18 +1,30 @@ +import sys +import os import base64 from django.db import migrations def insert_twine_game(apps, schema_editor): + # Skip during tests or if the file is missing + if "test" in sys.argv or os.environ.get("CI") == "true": + return + Game = apps.get_model("games", "Game") + file_path = "src/chigame/games/migrations/twine_b64.txt" + + if not os.path.exists(file_path): + print(f"Skipping migration: file not found at {file_path}") + return - with open("src/chigame/games/migrations/twine_b64.txt", "rb") as f: + with open(file_path, "rb") as f: html_bytes = base64.b64decode(f.read()) Game.objects.create( - name="Midterm Project", + name="Twine Test Game", description="Uploaded via migration", twine_file=html_bytes, min_players=1, - max_players=1 + max_players=1, + complexity=1, ) class Migration(migrations.Migration): diff --git a/src/chigame/games/tests.py b/src/chigame/games/tests.py index 0b89082ec..d3d4daccf 100644 --- a/src/chigame/games/tests.py +++ b/src/chigame/games/tests.py @@ -9,6 +9,14 @@ class RecommendationSystemTest(TestCase): def setUp(self): + super().setUp() + + # clear any leftover Twine game that may have been inserted by migrations + Game.objects.filter(name="Twine Test Game").delete() + + # clear any pre-existing test/migrated games + Game.objects.all().delete() + # Create test categories self.category1 = Category.objects.create(name="Strategy") self.category2 = Category.objects.create(name="Card Game") @@ -97,6 +105,8 @@ def test_played_games_penalty(self): Player.objects.create(user=self.user, match=match, outcome=Player.WIN) # Game2 should still be recommended but at a lower position - recommendations = get_recommended_games(self.game1, user=self.user) + recommendations = [ + game for game in get_recommended_games(self.game1, user=self.user) if game.name != "Twine Test Game" + ] self.assertIn(self.game2, recommendations) self.assertEqual(list(recommendations)[0], self.game3) # game3 should now be first From c27fed18072158e837252119f5414d9f532ba03c Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:02:46 -0500 Subject: [PATCH 30/37] [IF] Merge the conflict and making migrations --- .../games/migrations/0047_merge_20250523_0202.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/chigame/games/migrations/0047_merge_20250523_0202.py diff --git a/src/chigame/games/migrations/0047_merge_20250523_0202.py b/src/chigame/games/migrations/0047_merge_20250523_0202.py new file mode 100644 index 000000000..290f782b1 --- /dev/null +++ b/src/chigame/games/migrations/0047_merge_20250523_0202.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.20 on 2025-05-23 07:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0041_merge_20250521_2013"), + ("games", "0046_auto_20250521_1607"), + ] + + operations = [] From 48639a28411d5bcfe5e4c020382645f13ac6bd99 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:13:15 -0500 Subject: [PATCH 31/37] Fix migrations and restore working environment --- .../achievements/migrations/0001_initial.py | 22 +- ...shold_userachievement_progress_and_more.py | 37 --- .../achievements/migrations/0002_initial.py | 36 +++ ...3_userachievement_last_updated_and_more.py | 22 -- src/chigame/chat/migrations/0001_initial.py | 72 +---- src/chigame/chat/migrations/0002_initial.py | 91 ++++++ .../0002_livechat_pinned_message.py | 24 -- .../migrations/0002_livechatmessage_edited.py | 17 -- .../migrations/0003_merge_20250522_1426.py | 12 - .../migrations/0001_initial.py | 141 ++++----- .../migrations/0002_initial.py | 132 +++++++++ .../migrations/0002_post_anonymous_key.py | 18 -- .../migrations/0003_auto_20160228_2051.py | 25 -- .../migrations/0004_auto_20160427_0502.py | 22 -- .../migrations/0005_auto_20160607_0455.py | 24 -- .../migrations/0006_post_enable_signature.py | 19 -- .../migrations/0007_auto_20160903_0450.py | 41 --- .../migrations/0008_auto_20160903_0512.py | 29 -- .../migrations/0009_auto_20160925_2126.py | 19 -- .../migrations/0010_auto_20170120_0224.py | 28 -- .../migrations/0011_remove_post_poster_ip.py | 16 - .../migrations/0012_auto_20200423_1049.py | 23 -- .../migrations/0013_auto_20201220_1745.py | 31 -- .../0014_alter_post_id_alter_topic_id.py | 22 -- .../migrations/0015_post_like_counter.py | 17 -- .../0016_remove_post_like_counter.py | 16 - .../migrations/0017_vote.py | 19 -- ...0018_post_ratings_vote_post_vote_poster.py | 40 --- .../migrations/0019_vote_unique_rating.py | 16 - src/chigame/games/migrations/0001_initial.py | 236 ++++++++++++++- src/chigame/games/migrations/0002_initial.py | 274 ++++++++++++++---- ...ic_game_bgg_id_game_complexity_and_more.py | 102 ------- src/chigame/games/migrations/0004_initial.py | 18 -- src/chigame/games/migrations/0005_initial.py | 27 -- .../migrations/0006_Allow_null_fields.py | 57 ---- .../0006_matches_nullable_outcome.py | 45 --- .../migrations/0007_image_field_as_text.py | 22 -- .../migrations/0008_merge_20231113_1632.py | 12 - .../0009_announcement_delete_notification.py | 38 --- .../migrations/0010_categories_plural.py | 17 -- ...game_categories_category_image_and_more.py | 38 --- .../migrations/0011_revert_category_name.py | 17 -- .../migrations/0012_merge_20231115_1702.py | 12 - .../migrations/0012_update_tournaments.py | 29 -- .../migrations/0013_merge_20231116_0044.py | 12 - ...ove_chat_match_chat_tournament_and_more.py | 29 -- src/chigame/games/migrations/0014_review.py | 25 -- .../migrations/0015_merge_20231126_1835.py | 12 - ...age_token_id_message_update_on_and_more.py | 27 -- ...16_review_is_public_alter_review_rating.py | 22 -- .../migrations/0016_update_tournaments_2.py | 37 --- .../migrations/0017_merge_20231127_2228.py | 12 - .../0018_review_created_at_review_title.py | 27 -- .../migrations/0019_alter_review_rating.py | 24 -- .../migrations/0020_merge_20231204_1517.py | 12 - .../0021_alter_tournament_matches.py | 17 -- .../migrations/0022_tournament_created_by.py | 25 -- src/chigame/games/migrations/0023_feedback.py | 48 --- .../0023_game_published_guide_id.py | 21 -- src/chigame/games/migrations/0023_gamelist.py | 34 --- ...3_livechat_livechatuser_livechatmessage.py | 82 ------ .../migrations/0024_merge_20250428_1822.py | 12 - .../migrations/0024_merge_20250428_2051.py | 12 - .../migrations/0024_merge_20250428_2111.py | 12 - .../migrations/0025_alter_livechat_channel.py | 17 -- .../migrations/0026_merge_20250430_1102.py | 12 - .../migrations/0026_merge_20250430_1104.py | 12 - .../migrations/0027_merge_20250430_1134.py | 12 - .../games/migrations/0028_game_users.py | 19 -- ..._0023_feedback_0027_merge_20250430_1134.py | 12 - ...e_livechatmessage_live_chat_id_and_more.py | 37 --- .../migrations/0029_alter_review_game.py | 20 -- .../games/migrations/0029_game_twine_file.py | 17 -- ...equeue_alter_review_game_gamequeueentry.py | 54 ---- .../migrations/0029_interactivefictiongame.py | 31 -- .../migrations/0029_merge_20250505_2335.py | 12 - .../migrations/0029_merge_20250507_1534.py | 12 - ...er_review_game_0029_merge_20250507_1534.py | 12 - .../migrations/0030_merge_20250512_1728.py | 12 - .../migrations/0030_remove_game_twine_file.py | 16 - ...1_alter_feedback_user_alter_review_game.py | 29 -- .../games/migrations/0031_game_twine_file.py | 17 -- .../migrations/0032_alter_review_game.py | 20 -- ...ge_20250507_1534_0032_alter_review_game.py | 12 - .../migrations/0034_merge_20250512_1731.py | 12 - .../migrations/0035_merge_20250512_2236.py | 12 - .../migrations/0035_merge_20250513_1435.py | 13 - ...036_checkers_checkersboard_checkersturn.py | 67 ----- .../migrations/0036_merge_20250514_2202.py | 12 - .../migrations/0036_merge_20250514_2211.py | 12 - .../games/migrations/0036_wordgamedata.py | 36 --- .../0037_gamedata_delete_wordgamedata.py | 45 --- .../migrations/0037_merge_20250518_2303.py | 12 - .../migrations/0038_merge_20250519_0011.py | 12 - ...twine_file_content_game_twine_file_name.py | 23 -- .../migrations/0039_merge_20250519_0030.py | 12 - .../migrations/0039_merge_20250520_1918.py | 12 - .../migrations/0040_merge_20250520_2114.py | 12 - .../migrations/0040_merge_20250521_1413.py | 12 - ...wine_file_content_alter_game_twine_file.py | 22 -- .../migrations/0041_merge_20250521_2013.py | 12 - ...name_twine_file_game_twine_file_content.py | 18 -- ...name_twine_file_content_game_twine_file.py | 18 -- .../0043_remove_game_twine_file_name.py | 17 -- .../migrations/0044_game_twine_file_name.py | 18 -- .../migrations/0045_merge_20250521_1434.py | 13 - .../migrations/0046_auto_20250521_1607.py | 38 --- .../migrations/0047_merge_20250523_0202.py | 13 - .../knowledge_base/migrations/0001_initial.py | 72 ++--- ..._together_remove_like_guide_id_and_more.py | 56 ---- ...uide_likes_and_more.py => 0002_initial.py} | 43 ++- .../0004_alter_reviewfeedback_guide_id.py | 19 -- ...lfeedback_alter_reviewfeedback_guide_id.py | 33 --- ...back_seen_alter_reviewfeedback_guide_id.py | 25 -- .../migrations/0005_merge_20250517_1110.py | 12 - .../migrations/0006_merge_20250519_1518.py | 12 - .../leaderboards/migrations/0001_initial.py | 88 +----- .../leaderboards/migrations/0002_initial.py | 82 ++++++ .../0002_leaderboardentry_region.py | 20 -- src/chigame/users/migrations/0001_initial.py | 122 ++++++-- .../migrations/0002_categories_plural.py | 25 -- ...002_user_tokens_alter_notification_type.py | 33 --- .../migrations/0003_merge_20231115_1525.py | 12 - .../users/migrations/0004_user_username.py | 17 -- .../migrations/0005_alter_user_username.py | 25 -- .../0006_friendinvitation_is_deleted.py | 18 -- ...007_remove_userprofile_friends_and_more.py | 55 ---- .../0008_remove_userprofile_display_name.py | 16 - .../migrations/0008_user_profanity_filter.py | 17 -- ...okmarked_notification_category_and_more.py | 38 --- .../migrations/0010_merge_20250514_2202.py | 12 - .../migrations/0010_merge_20250514_2211.py | 12 - ...0_notificationlabel_notification_labels.py | 37 --- ...oup_description_alter_notification_type.py | 36 --- .../migrations/0011_merge_20250518_2303.py | 12 - .../migrations/0012_merge_20250518_2347.py | 12 - .../migrations/0013_merge_20250519_0011.py | 12 - ..._alter_friendinvitation_unique_together.py | 16 - 138 files changed, 1030 insertions(+), 3294 deletions(-) delete mode 100644 src/chigame/achievements/migrations/0002_achievement_threshold_userachievement_progress_and_more.py create mode 100644 src/chigame/achievements/migrations/0002_initial.py delete mode 100644 src/chigame/achievements/migrations/0003_userachievement_last_updated_and_more.py create mode 100644 src/chigame/chat/migrations/0002_initial.py delete mode 100644 src/chigame/chat/migrations/0002_livechat_pinned_message.py delete mode 100644 src/chigame/chat/migrations/0002_livechatmessage_edited.py delete mode 100644 src/chigame/chat/migrations/0003_merge_20250522_1426.py create mode 100644 src/chigame/forums/forum_conversation/migrations/0002_initial.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0002_post_anonymous_key.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0003_auto_20160228_2051.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0004_auto_20160427_0502.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0005_auto_20160607_0455.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0006_post_enable_signature.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0007_auto_20160903_0450.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0008_auto_20160903_0512.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0009_auto_20160925_2126.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0010_auto_20170120_0224.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0011_remove_post_poster_ip.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0012_auto_20200423_1049.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0013_auto_20201220_1745.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0014_alter_post_id_alter_topic_id.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0015_post_like_counter.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0016_remove_post_like_counter.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0017_vote.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0018_post_ratings_vote_post_vote_poster.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0019_vote_unique_rating.py delete mode 100644 src/chigame/games/migrations/0003_category_mechanic_game_bgg_id_game_complexity_and_more.py delete mode 100644 src/chigame/games/migrations/0004_initial.py delete mode 100644 src/chigame/games/migrations/0005_initial.py delete mode 100644 src/chigame/games/migrations/0006_Allow_null_fields.py delete mode 100644 src/chigame/games/migrations/0006_matches_nullable_outcome.py delete mode 100644 src/chigame/games/migrations/0007_image_field_as_text.py delete mode 100644 src/chigame/games/migrations/0008_merge_20231113_1632.py delete mode 100644 src/chigame/games/migrations/0009_announcement_delete_notification.py delete mode 100644 src/chigame/games/migrations/0010_categories_plural.py delete mode 100644 src/chigame/games/migrations/0010_rename_category_game_categories_category_image_and_more.py delete mode 100644 src/chigame/games/migrations/0011_revert_category_name.py delete mode 100644 src/chigame/games/migrations/0012_merge_20231115_1702.py delete mode 100644 src/chigame/games/migrations/0012_update_tournaments.py delete mode 100644 src/chigame/games/migrations/0013_merge_20231116_0044.py delete mode 100644 src/chigame/games/migrations/0014_remove_chat_match_chat_tournament_and_more.py delete mode 100644 src/chigame/games/migrations/0014_review.py delete mode 100644 src/chigame/games/migrations/0015_merge_20231126_1835.py delete mode 100644 src/chigame/games/migrations/0015_message_token_id_message_update_on_and_more.py delete mode 100644 src/chigame/games/migrations/0016_review_is_public_alter_review_rating.py delete mode 100644 src/chigame/games/migrations/0016_update_tournaments_2.py delete mode 100644 src/chigame/games/migrations/0017_merge_20231127_2228.py delete mode 100644 src/chigame/games/migrations/0018_review_created_at_review_title.py delete mode 100644 src/chigame/games/migrations/0019_alter_review_rating.py delete mode 100644 src/chigame/games/migrations/0020_merge_20231204_1517.py delete mode 100644 src/chigame/games/migrations/0021_alter_tournament_matches.py delete mode 100644 src/chigame/games/migrations/0022_tournament_created_by.py delete mode 100644 src/chigame/games/migrations/0023_feedback.py delete mode 100644 src/chigame/games/migrations/0023_game_published_guide_id.py delete mode 100644 src/chigame/games/migrations/0023_gamelist.py delete mode 100644 src/chigame/games/migrations/0023_livechat_livechatuser_livechatmessage.py delete mode 100644 src/chigame/games/migrations/0024_merge_20250428_1822.py delete mode 100644 src/chigame/games/migrations/0024_merge_20250428_2051.py delete mode 100644 src/chigame/games/migrations/0024_merge_20250428_2111.py delete mode 100644 src/chigame/games/migrations/0025_alter_livechat_channel.py delete mode 100644 src/chigame/games/migrations/0026_merge_20250430_1102.py delete mode 100644 src/chigame/games/migrations/0026_merge_20250430_1104.py delete mode 100644 src/chigame/games/migrations/0027_merge_20250430_1134.py delete mode 100644 src/chigame/games/migrations/0028_game_users.py delete mode 100644 src/chigame/games/migrations/0028_merge_0023_feedback_0027_merge_20250430_1134.py delete mode 100644 src/chigame/games/migrations/0028_remove_livechatmessage_live_chat_id_and_more.py delete mode 100644 src/chigame/games/migrations/0029_alter_review_game.py delete mode 100644 src/chigame/games/migrations/0029_game_twine_file.py delete mode 100644 src/chigame/games/migrations/0029_gamequeue_alter_review_game_gamequeueentry.py delete mode 100644 src/chigame/games/migrations/0029_interactivefictiongame.py delete mode 100644 src/chigame/games/migrations/0029_merge_20250505_2335.py delete mode 100644 src/chigame/games/migrations/0029_merge_20250507_1534.py delete mode 100644 src/chigame/games/migrations/0030_merge_0029_alter_review_game_0029_merge_20250507_1534.py delete mode 100644 src/chigame/games/migrations/0030_merge_20250512_1728.py delete mode 100644 src/chigame/games/migrations/0030_remove_game_twine_file.py delete mode 100644 src/chigame/games/migrations/0031_alter_feedback_user_alter_review_game.py delete mode 100644 src/chigame/games/migrations/0031_game_twine_file.py delete mode 100644 src/chigame/games/migrations/0032_alter_review_game.py delete mode 100644 src/chigame/games/migrations/0033_merge_0029_merge_20250507_1534_0032_alter_review_game.py delete mode 100644 src/chigame/games/migrations/0034_merge_20250512_1731.py delete mode 100644 src/chigame/games/migrations/0035_merge_20250512_2236.py delete mode 100644 src/chigame/games/migrations/0035_merge_20250513_1435.py delete mode 100644 src/chigame/games/migrations/0036_checkers_checkersboard_checkersturn.py delete mode 100644 src/chigame/games/migrations/0036_merge_20250514_2202.py delete mode 100644 src/chigame/games/migrations/0036_merge_20250514_2211.py delete mode 100644 src/chigame/games/migrations/0036_wordgamedata.py delete mode 100644 src/chigame/games/migrations/0037_gamedata_delete_wordgamedata.py delete mode 100644 src/chigame/games/migrations/0037_merge_20250518_2303.py delete mode 100644 src/chigame/games/migrations/0038_merge_20250519_0011.py delete mode 100644 src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py delete mode 100644 src/chigame/games/migrations/0039_merge_20250519_0030.py delete mode 100644 src/chigame/games/migrations/0039_merge_20250520_1918.py delete mode 100644 src/chigame/games/migrations/0040_merge_20250520_2114.py delete mode 100644 src/chigame/games/migrations/0040_merge_20250521_1413.py delete mode 100644 src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py delete mode 100644 src/chigame/games/migrations/0041_merge_20250521_2013.py delete mode 100644 src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py delete mode 100644 src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py delete mode 100644 src/chigame/games/migrations/0043_remove_game_twine_file_name.py delete mode 100644 src/chigame/games/migrations/0044_game_twine_file_name.py delete mode 100644 src/chigame/games/migrations/0045_merge_20250521_1434.py delete mode 100644 src/chigame/games/migrations/0046_auto_20250521_1607.py delete mode 100644 src/chigame/games/migrations/0047_merge_20250523_0202.py delete mode 100644 src/chigame/knowledge_base/migrations/0002_alter_like_unique_together_remove_like_guide_id_and_more.py rename src/chigame/knowledge_base/migrations/{0003_alter_guide_favorites_alter_guide_likes_and_more.py => 0002_initial.py} (55%) delete mode 100644 src/chigame/knowledge_base/migrations/0004_alter_reviewfeedback_guide_id.py delete mode 100644 src/chigame/knowledge_base/migrations/0004_generalfeedback_alter_reviewfeedback_guide_id.py delete mode 100644 src/chigame/knowledge_base/migrations/0004_reviewfeedback_seen_alter_reviewfeedback_guide_id.py delete mode 100644 src/chigame/knowledge_base/migrations/0005_merge_20250517_1110.py delete mode 100644 src/chigame/knowledge_base/migrations/0006_merge_20250519_1518.py create mode 100644 src/chigame/leaderboards/migrations/0002_initial.py delete mode 100644 src/chigame/leaderboards/migrations/0002_leaderboardentry_region.py delete mode 100644 src/chigame/users/migrations/0002_categories_plural.py delete mode 100644 src/chigame/users/migrations/0002_user_tokens_alter_notification_type.py delete mode 100644 src/chigame/users/migrations/0003_merge_20231115_1525.py delete mode 100644 src/chigame/users/migrations/0004_user_username.py delete mode 100644 src/chigame/users/migrations/0005_alter_user_username.py delete mode 100644 src/chigame/users/migrations/0006_friendinvitation_is_deleted.py delete mode 100644 src/chigame/users/migrations/0007_remove_userprofile_friends_and_more.py delete mode 100644 src/chigame/users/migrations/0008_remove_userprofile_display_name.py delete mode 100644 src/chigame/users/migrations/0008_user_profanity_filter.py delete mode 100644 src/chigame/users/migrations/0009_notification_bookmarked_notification_category_and_more.py delete mode 100644 src/chigame/users/migrations/0010_merge_20250514_2202.py delete mode 100644 src/chigame/users/migrations/0010_merge_20250514_2211.py delete mode 100644 src/chigame/users/migrations/0010_notificationlabel_notification_labels.py delete mode 100644 src/chigame/users/migrations/0011_group_description_alter_notification_type.py delete mode 100644 src/chigame/users/migrations/0011_merge_20250518_2303.py delete mode 100644 src/chigame/users/migrations/0012_merge_20250518_2347.py delete mode 100644 src/chigame/users/migrations/0013_merge_20250519_0011.py delete mode 100644 src/chigame/users/migrations/0014_alter_friendinvitation_unique_together.py diff --git a/src/chigame/achievements/migrations/0001_initial.py b/src/chigame/achievements/migrations/0001_initial.py index 347805ecd..3c045110a 100644 --- a/src/chigame/achievements/migrations/0001_initial.py +++ b/src/chigame/achievements/migrations/0001_initial.py @@ -1,6 +1,5 @@ -# Generated by Django 4.2.20 on 2025-05-02 01:36 +# Generated by Django 4.2.20 on 2025-05-23 07:12 -from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -8,10 +7,7 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ("games", "0027_merge_20250430_1134"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [] operations = [ migrations.CreateModel( @@ -20,28 +16,26 @@ class Migration(migrations.Migration): ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("name", models.TextField()), ("description", models.TextField(blank=True, null=True)), - ("spoiler", models.BooleanField()), + ("spoiler", models.BooleanField(default=False)), ( "rarity", models.IntegerField(choices=[(1, "Common"), (2, "Uncommon"), (3, "Rare"), (4, "Precious")]), ), - ("game", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game")), + ("threshold", models.FloatField(blank=True, default=1, null=True)), ], ), migrations.CreateModel( name="UserAchievement", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("pinned", models.BooleanField()), - ("date_earned", models.DateTimeField()), + ("pinned", models.BooleanField(default=False)), + ("date_earned", models.DateTimeField(blank=True, null=True)), + ("last_updated", models.DateTimeField(auto_now=True)), + ("progress", models.FloatField(blank=True, default=1, null=True)), ( "achievement", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="achievements.achievement"), ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - "unique_together": {("user", "achievement")}, - }, ), ] diff --git a/src/chigame/achievements/migrations/0002_achievement_threshold_userachievement_progress_and_more.py b/src/chigame/achievements/migrations/0002_achievement_threshold_userachievement_progress_and_more.py deleted file mode 100644 index 053f8ba4a..000000000 --- a/src/chigame/achievements/migrations/0002_achievement_threshold_userachievement_progress_and_more.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-07 19:31 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ("achievements", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="achievement", - name="threshold", - field=models.FloatField(blank=True, default=1, null=True), - ), - migrations.AddField( - model_name="userachievement", - name="progress", - field=models.FloatField(blank=True, default=1, null=True), - ), - migrations.AlterField( - model_name="achievement", - name="spoiler", - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name="userachievement", - name="pinned", - field=models.BooleanField(default=False), - ), - migrations.AlterUniqueTogether( - name="achievement", - unique_together={("name", "game")}, - ), - ] diff --git a/src/chigame/achievements/migrations/0002_initial.py b/src/chigame/achievements/migrations/0002_initial.py new file mode 100644 index 000000000..3975ce579 --- /dev/null +++ b/src/chigame/achievements/migrations/0002_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.20 on 2025-05-23 07:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("achievements", "0001_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("games", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="userachievement", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="achievement", + name="game", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game"), + ), + migrations.AlterUniqueTogether( + name="userachievement", + unique_together={("user", "achievement")}, + ), + migrations.AlterUniqueTogether( + name="achievement", + unique_together={("name", "game")}, + ), + ] diff --git a/src/chigame/achievements/migrations/0003_userachievement_last_updated_and_more.py b/src/chigame/achievements/migrations/0003_userachievement_last_updated_and_more.py deleted file mode 100644 index 8a88160f3..000000000 --- a/src/chigame/achievements/migrations/0003_userachievement_last_updated_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-13 21:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("achievements", "0002_achievement_threshold_userachievement_progress_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="userachievement", - name="last_updated", - field=models.DateTimeField(auto_now=True), - ), - migrations.AlterField( - model_name="userachievement", - name="date_earned", - field=models.DateTimeField(blank=True, null=True), - ), - ] diff --git a/src/chigame/chat/migrations/0001_initial.py b/src/chigame/chat/migrations/0001_initial.py index 5fc04aa12..d9189aca7 100644 --- a/src/chigame/chat/migrations/0001_initial.py +++ b/src/chigame/chat/migrations/0001_initial.py @@ -1,8 +1,6 @@ -# Generated by Django 4.2.20 on 2025-05-21 18:00 -# Generated by Django 4.2.20 on 2025-05-13 04:18 +# Generated by Django 4.2.20 on 2025-05-23 07:12 import chigame.chat.validators -from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -10,9 +8,7 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [] operations = [ migrations.CreateModel( @@ -29,14 +25,14 @@ class Migration(migrations.Migration): ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("sent_at", models.DateTimeField(auto_now_add=True)), ("content", models.TextField()), - ("live_chat", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechat")), - ( - "reply_to", - models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="chat.livechatmessage" - ), - ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ("edited", models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name="LiveChatMessageReaction", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("content", models.CharField(max_length=10, validators=[chigame.chat.validators.validate_emoji])), ], ), migrations.CreateModel( @@ -47,12 +43,6 @@ class Migration(migrations.Migration): ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ("closed_at", models.DateTimeField(help_text="The date and time the poll will be closed", null=True)), - ( - "live_chat", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="polls", to="chat.livechat" - ), - ), ], ), migrations.CreateModel( @@ -62,53 +52,17 @@ class Migration(migrations.Migration): ("content", models.TextField()), ], ), - migrations.CreateModel( - name="LiveChatUser", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("live_chat", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechat")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.AddField( - model_name="livechat", - name="users", - field=models.ManyToManyField( - related_name="live_chats", through="chat.LiveChatUser", to=settings.AUTH_USER_MODEL - ), - ), migrations.CreateModel( name="LiveChatPollVote", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ( - "option", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatpolloption"), - ), - ("poll", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatpoll")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), - migrations.AddField( - model_name="livechatpoll", - name="options", - field=models.ManyToManyField(blank=True, related_name="polls", to="chat.livechatpolloption"), - ), migrations.CreateModel( - name="LiveChatMessageReaction", + name="LiveChatUser", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("content", models.CharField(max_length=10, validators=[chigame.chat.validators.validate_emoji])), - ("message", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatmessage")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ("live_chat", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechat")), ], ), - migrations.AddConstraint( - model_name="livechatpollvote", - constraint=models.UniqueConstraint(fields=("poll", "option", "user"), name="unique_poll_option_user"), - ), - migrations.AlterUniqueTogether( - name="livechatmessagereaction", - unique_together={("user", "message", "content")}, - ), - ] \ No newline at end of file + ] diff --git a/src/chigame/chat/migrations/0002_initial.py b/src/chigame/chat/migrations/0002_initial.py new file mode 100644 index 000000000..43f840408 --- /dev/null +++ b/src/chigame/chat/migrations/0002_initial.py @@ -0,0 +1,91 @@ +# Generated by Django 4.2.20 on 2025-05-23 07:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("chat", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="livechatuser", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="livechatpollvote", + name="option", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatpolloption"), + ), + migrations.AddField( + model_name="livechatpollvote", + name="poll", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatpoll"), + ), + migrations.AddField( + model_name="livechatpollvote", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="livechatpoll", + name="live_chat", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="polls", to="chat.livechat" + ), + ), + migrations.AddField( + model_name="livechatpoll", + name="options", + field=models.ManyToManyField(blank=True, related_name="polls", to="chat.livechatpolloption"), + ), + migrations.AddField( + model_name="livechatmessagereaction", + name="message", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechatmessage"), + ), + migrations.AddField( + model_name="livechatmessagereaction", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="livechatmessage", + name="live_chat", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="chat.livechat"), + ), + migrations.AddField( + model_name="livechatmessage", + name="reply_to", + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="chat.livechatmessage" + ), + ), + migrations.AddField( + model_name="livechatmessage", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="livechat", + name="users", + field=models.ManyToManyField( + related_name="live_chats", through="chat.LiveChatUser", to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddConstraint( + model_name="livechatpollvote", + constraint=models.UniqueConstraint(fields=("poll", "option", "user"), name="unique_poll_option_user"), + ), + migrations.AlterUniqueTogether( + name="livechatmessagereaction", + unique_together={("user", "message", "content")}, + ), + ] diff --git a/src/chigame/chat/migrations/0002_livechat_pinned_message.py b/src/chigame/chat/migrations/0002_livechat_pinned_message.py deleted file mode 100644 index 60d083f7f..000000000 --- a/src/chigame/chat/migrations/0002_livechat_pinned_message.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-22 02:35 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("chat", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="livechat", - name="pinned_message", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="pinned_message", - to="chat.livechatmessage", - ), - ), - ] diff --git a/src/chigame/chat/migrations/0002_livechatmessage_edited.py b/src/chigame/chat/migrations/0002_livechatmessage_edited.py deleted file mode 100644 index 93cda80d1..000000000 --- a/src/chigame/chat/migrations/0002_livechatmessage_edited.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-22 01:58 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("chat", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="livechatmessage", - name="edited", - field=models.BooleanField(default=False), - ), - ] diff --git a/src/chigame/chat/migrations/0003_merge_20250522_1426.py b/src/chigame/chat/migrations/0003_merge_20250522_1426.py deleted file mode 100644 index afca2b6be..000000000 --- a/src/chigame/chat/migrations/0003_merge_20250522_1426.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-22 19:26 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("chat", "0002_livechat_pinned_message"), - ("chat", "0002_livechatmessage_edited"), - ] - - operations = [] diff --git a/src/chigame/forums/forum_conversation/migrations/0001_initial.py b/src/chigame/forums/forum_conversation/migrations/0001_initial.py index b70cb7471..b653e0611 100644 --- a/src/chigame/forums/forum_conversation/migrations/0001_initial.py +++ b/src/chigame/forums/forum_conversation/migrations/0001_initial.py @@ -1,148 +1,117 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 4.2.20 on 2025-05-23 07:12 -from django.db import models, migrations -from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import machina.core.validators import machina.models.fields class Migration(migrations.Migration): - dependencies = [ - ("forum", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + initial = True + + dependencies = [] operations = [ migrations.CreateModel( name="Post", fields=[ - ("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)), + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("created", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), ("updated", models.DateTimeField(auto_now=True, verbose_name="Update date")), ( - "poster_ip", - models.GenericIPAddressField( - default="2002::0", null=True, verbose_name="Poster IP address", blank=True - ), + "anonymous_key", + models.CharField(blank=True, max_length=100, null=True, verbose_name="Anonymous user forum key"), ), ("subject", models.CharField(max_length=255, verbose_name="Subject")), - ("content", machina.models.fields.MarkupTextField(no_rendered_field=True, verbose_name="Content")), - ("username", models.CharField(max_length=155, null=True, verbose_name="Username", blank=True)), - ("approved", models.BooleanField(default=True, verbose_name="Approved")), ( - "update_reason", - models.CharField(max_length=255, null=True, verbose_name="Update reason", blank=True), + "content", + machina.models.fields.MarkupTextField( + no_rendered_field=True, + validators=[machina.core.validators.MarkupMaxLengthValidator(None)], + verbose_name="Content", + ), ), + ("username", models.CharField(blank=True, max_length=155, null=True, verbose_name="Username")), + ("approved", models.BooleanField(db_index=True, default=True, verbose_name="Approved")), ( - "updates_count", - models.PositiveIntegerField(default=0, verbose_name="Updates count", editable=False, blank=True), + "enable_signature", + models.BooleanField(db_index=True, default=True, verbose_name="Attach a signature"), ), - ("_content_rendered", models.TextField(null=True, editable=False, blank=True)), ( - "poster", - models.ForeignKey( - related_name="posts", - verbose_name="Poster", - blank=True, - to=settings.AUTH_USER_MODEL, - null=True, - on_delete=models.CASCADE, - ), + "update_reason", + models.CharField(blank=True, max_length=255, null=True, verbose_name="Update reason"), + ), + ( + "updates_count", + models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Updates count"), ), + ("_content_rendered", models.TextField(blank=True, editable=False, null=True)), ], options={ - "ordering": ["created"], - "abstract": False, - "get_latest_by": "created", "verbose_name": "Post", "verbose_name_plural": "Posts", + "ordering": ["created"], + "get_latest_by": "created", + "abstract": False, }, ), migrations.CreateModel( name="Topic", fields=[ - ("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)), - ("created", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), - ("updated", models.DateTimeField(auto_now=True, verbose_name="Update date")), + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("subject", models.CharField(max_length=255, verbose_name="Subject")), ("slug", models.SlugField(max_length=255, verbose_name="Slug")), ( "type", models.PositiveSmallIntegerField( + choices=[(0, "Default topic"), (1, "Sticky"), (2, "Announce")], db_index=True, verbose_name="Topic type", - choices=[(0, "Default topic"), (1, "Sticky"), (2, "Announce")], ), ), ( "status", models.PositiveIntegerField( + choices=[(0, "Topic unlocked"), (1, "Topic locked"), (2, "Topic moved")], db_index=True, verbose_name="Topic status", - choices=[(0, "Topic unlocked"), (1, "Topic locked"), (2, "Topic moved")], ), ), - ("approved", models.BooleanField(default=True, verbose_name="Approved")), + ("approved", models.BooleanField(db_index=True, default=True, verbose_name="Approved")), ( "posts_count", - models.PositiveIntegerField(default=0, verbose_name="Posts count", editable=False, blank=True), + models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Posts count"), ), ( "views_count", - models.PositiveIntegerField(default=0, verbose_name="Views count", editable=False, blank=True), + models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Views count"), ), - ("last_post_on", models.DateTimeField(null=True, verbose_name="Last post added on", blank=True)), ( - "forum", - models.ForeignKey( - related_name="topics", verbose_name="Topic forum", to="forum.Forum", on_delete=models.CASCADE - ), - ), - ( - "poster", - models.ForeignKey( - verbose_name="Poster", - blank=True, - to=settings.AUTH_USER_MODEL, - null=True, - on_delete=models.CASCADE, - ), - ), - ( - "subscribers", - models.ManyToManyField( - related_name="subscriptions", - verbose_name="Subscribers", - to=settings.AUTH_USER_MODEL, - blank=True, - ), + "last_post_on", + models.DateTimeField(blank=True, db_index=True, null=True, verbose_name="Last post added on"), ), + ("created", models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="Creation date")), + ("updated", models.DateTimeField(auto_now=True, db_index=True, verbose_name="Update date")), ], options={ - "ordering": ["-type", "-last_post_on"], - "abstract": False, - "get_latest_by": "last_post_on", "verbose_name": "Topic", "verbose_name_plural": "Topics", + "ordering": ["-type", "-last_post_on"], + "get_latest_by": "last_post_on", + "abstract": False, }, ), - migrations.AddField( - model_name="post", - name="topic", - field=models.ForeignKey( - related_name="posts", verbose_name="Topic", to="forum_conversation.Topic", on_delete=models.CASCADE - ), - ), - migrations.AddField( - model_name="post", - name="updated_by", - field=models.ForeignKey( - blank=True, - editable=False, - to=settings.AUTH_USER_MODEL, - null=True, - verbose_name="Lastly updated by", - on_delete=models.SET_NULL, - ), + migrations.CreateModel( + name="Vote", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("rating", models.IntegerField(choices=[(1, "Like"), (-1, "Dislike")])), + ( + "post", + models.ForeignKey( + null=True, on_delete=django.db.models.deletion.CASCADE, to="forum_conversation.post" + ), + ), + ], ), ] diff --git a/src/chigame/forums/forum_conversation/migrations/0002_initial.py b/src/chigame/forums/forum_conversation/migrations/0002_initial.py new file mode 100644 index 000000000..581a01e68 --- /dev/null +++ b/src/chigame/forums/forum_conversation/migrations/0002_initial.py @@ -0,0 +1,132 @@ +# Generated by Django 4.2.20 on 2025-05-23 07:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("forum", "0002_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("forum_conversation", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="vote", + name="poster", + field=models.ForeignKey( + null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="topic", + name="first_post", + field=models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="forum_conversation.post", + verbose_name="First post", + ), + ), + migrations.AddField( + model_name="topic", + name="forum", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="topics", + to="forum.forum", + verbose_name="Topic forum", + ), + ), + migrations.AddField( + model_name="topic", + name="last_post", + field=models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="forum_conversation.post", + verbose_name="Last post", + ), + ), + migrations.AddField( + model_name="topic", + name="poster", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Poster", + ), + ), + migrations.AddField( + model_name="topic", + name="subscribers", + field=models.ManyToManyField( + blank=True, related_name="topic_subscriptions", to=settings.AUTH_USER_MODEL, verbose_name="Subscribers" + ), + ), + migrations.AddField( + model_name="post", + name="poster", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="posts", + to=settings.AUTH_USER_MODEL, + verbose_name="Poster", + ), + ), + migrations.AddField( + model_name="post", + name="ratings", + field=models.ManyToManyField( + blank=True, + editable=False, + related_name="ratings", + through="forum_conversation.Vote", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="post", + name="topic", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="posts", + to="forum_conversation.topic", + verbose_name="Topic", + ), + ), + migrations.AddField( + model_name="post", + name="updated_by", + field=models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + verbose_name="Lastly updated by", + ), + ), + migrations.AddConstraint( + model_name="vote", + constraint=models.UniqueConstraint(fields=("poster", "post"), name="unique_rating"), + ), + migrations.AddIndex( + model_name="topic", + index=models.Index(fields=["type", "last_post_on"], name="forum_conve_type_cc96d0_idx"), + ), + ] diff --git a/src/chigame/forums/forum_conversation/migrations/0002_post_anonymous_key.py b/src/chigame/forums/forum_conversation/migrations/0002_post_anonymous_key.py deleted file mode 100644 index d53cc41c9..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0002_post_anonymous_key.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="post", - name="anonymous_key", - field=models.CharField(max_length=100, null=True, verbose_name="Anonymous user forum key", blank=True), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0003_auto_20160228_2051.py b/src/chigame/forums/forum_conversation/migrations/0003_auto_20160228_2051.py deleted file mode 100644 index f188e30d6..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0003_auto_20160228_2051.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.2 on 2016-02-28 19:51 -from __future__ import unicode_literals - -from django.db import migrations -import machina.core.validators -import machina.models.fields - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0002_post_anonymous_key"), - ] - - operations = [ - migrations.AlterField( - model_name="post", - name="content", - field=machina.models.fields.MarkupTextField( - no_rendered_field=True, - validators=[machina.core.validators.NullableMaxLengthValidator(None)], - verbose_name="Content", - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0004_auto_20160427_0502.py b/src/chigame/forums/forum_conversation/migrations/0004_auto_20160427_0502.py deleted file mode 100644 index 4e071e7ea..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0004_auto_20160427_0502.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.3 on 2016-04-27 03:02 -from __future__ import unicode_literals - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0003_auto_20160228_2051"), - ] - - operations = [ - migrations.AlterField( - model_name="topic", - name="subscribers", - field=models.ManyToManyField( - blank=True, related_name="topic_subscriptions", to=settings.AUTH_USER_MODEL, verbose_name="Subscribers" - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0005_auto_20160607_0455.py b/src/chigame/forums/forum_conversation/migrations/0005_auto_20160607_0455.py deleted file mode 100644 index bda5876ec..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0005_auto_20160607_0455.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.6 on 2016-06-07 02:55 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0004_auto_20160427_0502"), - ] - - operations = [ - migrations.AlterField( - model_name="post", - name="approved", - field=models.BooleanField(db_index=True, default=True, verbose_name="Approved"), - ), - migrations.AlterField( - model_name="topic", - name="approved", - field=models.BooleanField(db_index=True, default=True, verbose_name="Approved"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0006_post_enable_signature.py b/src/chigame/forums/forum_conversation/migrations/0006_post_enable_signature.py deleted file mode 100644 index bfb69c89b..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0006_post_enable_signature.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.7 on 2016-07-09 04:16 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0005_auto_20160607_0455"), - ] - - operations = [ - migrations.AddField( - model_name="post", - name="enable_signature", - field=models.BooleanField(db_index=True, default=True, verbose_name="Attach a signature"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0007_auto_20160903_0450.py b/src/chigame/forums/forum_conversation/migrations/0007_auto_20160903_0450.py deleted file mode 100644 index d0e2226d0..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0007_auto_20160903_0450.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-09-03 02:50 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0006_post_enable_signature"), - ] - - operations = [ - migrations.AddField( - model_name="topic", - name="first_post", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="forum_conversation.Post", - verbose_name="Last post", - ), - ), - migrations.AddField( - model_name="topic", - name="last_post", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="forum_conversation.Post", - verbose_name="Last post", - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0008_auto_20160903_0512.py b/src/chigame/forums/forum_conversation/migrations/0008_auto_20160903_0512.py deleted file mode 100644 index eda19bce2..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0008_auto_20160903_0512.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-09-03 03:12 -from __future__ import unicode_literals - -from django.db import migrations - - -def update_topic_first_post_last_post(apps, schema_editor): - Topic = apps.get_model("forum_conversation", "Topic") - for topic in Topic.objects.all(): - first_post = topic.posts.all().order_by("created").first() - last_post = topic.posts.filter(approved=True).order_by("-created").first() - topic.first_post = first_post - topic.last_post = last_post - topic.save() - - -def reverse_topic_first_post_last_post(apps, schema_editor): - pass - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0007_auto_20160903_0450"), - ] - - operations = [ - migrations.RunPython(update_topic_first_post_last_post, reverse_code=reverse_topic_first_post_last_post), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0009_auto_20160925_2126.py b/src/chigame/forums/forum_conversation/migrations/0009_auto_20160925_2126.py deleted file mode 100644 index 65af347b7..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0009_auto_20160925_2126.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-09-25 19:26 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0008_auto_20160903_0512"), - ] - - operations = [ - migrations.AlterField( - model_name="topic", - name="slug", - field=models.SlugField(max_length=255, verbose_name="Slug"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0010_auto_20170120_0224.py b/src/chigame/forums/forum_conversation/migrations/0010_auto_20170120_0224.py deleted file mode 100644 index 28c975389..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0010_auto_20170120_0224.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-20 01:24 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0009_auto_20160925_2126"), - ] - - operations = [ - migrations.AlterField( - model_name="topic", - name="first_post", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="forum_conversation.Post", - verbose_name="First post", - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0011_remove_post_poster_ip.py b/src/chigame/forums/forum_conversation/migrations/0011_remove_post_poster_ip.py deleted file mode 100644 index c39a8040a..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0011_remove_post_poster_ip.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 2.1.2 on 2018-10-24 02:44 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0010_auto_20170120_0224"), - ] - - operations = [ - migrations.RemoveField( - model_name="post", - name="poster_ip", - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0012_auto_20200423_1049.py b/src/chigame/forums/forum_conversation/migrations/0012_auto_20200423_1049.py deleted file mode 100644 index f3984b18b..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0012_auto_20200423_1049.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.10 on 2020-04-23 15:49 - -from django.db import migrations -import machina.core.validators -import machina.models.fields - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0011_remove_post_poster_ip"), - ] - - operations = [ - migrations.AlterField( - model_name="post", - name="content", - field=machina.models.fields.MarkupTextField( - no_rendered_field=True, - validators=[machina.core.validators.MarkupMaxLengthValidator(None)], - verbose_name="Content", - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0013_auto_20201220_1745.py b/src/chigame/forums/forum_conversation/migrations/0013_auto_20201220_1745.py deleted file mode 100644 index 4c2a333c1..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0013_auto_20201220_1745.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 3.1.2 on 2020-12-20 22:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0012_auto_20200423_1049"), - ] - - operations = [ - migrations.AlterField( - model_name="topic", - name="created", - field=models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="Creation date"), - ), - migrations.AlterField( - model_name="topic", - name="last_post_on", - field=models.DateTimeField(blank=True, db_index=True, null=True, verbose_name="Last post added on"), - ), - migrations.AlterField( - model_name="topic", - name="updated", - field=models.DateTimeField(auto_now=True, db_index=True, verbose_name="Update date"), - ), - migrations.AddIndex( - model_name="topic", - index=models.Index(fields=["type", "last_post_on"], name="forum_conve_type_cc96d0_idx"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0014_alter_post_id_alter_topic_id.py b/src/chigame/forums/forum_conversation/migrations/0014_alter_post_id_alter_topic_id.py deleted file mode 100644 index 64c5c8f57..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0014_alter_post_id_alter_topic_id.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-29 00:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0013_auto_20201220_1745"), - ] - - operations = [ - migrations.AlterField( - model_name="post", - name="id", - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), - ), - migrations.AlterField( - model_name="topic", - name="id", - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0015_post_like_counter.py b/src/chigame/forums/forum_conversation/migrations/0015_post_like_counter.py deleted file mode 100644 index 099a2f588..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0015_post_like_counter.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-29 01:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0014_alter_post_id_alter_topic_id"), - ] - - operations = [ - migrations.AddField( - model_name="post", - name="like_counter", - field=models.IntegerField(blank=True, default=0, verbose_name="Likes"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0016_remove_post_like_counter.py b/src/chigame/forums/forum_conversation/migrations/0016_remove_post_like_counter.py deleted file mode 100644 index d65b4223b..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0016_remove_post_like_counter.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-29 21:16 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0015_post_like_counter"), - ] - - operations = [ - migrations.RemoveField( - model_name="post", - name="like_counter", - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0017_vote.py b/src/chigame/forums/forum_conversation/migrations/0017_vote.py deleted file mode 100644 index 62a9ad426..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0017_vote.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-29 23:04 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0016_remove_post_like_counter"), - ] - - operations = [ - migrations.CreateModel( - name="Vote", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("rating", models.IntegerField(choices=[(1, "Like"), (-1, "Dislike")])), - ], - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0018_post_ratings_vote_post_vote_poster.py b/src/chigame/forums/forum_conversation/migrations/0018_post_ratings_vote_post_vote_poster.py deleted file mode 100644 index 6d3a21e7f..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0018_post_ratings_vote_post_vote_poster.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-30 05:11 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("forum_conversation", "0017_vote"), - ] - - operations = [ - migrations.AddField( - model_name="post", - name="ratings", - field=models.ManyToManyField( - blank=True, - editable=False, - related_name="ratings", - through="forum_conversation.Vote", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="vote", - name="post", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="forum_conversation.post" - ), - ), - migrations.AddField( - model_name="vote", - name="poster", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0019_vote_unique_rating.py b/src/chigame/forums/forum_conversation/migrations/0019_vote_unique_rating.py deleted file mode 100644 index 030594d04..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0019_vote_unique_rating.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-30 08:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("forum_conversation", "0018_post_ratings_vote_post_vote_poster"), - ] - - operations = [ - migrations.AddConstraint( - model_name="vote", - constraint=models.UniqueConstraint(fields=("poster", "post"), name="unique_rating"), - ), - ] diff --git a/src/chigame/games/migrations/0001_initial.py b/src/chigame/games/migrations/0001_initial.py index 5032d6ab8..fe91fa2b7 100644 --- a/src/chigame/games/migrations/0001_initial.py +++ b/src/chigame/games/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 4.2.4 on 2023-11-07 23:01 +# Generated by Django 4.2.20 on 2025-05-23 07:12 +import django.core.validators from django.db import migrations, models import django.db.models.deletion import django.utils.timezone @@ -11,16 +12,144 @@ class Migration(migrations.Migration): dependencies = [] operations = [ + migrations.CreateModel( + name="Announcement", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("content", models.TextField()), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ("sent", models.BooleanField(default=False)), + ( + "type", + models.PositiveIntegerField( + choices=[(2, "REMINDER"), (3, "UPCOMING_MATCH"), (4, "MATCH_PROPOSAL")] + ), + ), + ], + ), + migrations.CreateModel( + name="Category", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255, unique=True)), + ("description", models.TextField(null=True)), + ("image", models.TextField(default="/static/images/no_picture_available.png")), + ], + ), + migrations.CreateModel( + name="Chat", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ], + ), + migrations.CreateModel( + name="Checkers", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("start_time", models.DateTimeField()), + ("end_time", models.DateTimeField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name="CheckersBoard", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("state", models.JSONField()), + ], + ), + migrations.CreateModel( + name="CheckersTurn", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("turn_number", models.PositiveIntegerField()), + ], + ), + migrations.CreateModel( + name="Feedback", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ( + "rating", + models.IntegerField( + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(5), + ] + ), + ), + ("comment", models.TextField(blank=True, null=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ], + ), migrations.CreateModel( name="Game", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("name", models.TextField()), ("description", models.TextField()), + ("year_published", models.IntegerField(blank=True, null=True)), + ("image", models.TextField(default="/static/images/no_picture_available.png")), + ("rules", models.TextField(blank=True, null=True)), ("min_players", models.PositiveIntegerField()), ("max_players", models.PositiveIntegerField()), + ("twine_file_name", models.CharField(blank=True, max_length=255, null=True)), + ("twine_file", models.BinaryField(blank=True, null=True)), + ("suggested_age", models.PositiveSmallIntegerField(blank=True, null=True)), + ("expected_playtime", models.PositiveIntegerField(blank=True, null=True)), + ("min_playtime", models.PositiveIntegerField(blank=True, null=True)), + ("max_playtime", models.PositiveIntegerField(blank=True, null=True)), + ( + "complexity", + models.DecimalField( + decimal_places=2, + max_digits=3, + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ("BGG_id", models.PositiveIntegerField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name="GameData", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("key", models.CharField(max_length=255)), + ("value", models.TextField()), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name="GameList", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), ], ), + migrations.CreateModel( + name="GameQueue", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_at", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="GameQueueEntry", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("position", models.PositiveIntegerField()), + ], + options={ + "ordering": ["position"], + }, + ), migrations.CreateModel( name="Lobby", fields=[ @@ -46,6 +175,7 @@ class Migration(migrations.Migration): name="Match", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("date_played", models.DateTimeField()), ], ), migrations.CreateModel( @@ -56,11 +186,113 @@ class Migration(migrations.Migration): ("min_players", models.PositiveIntegerField()), ], ), + migrations.CreateModel( + name="Mechanic", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255, unique=True)), + ("description", models.TextField(null=True)), + ("image", models.TextField(default="/static/images/no_picture_available.png")), + ], + ), + migrations.CreateModel( + name="Message", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("content", models.TextField(null=True)), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ("token_id", models.PositiveIntegerField(default=None)), + ("update_on", models.PositiveIntegerField(default=None, null=True)), + ], + ), + migrations.CreateModel( + name="Person", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.TextField()), + ("person_role", models.PositiveSmallIntegerField(choices=[(1, "Designer"), (2, "Artist")])), + ], + ), migrations.CreateModel( name="Player", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("match", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.match")), + ("team", models.TextField(blank=True, null=True)), + ("role", models.TextField(blank=True, null=True)), + ( + "outcome", + models.PositiveSmallIntegerField( + blank=True, choices=[(0, "win"), (1, "draw"), (2, "lose"), (3, "withdrawal")], null=True + ), + ), + ("victory_type", models.TextField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name="Publisher", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.TextField()), + ("website", models.URLField(null=True)), + ("year_established", models.PositiveIntegerField(null=True)), + ], + ), + migrations.CreateModel( + name="Review", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("title", models.TextField(blank=True, null=True)), + ("review", models.TextField(blank=True, null=True)), + ( + "rating", + models.DecimalField( + blank=True, + decimal_places=2, + max_digits=3, + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ("is_public", models.BooleanField(default=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name="Tournament", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255)), + ("registration_start_date", models.DateTimeField()), + ("registration_end_date", models.DateTimeField()), + ("tournament_start_date", models.DateTimeField()), + ("tournament_end_date", models.DateTimeField()), + ("max_players", models.PositiveIntegerField()), + ("description", models.TextField()), + ("rules", models.TextField()), + ("draw_rules", models.TextField()), + ("num_winner", models.PositiveIntegerField(default=1)), + ("archived", models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name="InteractiveFictionGame", + fields=[ + ( + "game_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="games.game", + ), + ), + ("content_warning", models.TextField(blank=True, null=True)), ], + bases=("games.game",), ), ] diff --git a/src/chigame/games/migrations/0002_initial.py b/src/chigame/games/migrations/0002_initial.py index 5e0d7bf91..4437f7131 100644 --- a/src/chigame/games/migrations/0002_initial.py +++ b/src/chigame/games/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.4 on 2023-11-07 23:01 +# Generated by Django 4.2.20 on 2025-05-23 07:12 from django.conf import settings from django.db import migrations, models @@ -9,17 +9,87 @@ class Migration(migrations.Migration): initial = True dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("knowledge_base", "0001_initial"), ("games", "0001_initial"), ("users", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ + migrations.AddField( + model_name="tournament", + name="created_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_tournaments", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="tournament", + name="game", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game"), + ), + migrations.AddField( + model_name="tournament", + name="matches", + field=models.ManyToManyField(blank=True, related_name="tournament", to="games.match"), + ), + migrations.AddField( + model_name="tournament", + name="players", + field=models.ManyToManyField(blank=True, related_name="joined_tournaments", to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="tournament", + name="winners", + field=models.ManyToManyField(blank=True, related_name="won_tournaments", to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="review", + name="game", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="reviews", to="games.game" + ), + ), + migrations.AddField( + model_name="review", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="publisher", + name="games", + field=models.ManyToManyField(related_name="publishers", to="games.game"), + ), + migrations.AddField( + model_name="player", + name="match", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.match"), + ), migrations.AddField( model_name="player", name="user", field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), + migrations.AddField( + model_name="person", + name="games", + field=models.ManyToManyField(related_name="people", to="games.game"), + ), + migrations.AddField( + model_name="message", + name="chat", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.chat"), + ), + migrations.AddField( + model_name="message", + name="sender", + field=models.ForeignKey( + null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + ), + ), migrations.AddField( model_name="matchproposal", name="game", @@ -55,11 +125,6 @@ class Migration(migrations.Migration): name="players", field=models.ManyToManyField(through="games.Player", to=settings.AUTH_USER_MODEL), ), - migrations.AddField( - model_name="match", - name="winners", - field=models.ManyToManyField(blank=True, related_name="won_matches", to=settings.AUTH_USER_MODEL), - ), migrations.AddField( model_name="lobby", name="created_by", @@ -75,53 +140,152 @@ class Migration(migrations.Migration): name="members", field=models.ManyToManyField(related_name="lobbies", to=settings.AUTH_USER_MODEL), ), - migrations.CreateModel( - name="Chat", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("match", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.match")), - ], - ), - migrations.CreateModel( - name="Tournament", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.CharField(max_length=255)), - ("start_date", models.DateTimeField()), - ("end_date", models.DateTimeField()), - ("max_players", models.PositiveIntegerField()), - ("description", models.TextField()), - ("rules", models.TextField()), - ("draw_rules", models.TextField()), - ("game", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game")), - ("matches", models.ManyToManyField(related_name="matches", to="games.match")), - ("players", models.ManyToManyField(to=settings.AUTH_USER_MODEL)), - ( - "winners", - models.ManyToManyField(blank=True, related_name="won_tournaments", to=settings.AUTH_USER_MODEL), - ), - ], - ), - migrations.CreateModel( - name="Notification", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("content", models.TextField()), - ("timestamp", models.DateTimeField(auto_now_add=True)), - ("receipients", models.ManyToManyField(related_name="notifications", to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name="Message", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("content", models.TextField()), - ("timestamp", models.DateTimeField(auto_now_add=True)), - ("chat", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.chat")), - ( - "sender", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - ], + migrations.AddField( + model_name="gamequeueentry", + name="game", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game"), + ), + migrations.AddField( + model_name="gamequeueentry", + name="queue", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="entries", to="games.gamequeue" + ), + ), + migrations.AddField( + model_name="gamequeue", + name="user", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, related_name="game_queue", to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="gamelist", + name="created_by", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="game_lists", to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="gamelist", + name="games", + field=models.ManyToManyField(blank=True, related_name="game_lists", to="games.game"), + ), + migrations.AddField( + model_name="gamedata", + name="game", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="game_data", to="games.game" + ), + ), + migrations.AddField( + model_name="gamedata", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="game_data", to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="game", + name="categories", + field=models.ManyToManyField(blank=True, related_name="games", to="games.category"), + ), + migrations.AddField( + model_name="game", + name="mechanics", + field=models.ManyToManyField(blank=True, related_name="games", to="games.mechanic"), + ), + migrations.AddField( + model_name="game", + name="published_guide_id", + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="knowledge_base.guide" + ), + ), + migrations.AddField( + model_name="game", + name="users", + field=models.ManyToManyField(blank=True, related_name="games", to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="feedback", + name="tournament", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="feedback", to="games.tournament" + ), + ), + migrations.AddField( + model_name="feedback", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="checkersturn", + name="board", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.checkersboard"), + ), + migrations.AddField( + model_name="checkersturn", + name="game", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="turns", to="games.checkers" + ), + ), + migrations.AddField( + model_name="checkersturn", + name="player", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.player"), + ), + migrations.AddField( + model_name="checkers", + name="player_1", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.player"), + ), + migrations.AddField( + model_name="checkers", + name="player_2", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="checkers_player_2", + to="games.player", + ), + ), + migrations.AddField( + model_name="checkers", + name="winner", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="checkers_winner", + to="games.player", + ), + ), + migrations.AddField( + model_name="chat", + name="tournament", + field=models.OneToOneField( + default=None, on_delete=django.db.models.deletion.CASCADE, to="games.tournament" + ), + ), + migrations.AddField( + model_name="announcement", + name="recipients", + field=models.ManyToManyField(related_name="announcements", to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="announcement", + name="sender", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name="gamedata", + unique_together={("user", "game", "key")}, + ), + migrations.AlterUniqueTogether( + name="checkersturn", + unique_together={("game", "turn_number")}, ), ] diff --git a/src/chigame/games/migrations/0003_category_mechanic_game_bgg_id_game_complexity_and_more.py b/src/chigame/games/migrations/0003_category_mechanic_game_bgg_id_game_complexity_and_more.py deleted file mode 100644 index a2032821b..000000000 --- a/src/chigame/games/migrations/0003_category_mechanic_game_bgg_id_game_complexity_and_more.py +++ /dev/null @@ -1,102 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-08 16:29 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0002_initial"), - ] - - operations = [ - migrations.CreateModel( - name="Category", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.CharField(max_length=255, unique=True)), - ("description", models.TextField(null=True)), - ], - ), - migrations.CreateModel( - name="Mechanic", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.CharField(max_length=255, unique=True)), - ("description", models.TextField(null=True)), - ], - ), - migrations.AddField( - model_name="game", - name="BGG_id", - field=models.PositiveIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="complexity", - field=models.PositiveSmallIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="expected_playtime", - field=models.PositiveIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="image", - field=models.URLField(default="/static/images/no_picture_available.png"), - ), - migrations.AddField( - model_name="game", - name="max_playtime", - field=models.PositiveIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="min_playtime", - field=models.PositiveIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="rules", - field=models.TextField(null=True), - ), - migrations.AddField( - model_name="game", - name="suggested_age", - field=models.PositiveSmallIntegerField(null=True), - ), - migrations.AddField( - model_name="game", - name="year_published", - field=models.PositiveIntegerField(null=True), - ), - migrations.CreateModel( - name="Publisher", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.TextField()), - ("website", models.URLField(null=True)), - ("year_established", models.PositiveIntegerField(null=True)), - ("games", models.ManyToManyField(related_name="publishers", to="games.game")), - ], - ), - migrations.CreateModel( - name="Person", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.TextField()), - ("person_role", models.PositiveSmallIntegerField(choices=[(1, "Designer"), (2, "Artist")])), - ("games", models.ManyToManyField(related_name="people", to="games.game")), - ], - ), - migrations.AddField( - model_name="game", - name="category", - field=models.ManyToManyField(related_name="games", to="games.category"), - ), - migrations.AddField( - model_name="game", - name="mechanics", - field=models.ManyToManyField(related_name="games", to="games.mechanic"), - ), - ] diff --git a/src/chigame/games/migrations/0004_initial.py b/src/chigame/games/migrations/0004_initial.py deleted file mode 100644 index a6f61abb2..000000000 --- a/src/chigame/games/migrations/0004_initial.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-06 03:56 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0003_category_mechanic_game_bgg_id_game_complexity_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="chat", - name="match", - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to="games.match"), - ), - ] diff --git a/src/chigame/games/migrations/0005_initial.py b/src/chigame/games/migrations/0005_initial.py deleted file mode 100644 index 934ddb6c7..000000000 --- a/src/chigame/games/migrations/0005_initial.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-09 03:41 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0004_initial"), - ] - - operations = [ - migrations.RenameField( - model_name="notification", - old_name="receipients", - new_name="recipients", - ), - migrations.AlterField( - model_name="message", - name="sender", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL - ), - ), - ] diff --git a/src/chigame/games/migrations/0006_Allow_null_fields.py b/src/chigame/games/migrations/0006_Allow_null_fields.py deleted file mode 100644 index 3ebbef473..000000000 --- a/src/chigame/games/migrations/0006_Allow_null_fields.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-10 21:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0005_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="game", - name="BGG_id", - field=models.PositiveIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="category", - field=models.ManyToManyField(blank=True, related_name="games", to="games.category"), - ), - migrations.AlterField( - model_name="game", - name="complexity", - field=models.PositiveSmallIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="expected_playtime", - field=models.PositiveIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="max_playtime", - field=models.PositiveIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="mechanics", - field=models.ManyToManyField(blank=True, related_name="games", to="games.mechanic"), - ), - migrations.AlterField( - model_name="game", - name="min_playtime", - field=models.PositiveIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="suggested_age", - field=models.PositiveSmallIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name="game", - name="year_published", - field=models.PositiveIntegerField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0006_matches_nullable_outcome.py b/src/chigame/games/migrations/0006_matches_nullable_outcome.py deleted file mode 100644 index a838d9062..000000000 --- a/src/chigame/games/migrations/0006_matches_nullable_outcome.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-12 00:10 - -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0005_initial"), - ] - - operations = [ - migrations.RemoveField( - model_name="match", - name="winners", - ), - migrations.AddField( - model_name="match", - name="date_played", - field=models.DateTimeField(default=django.utils.timezone.now), - preserve_default=False, - ), - migrations.AddField( - model_name="player", - name="outcome", - field=models.PositiveSmallIntegerField( - blank=True, choices=[(0, "win"), (1, "draw"), (2, "lose"), (3, "withdrawal")], null=True - ), - ), - migrations.AddField( - model_name="player", - name="role", - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name="player", - name="team", - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name="player", - name="victory_type", - field=models.TextField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0007_image_field_as_text.py b/src/chigame/games/migrations/0007_image_field_as_text.py deleted file mode 100644 index 8d3989ec8..000000000 --- a/src/chigame/games/migrations/0007_image_field_as_text.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-10 21:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0006_Allow_null_fields"), - ] - - operations = [ - migrations.AlterField( - model_name="game", - name="image", - field=models.TextField(default="/static/images/no_picture_available.png"), - ), - migrations.AlterField( - model_name="game", - name="rules", - field=models.TextField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0008_merge_20231113_1632.py b/src/chigame/games/migrations/0008_merge_20231113_1632.py deleted file mode 100644 index 7178fbf1c..000000000 --- a/src/chigame/games/migrations/0008_merge_20231113_1632.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-13 22:32 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0006_matches_nullable_outcome"), - ("games", "0007_image_field_as_text"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0009_announcement_delete_notification.py b/src/chigame/games/migrations/0009_announcement_delete_notification.py deleted file mode 100644 index bb6a8fd22..000000000 --- a/src/chigame/games/migrations/0009_announcement_delete_notification.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-14 07:39 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0008_merge_20231113_1632"), - ] - - operations = [ - migrations.CreateModel( - name="Announcement", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("content", models.TextField()), - ("timestamp", models.DateTimeField(auto_now_add=True)), - ("sent", models.BooleanField(default=False)), - ( - "type", - models.PositiveIntegerField( - choices=[(2, "REMINDER"), (3, "UPCOMING_MATCH"), (4, "MATCH_PROPOSAL")] - ), - ), - ("recipients", models.ManyToManyField(related_name="announcements", to=settings.AUTH_USER_MODEL)), - ( - "sender", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - ], - ), - migrations.DeleteModel( - name="Notification", - ), - ] diff --git a/src/chigame/games/migrations/0010_categories_plural.py b/src/chigame/games/migrations/0010_categories_plural.py deleted file mode 100644 index a7f440669..000000000 --- a/src/chigame/games/migrations/0010_categories_plural.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-14 23:57 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0009_announcement_delete_notification"), - ] - - operations = [ - migrations.RenameField( - model_name="game", - old_name="category", - new_name="categories", - ), - ] diff --git a/src/chigame/games/migrations/0010_rename_category_game_categories_category_image_and_more.py b/src/chigame/games/migrations/0010_rename_category_game_categories_category_image_and_more.py deleted file mode 100644 index d98c889a8..000000000 --- a/src/chigame/games/migrations/0010_rename_category_game_categories_category_image_and_more.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-15 22:03 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0009_announcement_delete_notification"), - ] - - operations = [ - migrations.RenameField( - model_name="game", - old_name="category", - new_name="categories", - ), - migrations.AddField( - model_name="category", - name="image", - field=models.TextField(default="/static/images/no_picture_available.png"), - ), - migrations.AddField( - model_name="mechanic", - name="image", - field=models.TextField(default="/static/images/no_picture_available.png"), - ), - migrations.AlterField( - model_name="game", - name="complexity", - field=models.DecimalField( - decimal_places=2, - max_digits=3, - null=True, - validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)], - ), - ), - ] diff --git a/src/chigame/games/migrations/0011_revert_category_name.py b/src/chigame/games/migrations/0011_revert_category_name.py deleted file mode 100644 index a51e0d9a1..000000000 --- a/src/chigame/games/migrations/0011_revert_category_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-15 00:10 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0010_categories_plural"), - ] - - operations = [ - migrations.RenameField( - model_name="game", - old_name="categories", - new_name="category", - ), - ] diff --git a/src/chigame/games/migrations/0012_merge_20231115_1702.py b/src/chigame/games/migrations/0012_merge_20231115_1702.py deleted file mode 100644 index 2f31c3051..000000000 --- a/src/chigame/games/migrations/0012_merge_20231115_1702.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-15 23:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0010_rename_category_game_categories_category_image_and_more"), - ("games", "0011_revert_category_name"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0012_update_tournaments.py b/src/chigame/games/migrations/0012_update_tournaments.py deleted file mode 100644 index fca74087e..000000000 --- a/src/chigame/games/migrations/0012_update_tournaments.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-13 22:10 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0011_revert_category_name"), - ] - - operations = [ - migrations.AddField( - model_name="tournament", - name="num_winner", - field=models.PositiveIntegerField(default=1), - ), - migrations.AlterField( - model_name="tournament", - name="matches", - field=models.ManyToManyField(blank=True, related_name="matches", to="games.match"), - ), - migrations.AlterField( - model_name="tournament", - name="players", - field=models.ManyToManyField(blank=True, related_name="joined_tournaments", to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/src/chigame/games/migrations/0013_merge_20231116_0044.py b/src/chigame/games/migrations/0013_merge_20231116_0044.py deleted file mode 100644 index 5c7ad5864..000000000 --- a/src/chigame/games/migrations/0013_merge_20231116_0044.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-16 06:44 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0012_merge_20231115_1702"), - ("games", "0012_update_tournaments"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0014_remove_chat_match_chat_tournament_and_more.py b/src/chigame/games/migrations/0014_remove_chat_match_chat_tournament_and_more.py deleted file mode 100644 index f9caafe63..000000000 --- a/src/chigame/games/migrations/0014_remove_chat_match_chat_tournament_and_more.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-24 21:05 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0013_merge_20231116_0044"), - ] - - operations = [ - migrations.RemoveField( - model_name="chat", - name="match", - ), - migrations.AddField( - model_name="chat", - name="tournament", - field=models.OneToOneField( - default=None, on_delete=django.db.models.deletion.CASCADE, to="games.tournament" - ), - ), - migrations.AlterField( - model_name="game", - name="year_published", - field=models.IntegerField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0014_review.py b/src/chigame/games/migrations/0014_review.py deleted file mode 100644 index f3533f2c4..000000000 --- a/src/chigame/games/migrations/0014_review.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-23 07:07 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0013_merge_20231116_0044"), - ] - - operations = [ - migrations.CreateModel( - name="Review", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("review", models.TextField(blank=True, null=True)), - ("rating", models.PositiveSmallIntegerField()), - ("game", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/src/chigame/games/migrations/0015_merge_20231126_1835.py b/src/chigame/games/migrations/0015_merge_20231126_1835.py deleted file mode 100644 index 6ac751424..000000000 --- a/src/chigame/games/migrations/0015_merge_20231126_1835.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-27 00:35 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0014_remove_chat_match_chat_tournament_and_more"), - ("games", "0014_review"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0015_message_token_id_message_update_on_and_more.py b/src/chigame/games/migrations/0015_message_token_id_message_update_on_and_more.py deleted file mode 100644 index e13c9f976..000000000 --- a/src/chigame/games/migrations/0015_message_token_id_message_update_on_and_more.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-25 21:17 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0014_remove_chat_match_chat_tournament_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="message", - name="token_id", - field=models.PositiveIntegerField(default=None), - ), - migrations.AddField( - model_name="message", - name="update_on", - field=models.PositiveIntegerField(default=None, null=True), - ), - migrations.AlterField( - model_name="message", - name="content", - field=models.TextField(null=True), - ), - ] diff --git a/src/chigame/games/migrations/0016_review_is_public_alter_review_rating.py b/src/chigame/games/migrations/0016_review_is_public_alter_review_rating.py deleted file mode 100644 index f2cba8063..000000000 --- a/src/chigame/games/migrations/0016_review_is_public_alter_review_rating.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-27 02:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0015_merge_20231126_1835"), - ] - - operations = [ - migrations.AddField( - model_name="review", - name="is_public", - field=models.BooleanField(default=True), - ), - migrations.AlterField( - model_name="review", - name="rating", - field=models.PositiveSmallIntegerField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0016_update_tournaments_2.py b/src/chigame/games/migrations/0016_update_tournaments_2.py deleted file mode 100644 index 6963d3ca7..000000000 --- a/src/chigame/games/migrations/0016_update_tournaments_2.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-17 01:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0015_message_token_id_message_update_on_and_more"), - ] - - operations = [ - migrations.RenameField( - model_name="tournament", - old_name="end_date", - new_name="tournament_end_date", - ), - migrations.RenameField( - model_name="tournament", - old_name="start_date", - new_name="tournament_start_date", - ), - migrations.AddField( - model_name="tournament", - name="archived", - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name="tournament", - name="registration_end_date", - field=models.DateTimeField(), - ), - migrations.AddField( - model_name="tournament", - name="registration_start_date", - field=models.DateTimeField(), - ), - ] diff --git a/src/chigame/games/migrations/0017_merge_20231127_2228.py b/src/chigame/games/migrations/0017_merge_20231127_2228.py deleted file mode 100644 index 3a36e4e5c..000000000 --- a/src/chigame/games/migrations/0017_merge_20231127_2228.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-28 04:28 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0015_message_token_id_message_update_on_and_more"), - ("games", "0016_review_is_public_alter_review_rating"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0018_review_created_at_review_title.py b/src/chigame/games/migrations/0018_review_created_at_review_title.py deleted file mode 100644 index 14165e4c6..000000000 --- a/src/chigame/games/migrations/0018_review_created_at_review_title.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-28 04:50 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0017_merge_20231127_2228"), - ] - - operations = [ - migrations.AddField( - model_name="review", - name="created_at", - field=models.DateTimeField( - auto_now_add=True, - default=datetime.datetime(2023, 11, 28, 4, 50, 25, 750080, tzinfo=datetime.timezone.utc), - ), - preserve_default=False, - ), - migrations.AddField( - model_name="review", - name="title", - field=models.TextField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0019_alter_review_rating.py b/src/chigame/games/migrations/0019_alter_review_rating.py deleted file mode 100644 index b6189afa9..000000000 --- a/src/chigame/games/migrations/0019_alter_review_rating.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-30 11:44 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0018_review_created_at_review_title"), - ] - - operations = [ - migrations.AlterField( - model_name="review", - name="rating", - field=models.DecimalField( - blank=True, - decimal_places=2, - max_digits=3, - null=True, - validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)], - ), - ), - ] diff --git a/src/chigame/games/migrations/0020_merge_20231204_1517.py b/src/chigame/games/migrations/0020_merge_20231204_1517.py deleted file mode 100644 index 0fd538a38..000000000 --- a/src/chigame/games/migrations/0020_merge_20231204_1517.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-12-04 21:17 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0016_update_tournaments_2"), - ("games", "0019_alter_review_rating"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0021_alter_tournament_matches.py b/src/chigame/games/migrations/0021_alter_tournament_matches.py deleted file mode 100644 index 3dd4d57c6..000000000 --- a/src/chigame/games/migrations/0021_alter_tournament_matches.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-12-05 02:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0020_merge_20231204_1517"), - ] - - operations = [ - migrations.AlterField( - model_name="tournament", - name="matches", - field=models.ManyToManyField(blank=True, related_name="tournament", to="games.match"), - ), - ] diff --git a/src/chigame/games/migrations/0022_tournament_created_by.py b/src/chigame/games/migrations/0022_tournament_created_by.py deleted file mode 100644 index 2bd35dfcc..000000000 --- a/src/chigame/games/migrations/0022_tournament_created_by.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.4 on 2023-12-06 01:16 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0021_alter_tournament_matches"), - ] - - operations = [ - migrations.AddField( - model_name="tournament", - name="created_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="created_tournaments", - to=settings.AUTH_USER_MODEL, - ), - ), - ] diff --git a/src/chigame/games/migrations/0023_feedback.py b/src/chigame/games/migrations/0023_feedback.py deleted file mode 100644 index 202ec52ef..000000000 --- a/src/chigame/games/migrations/0023_feedback.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-27 04:46 - -from django.conf import settings -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0022_tournament_created_by"), - ] - - operations = [ - migrations.CreateModel( - name="Feedback", - fields=[ - ("id", models.AutoField(primary_key=True, serialize=False)), - ( - "rating", - models.IntegerField( - validators=[ - django.core.validators.MinValueValidator(1), - django.core.validators.MaxValueValidator(5), - ] - ), - ), - ("comment", models.TextField(blank=True, null=True)), - ("created_at", models.DateTimeField(auto_now_add=True)), - ( - "tournament", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="feedback", to="games.tournament" - ), - ), - ( - "user", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - ] diff --git a/src/chigame/games/migrations/0023_game_published_guide_id.py b/src/chigame/games/migrations/0023_game_published_guide_id.py deleted file mode 100644 index b3b21dbd0..000000000 --- a/src/chigame/games/migrations/0023_game_published_guide_id.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-27 17:24 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0001_initial"), - ("games", "0022_tournament_created_by"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="published_guide_id", - field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="knowledge_base.guide" - ), - ), - ] diff --git a/src/chigame/games/migrations/0023_gamelist.py b/src/chigame/games/migrations/0023_gamelist.py deleted file mode 100644 index eac9ea801..000000000 --- a/src/chigame/games/migrations/0023_gamelist.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-28 01:57 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0022_tournament_created_by"), - ] - - operations = [ - migrations.CreateModel( - name="GameList", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.CharField(max_length=255)), - ("description", models.TextField(blank=True)), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "created_by", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="game_lists", - to=settings.AUTH_USER_MODEL, - ), - ), - ("games", models.ManyToManyField(blank=True, related_name="game_lists", to="games.game")), - ], - ), - ] diff --git a/src/chigame/games/migrations/0023_livechat_livechatuser_livechatmessage.py b/src/chigame/games/migrations/0023_livechat_livechatuser_livechatmessage.py deleted file mode 100644 index 7f3bc47f3..000000000 --- a/src/chigame/games/migrations/0023_livechat_livechatuser_livechatmessage.py +++ /dev/null @@ -1,82 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-23 04:10 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0022_tournament_created_by"), - ] - - operations = [ - migrations.CreateModel( - name="LiveChat", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("channel", models.TextField()), - ], - ), - migrations.CreateModel( - name="LiveChatUser", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "live_chat_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.livechat"), - ), - ( - "user_id", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - migrations.CreateModel( - name="LiveChatMessage", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("sent_at", models.DateTimeField(auto_now_add=True)), - ("message_content", models.TextField()), - ( - "live_chat_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.livechat"), - ), - ( - "user_id", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - ] diff --git a/src/chigame/games/migrations/0024_merge_20250428_1822.py b/src/chigame/games/migrations/0024_merge_20250428_1822.py deleted file mode 100644 index 0520952d1..000000000 --- a/src/chigame/games/migrations/0024_merge_20250428_1822.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-28 23:22 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0023_game_published_guide_id"), - ("games", "0023_livechat_livechatuser_livechatmessage"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0024_merge_20250428_2051.py b/src/chigame/games/migrations/0024_merge_20250428_2051.py deleted file mode 100644 index d87f64ee6..000000000 --- a/src/chigame/games/migrations/0024_merge_20250428_2051.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-29 01:51 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0023_gamelist"), - ("games", "0023_livechat_livechatuser_livechatmessage"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0024_merge_20250428_2111.py b/src/chigame/games/migrations/0024_merge_20250428_2111.py deleted file mode 100644 index bdf4899f8..000000000 --- a/src/chigame/games/migrations/0024_merge_20250428_2111.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-29 02:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0023_gamelist"), - ("games", "0023_livechat_livechatuser_livechatmessage"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0025_alter_livechat_channel.py b/src/chigame/games/migrations/0025_alter_livechat_channel.py deleted file mode 100644 index 9fac11415..000000000 --- a/src/chigame/games/migrations/0025_alter_livechat_channel.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-28 23:25 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0024_merge_20250428_1822"), - ] - - operations = [ - migrations.AlterField( - model_name="livechat", - name="channel", - field=models.TextField(unique=True), - ), - ] diff --git a/src/chigame/games/migrations/0026_merge_20250430_1102.py b/src/chigame/games/migrations/0026_merge_20250430_1102.py deleted file mode 100644 index 1d2bf41c1..000000000 --- a/src/chigame/games/migrations/0026_merge_20250430_1102.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-30 16:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0024_merge_20250428_2111"), - ("games", "0025_alter_livechat_channel"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0026_merge_20250430_1104.py b/src/chigame/games/migrations/0026_merge_20250430_1104.py deleted file mode 100644 index 9f4346cd6..000000000 --- a/src/chigame/games/migrations/0026_merge_20250430_1104.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-30 16:04 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0024_merge_20250428_2051"), - ("games", "0025_alter_livechat_channel"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0027_merge_20250430_1134.py b/src/chigame/games/migrations/0027_merge_20250430_1134.py deleted file mode 100644 index c3fb568fd..000000000 --- a/src/chigame/games/migrations/0027_merge_20250430_1134.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-30 16:34 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0026_merge_20250430_1102"), - ("games", "0026_merge_20250430_1104"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0028_game_users.py b/src/chigame/games/migrations/0028_game_users.py deleted file mode 100644 index ef51f1d25..000000000 --- a/src/chigame/games/migrations/0028_game_users.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-05 20:58 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0027_merge_20250430_1134"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="users", - field=models.ManyToManyField(blank=True, related_name="games", to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/src/chigame/games/migrations/0028_merge_0023_feedback_0027_merge_20250430_1134.py b/src/chigame/games/migrations/0028_merge_0023_feedback_0027_merge_20250430_1134.py deleted file mode 100644 index 11651d8c4..000000000 --- a/src/chigame/games/migrations/0028_merge_0023_feedback_0027_merge_20250430_1134.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-02 20:50 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0023_feedback"), - ("games", "0027_merge_20250430_1134"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0028_remove_livechatmessage_live_chat_id_and_more.py b/src/chigame/games/migrations/0028_remove_livechatmessage_live_chat_id_and_more.py deleted file mode 100644 index b729e25a9..000000000 --- a/src/chigame/games/migrations/0028_remove_livechatmessage_live_chat_id_and_more.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-01 04:54 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0027_merge_20250430_1134"), - ] - - operations = [ - migrations.RemoveField( - model_name="livechatmessage", - name="live_chat_id", - ), - migrations.RemoveField( - model_name="livechatmessage", - name="user_id", - ), - migrations.RemoveField( - model_name="livechatuser", - name="live_chat_id", - ), - migrations.RemoveField( - model_name="livechatuser", - name="user_id", - ), - migrations.DeleteModel( - name="LiveChat", - ), - migrations.DeleteModel( - name="LiveChatMessage", - ), - migrations.DeleteModel( - name="LiveChatUser", - ), - ] diff --git a/src/chigame/games/migrations/0029_alter_review_game.py b/src/chigame/games/migrations/0029_alter_review_game.py deleted file mode 100644 index 6d0fbc349..000000000 --- a/src/chigame/games/migrations/0029_alter_review_game.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 22:44 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="review", - name="game", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="reviews", to="games.game" - ), - ), - ] diff --git a/src/chigame/games/migrations/0029_game_twine_file.py b/src/chigame/games/migrations/0029_game_twine_file.py deleted file mode 100644 index a4392468b..000000000 --- a/src/chigame/games/migrations/0029_game_twine_file.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 18:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="twine_file", - field=models.FileField(blank=True, null=True, upload_to="twine_games/"), - ), - ] diff --git a/src/chigame/games/migrations/0029_gamequeue_alter_review_game_gamequeueentry.py b/src/chigame/games/migrations/0029_gamequeue_alter_review_game_gamequeueentry.py deleted file mode 100644 index e186f3e3f..000000000 --- a/src/chigame/games/migrations/0029_gamequeue_alter_review_game_gamequeueentry.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 15:30 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="GameQueue", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("created_at", models.DateTimeField(auto_now_add=True)), - ( - "user", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="game_queue", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - ), - migrations.AlterField( - model_name="review", - name="game", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="reviews", to="games.game" - ), - ), - migrations.CreateModel( - name="GameQueueEntry", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("position", models.PositiveIntegerField()), - ("game", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game")), - ( - "queue", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="entries", to="games.gamequeue" - ), - ), - ], - options={ - "ordering": ["position"], - }, - ), - ] diff --git a/src/chigame/games/migrations/0029_interactivefictiongame.py b/src/chigame/games/migrations/0029_interactivefictiongame.py deleted file mode 100644 index 24d32f75d..000000000 --- a/src/chigame/games/migrations/0029_interactivefictiongame.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 22:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="InteractiveFictionGame", - fields=[ - ( - "game_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="games.game", - ), - ), - ("content_warning", models.TextField(blank=True, null=True)), - ], - bases=("games.game",), - ), - ] diff --git a/src/chigame/games/migrations/0029_merge_20250505_2335.py b/src/chigame/games/migrations/0029_merge_20250505_2335.py deleted file mode 100644 index 19336bc06..000000000 --- a/src/chigame/games/migrations/0029_merge_20250505_2335.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-06 04:35 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_merge_0023_feedback_0027_merge_20250430_1134"), - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0029_merge_20250507_1534.py b/src/chigame/games/migrations/0029_merge_20250507_1534.py deleted file mode 100644 index bf24d7837..000000000 --- a/src/chigame/games/migrations/0029_merge_20250507_1534.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-07 20:34 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0028_game_users"), - ("games", "0028_remove_livechatmessage_live_chat_id_and_more"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0030_merge_0029_alter_review_game_0029_merge_20250507_1534.py b/src/chigame/games/migrations/0030_merge_0029_alter_review_game_0029_merge_20250507_1534.py deleted file mode 100644 index ea5a83b7b..000000000 --- a/src/chigame/games/migrations/0030_merge_0029_alter_review_game_0029_merge_20250507_1534.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 19:53 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_alter_review_game"), - ("games", "0029_merge_20250507_1534"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0030_merge_20250512_1728.py b/src/chigame/games/migrations/0030_merge_20250512_1728.py deleted file mode 100644 index 2ee1b5309..000000000 --- a/src/chigame/games/migrations/0030_merge_20250512_1728.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 22:28 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_merge_20250505_2335"), - ("games", "0029_merge_20250507_1534"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0030_remove_game_twine_file.py b/src/chigame/games/migrations/0030_remove_game_twine_file.py deleted file mode 100644 index c7a274cfa..000000000 --- a/src/chigame/games/migrations/0030_remove_game_twine_file.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 20:16 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_game_twine_file"), - ] - - operations = [ - migrations.RemoveField( - model_name="game", - name="twine_file", - ), - ] diff --git a/src/chigame/games/migrations/0031_alter_feedback_user_alter_review_game.py b/src/chigame/games/migrations/0031_alter_feedback_user_alter_review_game.py deleted file mode 100644 index f7e73888a..000000000 --- a/src/chigame/games/migrations/0031_alter_feedback_user_alter_review_game.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-13 19:25 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0030_merge_20250512_1728"), - ] - - operations = [ - migrations.AlterField( - model_name="feedback", - name="user", - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name="review", - name="game", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="reviews", - to="games.game", - ), - ), - ] diff --git a/src/chigame/games/migrations/0031_game_twine_file.py b/src/chigame/games/migrations/0031_game_twine_file.py deleted file mode 100644 index 2b87f9774..000000000 --- a/src/chigame/games/migrations/0031_game_twine_file.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 20:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0030_remove_game_twine_file"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="twine_file", - field=models.FileField(blank=True, null=True, upload_to="twine_games/"), - ), - ] diff --git a/src/chigame/games/migrations/0032_alter_review_game.py b/src/chigame/games/migrations/0032_alter_review_game.py deleted file mode 100644 index 76b9dfeba..000000000 --- a/src/chigame/games/migrations/0032_alter_review_game.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 19:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0031_game_twine_file"), - ] - - operations = [ - migrations.AlterField( - model_name="review", - name="game", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="reviews", to="games.game" - ), - ), - ] diff --git a/src/chigame/games/migrations/0033_merge_0029_merge_20250507_1534_0032_alter_review_game.py b/src/chigame/games/migrations/0033_merge_0029_merge_20250507_1534_0032_alter_review_game.py deleted file mode 100644 index 838d75407..000000000 --- a/src/chigame/games/migrations/0033_merge_0029_merge_20250507_1534_0032_alter_review_game.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 19:37 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_merge_20250507_1534"), - ("games", "0032_alter_review_game"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0034_merge_20250512_1731.py b/src/chigame/games/migrations/0034_merge_20250512_1731.py deleted file mode 100644 index 334fee84f..000000000 --- a/src/chigame/games/migrations/0034_merge_20250512_1731.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 22:31 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0030_merge_20250512_1728"), - ("games", "0033_merge_0029_merge_20250507_1534_0032_alter_review_game"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0035_merge_20250512_2236.py b/src/chigame/games/migrations/0035_merge_20250512_2236.py deleted file mode 100644 index ee584efd5..000000000 --- a/src/chigame/games/migrations/0035_merge_20250512_2236.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-13 03:36 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0030_merge_0029_alter_review_game_0029_merge_20250507_1534"), - ("games", "0034_merge_20250512_1731"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0035_merge_20250513_1435.py b/src/chigame/games/migrations/0035_merge_20250513_1435.py deleted file mode 100644 index f7f77dd0e..000000000 --- a/src/chigame/games/migrations/0035_merge_20250513_1435.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-13 19:35 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_interactivefictiongame"), - ("games", "0031_alter_feedback_user_alter_review_game"), - ("games", "0034_merge_20250512_1731"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0036_checkers_checkersboard_checkersturn.py b/src/chigame/games/migrations/0036_checkers_checkersboard_checkersturn.py deleted file mode 100644 index 19a7d3417..000000000 --- a/src/chigame/games/migrations/0036_checkers_checkersboard_checkersturn.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-16 20:47 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0035_merge_20250513_1435"), - ] - - operations = [ - migrations.CreateModel( - name="Checkers", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("start_time", models.DateTimeField()), - ("end_time", models.DateTimeField(blank=True, null=True)), - ("player_1", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.player")), - ( - "player_2", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="checkers_player_2", - to="games.player", - ), - ), - ( - "winner", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="checkers_winner", - to="games.player", - ), - ), - ], - ), - migrations.CreateModel( - name="CheckersBoard", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("state", models.JSONField()), - ], - ), - migrations.CreateModel( - name="CheckersTurn", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("turn_number", models.PositiveIntegerField()), - ("board", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.checkersboard")), - ( - "game", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="turns", to="games.checkers" - ), - ), - ("player", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.player")), - ], - options={ - "unique_together": {("game", "turn_number")}, - }, - ), - ] diff --git a/src/chigame/games/migrations/0036_merge_20250514_2202.py b/src/chigame/games/migrations/0036_merge_20250514_2202.py deleted file mode 100644 index 1441cda6d..000000000 --- a/src/chigame/games/migrations/0036_merge_20250514_2202.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-15 03:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0035_merge_20250512_2236"), - ("games", "0035_merge_20250513_1435"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0036_merge_20250514_2211.py b/src/chigame/games/migrations/0036_merge_20250514_2211.py deleted file mode 100644 index 28d32ef80..000000000 --- a/src/chigame/games/migrations/0036_merge_20250514_2211.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-15 03:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0035_merge_20250512_2236"), - ("games", "0035_merge_20250513_1435"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0036_wordgamedata.py b/src/chigame/games/migrations/0036_wordgamedata.py deleted file mode 100644 index a351876d1..000000000 --- a/src/chigame/games/migrations/0036_wordgamedata.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-16 22:30 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0035_merge_20250513_1435"), - ] - - operations = [ - migrations.CreateModel( - name="WordGameData", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("key", models.CharField(max_length=255)), - ("value", models.TextField()), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="word_game_data", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "unique_together": {("user", "key")}, - }, - ), - ] diff --git a/src/chigame/games/migrations/0037_gamedata_delete_wordgamedata.py b/src/chigame/games/migrations/0037_gamedata_delete_wordgamedata.py deleted file mode 100644 index 0a67e18ed..000000000 --- a/src/chigame/games/migrations/0037_gamedata_delete_wordgamedata.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-17 22:11 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0036_wordgamedata"), - ] - - operations = [ - migrations.CreateModel( - name="GameData", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("key", models.CharField(max_length=255)), - ("value", models.TextField()), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "game", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="game_data", to="games.game" - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="game_data", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "unique_together": {("user", "game", "key")}, - }, - ), - migrations.DeleteModel( - name="WordGameData", - ), - ] diff --git a/src/chigame/games/migrations/0037_merge_20250518_2303.py b/src/chigame/games/migrations/0037_merge_20250518_2303.py deleted file mode 100644 index 8fd6de921..000000000 --- a/src/chigame/games/migrations/0037_merge_20250518_2303.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 04:03 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0036_checkers_checkersboard_checkersturn"), - ("games", "0036_merge_20250514_2211"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0038_merge_20250519_0011.py b/src/chigame/games/migrations/0038_merge_20250519_0011.py deleted file mode 100644 index a4abcffe3..000000000 --- a/src/chigame/games/migrations/0038_merge_20250519_0011.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 05:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0036_merge_20250514_2202"), - ("games", "0037_merge_20250518_2303"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py b/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py deleted file mode 100644 index ca0c88ab8..000000000 --- a/src/chigame/games/migrations/0039_game_twine_file_content_game_twine_file_name.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.1.7 on 2025-05-21 00:36 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0038_merge_20250519_0011"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="twine_file_content", - field=models.BinaryField(blank=True, null=True), - ), - migrations.AddField( - model_name="game", - name="twine_file_name", - field=models.CharField(blank=True, max_length=255, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0039_merge_20250519_0030.py b/src/chigame/games/migrations/0039_merge_20250519_0030.py deleted file mode 100644 index 3729479ce..000000000 --- a/src/chigame/games/migrations/0039_merge_20250519_0030.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 05:30 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0037_gamedata_delete_wordgamedata"), - ("games", "0038_merge_20250519_0011"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0039_merge_20250520_1918.py b/src/chigame/games/migrations/0039_merge_20250520_1918.py deleted file mode 100644 index b02f624c1..000000000 --- a/src/chigame/games/migrations/0039_merge_20250520_1918.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 00:18 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0037_gamedata_delete_wordgamedata"), - ("games", "0038_merge_20250519_0011"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0040_merge_20250520_2114.py b/src/chigame/games/migrations/0040_merge_20250520_2114.py deleted file mode 100644 index f4e2d0139..000000000 --- a/src/chigame/games/migrations/0040_merge_20250520_2114.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 02:14 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0039_merge_20250519_0030"), - ("games", "0039_merge_20250520_1918"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0040_merge_20250521_1413.py b/src/chigame/games/migrations/0040_merge_20250521_1413.py deleted file mode 100644 index 9fe327f4d..000000000 --- a/src/chigame/games/migrations/0040_merge_20250521_1413.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 19:13 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0029_gamequeue_alter_review_game_gamequeueentry"), - ("games", "0039_merge_20250519_0030"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py b/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py deleted file mode 100644 index dd19d4434..000000000 --- a/src/chigame/games/migrations/0040_remove_game_twine_file_content_alter_game_twine_file.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.1.7 on 2025-05-21 01:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0039_game_twine_file_content_game_twine_file_name"), - ] - - operations = [ - migrations.RemoveField( - model_name="game", - name="twine_file_content", - ), - migrations.AlterField( - model_name="game", - name="twine_file", - field=models.BinaryField(blank=True, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0041_merge_20250521_2013.py b/src/chigame/games/migrations/0041_merge_20250521_2013.py deleted file mode 100644 index 9986fe455..000000000 --- a/src/chigame/games/migrations/0041_merge_20250521_2013.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-22 01:13 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("games", "0040_merge_20250520_2114"), - ("games", "0040_merge_20250521_1413"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py b/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py deleted file mode 100644 index 78fa198db..000000000 --- a/src/chigame/games/migrations/0041_rename_twine_file_game_twine_file_content.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 04:17 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0040_remove_game_twine_file_content_alter_game_twine_file"), - ] - - operations = [ - migrations.RenameField( - model_name="game", - old_name="twine_file", - new_name="twine_file_content", - ), - ] diff --git a/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py b/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py deleted file mode 100644 index 9b57f0107..000000000 --- a/src/chigame/games/migrations/0042_rename_twine_file_content_game_twine_file.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 04:26 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0041_rename_twine_file_game_twine_file_content"), - ] - - operations = [ - migrations.RenameField( - model_name="game", - old_name="twine_file_content", - new_name="twine_file", - ), - ] diff --git a/src/chigame/games/migrations/0043_remove_game_twine_file_name.py b/src/chigame/games/migrations/0043_remove_game_twine_file_name.py deleted file mode 100644 index 96a42524e..000000000 --- a/src/chigame/games/migrations/0043_remove_game_twine_file_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 05:05 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0042_rename_twine_file_content_game_twine_file"), - ] - - operations = [ - migrations.RemoveField( - model_name="game", - name="twine_file_name", - ), - ] diff --git a/src/chigame/games/migrations/0044_game_twine_file_name.py b/src/chigame/games/migrations/0044_game_twine_file_name.py deleted file mode 100644 index bbfd007e7..000000000 --- a/src/chigame/games/migrations/0044_game_twine_file_name.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 05:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0043_remove_game_twine_file_name"), - ] - - operations = [ - migrations.AddField( - model_name="game", - name="twine_file_name", - field=models.CharField(blank=True, max_length=255, null=True), - ), - ] diff --git a/src/chigame/games/migrations/0045_merge_20250521_1434.py b/src/chigame/games/migrations/0045_merge_20250521_1434.py deleted file mode 100644 index 41b1a0c41..000000000 --- a/src/chigame/games/migrations/0045_merge_20250521_1434.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 19:34 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0040_merge_20250521_1413"), - ("games", "0044_game_twine_file_name"), - ] - - operations = [] diff --git a/src/chigame/games/migrations/0046_auto_20250521_1607.py b/src/chigame/games/migrations/0046_auto_20250521_1607.py deleted file mode 100644 index 4725c9fe5..000000000 --- a/src/chigame/games/migrations/0046_auto_20250521_1607.py +++ /dev/null @@ -1,38 +0,0 @@ -import sys -import os -import base64 -from django.db import migrations - -def insert_twine_game(apps, schema_editor): - # Skip during tests or if the file is missing - if "test" in sys.argv or os.environ.get("CI") == "true": - return - - Game = apps.get_model("games", "Game") - file_path = "src/chigame/games/migrations/twine_b64.txt" - - if not os.path.exists(file_path): - print(f"Skipping migration: file not found at {file_path}") - return - - with open(file_path, "rb") as f: - html_bytes = base64.b64decode(f.read()) - - Game.objects.create( - name="Twine Test Game", - description="Uploaded via migration", - twine_file=html_bytes, - min_players=1, - max_players=1, - complexity=1, - ) - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0045_merge_20250521_1434"), - ] - - operations = [ - migrations.RunPython(insert_twine_game, atomic=False), - ] diff --git a/src/chigame/games/migrations/0047_merge_20250523_0202.py b/src/chigame/games/migrations/0047_merge_20250523_0202.py deleted file mode 100644 index 290f782b1..000000000 --- a/src/chigame/games/migrations/0047_merge_20250523_0202.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-23 07:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("games", "0041_merge_20250521_2013"), - ("games", "0046_auto_20250521_1607"), - ] - - operations = [] diff --git a/src/chigame/knowledge_base/migrations/0001_initial.py b/src/chigame/knowledge_base/migrations/0001_initial.py index 030ab76f8..791de7a78 100644 --- a/src/chigame/knowledge_base/migrations/0001_initial.py +++ b/src/chigame/knowledge_base/migrations/0001_initial.py @@ -1,6 +1,5 @@ -# Generated by Django 4.2.20 on 2025-04-27 17:24 +# Generated by Django 4.2.20 on 2025-05-23 07:12 -from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -8,12 +7,22 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("games", "0022_tournament_created_by"), - ] + dependencies = [] operations = [ + migrations.CreateModel( + name="GeneralFeedback", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("feedback", models.TextField(verbose_name="Feedback")), + ("created_at", models.DateTimeField(auto_now_add=True, verbose_name="Created at")), + ], + options={ + "verbose_name": "General Feedback", + "verbose_name_plural": "General Feedback", + "ordering": ["-created_at"], + }, + ), migrations.CreateModel( name="Guide", fields=[ @@ -26,12 +35,6 @@ class Migration(migrations.Migration): choices=[(0, "Pending"), (1, "Accepted"), (2, "Rejected"), (3, "Requested Change")], default=0 ), ), - ("n_likes", models.IntegerField(default=0)), - ( - "author", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - ("game_id", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game")), ], ), migrations.CreateModel( @@ -41,48 +44,15 @@ class Migration(migrations.Migration): ("comment", models.TextField(blank=True, null=True)), ("status", models.IntegerField(choices=[(1, "Accepted"), (2, "Rejected"), (3, "Requested Change")])), ("timestamp", models.DateTimeField(auto_now_add=True)), + ("seen", models.BooleanField(default=False)), ( "guide_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="knowledge_base.guide"), - ), - ( - "reviewer", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - ], - ), - migrations.CreateModel( - name="Like", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ( - "guide_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="knowledge_base.guide"), - ), - ( - "user_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - ], - options={ - "unique_together": {("user_id", "guide_id")}, - }, - ), - migrations.CreateModel( - name="Favorite", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ( - "guide_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="knowledge_base.guide"), - ), - ( - "user_id", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="feedbacks", + to="knowledge_base.guide", + ), ), ], - options={ - "unique_together": {("user_id", "guide_id")}, - }, ), ] diff --git a/src/chigame/knowledge_base/migrations/0002_alter_like_unique_together_remove_like_guide_id_and_more.py b/src/chigame/knowledge_base/migrations/0002_alter_like_unique_together_remove_like_guide_id_and_more.py deleted file mode 100644 index 574b56898..000000000 --- a/src/chigame/knowledge_base/migrations/0002_alter_like_unique_together_remove_like_guide_id_and_more.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-27 18:19 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("knowledge_base", "0001_initial"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="like", - unique_together=None, - ), - migrations.RemoveField( - model_name="like", - name="guide_id", - ), - migrations.RemoveField( - model_name="like", - name="user_id", - ), - migrations.RemoveField( - model_name="guide", - name="n_likes", - ), - migrations.AddField( - model_name="guide", - name="favorites", - field=models.ManyToManyField(related_name="favorite_guides", to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name="guide", - name="likes", - field=models.ManyToManyField(related_name="liked_guides", to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name="guide", - name="author", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="authored_guides", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.DeleteModel( - name="Favorite", - ), - migrations.DeleteModel( - name="Like", - ), - ] diff --git a/src/chigame/knowledge_base/migrations/0003_alter_guide_favorites_alter_guide_likes_and_more.py b/src/chigame/knowledge_base/migrations/0002_initial.py similarity index 55% rename from src/chigame/knowledge_base/migrations/0003_alter_guide_favorites_alter_guide_likes_and_more.py rename to src/chigame/knowledge_base/migrations/0002_initial.py index 013534dd2..3829a13c4 100644 --- a/src/chigame/knowledge_base/migrations/0003_alter_guide_favorites_alter_guide_likes_and_more.py +++ b/src/chigame/knowledge_base/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.20 on 2025-05-06 02:59 +# Generated by Django 4.2.20 on 2025-05-23 07:12 from django.conf import settings from django.db import migrations, models @@ -6,23 +6,16 @@ class Migration(migrations.Migration): + initial = True + dependencies = [ + ("games", "0002_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("knowledge_base", "0002_alter_like_unique_together_remove_like_guide_id_and_more"), + ("knowledge_base", "0001_initial"), ] operations = [ - migrations.AlterField( - model_name="guide", - name="favorites", - field=models.ManyToManyField(blank=True, related_name="favorite_guides", to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name="guide", - name="likes", - field=models.ManyToManyField(blank=True, related_name="liked_guides", to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( + migrations.AddField( model_name="reviewfeedback", name="reviewer", field=models.ForeignKey( @@ -31,4 +24,28 @@ class Migration(migrations.Migration): to=settings.AUTH_USER_MODEL, ), ), + migrations.AddField( + model_name="guide", + name="author", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="authored_guides", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="guide", + name="favorites", + field=models.ManyToManyField(blank=True, related_name="favorite_guides", to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name="guide", + name="game_id", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="games.game"), + ), + migrations.AddField( + model_name="guide", + name="likes", + field=models.ManyToManyField(blank=True, related_name="liked_guides", to=settings.AUTH_USER_MODEL), + ), ] diff --git a/src/chigame/knowledge_base/migrations/0004_alter_reviewfeedback_guide_id.py b/src/chigame/knowledge_base/migrations/0004_alter_reviewfeedback_guide_id.py deleted file mode 100644 index c6886f170..000000000 --- a/src/chigame/knowledge_base/migrations/0004_alter_reviewfeedback_guide_id.py +++ /dev/null @@ -1,19 +0,0 @@ - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0003_alter_guide_favorites_alter_guide_likes_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="reviewfeedback", - name="guide_id", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="feedbacks", to="knowledge_base.guide" - ), - ), - ] diff --git a/src/chigame/knowledge_base/migrations/0004_generalfeedback_alter_reviewfeedback_guide_id.py b/src/chigame/knowledge_base/migrations/0004_generalfeedback_alter_reviewfeedback_guide_id.py deleted file mode 100644 index e16451d0c..000000000 --- a/src/chigame/knowledge_base/migrations/0004_generalfeedback_alter_reviewfeedback_guide_id.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-15 05:08 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0003_alter_guide_favorites_alter_guide_likes_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="GeneralFeedback", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("feedback", models.TextField(verbose_name="Feedback")), - ("created_at", models.DateTimeField(auto_now_add=True, verbose_name="Created at")), - ], - options={ - "verbose_name": "General Feedback", - "verbose_name_plural": "General Feedback", - "ordering": ["-created_at"], - }, - ), - migrations.AlterField( - model_name="reviewfeedback", - name="guide_id", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="feedbacks", to="knowledge_base.guide" - ), - ), - ] diff --git a/src/chigame/knowledge_base/migrations/0004_reviewfeedback_seen_alter_reviewfeedback_guide_id.py b/src/chigame/knowledge_base/migrations/0004_reviewfeedback_seen_alter_reviewfeedback_guide_id.py deleted file mode 100644 index 98aa9f66b..000000000 --- a/src/chigame/knowledge_base/migrations/0004_reviewfeedback_seen_alter_reviewfeedback_guide_id.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-16 17:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0003_alter_guide_favorites_alter_guide_likes_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="reviewfeedback", - name="seen", - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name="reviewfeedback", - name="guide_id", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="feedbacks", to="knowledge_base.guide" - ), - ), - ] diff --git a/src/chigame/knowledge_base/migrations/0005_merge_20250517_1110.py b/src/chigame/knowledge_base/migrations/0005_merge_20250517_1110.py deleted file mode 100644 index c52c16c89..000000000 --- a/src/chigame/knowledge_base/migrations/0005_merge_20250517_1110.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-17 16:10 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0004_alter_reviewfeedback_guide_id"), - ("knowledge_base", "0004_reviewfeedback_seen_alter_reviewfeedback_guide_id"), - ] - - operations = [] diff --git a/src/chigame/knowledge_base/migrations/0006_merge_20250519_1518.py b/src/chigame/knowledge_base/migrations/0006_merge_20250519_1518.py deleted file mode 100644 index 43177715a..000000000 --- a/src/chigame/knowledge_base/migrations/0006_merge_20250519_1518.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-19 20:18 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("knowledge_base", "0004_generalfeedback_alter_reviewfeedback_guide_id"), - ("knowledge_base", "0005_merge_20250517_1110"), - ] - - operations = [] diff --git a/src/chigame/leaderboards/migrations/0001_initial.py b/src/chigame/leaderboards/migrations/0001_initial.py index b5c940618..ed6bce298 100644 --- a/src/chigame/leaderboards/migrations/0001_initial.py +++ b/src/chigame/leaderboards/migrations/0001_initial.py @@ -1,40 +1,23 @@ -# Generated by Django 5.1.7 on 2025-05-21 01:03 +# Generated by Django 4.2.20 on 2025-05-23 07:12 -import django.db.models.deletion from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): - initial = True dependencies = [ - ("games", "0039_game_twine_file_content_game_twine_file_name"), - ("users", "0013_merge_20250519_0011"), + ("games", "0001_initial"), ] operations = [ - migrations.CreateModel( - name="Region", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("continent", models.CharField(max_length=100)), - ("country", models.CharField(max_length=100)), - ("region", models.CharField(max_length=100)), - ], - ), migrations.CreateModel( name="Leaderboard", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("name", models.CharField(max_length=255)), ("description", models.TextField(blank=True)), - ( - "game", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="leaderboards", to="games.game" - ), - ), ], ), migrations.CreateModel( @@ -42,22 +25,14 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("rank", models.IntegerField()), - ( - "leaderboard", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="entries", - to="leaderboards.leaderboard", - ), - ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="leaderboard_entries", - to="users.userprofile", - ), - ), + ], + ), + migrations.CreateModel( + name="LeaderboardPrivacySetting", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("complete_opt_out", models.BooleanField(default=False)), + ("display_as_anonymous", models.BooleanField(default=False)), ], ), migrations.CreateModel( @@ -67,12 +42,6 @@ class Migration(migrations.Migration): ("name", models.CharField(max_length=255)), ("unit", models.CharField(max_length=50)), ("description", models.TextField(blank=True)), - ( - "game", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="metrics", to="games.game" - ), - ), ], ), migrations.CreateModel( @@ -111,41 +80,6 @@ class Migration(migrations.Migration): to="leaderboards.metric", ), ), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="metric_scores", - to="users.userprofile", - ), - ), - ], - ), - migrations.CreateModel( - name="LeaderboardPrivacySetting", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("complete_opt_out", models.BooleanField(default=False)), - ("display_as_anonymous", models.BooleanField(default=False)), - ( - "game", - models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="games.game" - ), - ), - ( - "leaderboard", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="leaderboards.leaderboard", - ), - ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="users.userprofile")), ], - options={ - "unique_together": {("user", "game", "leaderboard")}, - }, ), ] diff --git a/src/chigame/leaderboards/migrations/0002_initial.py b/src/chigame/leaderboards/migrations/0002_initial.py new file mode 100644 index 000000000..c8dac6fd1 --- /dev/null +++ b/src/chigame/leaderboards/migrations/0002_initial.py @@ -0,0 +1,82 @@ +# Generated by Django 4.2.20 on 2025-05-23 07:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("games", "0002_initial"), + ("leaderboards", "0001_initial"), + ("users", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="metricscore", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="metric_scores", to="users.userprofile" + ), + ), + migrations.AddField( + model_name="metric", + name="game", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="metrics", to="games.game" + ), + ), + migrations.AddField( + model_name="leaderboardprivacysetting", + name="game", + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="games.game" + ), + ), + migrations.AddField( + model_name="leaderboardprivacysetting", + name="leaderboard", + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="leaderboards.leaderboard" + ), + ), + migrations.AddField( + model_name="leaderboardprivacysetting", + name="user", + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="users.userprofile"), + ), + migrations.AddField( + model_name="leaderboardentry", + name="leaderboard", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="entries", to="leaderboards.leaderboard" + ), + ), + migrations.AddField( + model_name="leaderboardentry", + name="region", + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="leaderboards.region" + ), + ), + migrations.AddField( + model_name="leaderboardentry", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="leaderboard_entries", to="users.userprofile" + ), + ), + migrations.AddField( + model_name="leaderboard", + name="game", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="leaderboards", to="games.game" + ), + ), + migrations.AlterUniqueTogether( + name="leaderboardprivacysetting", + unique_together={("user", "game", "leaderboard")}, + ), + ] diff --git a/src/chigame/leaderboards/migrations/0002_leaderboardentry_region.py b/src/chigame/leaderboards/migrations/0002_leaderboardentry_region.py deleted file mode 100644 index 862d1e172..000000000 --- a/src/chigame/leaderboards/migrations/0002_leaderboardentry_region.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-21 15:56 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("leaderboards", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="leaderboardentry", - name="region", - field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="leaderboards.region" - ), - ), - ] diff --git a/src/chigame/users/migrations/0001_initial.py b/src/chigame/users/migrations/0001_initial.py index d0f7d5ec8..5deb2c1bc 100644 --- a/src/chigame/users/migrations/0001_initial.py +++ b/src/chigame/users/migrations/0001_initial.py @@ -1,7 +1,9 @@ -# Generated by Django 4.2.4 on 2023-11-07 23:01 +# Generated by Django 4.2.20 on 2025-05-23 07:12 import chigame.users.managers +import chigame.users.models from django.conf import settings +import django.core.validators from django.db import migrations, models import django.db.models.deletion import django.utils.timezone @@ -49,6 +51,26 @@ class Migration(migrations.Migration): ("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")), ("name", models.CharField(blank=True, max_length=255, verbose_name="Name of User")), ("email", models.EmailField(max_length=254, unique=True, verbose_name="email address")), + ( + "username", + models.CharField( + blank=True, + max_length=255, + null=True, + unique=True, + validators=[chigame.users.models.validate_username], + verbose_name="username", + ), + ), + ( + "tokens", + models.PositiveSmallIntegerField( + default=1, validators=[django.core.validators.MaxValueValidator(3)] + ), + ), + ("moderator", models.BooleanField(default=False)), + ("profanity_filter", models.BooleanField(default=True)), + ("friends", models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL)), ( "groups", models.ManyToManyField( @@ -86,6 +108,7 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("name", models.TextField()), + ("description", models.TextField(blank=True)), ("date_created", models.DateTimeField(auto_now_add=True)), ( "created_by", @@ -102,13 +125,9 @@ class Migration(migrations.Migration): name="UserProfile", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("display_name", models.TextField()), ("bio", models.TextField(blank=True)), ("date_joined", models.DateTimeField(auto_now_add=True)), - ( - "friends", - models.ManyToManyField(blank=True, related_name="friendship", to=settings.AUTH_USER_MODEL), - ), + ("profile_photo", models.ImageField(blank=True, null=True, upload_to="profile_photos/")), ( "user", models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), @@ -116,30 +135,22 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name="Notification", + name="NotificationLabel", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("first_sent", models.DateTimeField(auto_now_add=True)), - ("last_sent", models.DateTimeField(auto_now_add=True)), + ("name", models.CharField(max_length=50)), ( - "type", - models.PositiveIntegerField( - choices=[(1, "FRIEND_REQUEST"), (2, "REMINDER"), (3, "UPCOMING_MATCH"), (4, "MATCH_PROPOSAL")] + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="notification_labels", + to=settings.AUTH_USER_MODEL, ), ), - ("read", models.BooleanField(default=False)), - ("visible", models.BooleanField(default=True)), - ("actor_object_id", models.PositiveIntegerField()), - ("message", models.CharField(blank=True, max_length=255, null=True)), - ( - "actor_content_type", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="contenttypes.contenttype"), - ), - ( - "receiver", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), ], + options={ + "unique_together": {("name", "user")}, + }, ), migrations.CreateModel( name="GroupInvitation", @@ -147,6 +158,7 @@ class Migration(migrations.Migration): ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("accepted", models.BooleanField(default=False)), ("timestamp", models.DateTimeField(auto_now_add=True)), + ("is_deleted", models.BooleanField(default=False)), ("friend_group", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="users.group")), ( "receiver", @@ -172,6 +184,7 @@ class Migration(migrations.Migration): ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("accepted", models.BooleanField(default=False)), ("timestamp", models.DateTimeField(auto_now_add=True)), + ("is_deleted", models.BooleanField(default=False)), ( "receiver", models.ForeignKey( @@ -190,4 +203,65 @@ class Migration(migrations.Migration): ), ], ), + migrations.CreateModel( + name="Notification", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "category", + models.CharField( + choices=[ + ("inbox", "Inbox"), + ("spam", "Spam"), + ("social", "Social"), + ("promotions", "Promotions"), + ("updates", "Updates"), + ("archived", "Archived"), + ], + default="inbox", + max_length=20, + ), + ), + ("first_sent", models.DateTimeField(auto_now_add=True)), + ("last_sent", models.DateTimeField(auto_now_add=True)), + ( + "type", + models.PositiveIntegerField( + choices=[ + (1, "FRIEND_REQUEST"), + (2, "REMINDER"), + (3, "UPCOMING_MATCH"), + (4, "MATCH_INVITATION"), + (5, "GROUP_INVITATION"), + (6, "ACHIEVEMENT"), + (7, "TOURNAMENT_INVITATION"), + (8, "TOURNAMENT_INVITATION_ACCEPTED"), + (9, "TOURNAMENT_STARTING"), + (10, "TOURNAMENT_ROUND_COMPLETED"), + (11, "TOURNAMENT_COMPLETED"), + ] + ), + ), + ("read", models.BooleanField(default=False)), + ("visible", models.BooleanField(default=True)), + ("actor_object_id", models.PositiveIntegerField()), + ("message", models.CharField(blank=True, max_length=255, null=True)), + ("bookmarked", models.BooleanField(default=False)), + ( + "actor_content_type", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="contenttypes.contenttype"), + ), + ( + "labels", + models.ManyToManyField(blank=True, related_name="notifications", to="users.notificationlabel"), + ), + ( + "receiver", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ], + options={ + "unique_together": {("receiver", "actor_content_type", "actor_object_id", "type")}, + }, + ), ] diff --git a/src/chigame/users/migrations/0002_categories_plural.py b/src/chigame/users/migrations/0002_categories_plural.py deleted file mode 100644 index 8e54aa469..000000000 --- a/src/chigame/users/migrations/0002_categories_plural.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-14 23:57 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="notification", - name="type", - field=models.PositiveIntegerField( - choices=[ - (1, "FRIEND_REQUEST"), - (2, "REMINDER"), - (3, "UPCOMING_MATCH"), - (4, "MATCH_PROPOSAL"), - (5, "GROUP_INVITATION"), - ] - ), - ), - ] diff --git a/src/chigame/users/migrations/0002_user_tokens_alter_notification_type.py b/src/chigame/users/migrations/0002_user_tokens_alter_notification_type.py deleted file mode 100644 index 3171fccd7..000000000 --- a/src/chigame/users/migrations/0002_user_tokens_alter_notification_type.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-15 08:29 - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="tokens", - field=models.PositiveSmallIntegerField( - default=1, validators=[django.core.validators.MaxValueValidator(3)] - ), - ), - migrations.AlterField( - model_name="notification", - name="type", - field=models.PositiveIntegerField( - choices=[ - (1, "FRIEND_REQUEST"), - (2, "REMINDER"), - (3, "UPCOMING_MATCH"), - (4, "MATCH_PROPOSAL"), - (5, "GROUP_INVITATION"), - ] - ), - ), - ] diff --git a/src/chigame/users/migrations/0003_merge_20231115_1525.py b/src/chigame/users/migrations/0003_merge_20231115_1525.py deleted file mode 100644 index 00492f829..000000000 --- a/src/chigame/users/migrations/0003_merge_20231115_1525.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-15 21:25 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0002_categories_plural"), - ("users", "0002_user_tokens_alter_notification_type"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0004_user_username.py b/src/chigame/users/migrations/0004_user_username.py deleted file mode 100644 index 147de8139..000000000 --- a/src/chigame/users/migrations/0004_user_username.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.4 on 2023-11-29 16:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0003_merge_20231115_1525"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="username", - field=models.CharField(blank=True, max_length=255, null=True, unique=True, verbose_name="username"), - ), - ] diff --git a/src/chigame/users/migrations/0005_alter_user_username.py b/src/chigame/users/migrations/0005_alter_user_username.py deleted file mode 100644 index d3cc9c415..000000000 --- a/src/chigame/users/migrations/0005_alter_user_username.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.4 on 2023-12-04 22:15 - -import chigame.users.models -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0004_user_username"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="username", - field=models.CharField( - blank=True, - max_length=255, - null=True, - unique=True, - validators=[chigame.users.models.validate_username], - verbose_name="username", - ), - ), - ] diff --git a/src/chigame/users/migrations/0006_friendinvitation_is_deleted.py b/src/chigame/users/migrations/0006_friendinvitation_is_deleted.py deleted file mode 100644 index b98e66ffd..000000000 --- a/src/chigame/users/migrations/0006_friendinvitation_is_deleted.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.20 on 2025-04-27 23:37 - -from django.db import migrations, models - - -# added is_deleted -class Migration(migrations.Migration): - dependencies = [ - ("users", "0005_alter_user_username"), - ] - - operations = [ - migrations.AddField( - model_name="friendinvitation", - name="is_deleted", - field=models.BooleanField(default=False), - ), - ] diff --git a/src/chigame/users/migrations/0007_remove_userprofile_friends_and_more.py b/src/chigame/users/migrations/0007_remove_userprofile_friends_and_more.py deleted file mode 100644 index 993fef9ba..000000000 --- a/src/chigame/users/migrations/0007_remove_userprofile_friends_and_more.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-05 05:27 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("contenttypes", "0002_remove_content_type_name"), - ("users", "0006_friendinvitation_is_deleted"), - ] - - operations = [ - migrations.RemoveField( - model_name="userprofile", - name="friends", - ), - migrations.AddField( - model_name="groupinvitation", - name="is_deleted", - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name="user", - name="friends", - field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name="user", - name="moderator", - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name="notification", - name="type", - field=models.PositiveIntegerField( - choices=[ - (1, "FRIEND_REQUEST"), - (2, "REMINDER"), - (3, "UPCOMING_MATCH"), - (4, "MATCH_PROPOSAL"), - (5, "GROUP_INVITATION"), - (6, "ACHIEVEMENT"), - ] - ), - ), - migrations.AlterUniqueTogether( - name="friendinvitation", - unique_together={("sender", "receiver")}, - ), - migrations.AlterUniqueTogether( - name="notification", - unique_together={("receiver", "actor_content_type", "actor_object_id", "type")}, - ), - ] diff --git a/src/chigame/users/migrations/0008_remove_userprofile_display_name.py b/src/chigame/users/migrations/0008_remove_userprofile_display_name.py deleted file mode 100644 index 343d8e960..000000000 --- a/src/chigame/users/migrations/0008_remove_userprofile_display_name.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-12 05:03 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0007_remove_userprofile_friends_and_more"), - ] - - operations = [ - migrations.RemoveField( - model_name="userprofile", - name="display_name", - ), - ] diff --git a/src/chigame/users/migrations/0008_user_profanity_filter.py b/src/chigame/users/migrations/0008_user_profanity_filter.py deleted file mode 100644 index e886cc715..000000000 --- a/src/chigame/users/migrations/0008_user_profanity_filter.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-11 22:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0007_remove_userprofile_friends_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="profanity_filter", - field=models.BooleanField(default=True), - ), - ] diff --git a/src/chigame/users/migrations/0009_notification_bookmarked_notification_category_and_more.py b/src/chigame/users/migrations/0009_notification_bookmarked_notification_category_and_more.py deleted file mode 100644 index 1a1f9fb35..000000000 --- a/src/chigame/users/migrations/0009_notification_bookmarked_notification_category_and_more.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-13 06:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0008_remove_userprofile_display_name"), - ] - - operations = [ - migrations.AddField( - model_name="notification", - name="bookmarked", - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name="notification", - name="category", - field=models.CharField( - choices=[ - ("inbox", "Inbox"), - ("spam", "Spam"), - ("social", "Social"), - ("promotions", "Promotions"), - ("updates", "Updates"), - ("archived", "Archived"), - ], - default="inbox", - max_length=20, - ), - ), - migrations.AddField( - model_name="userprofile", - name="profile_photo", - field=models.ImageField(blank=True, null=True, upload_to="profile_photos/"), - ), - ] diff --git a/src/chigame/users/migrations/0010_merge_20250514_2202.py b/src/chigame/users/migrations/0010_merge_20250514_2202.py deleted file mode 100644 index 42ab00199..000000000 --- a/src/chigame/users/migrations/0010_merge_20250514_2202.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-15 03:02 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0008_user_profanity_filter"), - ("users", "0009_notification_bookmarked_notification_category_and_more"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0010_merge_20250514_2211.py b/src/chigame/users/migrations/0010_merge_20250514_2211.py deleted file mode 100644 index b4c7eac3a..000000000 --- a/src/chigame/users/migrations/0010_merge_20250514_2211.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-15 03:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0008_user_profanity_filter"), - ("users", "0009_notification_bookmarked_notification_category_and_more"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0010_notificationlabel_notification_labels.py b/src/chigame/users/migrations/0010_notificationlabel_notification_labels.py deleted file mode 100644 index ccd2d49da..000000000 --- a/src/chigame/users/migrations/0010_notificationlabel_notification_labels.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-15 18:27 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0009_notification_bookmarked_notification_category_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="NotificationLabel", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("name", models.CharField(max_length=50)), - ( - "user", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="notification_labels", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "unique_together": {("name", "user")}, - }, - ), - migrations.AddField( - model_name="notification", - name="labels", - field=models.ManyToManyField(blank=True, related_name="notifications", to="users.notificationlabel"), - ), - ] diff --git a/src/chigame/users/migrations/0011_group_description_alter_notification_type.py b/src/chigame/users/migrations/0011_group_description_alter_notification_type.py deleted file mode 100644 index ad549d6c9..000000000 --- a/src/chigame/users/migrations/0011_group_description_alter_notification_type.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 04:40 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0010_notificationlabel_notification_labels"), - ] - - operations = [ - migrations.AddField( - model_name="group", - name="description", - field=models.TextField(blank=True), - ), - migrations.AlterField( - model_name="notification", - name="type", - field=models.PositiveIntegerField( - choices=[ - (1, "FRIEND_REQUEST"), - (2, "REMINDER"), - (3, "UPCOMING_MATCH"), - (4, "MATCH_INVITATION"), - (5, "GROUP_INVITATION"), - (6, "ACHIEVEMENT"), - (7, "TOURNAMENT_INVITATION"), - (8, "TOURNAMENT_INVITATION_ACCEPTED"), - (9, "TOURNAMENT_STARTING"), - (10, "TOURNAMENT_ROUND_COMPLETED"), - (11, "TOURNAMENT_COMPLETED"), - ] - ), - ), - ] diff --git a/src/chigame/users/migrations/0011_merge_20250518_2303.py b/src/chigame/users/migrations/0011_merge_20250518_2303.py deleted file mode 100644 index 8d8a8a2ea..000000000 --- a/src/chigame/users/migrations/0011_merge_20250518_2303.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 04:03 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0010_merge_20250514_2211"), - ("users", "0010_notificationlabel_notification_labels"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0012_merge_20250518_2347.py b/src/chigame/users/migrations/0012_merge_20250518_2347.py deleted file mode 100644 index 6b20e0b2c..000000000 --- a/src/chigame/users/migrations/0012_merge_20250518_2347.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 04:47 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0011_group_description_alter_notification_type"), - ("users", "0011_merge_20250518_2303"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0013_merge_20250519_0011.py b/src/chigame/users/migrations/0013_merge_20250519_0011.py deleted file mode 100644 index 9fead061b..000000000 --- a/src/chigame/users/migrations/0013_merge_20250519_0011.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 05:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0010_merge_20250514_2202"), - ("users", "0012_merge_20250518_2347"), - ] - - operations = [] diff --git a/src/chigame/users/migrations/0014_alter_friendinvitation_unique_together.py b/src/chigame/users/migrations/0014_alter_friendinvitation_unique_together.py deleted file mode 100644 index 919fecbf2..000000000 --- a/src/chigame/users/migrations/0014_alter_friendinvitation_unique_together.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-19 22:15 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("users", "0013_merge_20250519_0011"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="friendinvitation", - unique_together=set(), - ), - ] From 494ad2ca6aa026cc151cf4bf90b8a6a49f9642f7 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:20:10 -0500 Subject: [PATCH 32/37] Add dummy migration to bypass missing forum_conversation dependency --- src/chigame/forum/migrations/0006_bypass_missing_dependency.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/chigame/forum/migrations/0006_bypass_missing_dependency.py diff --git a/src/chigame/forum/migrations/0006_bypass_missing_dependency.py b/src/chigame/forum/migrations/0006_bypass_missing_dependency.py new file mode 100644 index 000000000..e69de29bb From 3c01eee5e5957d406e114c1bac0f602a97f1abd1 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:23:34 -0500 Subject: [PATCH 33/37] Add fake migration to satisfy missing forum_conversation.0010 dependency --- .../migrations/0010_auto_20170120_0224.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/chigame/forum_conversation/migrations/0010_auto_20170120_0224.py diff --git a/src/chigame/forum_conversation/migrations/0010_auto_20170120_0224.py b/src/chigame/forum_conversation/migrations/0010_auto_20170120_0224.py new file mode 100644 index 000000000..6e51f69d1 --- /dev/null +++ b/src/chigame/forum_conversation/migrations/0010_auto_20170120_0224.py @@ -0,0 +1,9 @@ +from django.db import migrations + +class Migration(migrations.Migration): + + dependencies = [ + ('forum_conversation', '0009_auto_20170119_1833'), # or whatever the last real one was + ] + + operations = [] From 7ed8cfb1e9dcce0a4ad853b7306016922131d23f Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:26:36 -0500 Subject: [PATCH 34/37] Add missing __init__.py to forum/migrations to complete migration fix --- src/chigame/forum/migrations/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/chigame/forum/migrations/__init__.py diff --git a/src/chigame/forum/migrations/__init__.py b/src/chigame/forum/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb From 65ffd8ba14180af9d7b05dbc5c4f3c99a409c9a3 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:30:21 -0500 Subject: [PATCH 35/37] Ensure forum_conversation migration 0010 is tracked and committed --- src/chigame/forum_conversation/migrations/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/chigame/forum_conversation/migrations/__init__.py diff --git a/src/chigame/forum_conversation/migrations/__init__.py b/src/chigame/forum_conversation/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb From 3700b423ecbad45360c0f770ea4357ff33ac3c28 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Fri, 23 May 2025 02:33:41 -0500 Subject: [PATCH 36/37] Remove incorrect chigame.forums.forum_conversation module --- .../forums/forum_conversation/__init__.py | 0 .../forums/forum_conversation/admin.py | 0 src/chigame/forums/forum_conversation/apps.py | 6 - .../migrations/0001_initial.py | 117 ---------------- .../migrations/0002_initial.py | 132 ------------------ .../forum_conversation/migrations/__init__.py | 0 .../forums/forum_conversation/models.py | 35 ----- .../forums/forum_conversation/tests.py | 0 .../forums/forum_conversation/views.py | 71 ---------- src/config/settings/base.py | 2 +- 10 files changed, 1 insertion(+), 362 deletions(-) delete mode 100644 src/chigame/forums/forum_conversation/__init__.py delete mode 100644 src/chigame/forums/forum_conversation/admin.py delete mode 100644 src/chigame/forums/forum_conversation/apps.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0001_initial.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/0002_initial.py delete mode 100644 src/chigame/forums/forum_conversation/migrations/__init__.py delete mode 100644 src/chigame/forums/forum_conversation/models.py delete mode 100644 src/chigame/forums/forum_conversation/tests.py delete mode 100644 src/chigame/forums/forum_conversation/views.py diff --git a/src/chigame/forums/forum_conversation/__init__.py b/src/chigame/forums/forum_conversation/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/chigame/forums/forum_conversation/admin.py b/src/chigame/forums/forum_conversation/admin.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/chigame/forums/forum_conversation/apps.py b/src/chigame/forums/forum_conversation/apps.py deleted file mode 100644 index 889cf247c..000000000 --- a/src/chigame/forums/forum_conversation/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from machina.apps.forum_conversation.apps import ForumConversationAppConfig as BaseForumConversationAppConfig - - -class ForumConversationConfig(BaseForumConversationAppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "chigame.forum_conversation" diff --git a/src/chigame/forums/forum_conversation/migrations/0001_initial.py b/src/chigame/forums/forum_conversation/migrations/0001_initial.py deleted file mode 100644 index b653e0611..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0001_initial.py +++ /dev/null @@ -1,117 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-23 07:12 - -from django.db import migrations, models -import django.db.models.deletion -import machina.core.validators -import machina.models.fields - - -class Migration(migrations.Migration): - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Post", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("created", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), - ("updated", models.DateTimeField(auto_now=True, verbose_name="Update date")), - ( - "anonymous_key", - models.CharField(blank=True, max_length=100, null=True, verbose_name="Anonymous user forum key"), - ), - ("subject", models.CharField(max_length=255, verbose_name="Subject")), - ( - "content", - machina.models.fields.MarkupTextField( - no_rendered_field=True, - validators=[machina.core.validators.MarkupMaxLengthValidator(None)], - verbose_name="Content", - ), - ), - ("username", models.CharField(blank=True, max_length=155, null=True, verbose_name="Username")), - ("approved", models.BooleanField(db_index=True, default=True, verbose_name="Approved")), - ( - "enable_signature", - models.BooleanField(db_index=True, default=True, verbose_name="Attach a signature"), - ), - ( - "update_reason", - models.CharField(blank=True, max_length=255, null=True, verbose_name="Update reason"), - ), - ( - "updates_count", - models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Updates count"), - ), - ("_content_rendered", models.TextField(blank=True, editable=False, null=True)), - ], - options={ - "verbose_name": "Post", - "verbose_name_plural": "Posts", - "ordering": ["created"], - "get_latest_by": "created", - "abstract": False, - }, - ), - migrations.CreateModel( - name="Topic", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("subject", models.CharField(max_length=255, verbose_name="Subject")), - ("slug", models.SlugField(max_length=255, verbose_name="Slug")), - ( - "type", - models.PositiveSmallIntegerField( - choices=[(0, "Default topic"), (1, "Sticky"), (2, "Announce")], - db_index=True, - verbose_name="Topic type", - ), - ), - ( - "status", - models.PositiveIntegerField( - choices=[(0, "Topic unlocked"), (1, "Topic locked"), (2, "Topic moved")], - db_index=True, - verbose_name="Topic status", - ), - ), - ("approved", models.BooleanField(db_index=True, default=True, verbose_name="Approved")), - ( - "posts_count", - models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Posts count"), - ), - ( - "views_count", - models.PositiveIntegerField(blank=True, default=0, editable=False, verbose_name="Views count"), - ), - ( - "last_post_on", - models.DateTimeField(blank=True, db_index=True, null=True, verbose_name="Last post added on"), - ), - ("created", models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="Creation date")), - ("updated", models.DateTimeField(auto_now=True, db_index=True, verbose_name="Update date")), - ], - options={ - "verbose_name": "Topic", - "verbose_name_plural": "Topics", - "ordering": ["-type", "-last_post_on"], - "get_latest_by": "last_post_on", - "abstract": False, - }, - ), - migrations.CreateModel( - name="Vote", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("rating", models.IntegerField(choices=[(1, "Like"), (-1, "Dislike")])), - ( - "post", - models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="forum_conversation.post" - ), - ), - ], - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/0002_initial.py b/src/chigame/forums/forum_conversation/migrations/0002_initial.py deleted file mode 100644 index 581a01e68..000000000 --- a/src/chigame/forums/forum_conversation/migrations/0002_initial.py +++ /dev/null @@ -1,132 +0,0 @@ -# Generated by Django 4.2.20 on 2025-05-23 07:12 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - ("forum", "0002_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("forum_conversation", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="vote", - name="poster", - field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), - ), - migrations.AddField( - model_name="topic", - name="first_post", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="forum_conversation.post", - verbose_name="First post", - ), - ), - migrations.AddField( - model_name="topic", - name="forum", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="topics", - to="forum.forum", - verbose_name="Topic forum", - ), - ), - migrations.AddField( - model_name="topic", - name="last_post", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="forum_conversation.post", - verbose_name="Last post", - ), - ), - migrations.AddField( - model_name="topic", - name="poster", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - verbose_name="Poster", - ), - ), - migrations.AddField( - model_name="topic", - name="subscribers", - field=models.ManyToManyField( - blank=True, related_name="topic_subscriptions", to=settings.AUTH_USER_MODEL, verbose_name="Subscribers" - ), - ), - migrations.AddField( - model_name="post", - name="poster", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="posts", - to=settings.AUTH_USER_MODEL, - verbose_name="Poster", - ), - ), - migrations.AddField( - model_name="post", - name="ratings", - field=models.ManyToManyField( - blank=True, - editable=False, - related_name="ratings", - through="forum_conversation.Vote", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="post", - name="topic", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="posts", - to="forum_conversation.topic", - verbose_name="Topic", - ), - ), - migrations.AddField( - model_name="post", - name="updated_by", - field=models.ForeignKey( - blank=True, - editable=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - verbose_name="Lastly updated by", - ), - ), - migrations.AddConstraint( - model_name="vote", - constraint=models.UniqueConstraint(fields=("poster", "post"), name="unique_rating"), - ), - migrations.AddIndex( - model_name="topic", - index=models.Index(fields=["type", "last_post_on"], name="forum_conve_type_cc96d0_idx"), - ), - ] diff --git a/src/chigame/forums/forum_conversation/migrations/__init__.py b/src/chigame/forums/forum_conversation/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/chigame/forums/forum_conversation/models.py b/src/chigame/forums/forum_conversation/models.py deleted file mode 100644 index 76e15ad9f..000000000 --- a/src/chigame/forums/forum_conversation/models.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.conf import settings -from django.db import models -from machina.apps.forum_conversation.abstract_models import AbstractPost - -from chigame.users.models import User - - -class Post(AbstractPost): - # Each post may be liked or disliked - ratings = models.ManyToManyField( - settings.AUTH_USER_MODEL, - through="Vote", - related_name="ratings", - editable=False, - blank=True, - ) - - -class Vote(models.Model): - class Rating(models.IntegerChoices): - LIKE = 1, "Like" - DISLIKE = -1, "Dislike" - - poster = models.ForeignKey(User, on_delete=models.CASCADE, null=True) - post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True) - rating = models.IntegerField(choices=Rating.choices) - - class Meta: - constraints = [models.UniqueConstraint(fields=["poster", "post"], name="unique_rating")] - - -# This import must be at the bottom: -# https://django-machina.readthedocs.io/en/latest/customization/recipes/overriding_models.html#defining-a-new-custom-model -# `noqa` means "no quality assurance." It tells the linter to not worry about this line -from machina.apps.forum_conversation.models import * # noqa diff --git a/src/chigame/forums/forum_conversation/tests.py b/src/chigame/forums/forum_conversation/tests.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/chigame/forums/forum_conversation/views.py b/src/chigame/forums/forum_conversation/views.py deleted file mode 100644 index 1123e8833..000000000 --- a/src/chigame/forums/forum_conversation/views.py +++ /dev/null @@ -1,71 +0,0 @@ -from django.core.exceptions import ValidationError -from django.db.models import Case, F, IntegerField, Sum, When -from django.db.models.functions import Coalesce -from django.http import HttpResponse -from machina.apps.forum_conversation.views import TopicView as BaseTopicView -from machina.core.db.models import get_model -from rest_framework import status - -from .models import Vote - -Post = get_model("forum_conversation", "Post") - - -class TopicView(BaseTopicView): - def post(self, request, **kwargs): - """Handles POST requests.""" - - # Retrieve the liked post - liked_post = request.POST.get("post_id", None) - if liked_post: - try: - assert liked_post.isdigit() - vote_value = request.POST.get("rate") - - if vote_value == "like": - rating = 1 - elif vote_value == "dislike": - rating = -1 - else: - raise ValidationError - - post = Post.objects.filter(pk=liked_post).first() - vote = Vote.objects.get(rating=rating, post=post, poster=post.poster) - - # Remove the vote if it existed previously - vote.delete() - except Vote.DoesNotExist: - Vote.objects.filter(post=post, poster=post.poster).delete() - - # Create a new `Vote` - vote = Vote.objects.create(rating=rating, post=post, poster=post.poster) - vote.full_clean() - vote.save() - return HttpResponse(status=status.HTTP_201_CREATED) - except (Post.DoesNotExist, ValidationError): - return HttpResponse(status=status.HTTP_400_BAD_REQUEST) - - return HttpResponse(status=status.HTTP_204_NO_CONTENT) - - def get_queryset(self): - """Returns the list of items for this view.""" - self.topic = self.get_topic() - qs = ( - self.topic.posts.all() - .exclude(approved=False) - .select_related("poster", "updated_by") - .prefetch_related("attachments", "poster__forum_profile") - .annotate( - rating=Coalesce(Sum(F("vote__rating"), output_field=IntegerField()), 0), - user_rating=Coalesce( - Case( - When(vote__poster=self.request.user, then=F("vote__rating")), - default=0, - output_field=IntegerField(), - ), - 0, - ), - ) - ) - - return qs diff --git a/src/config/settings/base.py b/src/config/settings/base.py index 567b0aae5..c480ef5dc 100644 --- a/src/config/settings/base.py +++ b/src/config/settings/base.py @@ -121,7 +121,7 @@ "chigame.leaderboards", "chigame.chat", # Overridden django-machina apps - "chigame.forums.forum_conversation", + "chigame.forum_conversation", ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS From f856ec5bfb76ef8eee1a44ce4a8ca31810d44f81 Mon Sep 17 00:00:00 2001 From: Zayna Cheema Date: Sat, 24 May 2025 20:44:13 -0500 Subject: [PATCH 37/37] [Revert] Restore forum_conversation and migration file --- frontend/vue/src/components/Footer.vue | 2 +- frontend/vue/src/components/NavBar.vue | 2 - frontend/vue/src/pages/TournamentPage.vue | 316 ----------- .../vue/src/pages/images/profile_logo.png | Bin 4089 -> 0 bytes frontend/vue/src/router.js | 2 - src/chigame/achievements/api/urls.py | 6 +- src/chigame/achievements/api/views.py | 30 +- src/chigame/achievements/models.py | 14 - src/chigame/achievements/tests/tests.py | 21 +- src/chigame/achievements/urls.py | 2 +- src/chigame/achievements/views.py | 11 +- src/chigame/api/serializers.py | 36 +- src/chigame/api/tests/factories.py | 14 +- src/chigame/api/tests/test_api.py | 106 ---- src/chigame/api/tests/test_popups.py | 45 -- src/chigame/api/tests/test_review_stats.py | 56 -- src/chigame/api/urls.py | 19 +- src/chigame/api/views.py | 138 +---- src/chigame/chat/consumers.py | 109 ++-- src/chigame/chat/migrations/0001_initial.py | 46 +- src/chigame/chat/models.py | 2 - src/chigame/chat/urls.py | 1 - src/chigame/chat/views.py | 33 +- src/chigame/games/models.py | 4 +- src/chigame/games/tests.py | 133 +---- src/chigame/games/urls.py | 10 +- src/chigame/games/views.py | 278 +++++----- .../0004_alter_reviewfeedback_guide_id.py | 19 + src/chigame/knowledge_base/urls.py | 4 - src/chigame/knowledge_base/views.py | 36 +- src/config/settings/base.py | 1 - src/sandbox/checkers-prototype/game.js | 122 ++--- src/sandbox/live-chat-demo/.gitignore | 1 + src/sandbox/live-chat-demo/README.md | 25 - .../live-chat-demo/chatdemo/chat/consumers.py | 29 -- .../live-chat-demo/chatdemo/chat/models.py | 8 +- .../live-chat-demo/chatdemo/chat/views.py | 15 +- src/static/checkers-prototype/game.js | 2 +- src/static/css/achievements.css | 389 -------------- src/static/css/knowledge-base-styles.css | 63 +-- .../css/knowledge-base/single-guide.css | 38 -- src/static/js/achievements.js | 286 ---------- src/static/js/knowledge-base/like-favorite.js | 80 --- src/templates/achievements/demo_game.html | 108 +--- .../achievements/user_achievements.html | 489 +++++++++++++++++- .../chat/components/_context_menu.html | 89 +--- src/templates/chat/components/_input.html | 6 - src/templates/chat/components/_messages.html | 1 - src/templates/chat/components/_script.html | 73 +-- src/templates/chat/live-chat-list.html | 1 - src/templates/games/game_grid.html | 22 +- src/templates/games/gamelist_detail.html | 28 - .../interactive-fiction/IF_game_create.html | 58 +-- src/templates/knowledge-base/base.html | 2 +- .../contributor_manage_guide.html | 43 +- .../knowledge-base/guide_detail.html | 50 +- src/templates/knowledge-base/landing.html | 30 +- .../tournaments/tournament_detail.html | 37 -- .../tournaments/tournament_feedback_list.html | 63 --- .../tournament_update_feedback.html | 24 - .../tournaments/tournament_user_feedback.html | 76 --- 61 files changed, 887 insertions(+), 2867 deletions(-) delete mode 100644 frontend/vue/src/pages/TournamentPage.vue delete mode 100644 frontend/vue/src/pages/images/profile_logo.png delete mode 100644 src/chigame/api/tests/test_popups.py delete mode 100644 src/chigame/api/tests/test_review_stats.py create mode 100644 src/chigame/knowledge_base/migrations/0004_alter_reviewfeedback_guide_id.py create mode 100644 src/sandbox/live-chat-demo/.gitignore delete mode 100644 src/sandbox/live-chat-demo/README.md delete mode 100644 src/static/css/achievements.css delete mode 100644 src/static/js/achievements.js delete mode 100644 src/static/js/knowledge-base/like-favorite.js delete mode 100644 src/templates/games/gamelist_detail.html delete mode 100644 src/templates/tournaments/tournament_feedback_list.html delete mode 100644 src/templates/tournaments/tournament_update_feedback.html delete mode 100644 src/templates/tournaments/tournament_user_feedback.html diff --git a/frontend/vue/src/components/Footer.vue b/frontend/vue/src/components/Footer.vue index 400601d14..e20a78168 100644 --- a/frontend/vue/src/components/Footer.vue +++ b/frontend/vue/src/components/Footer.vue @@ -24,7 +24,7 @@ Lobbies
  • Forums
  • Lobbies
  • Profile
  • -
  • Tournaments
  • - {% endfor %} {% else %} diff --git a/src/templates/chat/components/_script.html b/src/templates/chat/components/_script.html index 654a85098..c96f6131b 100644 --- a/src/templates/chat/components/_script.html +++ b/src/templates/chat/components/_script.html @@ -14,13 +14,6 @@ }; document.querySelector("#id_message_send_input").focus(); - document.getElementById("cancel-reply").addEventListener("click", () => { - replyToMessageId = null; - replyToUsername = null; - replyToContent = null; - document.getElementById('replying-to-preview').classList.add('d-none'); - }); - document.querySelector("#id_message_send_input").onkeyup = function(e) { if (e.key === "Enter") { document.querySelector("#id_message_send_button").click(); @@ -35,26 +28,16 @@ JSON.stringify({ message: messageInput, user_id: "{{ request.user.id }}", - reply_to: replyToMessageId, + reply_to: replyToMessageId }) ); + // Clear reply state replyToMessageId = null; replyToUsername = null; replyToContent = null; - - messageInput = ""; - document.getElementById("replying-to-preview").classList.add("d-none"); }; - function escapeHTML(str) { - return str - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - } - /** * This function is called when a message is received from the server. * It creates a new div element with the message and appends it to the chat container. @@ -70,41 +53,13 @@ // Create message container const messageContainer = document.createElement("div"); - messageContainer.className = `mb-3 ${ - data.user_id === "{{ request.user.id }}" - ? "align-self-end" - : "align-self-start" - }`; + messageContainer.className = `mb-3 ${data.user_id === "{{ request.user.id }}" ? "align-self-end" : "align-self-start"}`; messageContainer.setAttribute("data-message-id", data.message_id); - const escapedUsername = escapeHTML(data.username); - const escapedMessage = escapeHTML(data.message); - messageContainer.setAttribute("oncontextmenu", `showContextMenu(event, ${data.message_id}, '${escapedUsername}', '${escapedMessage}'); return false;`); - const escapeHtml = (str) => - str.replace( - /[&<>'"]/g, - (char) => - ({ - "&": "&", - "<": "<", - ">": ">", - "'": "'", - '"': """, - } [char]) - ); - - const escapedUsername = escapeHtml(data.username); - const escapedMessage = escapeHtml(data.message); - messageContainer.setAttribute( - "oncontextmenu", - `showContextMenu(event, ${data.message_id}, '${escapedUsername}', '${escapedMessage}'); return false;` - ); + messageContainer.setAttribute("oncontextmenu", `showContextMenu(event, ${data.message_id}, '${data.username}', '${data.message}'); return false;`); + // Create message bubble const messageBubble = document.createElement("div"); - messageBubble.className = `${ - data.user_id === "{{ request.user.id }}" - ? "bg-success-subtle" - : "bg-white" - } rounded p-2 shadow-sm`; + messageBubble.className = `${data.user_id === "{{ request.user.id }}" ? "bg-success-subtle" : "bg-white"} rounded p-2 shadow-sm`; messageBubble.style.maxWidth = "80%"; // Add reply preview if this is a reply @@ -139,8 +94,8 @@ const timestamp = document.createElement("div"); timestamp.className = "text-end text-muted small mt-1"; timestamp.textContent = new Date().toLocaleTimeString([], { - hour: "2-digit", - minute: "2-digit", + hour: '2-digit', + minute: '2-digit' }); // Assemble message @@ -184,20 +139,10 @@ // Show collapse button only in floating mode if (chatContainer.classList.contains("floating-chat")) { collapseButton.classList.remove("d-none"); - collapseButton.classList.remove("d-none"); } else { collapseButton.classList.add("d-none"); - - if (collapseButton) { - collapseButton.classList.remove("d-none"); - } + chatContainer.classList.remove("collapsed-chat"); } - if (collapseButton) { - collapseButton.classList.add("d-none"); - } - - chatContainer.classList.remove("collapsed-chat"); - }); } diff --git a/src/templates/chat/live-chat-list.html b/src/templates/chat/live-chat-list.html index 91416eb3d..66c576358 100644 --- a/src/templates/chat/live-chat-list.html +++ b/src/templates/chat/live-chat-list.html @@ -53,7 +53,6 @@

    Live Chats

    } }); }); - searchInput.addEventListener('input', handleSearchInput); }); {% endblock content %} diff --git a/src/templates/games/game_grid.html b/src/templates/games/game_grid.html index fa0fdf203..903c5f79d 100644 --- a/src/templates/games/game_grid.html +++ b/src/templates/games/game_grid.html @@ -104,26 +104,8 @@

    Games

    - {% if user.is_authenticated and game_lists %} -
    - - -
    - {% elif user.is_authenticated %} - {# Fallback if user is authenticated but has no lists yet - direct link to favorites #} - {# This also handles the case where get_or_create for Favorites might be the only list #} - My Favorites - {% endif %} + My Favorites
    {% if query_type %}{% endif %} diff --git a/src/templates/games/gamelist_detail.html b/src/templates/games/gamelist_detail.html deleted file mode 100644 index b6e3ac639..000000000 --- a/src/templates/games/gamelist_detail.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "base.html" %} - -{% block title %} - {{ gamelist.name }} -{% endblock title %} -{% block content %} -
    -

    {{ gamelist.name }}

    - {% if gamelist.description %}

    {{ gamelist.description }}

    {% endif %} - {% if gamelist.games.all %} -
      - {% for game in gamelist.games.all %} -
    • - {{ game.name }} - {# Optionally, add a button to remove from this specific list #} - Remove -
    • - {% endfor %} -
    - {% else %} -

    - This list is empty. Browse games to add some! -

    - {% endif %} - Back to Games -
    -{% endblock content %} diff --git a/src/templates/games/interactive-fiction/IF_game_create.html b/src/templates/games/interactive-fiction/IF_game_create.html index 83921b396..b6da80952 100644 --- a/src/templates/games/interactive-fiction/IF_game_create.html +++ b/src/templates/games/interactive-fiction/IF_game_create.html @@ -48,11 +48,6 @@ min-height: 6rem; } - #game_form textarea { - vertical-align: top; - white-space: pre-wrap; - } - #game_form input[type="checkbox"] { margin-right: 0.5rem; vertical-align: middle; @@ -80,10 +75,7 @@ /* slightly darker to differentiate */ text-decoration: none; margin-top: 50px; - } - .custom-label-section .btn-secondary { - margin-top: 0; } .upload-zone { @@ -109,40 +101,11 @@ .label-add-wrapper { margin-top: 0.75rem; display: flex; - gap: 10px; } .label-add-wrapper input { flex: 1; } - - /* custom-label section styling */ - .custom-label-section { - margin-top: 1rem; - background-color: #f8f9fa; - padding: 12px 15px; - border-radius: 4px; - border: 1px solid #e9ecef; - } - - .custom-label-prompt { - font-size: 0.95rem; - color: #495057; - margin-bottom: 10px; - margin-top: 0; - } - - .custom-label-input { - padding: 8px 12px; - border: 1px solid #ced4da; - border-radius: 4px; - transition: border-color 0.2s; - } - - .custom-label-input:focus { - border-color: #0d9b40; - outline: none; - } -{% endblock javascript %} {% block css %} {{ block.super }}

    Authored by {{ guide.author }}

    Last edited {{ guide.recent_upload }}

    -

    - {{ guide.likes.count }} ♥ and - {{ guide.favorites.count }} ★ -

    +

    {{ guide.likes.count }} ♥ and {{ guide.favorites.count }} ★

    @@ -50,43 +43,4 @@

    Guide Detail Page

    {{ guide.game_id }}, please go back to the knowledge base landing page. {% endif %} - {% if request.user.is_authenticated %} - - - - {% if request.user in guide.likes.all %} - Unlike - {% else %} - Like - {% endif %} - - -   - - - - {% if request.user in guide.favorites.all %} - Unfavorite - {% else %} - Favorite - {% endif %} - - - {% csrf_token %} - {% endif %} - {% endblock page-content %} +{% endblock page-content %} diff --git a/src/templates/knowledge-base/landing.html b/src/templates/knowledge-base/landing.html index 120fef4f7..fc4528347 100644 --- a/src/templates/knowledge-base/landing.html +++ b/src/templates/knowledge-base/landing.html @@ -1,14 +1,34 @@ {% extends "knowledge-base/base.html" %} -{% load static %} - {% block page-content %} {% if unseen_feedbacks %} +
    + {% for feedback in unseen_feedbacks %} + {% if feedback.get_status_display == "Accepted" %} + + {% elif feedback.get_status_display == "Rejected" %} + + {% else %} + + {% endif %} + {% endfor %} {% endif %}
    diff --git a/src/templates/tournaments/tournament_detail.html b/src/templates/tournaments/tournament_detail.html index 25f1d38ae..c9129be1f 100644 --- a/src/templates/tournaments/tournament_detail.html +++ b/src/templates/tournaments/tournament_detail.html @@ -373,41 +373,4 @@

    Tournament Simulation

    Update

    {% endif %} - -

    Submit Feedback

    - - {% csrf_token %} - -
    - -
    -
    - -
    - -
    -
    - - - - {% if request.user == tournament.created_by %} -

    - All Feedback -

    - {% endif %} - - {% if user_feedback %} -

    - My Feedback -

    - {% endif %} {% endblock content %} diff --git a/src/templates/tournaments/tournament_feedback_list.html b/src/templates/tournaments/tournament_feedback_list.html deleted file mode 100644 index 256a90a55..000000000 --- a/src/templates/tournaments/tournament_feedback_list.html +++ /dev/null @@ -1,63 +0,0 @@ -{% extends "base.html" %} - -{% block extra_head %} - -{% endblock extra_head %} -{% block content %} -

    Feedback for {{ tournament.name }}

    - {% if feedback_list %} - - {% else %} -

    No feedback has been submitted for this tournament yet.

    - {% endif %} - - - - -{% endblock content %} diff --git a/src/templates/tournaments/tournament_update_feedback.html b/src/templates/tournaments/tournament_update_feedback.html deleted file mode 100644 index 72eb86514..000000000 --- a/src/templates/tournaments/tournament_update_feedback.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

    Update Feedback

    -
    - {% csrf_token %} - -
    - -
    -
    - -
    - -
    -
    - -
    -{% endblock content %} diff --git a/src/templates/tournaments/tournament_user_feedback.html b/src/templates/tournaments/tournament_user_feedback.html deleted file mode 100644 index af5793b98..000000000 --- a/src/templates/tournaments/tournament_user_feedback.html +++ /dev/null @@ -1,76 +0,0 @@ -{% extends "base.html" %} - -{% block extra_head %} - -{% endblock extra_head %} -{% block content %} -

    My Feedback

    - {% if user_feedback %} - - {% else %} -

    You have not submitted any feedback yet.

    - {% endif %} - - {% if tournament %} - - - - {% endif %} -{% endblock content %}