Skip to content

Instantly share code, notes, and snippets.

@drdebian
Created August 20, 2019 09:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drdebian/9ff9fbd446cbfcc3370c06ce754e5a7c to your computer and use it in GitHub Desktop.
Save drdebian/9ff9fbd446cbfcc3370c06ce754e5a7c to your computer and use it in GitHub Desktop.
Created on Cognitive Class Labs
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Explore, segment, and cluster the neighborhoods in the city of Toronto"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this assignment, you will be required to explore, segment, and cluster the neighborhoods in the city of Toronto. However, unlike New York, the neighborhood data is not readily available on the internet. What is interesting about the field of data science is that each project can be challenging in its unique way, so you need to learn to be agile and refine the skill to learn new libraries and tools quickly depending on the project.\n",
"\n",
"For the Toronto neighborhood data, a Wikipedia page exists that has all the information we need to explore and cluster the neighborhoods in Toronto. You will be required to scrape the Wikipedia page and wrangle the data, clean it, and then read it into a pandas dataframe so that it is in a structured format like the New York dataset.\n",
"\n",
"Once the data is in a structured format, you can replicate the analysis that we did to the New York City dataset to explore and cluster the neighborhoods in the city of Toronto.\n",
"\n",
"Your submission will be a link to your Jupyter Notebook on your Github repository."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Get Toronto neighborhood data\n",
"\n",
"For this assignment, you will be required to explore and cluster the neighborhoods in Toronto.\n",
"\n",
"1. Start by creating a new Notebook for this assignment.\n",
"2. Use the Notebook to build the code to scrape the following Wikipedia page, https://en.wikipedia.org/wiki/List_of_postal_codes_of_Canada:_M, in order to obtain the data that is in the table of postal codes and to transform the data into a pandas dataframe like the one shown below:\n",
"![](https://d3c33hcgiwev3.cloudfront.net/imageAssetProxy.v1/7JXaz3NNEeiMwApe4i-fLg_40e690ae0e927abda2d4bde7d94ed133_Screen-Shot-2018-06-18-at-7.17.57-PM.png?expiry=1566000000000&hmac=AN3CJ7qeqs6bod-Dt7oM7fnL3e5Hx_ERYwMV3M1TSyM)\n",
"\n",
"3. To create the above dataframe:\n",
"\n",
"- The dataframe will consist of three columns: PostalCode, Borough, and Neighborhood\n",
"- Only process the cells that have an assigned borough. Ignore cells with a borough that is Not assigned.\n",
"- More than one neighborhood can exist in one postal code area. For example, in the table on the Wikipedia page, you will notice that M5A is listed twice and has two neighborhoods: Harbourfront and Regent Park. These two rows will be combined into one row with the neighborhoods separated with a comma as shown in row 11 in the above table.\n",
"- If a cell has a borough but a Not assigned neighborhood, then the neighborhood will be the same as the borough. So for the 9th cell in the table on the Wikipedia page, the value of the Borough and the Neighborhood columns will be Queen's Park.\n",
"- Clean your Notebook and add Markdown cells to explain your work and any assumptions you are making.\n",
"- In the last cell of your notebook, use the .shape method to print the number of rows of your dataframe.\n",
"4. Submit a link to your Notebook on your Github repository."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pull the data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's load the necessary libraries first..."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Solving environment: done\n",
"\n",
"\n",
"==> WARNING: A newer version of conda exists. <==\n",
" current version: 4.5.11\n",
" latest version: 4.7.11\n",
"\n",
"Please update conda by running\n",
"\n",
" $ conda update -n base -c defaults conda\n",
"\n",
"\n",
"\n",
"# All requested packages already installed.\n",
"\n"
]
}
],
"source": [
"### libraries\n",
"import requests\n",
"import pandas as pd\n",
"pd.set_option('display.max_columns', 100)\n",
"pd.set_option('display.max_rows', 100)\n",
"\n",
"!conda install -c conda-forge beautifulsoup4 lxml html5lib --yes\n",
"from bs4 import BeautifulSoup"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's pull down the data from that Wiki page..."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1A</td>\n",
" <td>Not assigned</td>\n",
" <td>Not assigned</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M2A</td>\n",
" <td>Not assigned</td>\n",
" <td>Not assigned</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M3A</td>\n",
" <td>North York</td>\n",
" <td>Parkwoods</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M4A</td>\n",
" <td>North York</td>\n",
" <td>Victoria Village</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M5A</td>\n",
" <td>Downtown Toronto</td>\n",
" <td>Harbourfront</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood\n",
"0 M1A Not assigned Not assigned\n",
"1 M2A Not assigned Not assigned\n",
"2 M3A North York Parkwoods\n",
"3 M4A North York Victoria Village\n",
"4 M5A Downtown Toronto Harbourfront"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"### data\n",
"wiki_url = \"https://en.wikipedia.org/wiki/List_of_postal_codes_of_Canada:_M\"\n",
"\n",
"# request\n",
"myres = requests.get(wiki_url)\n",
"mysoup = BeautifulSoup(myres.content, 'html5lib')\n",
"\n",
"# read table into df\n",
"mytable = mysoup.find_all('table')[0] \n",
"mydf = pd.read_html(str(mytable))[0]\n",
"\n",
"# check it\n",
"mydf.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Process the data\n",
"\n",
"Time for some filtering and postprocessing..."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M3A</td>\n",
" <td>North York</td>\n",
" <td>Parkwoods</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M4A</td>\n",
" <td>North York</td>\n",
" <td>Victoria Village</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M5A</td>\n",
" <td>Downtown Toronto</td>\n",
" <td>Harbourfront</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>M5A</td>\n",
" <td>Downtown Toronto</td>\n",
" <td>Regent Park</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>M6A</td>\n",
" <td>North York</td>\n",
" <td>Lawrence Heights</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood\n",
"2 M3A North York Parkwoods\n",
"3 M4A North York Victoria Village\n",
"4 M5A Downtown Toronto Harbourfront\n",
"5 M5A Downtown Toronto Regent Park\n",
"6 M6A North York Lawrence Heights"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get rid of the \"Not assigned\" boroughs\n",
"mydf_bor = mydf[~mydf.Borough.isin(['Not assigned'])]\n",
"mydf_bor.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Postcodes appearing multiple times should be combined into one line with the neighbourhoods concatenated..."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1B</td>\n",
" <td>Scarborough</td>\n",
" <td>Rouge, Malvern</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M1C</td>\n",
" <td>Scarborough</td>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M1E</td>\n",
" <td>Scarborough</td>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M1G</td>\n",
" <td>Scarborough</td>\n",
" <td>Woburn</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M1H</td>\n",
" <td>Scarborough</td>\n",
" <td>Cedarbrae</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood\n",
"0 M1B Scarborough Rouge, Malvern\n",
"1 M1C Scarborough Highland Creek, Rouge Hill, Port Union\n",
"2 M1E Scarborough Guildwood, Morningside, West Hill\n",
"3 M1G Scarborough Woburn\n",
"4 M1H Scarborough Cedarbrae"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# make those postcodes unique\n",
"mydf_combined = mydf_bor.groupby(['Postcode','Borough'])['Neighbourhood'].apply(', '.join).reset_index()\n",
"mydf_combined.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, let's fix those rows where the Neighbourhood is \"not assigned\" by filling it with the content of the Borough column..."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1B</td>\n",
" <td>Scarborough</td>\n",
" <td>Rouge, Malvern</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M1C</td>\n",
" <td>Scarborough</td>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M1E</td>\n",
" <td>Scarborough</td>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M1G</td>\n",
" <td>Scarborough</td>\n",
" <td>Woburn</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M1H</td>\n",
" <td>Scarborough</td>\n",
" <td>Cedarbrae</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood\n",
"0 M1B Scarborough Rouge, Malvern\n",
"1 M1C Scarborough Highland Creek, Rouge Hill, Port Union\n",
"2 M1E Scarborough Guildwood, Morningside, West Hill\n",
"3 M1G Scarborough Woburn\n",
"4 M1H Scarborough Cedarbrae"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# fix the neighbourhood column where it contains \"not assigned\"\n",
"mydf_combined.loc[mydf_combined['Neighbourhood']==\"Not assigned\", 'Neighbourhood'] = mydf_combined.loc[mydf_combined['Neighbourhood']==\"Not assigned\", 'Borough']\n",
"mydf_combined.head()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# save the Toronto data to CSV for later use\n",
"mydf_combined.to_csv('toronto_postcodes.csv', index=False)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(103, 3)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mydf_combined.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Enrich the Data\n",
"\n",
"### Getting geospatial coordinates\n",
"\n",
"Since the routine for obtaining geo coordinates described in the task outline did indeed prove to be rather unreliable, I opted for proceeding with the provided CSV file.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postal Code</th>\n",
" <th>Latitude</th>\n",
" <th>Longitude</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1B</td>\n",
" <td>43.806686</td>\n",
" <td>-79.194353</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M1C</td>\n",
" <td>43.784535</td>\n",
" <td>-79.160497</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M1E</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M1G</td>\n",
" <td>43.770992</td>\n",
" <td>-79.216917</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M1H</td>\n",
" <td>43.773136</td>\n",
" <td>-79.239476</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postal Code Latitude Longitude\n",
"0 M1B 43.806686 -79.194353\n",
"1 M1C 43.784535 -79.160497\n",
"2 M1E 43.763573 -79.188711\n",
"3 M1G 43.770992 -79.216917\n",
"4 M1H 43.773136 -79.239476"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# read geo coordinates from CSV\n",
"mydf_geo = pd.read_csv('Geospatial_Coordinates.csv')\n",
"mydf_geo.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's add the 2 new Latitude and Longitude columns to the existing data frame."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" <th>Latitude</th>\n",
" <th>Longitude</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1B</td>\n",
" <td>Scarborough</td>\n",
" <td>Rouge, Malvern</td>\n",
" <td>43.806686</td>\n",
" <td>-79.194353</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M1C</td>\n",
" <td>Scarborough</td>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" <td>43.784535</td>\n",
" <td>-79.160497</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M1E</td>\n",
" <td>Scarborough</td>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M1G</td>\n",
" <td>Scarborough</td>\n",
" <td>Woburn</td>\n",
" <td>43.770992</td>\n",
" <td>-79.216917</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M1H</td>\n",
" <td>Scarborough</td>\n",
" <td>Cedarbrae</td>\n",
" <td>43.773136</td>\n",
" <td>-79.239476</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood Latitude \\\n",
"0 M1B Scarborough Rouge, Malvern 43.806686 \n",
"1 M1C Scarborough Highland Creek, Rouge Hill, Port Union 43.784535 \n",
"2 M1E Scarborough Guildwood, Morningside, West Hill 43.763573 \n",
"3 M1G Scarborough Woburn 43.770992 \n",
"4 M1H Scarborough Cedarbrae 43.773136 \n",
"\n",
" Longitude \n",
"0 -79.194353 \n",
"1 -79.160497 \n",
"2 -79.188711 \n",
"3 -79.216917 \n",
"4 -79.239476 "
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# add geo columns to the existing data frame, remove redundant Postal Code column\n",
"mydf_post = pd.merge(mydf_combined, mydf_geo, how='left', left_on='Postcode', right_on='Postal Code')\n",
"mydf_post.drop('Postal Code', axis=1, inplace=True)\n",
"mydf_post.head()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(103, 5)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mydf_post.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Explore and cluster the neighborhoods in Toronto\n",
"\n",
"In the following, we want to separate Toronto's Neighbourhoods into different clusters as a guide to people thinking about moving to or within Toronto. To do so, we use the previously prepared data and enrich it with the venues present in Toronto using Foursquare as an external data source. With this data, we proceed to determine the top 10 venues found in each neighbourhood and use this data to actually find clusters. In the process, we will also make an informed decision about how many clusters make sense and proceed to visualize them using Folium, after which the clusters are inspected and a final conclusion will be drawn."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's download all the dependencies that we will need."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Solving environment: done\n",
"\n",
"\n",
"==> WARNING: A newer version of conda exists. <==\n",
" current version: 4.5.11\n",
" latest version: 4.7.11\n",
"\n",
"Please update conda by running\n",
"\n",
" $ conda update -n base -c defaults conda\n",
"\n",
"\n",
"\n",
"# All requested packages already installed.\n",
"\n",
"Solving environment: done\n",
"\n",
"\n",
"==> WARNING: A newer version of conda exists. <==\n",
" current version: 4.5.11\n",
" latest version: 4.7.11\n",
"\n",
"Please update conda by running\n",
"\n",
" $ conda update -n base -c defaults conda\n",
"\n",
"\n",
"\n",
"# All requested packages already installed.\n",
"\n",
"Libraries imported.\n"
]
}
],
"source": [
"### libraries\n",
"import numpy as np # library to handle data in a vectorized manner\n",
"\n",
"import json # library to handle JSON files\n",
"\n",
"!conda install -c conda-forge geopy --yes # uncomment this line if you haven't completed the Foursquare API lab\n",
"from geopy.geocoders import Nominatim # convert an address into latitude and longitude values\n",
"\n",
"import requests # library to handle requests\n",
"from pandas.io.json import json_normalize # tranform JSON file into a pandas dataframe\n",
"\n",
"# Matplotlib and associated plotting modules\n",
"import matplotlib.cm as cm\n",
"import matplotlib.colors as colors\n",
"\n",
"# import k-means from clustering stage\n",
"from sklearn.cluster import KMeans\n",
"\n",
"!conda install -c conda-forge folium --yes \n",
"import folium # map rendering library\n",
"\n",
"print('Libraries imported.')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create a map of Toronto with neighborhoods superimposed on top.\n",
"\n",
"Since our analysis will focus on Toronto, let's determine the central coordinates using Nominatim."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The geograpical coordinate of Toronto City are 43.653963, -79.387207.\n"
]
}
],
"source": [
"address = 'Toronto, ON'\n",
"\n",
"geolocator = Nominatim(user_agent=\"toronto_explorer\")\n",
"location = geolocator.geocode(address)\n",
"latitude = location.latitude\n",
"longitude = location.longitude\n",
"print('The geograpical coordinate of Toronto City are {}, {}.'.format(latitude, longitude))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To verify that we're on the right track, let's quickly plot a map centered on those coordinates."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgCiAgICAgICAgPHNjcmlwdD4KICAgICAgICAgICAgTF9OT19UT1VDSCA9IGZhbHNlOwogICAgICAgICAgICBMX0RJU0FCTEVfM0QgPSBmYWxzZTsKICAgICAgICA8L3NjcmlwdD4KICAgIAogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbGVhZmxldEAxLjUuMS9kaXN0L2xlYWZsZXQuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY29kZS5qcXVlcnkuY29tL2pxdWVyeS0xLjEyLjQubWluLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9qcy9ib290c3RyYXAubWluLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5qcyI+PC9zY3JpcHQ+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbGVhZmxldEAxLjUuMS9kaXN0L2xlYWZsZXQuY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vYm9vdHN0cmFwLzMuMi4wL2Nzcy9ib290c3RyYXAubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLXRoZW1lLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9mb250LWF3ZXNvbWUvNC42LjMvY3NzL2ZvbnQtYXdlc29tZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL0xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLzIuMC4yL2xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL3Jhd2Nkbi5naXRoYWNrLmNvbS9weXRob24tdmlzdWFsaXphdGlvbi9mb2xpdW0vbWFzdGVyL2ZvbGl1bS90ZW1wbGF0ZXMvbGVhZmxldC5hd2Vzb21lLnJvdGF0ZS5jc3MiLz4KICAgIDxzdHlsZT5odG1sLCBib2R5IHt3aWR0aDogMTAwJTtoZWlnaHQ6IDEwMCU7bWFyZ2luOiAwO3BhZGRpbmc6IDA7fTwvc3R5bGU+CiAgICA8c3R5bGU+I21hcCB7cG9zaXRpb246YWJzb2x1dGU7dG9wOjA7Ym90dG9tOjA7cmlnaHQ6MDtsZWZ0OjA7fTwvc3R5bGU+CiAgICAKICAgICAgICAgICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwKICAgICAgICAgICAgICAgIGluaXRpYWwtc2NhbGU9MS4wLCBtYXhpbXVtLXNjYWxlPTEuMCwgdXNlci1zY2FsYWJsZT1ubyIgLz4KICAgICAgICAgICAgPHN0eWxlPgogICAgICAgICAgICAgICAgI21hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyB7CiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlOwogICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAuMCU7CiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICAgICAgbGVmdDogMC4wJTsKICAgICAgICAgICAgICAgICAgICB0b3A6IDAuMCU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIDwvc3R5bGU+CiAgICAgICAgCjwvaGVhZD4KPGJvZHk+ICAgIAogICAgCiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZvbGl1bS1tYXAiIGlkPSJtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMiID48L2Rpdj4KICAgICAgICAKPC9ib2R5Pgo8c2NyaXB0PiAgICAKICAgIAogICAgICAgICAgICB2YXIgbWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjID0gTC5tYXAoCiAgICAgICAgICAgICAgICAibWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjIiwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBjZW50ZXI6IFs0My42NTM5NjMsIC03OS4zODcyMDddLAogICAgICAgICAgICAgICAgICAgIGNyczogTC5DUlMuRVBTRzM4NTcsCiAgICAgICAgICAgICAgICAgICAgem9vbTogMTEsCiAgICAgICAgICAgICAgICAgICAgem9vbUNvbnRyb2w6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgcHJlZmVyQ2FudmFzOiBmYWxzZSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIAoKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl85NTIyNTM5NDQ1N2I0MzhiODkyMzQxMDViNjA2ZWJhNCA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgImh0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nIiwKICAgICAgICAgICAgICAgIHsiYXR0cmlidXRpb24iOiAiRGF0YSBieSBcdTAwMjZjb3B5OyBcdTAwM2NhIGhyZWY9XCJodHRwOi8vb3BlbnN0cmVldG1hcC5vcmdcIlx1MDAzZU9wZW5TdHJlZXRNYXBcdTAwM2MvYVx1MDAzZSwgdW5kZXIgXHUwMDNjYSBocmVmPVwiaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIlx1MDAzZU9EYkxcdTAwM2MvYVx1MDAzZS4iLCAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsICJtYXhOYXRpdmVab29tIjogMTgsICJtYXhab29tIjogMTgsICJtaW5ab29tIjogMCwgIm5vV3JhcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEsICJzdWJkb21haW5zIjogImFiYyIsICJ0bXMiOiBmYWxzZX0KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzBmZmIxMTk5YWVjNjRhMGFhM2FhMTVjZjNhMzZlNjI0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuODA2Njg2Mjk5OTk5OTk2LCAtNzkuMTk0MzUzNDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYWU2ZGNjZDFjMGM1NDM0MTliNjVkOGZjMDUzMDRjOTUgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzM1N2Y3YWI1ZTczYzRhOTFhNjY0NGEzNjZiZmFiNjIyID0gJChgPGRpdiBpZD0iaHRtbF8zNTdmN2FiNWU3M2M0YTkxYTY2NDRhMzY2YmZhYjYyMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Um91Z2UsIE1hbHZlcm4sIFNjYXJib3JvdWdoPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2FlNmRjY2QxYzBjNTQzNDE5YjY1ZDhmYzA1MzA0Yzk1LnNldENvbnRlbnQoaHRtbF8zNTdmN2FiNWU3M2M0YTkxYTY2NDRhMzY2YmZhYjYyMik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMGZmYjExOTlhZWM2NGEwYWEzYWExNWNmM2EzNmU2MjQuYmluZFBvcHVwKHBvcHVwX2FlNmRjY2QxYzBjNTQzNDE5YjY1ZDhmYzA1MzA0Yzk1KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81NGRjMGQ0ZTNhNGE0MjU3ODM2MjA4NzU2Mzc5ODUxMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc4NDUzNTEsIC03OS4xNjA0OTcwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wNzdhM2I4MGMzZjQ0OWY1OTRmMTQwM2I1YjcyOTI4OSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjkzZjY2OGU5YjRhNDllM2E3ZDRhYzNiZDg4NTM5NWIgPSAkKGA8ZGl2IGlkPSJodG1sXzY5M2Y2NjhlOWI0YTQ5ZTNhN2Q0YWMzYmQ4ODUzOTViIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IaWdobGFuZCBDcmVlaywgUm91Z2UgSGlsbCwgUG9ydCBVbmlvbiwgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMDc3YTNiODBjM2Y0NDlmNTk0ZjE0MDNiNWI3MjkyODkuc2V0Q29udGVudChodG1sXzY5M2Y2NjhlOWI0YTQ5ZTNhN2Q0YWMzYmQ4ODUzOTViKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl81NGRjMGQ0ZTNhNGE0MjU3ODM2MjA4NzU2Mzc5ODUxMi5iaW5kUG9wdXAocG9wdXBfMDc3YTNiODBjM2Y0NDlmNTk0ZjE0MDNiNWI3MjkyODkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM2ODA2NGIyZDcyYjRkMjE5N2UyMDE1Mjg3YWQ3ZTBmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzYzNTcyNiwgLTc5LjE4ODcxMTVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjY2ZTMwYmYwYmJjNDI3N2I2YzZhMmJmZWJjODU4MDkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzA3YmM2MTk0Yjk1NzRmNGNiZjViMzA2ODExOTNkNjQ2ID0gJChgPGRpdiBpZD0iaHRtbF8wN2JjNjE5NGI5NTc0ZjRjYmY1YjMwNjgxMTkzZDY0NiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+R3VpbGR3b29kLCBNb3JuaW5nc2lkZSwgV2VzdCBIaWxsLCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF82NjZlMzBiZjBiYmM0Mjc3YjZjNmEyYmZlYmM4NTgwOS5zZXRDb250ZW50KGh0bWxfMDdiYzYxOTRiOTU3NGY0Y2JmNWIzMDY4MTE5M2Q2NDYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzM2ODA2NGIyZDcyYjRkMjE5N2UyMDE1Mjg3YWQ3ZTBmLmJpbmRQb3B1cChwb3B1cF82NjZlMzBiZjBiYmM0Mjc3YjZjNmEyYmZlYmM4NTgwOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjRkYjFiOGE5OGE0NGM3NTgyYmE1N2Y2MTAyMjk1NTcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NzA5OTIxLCAtNzkuMjE2OTE3NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjQyMTdiMzM4MzEyNGM4Yzg3OGJkOTdmOGY5OTI2NGYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzlkOTM4OTJjNTM2OTRkN2JhMWY0OWUzMzNlMmM4Zjc1ID0gJChgPGRpdiBpZD0iaHRtbF85ZDkzODkyYzUzNjk0ZDdiYTFmNDllMzMzZTJjOGY3NSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V29idXJuLCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF82NDIxN2IzMzgzMTI0YzhjODc4YmQ5N2Y4Zjk5MjY0Zi5zZXRDb250ZW50KGh0bWxfOWQ5Mzg5MmM1MzY5NGQ3YmExZjQ5ZTMzM2UyYzhmNzUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2I0ZGIxYjhhOThhNDRjNzU4MmJhNTdmNjEwMjI5NTU3LmJpbmRQb3B1cChwb3B1cF82NDIxN2IzMzgzMTI0YzhjODc4YmQ5N2Y4Zjk5MjY0ZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNTVlY2FjYzAzODlmNGY4MTlmOGY2YjQ0ZTM5MzI5ZDggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NzMxMzYsIC03OS4yMzk0NzYwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wZDhjMDQ3OWQ3N2Q0YWIyYjQyNTcxM2NmNDlkMDI0YyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjc2M2ZlNzUyOWI1NDBjODljNTM4NTdkNzI0ZDU3ZWUgPSAkKGA8ZGl2IGlkPSJodG1sXzI3NjNmZTc1MjliNTQwYzg5YzUzODU3ZDcyNGQ1N2VlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DZWRhcmJyYWUsIFNjYXJib3JvdWdoPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzBkOGMwNDc5ZDc3ZDRhYjJiNDI1NzEzY2Y0OWQwMjRjLnNldENvbnRlbnQoaHRtbF8yNzYzZmU3NTI5YjU0MGM4OWM1Mzg1N2Q3MjRkNTdlZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNTVlY2FjYzAzODlmNGY4MTlmOGY2YjQ0ZTM5MzI5ZDguYmluZFBvcHVwKHBvcHVwXzBkOGMwNDc5ZDc3ZDRhYjJiNDI1NzEzY2Y0OWQwMjRjKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kNDBmNzY3OGU3MTU0MWJhOWI5OWI0OGUxNGE5ZWM0ZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc0NDczNDIsIC03OS4yMzk0NzYwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kOGU1MjQ1YWU4ODI0OWI1YTM4NGQwYjdkZDA4OWVmNSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOWZjNTMwMzY2MTM1NGYxYTg2YTdmNWE5MGNiZWRmZWEgPSAkKGA8ZGl2IGlkPSJodG1sXzlmYzUzMDM2NjEzNTRmMWE4NmE3ZjVhOTBjYmVkZmVhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TY2FyYm9yb3VnaCBWaWxsYWdlLCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kOGU1MjQ1YWU4ODI0OWI1YTM4NGQwYjdkZDA4OWVmNS5zZXRDb250ZW50KGh0bWxfOWZjNTMwMzY2MTM1NGYxYTg2YTdmNWE5MGNiZWRmZWEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2Q0MGY3Njc4ZTcxNTQxYmE5Yjk5YjQ4ZTE0YTllYzRlLmJpbmRQb3B1cChwb3B1cF9kOGU1MjQ1YWU4ODI0OWI1YTM4NGQwYjdkZDA4OWVmNSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWYyZWFkZmEyYjc0NGI5ZWE2YjQwZjE0ZmQ3MGE3ODggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Mjc5MjkyLCAtNzkuMjYyMDI5NDAwMDAwMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzM5MzkzMmZmOGY4NDc3ZDg2MjVkMjc3NmFiY2VhYmIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzBiMzVjZGUzZDYxOTQxOWE5MzEyZTViY2M2N2ZkMDU5ID0gJChgPGRpdiBpZD0iaHRtbF8wYjM1Y2RlM2Q2MTk0MTlhOTMxMmU1YmNjNjdmZDA1OSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RWFzdCBCaXJjaG1vdW50IFBhcmssIElvbnZpZXcsIEtlbm5lZHkgUGFyaywgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNzM5MzkzMmZmOGY4NDc3ZDg2MjVkMjc3NmFiY2VhYmIuc2V0Q29udGVudChodG1sXzBiMzVjZGUzZDYxOTQxOWE5MzEyZTViY2M2N2ZkMDU5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8xZjJlYWRmYTJiNzQ0YjllYTZiNDBmMTRmZDcwYTc4OC5iaW5kUG9wdXAocG9wdXBfNzM5MzkzMmZmOGY4NDc3ZDg2MjVkMjc3NmFiY2VhYmIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzJhNmIxMzEyNmVjZTQ2NGRiMjQ5ODJmYzUwYTMzMDQ1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzExMTExNzAwMDAwMDA0LCAtNzkuMjg0NTc3Ml0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9lNThhNGJiODUzNGQ0MGQzODgwMGVhOWRiYWVmMTUzOCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNTg1NDA5MjUxYTZjNDYwNGE0MDg2MWViODA5ZTFlNjYgPSAkKGA8ZGl2IGlkPSJodG1sXzU4NTQwOTI1MWE2YzQ2MDRhNDA4NjFlYjgwOWUxZTY2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbGFpcmxlYSwgR29sZGVuIE1pbGUsIE9ha3JpZGdlLCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9lNThhNGJiODUzNGQ0MGQzODgwMGVhOWRiYWVmMTUzOC5zZXRDb250ZW50KGh0bWxfNTg1NDA5MjUxYTZjNDYwNGE0MDg2MWViODA5ZTFlNjYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzJhNmIxMzEyNmVjZTQ2NGRiMjQ5ODJmYzUwYTMzMDQ1LmJpbmRQb3B1cChwb3B1cF9lNThhNGJiODUzNGQ0MGQzODgwMGVhOWRiYWVmMTUzOCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMDEzN2EwNzc0OTQ1NDFmODljM2E4YjZkODZiNmQ3NmQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTYzMTYsIC03OS4yMzk0NzYwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80MDE1YzRjY2VhODQ0OGNiYTViYTU0YzYyMmU2Njk3NSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNzUwMDFhZTMxMTM0NDIzY2I3MDdjZjI3ZjU0NDYxODQgPSAkKGA8ZGl2IGlkPSJodG1sXzc1MDAxYWUzMTEzNDQyM2NiNzA3Y2YyN2Y1NDQ2MTg0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbGlmZmNyZXN0LCBDbGlmZnNpZGUsIFNjYXJib3JvdWdoIFZpbGxhZ2UgV2VzdCwgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNDAxNWM0Y2NlYTg0NDhjYmE1YmE1NGM2MjJlNjY5NzUuc2V0Q29udGVudChodG1sXzc1MDAxYWUzMTEzNDQyM2NiNzA3Y2YyN2Y1NDQ2MTg0KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8wMTM3YTA3NzQ5NDU0MWY4OWMzYThiNmQ4NmI2ZDc2ZC5iaW5kUG9wdXAocG9wdXBfNDAxNWM0Y2NlYTg0NDhjYmE1YmE1NGM2MjJlNjY5NzUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzViY2E1MjE5M2QxYzRiMjE5NzE4MTQ3MDZjMDBkN2Q0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjkyNjU3MDAwMDAwMDA0LCAtNzkuMjY0ODQ4MV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8xY2RiYmNlMTU5OWY0Zjk4YjYxYzA1ZDg4YTA2NzQ2MyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYWEwNzlmMTY2NjhmNDk3Mjg2ZWI3MjA2ZGEzMDNkNDYgPSAkKGA8ZGl2IGlkPSJodG1sX2FhMDc5ZjE2NjY4ZjQ5NzI4NmViNzIwNmRhMzAzZDQ2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CaXJjaCBDbGlmZiwgQ2xpZmZzaWRlIFdlc3QsIFNjYXJib3JvdWdoPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzFjZGJiY2UxNTk5ZjRmOThiNjFjMDVkODhhMDY3NDYzLnNldENvbnRlbnQoaHRtbF9hYTA3OWYxNjY2OGY0OTcyODZlYjcyMDZkYTMwM2Q0Nik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNWJjYTUyMTkzZDFjNGIyMTk3MTgxNDcwNmMwMGQ3ZDQuYmluZFBvcHVwKHBvcHVwXzFjZGJiY2UxNTk5ZjRmOThiNjFjMDVkODhhMDY3NDYzKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85MTAzZGU3NmJlMDg0M2I2OTNkNjI5ZTAzOThmNjIxYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1NzQwOTYsIC03OS4yNzMzMDQwMDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kOTAyMDdkMGNjZmI0MzU2OWQwYjlkODczZmZhYTYyOSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfN2ZiZjhjNTk4MzE4NDMzNzg2NmI2Njg3YTViYThlZmUgPSAkKGA8ZGl2IGlkPSJodG1sXzdmYmY4YzU5ODMxODQzMzc4NjZiNjY4N2E1YmE4ZWZlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3JzZXQgUGFyaywgU2NhcmJvcm91Z2ggVG93biBDZW50cmUsIFdleGZvcmQgSGVpZ2h0cywgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZDkwMjA3ZDBjY2ZiNDM1NjlkMGI5ZDg3M2ZmYWE2Mjkuc2V0Q29udGVudChodG1sXzdmYmY4YzU5ODMxODQzMzc4NjZiNjY4N2E1YmE4ZWZlKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85MTAzZGU3NmJlMDg0M2I2OTNkNjI5ZTAzOThmNjIxYy5iaW5kUG9wdXAocG9wdXBfZDkwMjA3ZDBjY2ZiNDM1NjlkMGI5ZDg3M2ZmYWE2MjkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzQ1MDhhYWY0MmZkYTQwODViNzVmYTFhNzU3NzEyZThiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzUwMDcxNTAwMDAwMDA0LCAtNzkuMjk1ODQ5MV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85MTZlNGZjMGYxNTg0ZWU2YWVkNDc3M2ZkN2NjZTlhNSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMmQ2ODBlMGYxNmNkNDQ4MTk5YjFkZDA4NDE3ZGViYWIgPSAkKGA8ZGl2IGlkPSJodG1sXzJkNjgwZTBmMTZjZDQ0ODE5OWIxZGQwODQxN2RlYmFiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5NYXJ5dmFsZSwgV2V4Zm9yZCwgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTE2ZTRmYzBmMTU4NGVlNmFlZDQ3NzNmZDdjY2U5YTUuc2V0Q29udGVudChodG1sXzJkNjgwZTBmMTZjZDQ0ODE5OWIxZGQwODQxN2RlYmFiKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl80NTA4YWFmNDJmZGE0MDg1Yjc1ZmExYTc1NzcxMmU4Yi5iaW5kUG9wdXAocG9wdXBfOTE2ZTRmYzBmMTU4NGVlNmFlZDQ3NzNmZDdjY2U5YTUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM2NjYyMTVmYmU2ODQ2OTg4NWZkYzU3NTRlNTM0NTU5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzk0MjAwMywgLTc5LjI2MjAyOTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzQxZWI0NTAwNjU5MjQxZjE5ZjBiMDQ2NzQyMWU1NTgxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82YTk2Y2VmYTBjNDg0ZjVhYTQ4NzIxODlkYTZmMTI2NCA9ICQoYDxkaXYgaWQ9Imh0bWxfNmE5NmNlZmEwYzQ4NGY1YWE0ODcyMTg5ZGE2ZjEyNjQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkFnaW5jb3VydCwgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNDFlYjQ1MDA2NTkyNDFmMTlmMGIwNDY3NDIxZTU1ODEuc2V0Q29udGVudChodG1sXzZhOTZjZWZhMGM0ODRmNWFhNDg3MjE4OWRhNmYxMjY0KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zNjY2MjE1ZmJlNjg0Njk4ODVmZGM1NzU0ZTUzNDU1OS5iaW5kUG9wdXAocG9wdXBfNDFlYjQ1MDA2NTkyNDFmMTlmMGIwNDY3NDIxZTU1ODEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzljNWU1NmFhMThmNjRiOTJhNTJkZTdmMTdhZGYwOGZjID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzgxNjM3NSwgLTc5LjMwNDMwMjFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNDUyOWM5ZGE4OTE0NDI2YjllZTI4NjgzYWEyOWNmNTEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzY4NjU2YzBlMGRjODQ2MTM5ZjdkOGMzY2U1MTRmNTNlID0gJChgPGRpdiBpZD0iaHRtbF82ODY1NmMwZTBkYzg0NjEzOWY3ZDhjM2NlNTE0ZjUzZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2xhcmtzIENvcm5lcnMsIFN1bGxpdmFuLCBUYW0gTyYjMzk7U2hhbnRlciwgU2NhcmJvcm91Z2g8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNDUyOWM5ZGE4OTE0NDI2YjllZTI4NjgzYWEyOWNmNTEuc2V0Q29udGVudChodG1sXzY4NjU2YzBlMGRjODQ2MTM5ZjdkOGMzY2U1MTRmNTNlKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85YzVlNTZhYTE4ZjY0YjkyYTUyZGU3ZjE3YWRmMDhmYy5iaW5kUG9wdXAocG9wdXBfNDUyOWM5ZGE4OTE0NDI2YjllZTI4NjgzYWEyOWNmNTEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NmZDRhZjAyMzUxMDRmYWViYzU4YTU1OTYwNzU5ZmY5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuODE1MjUyMiwgLTc5LjI4NDU3NzJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfM2ZjZjYwMmIxNmMzNDIyY2FmY2UwNjZhNzJlZTk2ZTMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzkwMGQzZDk5NjU1MTRiOTA5OGRmNzM5MTBjY2FjYzhlID0gJChgPGRpdiBpZD0iaHRtbF85MDBkM2Q5OTY1NTE0YjkwOThkZjczOTEwY2NhY2M4ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QWdpbmNvdXJ0IE5vcnRoLCBMJiMzOTtBbW9yZWF1eCBFYXN0LCBNaWxsaWtlbiwgU3RlZWxlcyBFYXN0LCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zZmNmNjAyYjE2YzM0MjJjYWZjZTA2NmE3MmVlOTZlMy5zZXRDb250ZW50KGh0bWxfOTAwZDNkOTk2NTUxNGI5MDk4ZGY3MzkxMGNjYWNjOGUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2NmZDRhZjAyMzUxMDRmYWViYzU4YTU1OTYwNzU5ZmY5LmJpbmRQb3B1cChwb3B1cF8zZmNmNjAyYjE2YzM0MjJjYWZjZTA2NmE3MmVlOTZlMykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDkwMjA5NDAwODE5NGE5ODllNGM2YTY4OTY4OTdkODMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43OTk1MjUyMDAwMDAwMDUsIC03OS4zMTgzODg3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2Q3NjgxMzRiM2UxZTQwMmVhNzA2NTBiMTE2NzI1ZDdmID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMmNkNDIzMDBmMGE0Y2Q5YjM2NGY3OTVkZjFiOTUyNiA9ICQoYDxkaXYgaWQ9Imh0bWxfZjJjZDQyMzAwZjBhNGNkOWIzNjRmNzk1ZGYxYjk1MjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkwmIzM5O0Ftb3JlYXV4IFdlc3QsIFNjYXJib3JvdWdoPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2Q3NjgxMzRiM2UxZTQwMmVhNzA2NTBiMTE2NzI1ZDdmLnNldENvbnRlbnQoaHRtbF9mMmNkNDIzMDBmMGE0Y2Q5YjM2NGY3OTVkZjFiOTUyNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDkwMjA5NDAwODE5NGE5ODllNGM2YTY4OTY4OTdkODMuYmluZFBvcHVwKHBvcHVwX2Q3NjgxMzRiM2UxZTQwMmVhNzA2NTBiMTE2NzI1ZDdmKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jMWU2OTM5NmJjOTI0MjIwYmE2ZmVkZWUxMGM2NjAxNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjgzNjEyNDcwMDAwMDAwNiwgLTc5LjIwNTYzNjA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2ZjYTlkNzIzZWI1ZjQ5YmU4MDhjZjlmZTBjM2RhY2U0ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF83MjI2YTRkMmUyYTI0MmU4ODc0NTgzYjlhMDhlNzYyYSA9ICQoYDxkaXYgaWQ9Imh0bWxfNzIyNmE0ZDJlMmEyNDJlODg3NDU4M2I5YTA4ZTc2MmEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlVwcGVyIFJvdWdlLCBTY2FyYm9yb3VnaDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9mY2E5ZDcyM2ViNWY0OWJlODA4Y2Y5ZmUwYzNkYWNlNC5zZXRDb250ZW50KGh0bWxfNzIyNmE0ZDJlMmEyNDJlODg3NDU4M2I5YTA4ZTc2MmEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2MxZTY5Mzk2YmM5MjQyMjBiYTZmZWRlZTEwYzY2MDE2LmJpbmRQb3B1cChwb3B1cF9mY2E5ZDcyM2ViNWY0OWJlODA4Y2Y5ZmUwYzNkYWNlNCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNmU3MTAwYTM4YzYzNDczNmEyMDNjNGU1MzMzYWMxYTQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My44MDM3NjIyLCAtNzkuMzYzNDUxN10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8xMzU1Y2NmM2E4M2M0M2FkYTFjYWEzNjgxNTRhM2NiZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYWEwYjdlM2FmNzUxNDU0ODgwMmY3OGMzZmQ3OTlmY2YgPSAkKGA8ZGl2IGlkPSJodG1sX2FhMGI3ZTNhZjc1MTQ1NDg4MDJmNzhjM2ZkNzk5ZmNmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IaWxsY3Jlc3QgVmlsbGFnZSwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xMzU1Y2NmM2E4M2M0M2FkYTFjYWEzNjgxNTRhM2NiZC5zZXRDb250ZW50KGh0bWxfYWEwYjdlM2FmNzUxNDU0ODgwMmY3OGMzZmQ3OTlmY2YpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzZlNzEwMGEzOGM2MzQ3MzZhMjAzYzRlNTMzM2FjMWE0LmJpbmRQb3B1cChwb3B1cF8xMzU1Y2NmM2E4M2M0M2FkYTFjYWEzNjgxNTRhM2NiZCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNjNiZjkzMTE0NGVkNGJmMWExNWJhYmQxZmRmYzdkNmUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Nzg1MTc1LCAtNzkuMzQ2NTU1N10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9iYWQxMmQ4Zjk2ODI0YzkzOWRkMGJiMzc2NTY2NGE3NiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYTYyOTBiMDliNjJjNDc2MThjN2QwOTI5OTlmMzIxMDMgPSAkKGA8ZGl2IGlkPSJodG1sX2E2MjkwYjA5YjYyYzQ3NjE4YzdkMDkyOTk5ZjMyMTAzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5GYWlydmlldywgSGVucnkgRmFybSwgT3Jpb2xlLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2JhZDEyZDhmOTY4MjRjOTM5ZGQwYmIzNzY1NjY0YTc2LnNldENvbnRlbnQoaHRtbF9hNjI5MGIwOWI2MmM0NzYxOGM3ZDA5Mjk5OWYzMjEwMyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNjNiZjkzMTE0NGVkNGJmMWExNWJhYmQxZmRmYzdkNmUuYmluZFBvcHVwKHBvcHVwX2JhZDEyZDhmOTY4MjRjOTM5ZGQwYmIzNzY1NjY0YTc2KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81NzFhOTczYTgzYmI0ZmVhYTI4YWRjZjNhM2JiNzc0MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc4Njk0NzMsIC03OS4zODU5NzVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOWJkMWE5NWIzYjg3NGI0MzkwNDA2YmQyZDYxYWUyYmUgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzFhOTIzOTU4MGFlZjQ1MWU5YmUxZDhjZDIyMjE0ZGFlID0gJChgPGRpdiBpZD0iaHRtbF8xYTkyMzk1ODBhZWY0NTFlOWJlMWQ4Y2QyMjIxNGRhZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QmF5dmlldyBWaWxsYWdlLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzliZDFhOTViM2I4NzRiNDM5MDQwNmJkMmQ2MWFlMmJlLnNldENvbnRlbnQoaHRtbF8xYTkyMzk1ODBhZWY0NTFlOWJlMWQ4Y2QyMjIxNGRhZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNTcxYTk3M2E4M2JiNGZlYWEyOGFkY2YzYTNiYjc3NDEuYmluZFBvcHVwKHBvcHVwXzliZDFhOTViM2I4NzRiNDM5MDQwNmJkMmQ2MWFlMmJlKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zYzZiZTZiNTIxZmQ0ZDBmOGE2ODlhMmJlNDhmNmQzMCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1NzQ5MDIsIC03OS4zNzQ3MTQwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82OGU2YzBiMTkwOWE0ODU5OWI0NTljMTQ3NDE5YWY4MiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNTBkM2M0NTJiM2YyNDVkOGE3M2Y3MGM4ZTY3ZmU5NWMgPSAkKGA8ZGl2IGlkPSJodG1sXzUwZDNjNDUyYjNmMjQ1ZDhhNzNmNzBjOGU2N2ZlOTVjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TaWx2ZXIgSGlsbHMsIFlvcmsgTWlsbHMsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjhlNmMwYjE5MDlhNDg1OTliNDU5YzE0NzQxOWFmODIuc2V0Q29udGVudChodG1sXzUwZDNjNDUyYjNmMjQ1ZDhhNzNmNzBjOGU2N2ZlOTVjKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zYzZiZTZiNTIxZmQ0ZDBmOGE2ODlhMmJlNDhmNmQzMC5iaW5kUG9wdXAocG9wdXBfNjhlNmMwYjE5MDlhNDg1OTliNDU5YzE0NzQxOWFmODIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzk3NDc1MjNlODAwYjQxOTg5ZThhY2E3YmFlOTA3ODRhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzg5MDUzLCAtNzkuNDA4NDkyNzk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZDcyZjM0ZDIwNzg4NDc2YzkzZDlmNTllODNlNjlkZWYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2RjMzk5ZmRmMTA1MjRjN2M5MTcwY2VmM2U3YzJhYjljID0gJChgPGRpdiBpZD0iaHRtbF9kYzM5OWZkZjEwNTI0YzdjOTE3MGNlZjNlN2MyYWI5YyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TmV3dG9uYnJvb2ssIFdpbGxvd2RhbGUsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZDcyZjM0ZDIwNzg4NDc2YzkzZDlmNTllODNlNjlkZWYuc2V0Q29udGVudChodG1sX2RjMzk5ZmRmMTA1MjRjN2M5MTcwY2VmM2U3YzJhYjljKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85NzQ3NTIzZTgwMGI0MTk4OWU4YWNhN2JhZTkwNzg0YS5iaW5kUG9wdXAocG9wdXBfZDcyZjM0ZDIwNzg4NDc2YzkzZDlmNTllODNlNjlkZWYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM0OTM5ZjkwYzE3NDQ1NTk5NWExNjhlMjIzMjI3ZDQwID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzcwMTE5OSwgLTc5LjQwODQ5Mjc5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzJjOWU1NzUzN2JiZTQ4YjQ5MDI3MmVkNmU1MTI5MDgwID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9hNDYyNTdhYmVjNjY0ZDc5OGRjMTYwNTI0MzA0ZjNjNSA9ICQoYDxkaXYgaWQ9Imh0bWxfYTQ2MjU3YWJlYzY2NGQ3OThkYzE2MDUyNDMwNGYzYzUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldpbGxvd2RhbGUgU291dGgsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMmM5ZTU3NTM3YmJlNDhiNDkwMjcyZWQ2ZTUxMjkwODAuc2V0Q29udGVudChodG1sX2E0NjI1N2FiZWM2NjRkNzk4ZGMxNjA1MjQzMDRmM2M1KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zNDkzOWY5MGMxNzQ0NTU5OTVhMTY4ZTIyMzIyN2Q0MC5iaW5kUG9wdXAocG9wdXBfMmM5ZTU3NTM3YmJlNDhiNDkwMjcyZWQ2ZTUxMjkwODApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzVkZmI0NzY4MWVhNDQ5ZTBiY2Y5NTJiMzY5Zjc0ZmVjID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzUyNzU4Mjk5OTk5OTk2LCAtNzkuNDAwMDQ5M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82ODM0NWUxNjY2YzY0ZjY1ODM2MmNjN2ZmYjc2NWM1NiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMzVkNzdhZmQxZjJhNDZjMDkzZjcyMmZmNTdhNjQ0NGUgPSAkKGA8ZGl2IGlkPSJodG1sXzM1ZDc3YWZkMWYyYTQ2YzA5M2Y3MjJmZjU3YTY0NDRlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Zb3JrIE1pbGxzIFdlc3QsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjgzNDVlMTY2NmM2NGY2NTgzNjJjYzdmZmI3NjVjNTYuc2V0Q29udGVudChodG1sXzM1ZDc3YWZkMWYyYTQ2YzA5M2Y3MjJmZjU3YTY0NDRlKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl81ZGZiNDc2ODFlYTQ0OWUwYmNmOTUyYjM2OWY3NGZlYy5iaW5kUG9wdXAocG9wdXBfNjgzNDVlMTY2NmM2NGY2NTgzNjJjYzdmZmI3NjVjNTYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzhhYjVhZTA4M2I3NDQ3NThiYWM3ZGVjMzcxYTA0ODI3ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzgyNzM2NCwgLTc5LjQ0MjI1OTNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzAyMTgzMjkyZWRhNGNiNjhhZGQxYjZkMGY2MWU1MDQgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2NjODkzMjA3YWQyZTQxZDNiYjNlM2JmYjA3OWU5NDQxID0gJChgPGRpdiBpZD0iaHRtbF9jYzg5MzIwN2FkMmU0MWQzYmIzZTNiZmIwNzllOTQ0MSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2lsbG93ZGFsZSBXZXN0LCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzcwMjE4MzI5MmVkYTRjYjY4YWRkMWI2ZDBmNjFlNTA0LnNldENvbnRlbnQoaHRtbF9jYzg5MzIwN2FkMmU0MWQzYmIzZTNiZmIwNzllOTQ0MSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfOGFiNWFlMDgzYjc0NDc1OGJhYzdkZWMzNzFhMDQ4MjcuYmluZFBvcHVwKHBvcHVwXzcwMjE4MzI5MmVkYTRjYjY4YWRkMWI2ZDBmNjFlNTA0KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hNjE5NDk1NmRkYjA0OTQ3ODlkMmRhMmJmNzhjNzkzMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1MzI1ODYsIC03OS4zMjk2NTY1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzAxODUwNTYxOGM4MzQzYmNhMDcwODI4NmU5MGFhZGU5ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF83Yzg3YTQ3NmM1MGU0MDQ5OThiMGUwN2ZlNTcyNTJhZSA9ICQoYDxkaXYgaWQ9Imh0bWxfN2M4N2E0NzZjNTBlNDA0OTk4YjBlMDdmZTU3MjUyYWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlBhcmt3b29kcywgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8wMTg1MDU2MThjODM0M2JjYTA3MDgyODZlOTBhYWRlOS5zZXRDb250ZW50KGh0bWxfN2M4N2E0NzZjNTBlNDA0OTk4YjBlMDdmZTU3MjUyYWUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2E2MTk0OTU2ZGRiMDQ5NDc4OWQyZGEyYmY3OGM3OTMyLmJpbmRQb3B1cChwb3B1cF8wMTg1MDU2MThjODM0M2JjYTA3MDgyODZlOTBhYWRlOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMGJkNmE1N2M4MjVlNGFmNzlhOTFjMTc0YTA2NDk2MDQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NDU5MDU3OTk5OTk5OTYsIC03OS4zNTIxODhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMDc0YjhlMmNhMzI3NDI3M2E3YTg1MDA0YzA1Mjg4OGEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzY1Yjg0MzY4MzFhYTRiNmNiMzk5YzA5MzYxOTE3Y2IzID0gJChgPGRpdiBpZD0iaHRtbF82NWI4NDM2ODMxYWE0YjZjYjM5OWMwOTM2MTkxN2NiMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG9uIE1pbGxzIE5vcnRoLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzA3NGI4ZTJjYTMyNzQyNzNhN2E4NTAwNGMwNTI4ODhhLnNldENvbnRlbnQoaHRtbF82NWI4NDM2ODMxYWE0YjZjYjM5OWMwOTM2MTkxN2NiMyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMGJkNmE1N2M4MjVlNGFmNzlhOTFjMTc0YTA2NDk2MDQuYmluZFBvcHVwKHBvcHVwXzA3NGI4ZTJjYTMyNzQyNzNhN2E4NTAwNGMwNTI4ODhhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81NTgyNzljZTIzYWU0MjY3YjJmMzY5Mzk2NmQyMjI0MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcyNTg5OTcwMDAwMDAxLCAtNzkuMzQwOTIzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2JjYWNiMmRkYzY3NDQwMThiNGI3N2RmNGMzZTczNGM3ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82YWQzNDRmMWZmOWM0YTUyYjVmZTRiMjM0NWJhNjJmYSA9ICQoYDxkaXYgaWQ9Imh0bWxfNmFkMzQ0ZjFmZjljNGE1MmI1ZmU0YjIzNDViYTYyZmEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkZsZW1pbmdkb24gUGFyaywgRG9uIE1pbGxzIFNvdXRoLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2JjYWNiMmRkYzY3NDQwMThiNGI3N2RmNGMzZTczNGM3LnNldENvbnRlbnQoaHRtbF82YWQzNDRmMWZmOWM0YTUyYjVmZTRiMjM0NWJhNjJmYSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNTU4Mjc5Y2UyM2FlNDI2N2IyZjM2OTM5NjZkMjIyNDEuYmluZFBvcHVwKHBvcHVwX2JjYWNiMmRkYzY3NDQwMThiNGI3N2RmNGMzZTczNGM3KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wYzVlZjBhNTFjNTI0MGY3OTg3ZTUxMGU5ZTk1NDI3YiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1NDMyODMsIC03OS40NDIyNTkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzdhMWNjZWI2Mjc1MjRmMTlhYTA2YWRiY2Y4YWNmZjUxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8xZjY3Zjc3ODZlZmI0Y2U1YTA3MDEwMmUyZDg5NTY1NiA9ICQoYDxkaXYgaWQ9Imh0bWxfMWY2N2Y3Nzg2ZWZiNGNlNWEwNzAxMDJlMmQ4OTU2NTYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJhdGh1cnN0IE1hbm9yLCBEb3duc3ZpZXcgTm9ydGgsIFdpbHNvbiBIZWlnaHRzLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzdhMWNjZWI2Mjc1MjRmMTlhYTA2YWRiY2Y4YWNmZjUxLnNldENvbnRlbnQoaHRtbF8xZjY3Zjc3ODZlZmI0Y2U1YTA3MDEwMmUyZDg5NTY1Nik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMGM1ZWYwYTUxYzUyNDBmNzk4N2U1MTBlOWU5NTQyN2IuYmluZFBvcHVwKHBvcHVwXzdhMWNjZWI2Mjc1MjRmMTlhYTA2YWRiY2Y4YWNmZjUxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kMzJmOTg0NWIzZmU0MzljODdiMmY5YTE1MmYzODkxNSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc2Nzk4MDMsIC03OS40ODcyNjE5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yOTIwMDkzZGE4NTc0NTQwOTNlZjk3ZTQ5YjMwNWNhNyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjAxZGRlYjI5ZTYzNGRmZWJiZjk3NzQ5YzJlZTljN2YgPSAkKGA8ZGl2IGlkPSJodG1sXzIwMWRkZWIyOWU2MzRkZmViYmY5Nzc0OWMyZWU5YzdmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ob3J0aHdvb2QgUGFyaywgWW9yayBVbml2ZXJzaXR5LCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzI5MjAwOTNkYTg1NzQ1NDA5M2VmOTdlNDliMzA1Y2E3LnNldENvbnRlbnQoaHRtbF8yMDFkZGViMjllNjM0ZGZlYmJmOTc3NDljMmVlOWM3Zik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZDMyZjk4NDViM2ZlNDM5Yzg3YjJmOWExNTJmMzg5MTUuYmluZFBvcHVwKHBvcHVwXzI5MjAwOTNkYTg1NzQ1NDA5M2VmOTdlNDliMzA1Y2E3KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iYTcwNGYwZTdkMTA0YWI5YmM4MzI3M2NkZTJmMDY2ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjczNzQ3MzIwMDAwMDAwNCwgLTc5LjQ2NDc2MzI5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzE2ZjhiMTE0YTJkOTQ2MWQ4MGE4NGY5YjcxNmJlNWE5ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82MmY5MzYzZWQ2NzI0ZThiYjhlNzFhMGQ3NTRkMTQ1ZSA9ICQoYDxkaXYgaWQ9Imh0bWxfNjJmOTM2M2VkNjcyNGU4YmI4ZTcxYTBkNzU0ZDE0NWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNGQiBUb3JvbnRvLCBEb3duc3ZpZXcgRWFzdCwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xNmY4YjExNGEyZDk0NjFkODBhODRmOWI3MTZiZTVhOS5zZXRDb250ZW50KGh0bWxfNjJmOTM2M2VkNjcyNGU4YmI4ZTcxYTBkNzU0ZDE0NWUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2JhNzA0ZjBlN2QxMDRhYjliYzgzMjczY2RlMmYwNjZkLmJpbmRQb3B1cChwb3B1cF8xNmY4YjExNGEyZDk0NjFkODBhODRmOWI3MTZiZTVhOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWI4YTYxM2E4YTY0NDMwODljZmYyYjdmMDRhMTMyNGEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MzkwMTQ2LCAtNzkuNTA2OTQzNl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yYWUzYjY2ZWEzZTg0YzUxYTIwNDY2OTE0MmFmMTRmZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjI2OGM3MDdmYjBiNDAzNWJhMWY4ZjU3NzdjN2Q0MDUgPSAkKGA8ZGl2IGlkPSJodG1sXzIyNjhjNzA3ZmIwYjQwMzViYTFmOGY1Nzc3YzdkNDA1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3duc3ZpZXcgV2VzdCwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yYWUzYjY2ZWEzZTg0YzUxYTIwNDY2OTE0MmFmMTRmZS5zZXRDb250ZW50KGh0bWxfMjI2OGM3MDdmYjBiNDAzNWJhMWY4ZjU3NzdjN2Q0MDUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzFiOGE2MTNhOGE2NDQzMDg5Y2ZmMmI3ZjA0YTEzMjRhLmJpbmRQb3B1cChwb3B1cF8yYWUzYjY2ZWEzZTg0YzUxYTIwNDY2OTE0MmFmMTRmZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDA0NGE3YmFjNTlmNDRhODllNGY3MmY1ODlhYzI1OGEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Mjg0OTY0LCAtNzkuNDk1Njk3NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYzM0MTdmM2VlNGJjNGU0ZmI0OWUyMWFkNjI2MWZlMTcgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2ZiZmJmMWU0NWE1ZTQzYzU4NmJkMDJiZmU3YjgwZWFmID0gJChgPGRpdiBpZD0iaHRtbF9mYmZiZjFlNDVhNWU0M2M1ODZiZDAyYmZlN2I4MGVhZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnN2aWV3IENlbnRyYWwsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYzM0MTdmM2VlNGJjNGU0ZmI0OWUyMWFkNjI2MWZlMTcuc2V0Q29udGVudChodG1sX2ZiZmJmMWU0NWE1ZTQzYzU4NmJkMDJiZmU3YjgwZWFmKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kMDQ0YTdiYWM1OWY0NGE4OWU0ZjcyZjU4OWFjMjU4YS5iaW5kUG9wdXAocG9wdXBfYzM0MTdmM2VlNGJjNGU0ZmI0OWUyMWFkNjI2MWZlMTcpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2M5NzVlOTE0NjE3NTRmY2ZhNGYxNTE1Mzc2YjI0YTRhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzYxNjMxMywgLTc5LjUyMDk5OTQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzJkZWYwYTdmYjdhYzQ3ZjQ4OTU5NTk1Nzk1MTc2ZmNkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9kY2E3MjMxZGNlNWE0ZjcyYWYyOTVkNjdlZjBiNjlhMiA9ICQoYDxkaXYgaWQ9Imh0bWxfZGNhNzIzMWRjZTVhNGY3MmFmMjk1ZDY3ZWYwYjY5YTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd25zdmlldyBOb3J0aHdlc3QsIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMmRlZjBhN2ZiN2FjNDdmNDg5NTk1OTU3OTUxNzZmY2Quc2V0Q29udGVudChodG1sX2RjYTcyMzFkY2U1YTRmNzJhZjI5NWQ2N2VmMGI2OWEyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9jOTc1ZTkxNDYxNzU0ZmNmYTRmMTUxNTM3NmIyNGE0YS5iaW5kUG9wdXAocG9wdXBfMmRlZjBhN2ZiN2FjNDdmNDg5NTk1OTU3OTUxNzZmY2QpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzZiOTQ5MTYxMDkwNjRiZGE4ZjdhMTU3MmRjNGQ4Nzg1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzI1ODgyMjk5OTk5OTk1LCAtNzkuMzE1NTcxNTk5OTk5OThdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNTZlODUzZTJjM2IxNDkwYWIyNDA4MzcyYWY5NGQ0NjMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzM1MzQyMzA5YjYxYzQ2ZmFhMDI4ZWM3NDdlMjQyM2YyID0gJChgPGRpdiBpZD0iaHRtbF8zNTM0MjMwOWI2MWM0NmZhYTAyOGVjNzQ3ZTI0MjNmMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VmljdG9yaWEgVmlsbGFnZSwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81NmU4NTNlMmMzYjE0OTBhYjI0MDgzNzJhZjk0ZDQ2My5zZXRDb250ZW50KGh0bWxfMzUzNDIzMDliNjFjNDZmYWEwMjhlYzc0N2UyNDIzZjIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzZiOTQ5MTYxMDkwNjRiZGE4ZjdhMTU3MmRjNGQ4Nzg1LmJpbmRQb3B1cChwb3B1cF81NmU4NTNlMmMzYjE0OTBhYjI0MDgzNzJhZjk0ZDQ2MykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGU5YzcxOTY5NjVhNGQzM2JkZDY4MzQ5Mjc3YWZiNjAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDYzOTcyLCAtNzkuMzA5OTM3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2M4MmQzNTI5NDI3NTRhOTQ5MzA3ZmEzMWExYmE4NzgyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMzAyNjdiNWZiOTE0NGJjYmU1MDVmYmY2ZTRhMzI4OCA9ICQoYDxkaXYgaWQ9Imh0bWxfZjMwMjY3YjVmYjkxNDRiY2JlNTA1ZmJmNmU0YTMyODgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldvb2RiaW5lIEdhcmRlbnMsIFBhcmt2aWV3IEhpbGwsIEVhc3QgWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9jODJkMzUyOTQyNzU0YTk0OTMwN2ZhMzFhMWJhODc4Mi5zZXRDb250ZW50KGh0bWxfZjMwMjY3YjVmYjkxNDRiY2JlNTA1ZmJmNmU0YTMyODgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzRlOWM3MTk2OTY1YTRkMzNiZGQ2ODM0OTI3N2FmYjYwLmJpbmRQb3B1cChwb3B1cF9jODJkMzUyOTQyNzU0YTk0OTMwN2ZhMzFhMWJhODc4MikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWM1MjU5MGQzNjBlNGRjN2FkYWIwYWFhYmUxNzcxMjYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42OTUzNDM5MDAwMDAwMDUsIC03OS4zMTgzODg3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzAyMGVjYWRhOTRkYjQ4NGU5NjBhODJiZTJkMmVjMmEzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8zM2JjYjJlZTA5OTA0NmVhYTRlMjA1MGUyODM2YmNjMiA9ICQoYDxkaXYgaWQ9Imh0bWxfMzNiY2IyZWUwOTkwNDZlYWE0ZTIwNTBlMjgzNmJjYzIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldvb2RiaW5lIEhlaWdodHMsIEVhc3QgWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8wMjBlY2FkYTk0ZGI0ODRlOTYwYTgyYmUyZDJlYzJhMy5zZXRDb250ZW50KGh0bWxfMzNiY2IyZWUwOTkwNDZlYWE0ZTIwNTBlMjgzNmJjYzIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2VjNTI1OTBkMzYwZTRkYzdhZGFiMGFhYWJlMTc3MTI2LmJpbmRQb3B1cChwb3B1cF8wMjBlY2FkYTk0ZGI0ODRlOTYwYTgyYmUyZDJlYzJhMykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYWE5Y2Y0NDhhOTg1NDkzYzljY2IwYTdhZDQ3OTM3NGYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NzYzNTczOTk5OTk5OSwgLTc5LjI5MzAzMTJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfM2M0ZjNmZDc4ZDU3NGU4OGIxNzMwZDk2NDQ3MmQ1NjEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzZiNjJkMGUwYjM0NDQ4MDJhOTgyZmI0NTZlNDRhNjEyID0gJChgPGRpdiBpZD0iaHRtbF82YjYyZDBlMGIzNDQ0ODAyYTk4MmZiNDU2ZTQ0YTYxMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEJlYWNoZXMsIEVhc3QgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zYzRmM2ZkNzhkNTc0ZTg4YjE3MzBkOTY0NDcyZDU2MS5zZXRDb250ZW50KGh0bWxfNmI2MmQwZTBiMzQ0NDgwMmE5ODJmYjQ1NmU0NGE2MTIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2FhOWNmNDQ4YTk4NTQ5M2M5Y2NiMGE3YWQ0NzkzNzRmLmJpbmRQb3B1cChwb3B1cF8zYzRmM2ZkNzhkNTc0ZTg4YjE3MzBkOTY0NDcyZDU2MSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNjU5NmExNDEyMjc2NDNjNzhhZTAzMzQyMGY4ZTZkZDEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDkwNjA0LCAtNzkuMzYzNDUxN10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83YzM2NmZhNmRiNjA0MmYwOGY5OTViNjVmMjhiODAzZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfM2NlMGFiNmQwYzRmNDFkMmEzYzBiOWJkM2Q1Y2VjOTggPSAkKGA8ZGl2IGlkPSJodG1sXzNjZTBhYjZkMGM0ZjQxZDJhM2MwYjliZDNkNWNlYzk4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5MZWFzaWRlLCBFYXN0IFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfN2MzNjZmYTZkYjYwNDJmMDhmOTk1YjY1ZjI4YjgwM2Uuc2V0Q29udGVudChodG1sXzNjZTBhYjZkMGM0ZjQxZDJhM2MwYjliZDNkNWNlYzk4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82NTk2YTE0MTIyNzY0M2M3OGFlMDMzNDIwZjhlNmRkMS5iaW5kUG9wdXAocG9wdXBfN2MzNjZmYTZkYjYwNDJmMDhmOTk1YjY1ZjI4YjgwM2UpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzA2YjI0MWJjNDI1YTRiYmRhMmM2M2IzMzljMmNlMmZmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzA1MzY4OSwgLTc5LjM0OTM3MTkwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzRmNjEwNjM1ODUxYjQ0YzBiOTVjNWJjMGUyYTkwZTJjID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82NTdlZWRkMzUzMmM0YjU4YTg5ZTAzOTQwYmY4Mjg1MyA9ICQoYDxkaXYgaWQ9Imh0bWxfNjU3ZWVkZDM1MzJjNGI1OGE4OWUwMzk0MGJmODI4NTMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRob3JuY2xpZmZlIFBhcmssIEVhc3QgWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80ZjYxMDYzNTg1MWI0NGMwYjk1YzViYzBlMmE5MGUyYy5zZXRDb250ZW50KGh0bWxfNjU3ZWVkZDM1MzJjNGI1OGE4OWUwMzk0MGJmODI4NTMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzA2YjI0MWJjNDI1YTRiYmRhMmM2M2IzMzljMmNlMmZmLmJpbmRQb3B1cChwb3B1cF80ZjYxMDYzNTg1MWI0NGMwYjk1YzViYzBlMmE5MGUyYykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzUxNmZkOTg3M2Q3NDRkZDg3NGY0OGQ1MGNkNDdiYjcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODUzNDcsIC03OS4zMzgxMDY1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzNiYTVmMGEzMTcwOTRlZDg5NDJmODAyMjc0YmFjZTNhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iYjM0YTcwMGIxNjk0ZWFlYTJiNjRiNTBjNWM1YTdjZCA9ICQoYDxkaXYgaWQ9Imh0bWxfYmIzNGE3MDBiMTY5NGVhZWEyYjY0YjUwYzVjNWE3Y2QiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgVG9yb250bywgRWFzdCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzNiYTVmMGEzMTcwOTRlZDg5NDJmODAyMjc0YmFjZTNhLnNldENvbnRlbnQoaHRtbF9iYjM0YTcwMGIxNjk0ZWFlYTJiNjRiNTBjNWM1YTdjZCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNzUxNmZkOTg3M2Q3NDRkZDg3NGY0OGQ1MGNkNDdiYjcuYmluZFBvcHVwKHBvcHVwXzNiYTVmMGEzMTcwOTRlZDg5NDJmODAyMjc0YmFjZTNhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wMDVlYWM2YWU4MDQ0YmExYjRiNDQ1ZjllNWRiOGVkYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3OTU1NzEsIC03OS4zNTIxODhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMzI4Yzk5MTc3ZDdhNGQyYmEwNjQzZDNhZDM3ZDM4YmMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzBlZDNmY2VhNjllYjRlZDlhYTVjM2JhOWE4NmQxODMxID0gJChgPGRpdiBpZD0iaHRtbF8wZWQzZmNlYTY5ZWI0ZWQ5YWE1YzNiYTlhODZkMTgzMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIERhbmZvcnRoIFdlc3QsIFJpdmVyZGFsZSwgRWFzdCBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzMyOGM5OTE3N2Q3YTRkMmJhMDY0M2QzYWQzN2QzOGJjLnNldENvbnRlbnQoaHRtbF8wZWQzZmNlYTY5ZWI0ZWQ5YWE1YzNiYTlhODZkMTgzMSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMDA1ZWFjNmFlODA0NGJhMWI0YjQ0NWY5ZTVkYjhlZGMuYmluZFBvcHVwKHBvcHVwXzMyOGM5OTE3N2Q3YTRkMmJhMDY0M2QzYWQzN2QzOGJjKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83N2Q3ZjQwY2UzNzk0ZmVmOTIwYTY4NjdjMjE1MzIzNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2ODk5ODUsIC03OS4zMTU1NzE1OTk5OTk5OF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8xYjQyYjU0YTc3MjA0ODliODJlNGRhZGI0MjFiZTM1ZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMTZhMjQzNjA0OTViNDg1YmI3YWQyNmIzZWM4ZDdkMzQgPSAkKGA8ZGl2IGlkPSJodG1sXzE2YTI0MzYwNDk1YjQ4NWJiN2FkMjZiM2VjOGQ3ZDM0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5UaGUgQmVhY2hlcyBXZXN0LCBJbmRpYSBCYXphYXIsIEVhc3QgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xYjQyYjU0YTc3MjA0ODliODJlNGRhZGI0MjFiZTM1ZS5zZXRDb250ZW50KGh0bWxfMTZhMjQzNjA0OTViNDg1YmI3YWQyNmIzZWM4ZDdkMzQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzc3ZDdmNDBjZTM3OTRmZWY5MjBhNjg2N2MyMTUzMjM2LmJpbmRQb3B1cChwb3B1cF8xYjQyYjU0YTc3MjA0ODliODJlNGRhZGI0MjFiZTM1ZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGVmMDAyZmExYTU0NGJmNDlkZTcxMTE5MDcwZmZmOTUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTk1MjU1LCAtNzkuMzQwOTIzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzhhODUwMzhmYmY3OTRlMWM4Zjg3MDVhMzZhZjBjYWVhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80MGFlMDU0ZjNmMmQ0YTliYTQyMGQ5NjEwNDM1ZTcxYSA9ICQoYDxkaXYgaWQ9Imh0bWxfNDBhZTA1NGYzZjJkNGE5YmE0MjBkOTYxMDQzNWU3MWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlN0dWRpbyBEaXN0cmljdCwgRWFzdCBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzhhODUwMzhmYmY3OTRlMWM4Zjg3MDVhMzZhZjBjYWVhLnNldENvbnRlbnQoaHRtbF80MGFlMDU0ZjNmMmQ0YTliYTQyMGQ5NjEwNDM1ZTcxYSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZGVmMDAyZmExYTU0NGJmNDlkZTcxMTE5MDcwZmZmOTUuYmluZFBvcHVwKHBvcHVwXzhhODUwMzhmYmY3OTRlMWM4Zjg3MDVhMzZhZjBjYWVhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jNmNiODJmMWRiYjA0Y2E3YTdlMjZkNDJmN2RlZmI4MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcyODAyMDUsIC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzI5ZmM0NjExMWJmYzRlNjI5YThjOTE4OTZmZWE1ZTJjID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMDg1MGY3YzFkZGY0ZTQ1OTVmNTBmMzExNjUzZDM1MSA9ICQoYDxkaXYgaWQ9Imh0bWxfZjA4NTBmN2MxZGRmNGU0NTk1ZjUwZjMxMTY1M2QzNTEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxhd3JlbmNlIFBhcmssIENlbnRyYWwgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yOWZjNDYxMTFiZmM0ZTYyOWE4YzkxODk2ZmVhNWUyYy5zZXRDb250ZW50KGh0bWxfZjA4NTBmN2MxZGRmNGU0NTk1ZjUwZjMxMTY1M2QzNTEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2M2Y2I4MmYxZGJiMDRjYTdhN2UyNmQ0MmY3ZGVmYjgxLmJpbmRQb3B1cChwb3B1cF8yOWZjNDYxMTFiZmM0ZTYyOWE4YzkxODk2ZmVhNWUyYykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTZhMDIxNDMxZWE3NDFkZTg3Yjk4YTE0ZmU2MjE5NmUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTI3NTExLCAtNzkuMzkwMTk3NV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82MzliNTNjZThkODQ0NjgyYjUyMTU5ODFkZmIzZGE3OSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZDY5NWUwZDE1YWY4NGZmZWFkODc0NjZlN2Q5YjZiMDIgPSAkKGA8ZGl2IGlkPSJodG1sX2Q2OTVlMGQxNWFmODRmZmVhZDg3NDY2ZTdkOWI2YjAyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EYXZpc3ZpbGxlIE5vcnRoLCBDZW50cmFsIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjM5YjUzY2U4ZDg0NDY4MmI1MjE1OTgxZGZiM2RhNzkuc2V0Q29udGVudChodG1sX2Q2OTVlMGQxNWFmODRmZmVhZDg3NDY2ZTdkOWI2YjAyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8xNmEwMjE0MzFlYTc0MWRlODdiOThhMTRmZTYyMTk2ZS5iaW5kUG9wdXAocG9wdXBfNjM5YjUzY2U4ZDg0NDY4MmI1MjE1OTgxZGZiM2RhNzkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U0ZjFiZTQ3NDI4ZDQ3ZTU5MzIzZmQ3OTlmNjU3OGUwID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzE1MzgzNCwgLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzYzYTZiNTI5NmUwOTQ1ZjJiZjk2MGRmMmYxOGQyNDZjID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wNzA1ZDhjMDAwYTY0MGM2OTQ3ZDAyM2IwMTQ3ZjNlMiA9ICQoYDxkaXYgaWQ9Imh0bWxfMDcwNWQ4YzAwMGE2NDBjNjk0N2QwMjNiMDE0N2YzZTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPk5vcnRoIFRvcm9udG8gV2VzdCwgQ2VudHJhbCBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzYzYTZiNTI5NmUwOTQ1ZjJiZjk2MGRmMmYxOGQyNDZjLnNldENvbnRlbnQoaHRtbF8wNzA1ZDhjMDAwYTY0MGM2OTQ3ZDAyM2IwMTQ3ZjNlMik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZTRmMWJlNDc0MjhkNDdlNTkzMjNmZDc5OWY2NTc4ZTAuYmluZFBvcHVwKHBvcHVwXzYzYTZiNTI5NmUwOTQ1ZjJiZjk2MGRmMmYxOGQyNDZjKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83MzM4NzAxZWRkNjc0NjczYmE4Mjg4MWEwM2VkZTRmNyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcwNDMyNDQsIC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzMxM2Y0M2YzYWM5ZDQ5OWVhNTc0NDM4NTBjNTQ1MWYzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMDRmZDVlOGVmYmI0MDFiYWMzNDI1NjA2NWRhODJhZSA9ICQoYDxkaXYgaWQ9Imh0bWxfZjA0ZmQ1ZThlZmJiNDAxYmFjMzQyNTYwNjVkYTgyYWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRhdmlzdmlsbGUsIENlbnRyYWwgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zMTNmNDNmM2FjOWQ0OTllYTU3NDQzODUwYzU0NTFmMy5zZXRDb250ZW50KGh0bWxfZjA0ZmQ1ZThlZmJiNDAxYmFjMzQyNTYwNjVkYTgyYWUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzczMzg3MDFlZGQ2NzQ2NzNiYTgyODgxYTAzZWRlNGY3LmJpbmRQb3B1cChwb3B1cF8zMTNmNDNmM2FjOWQ0OTllYTU3NDQzODUwYzU0NTFmMykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTNkMmQzZDc4NmUxNDQ1ZDg2ZDJjMGQzOTZhMGI5YjIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODk1NzQzLCAtNzkuMzgzMTU5OTAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMWVkMzQ3ODg1YjcyNGU5Yzk2N2M5ZTU4YzU0OTBiNzYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzZiYTVlMDk5MjAzMzQ5NmQ4NjA4Yjg2MzRhMzRjZDBhID0gJChgPGRpdiBpZD0iaHRtbF82YmE1ZTA5OTIwMzM0OTZkODYwOGI4NjM0YTM0Y2QwYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TW9vcmUgUGFyaywgU3VtbWVyaGlsbCBFYXN0LCBDZW50cmFsIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMWVkMzQ3ODg1YjcyNGU5Yzk2N2M5ZTU4YzU0OTBiNzYuc2V0Q29udGVudChodG1sXzZiYTVlMDk5MjAzMzQ5NmQ4NjA4Yjg2MzRhMzRjZDBhKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8xM2QyZDNkNzg2ZTE0NDVkODZkMmMwZDM5NmEwYjliMi5iaW5kUG9wdXAocG9wdXBfMWVkMzQ3ODg1YjcyNGU5Yzk2N2M5ZTU4YzU0OTBiNzYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzQzMzlkM2RlNTFjMDQ5Njg4NmI2ODI4NmQ0N2Q2MWJlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjg2NDEyMjk5OTk5OTksIC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzNjMGZkNjdlMDNmMDQ3Yjg5NjY1ZThmOWQxNjFmYTQxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF81ZGY2ZDVlYzRhMjA0MDRhOWZmNzMzZWQxODAxMjgxYSA9ICQoYDxkaXYgaWQ9Imh0bWxfNWRmNmQ1ZWM0YTIwNDA0YTlmZjczM2VkMTgwMTI4MWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRlZXIgUGFyaywgRm9yZXN0IEhpbGwgU0UsIFJhdGhuZWxseSwgU291dGggSGlsbCwgU3VtbWVyaGlsbCBXZXN0LCBDZW50cmFsIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfM2MwZmQ2N2UwM2YwNDdiODk2NjVlOGY5ZDE2MWZhNDEuc2V0Q29udGVudChodG1sXzVkZjZkNWVjNGEyMDQwNGE5ZmY3MzNlZDE4MDEyODFhKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl80MzM5ZDNkZTUxYzA0OTY4ODZiNjgyODZkNDdkNjFiZS5iaW5kUG9wdXAocG9wdXBfM2MwZmQ2N2UwM2YwNDdiODk2NjVlOGY5ZDE2MWZhNDEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NmZjFjNWRkMDI1MDRhYzQ5MzNlODIzNmVjYzdkNGI1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjc5NTYyNiwgLTc5LjM3NzUyOTQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2E4Y2I1MzU3ZTU1NzQyZDNhODAwZDQ0Y2Y4MGU1ZWM2ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF84ZTRhNmY2ZTY5Njk0NjRiYTExZDFhOTNhZjVmMTAyNCA9ICQoYDxkaXYgaWQ9Imh0bWxfOGU0YTZmNmU2OTY5NDY0YmExMWQxYTkzYWY1ZjEwMjQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJvc2VkYWxlLCBEb3dudG93biBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2E4Y2I1MzU3ZTU1NzQyZDNhODAwZDQ0Y2Y4MGU1ZWM2LnNldENvbnRlbnQoaHRtbF84ZTRhNmY2ZTY5Njk0NjRiYTExZDFhOTNhZjVmMTAyNCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfY2ZmMWM1ZGQwMjUwNGFjNDkzM2U4MjM2ZWNjN2Q0YjUuYmluZFBvcHVwKHBvcHVwX2E4Y2I1MzU3ZTU1NzQyZDNhODAwZDQ0Y2Y4MGU1ZWM2KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mMzBiMzczZDEzMzc0MDZmODI3MDA0NGQ0NDUxNmVkMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2Nzk2NywgLTc5LjM2NzY3NTNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNWQzNGI1Y2FkMjZjNDM4ZDk3ZmJhMDJkNTY1ODdmZGIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzBlNWNiMDliMGE1MzQzYTc4OWQ4MTY0Zjk0ZmE0NzQ5ID0gJChgPGRpdiBpZD0iaHRtbF8wZTVjYjA5YjBhNTM0M2E3ODlkODE2NGY5NGZhNDc0OSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2FiYmFnZXRvd24sIFN0LiBKYW1lcyBUb3duLCBEb3dudG93biBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzVkMzRiNWNhZDI2YzQzOGQ5N2ZiYTAyZDU2NTg3ZmRiLnNldENvbnRlbnQoaHRtbF8wZTVjYjA5YjBhNTM0M2E3ODlkODE2NGY5NGZhNDc0OSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZjMwYjM3M2QxMzM3NDA2ZjgyNzAwNDRkNDQ1MTZlZDIuYmluZFBvcHVwKHBvcHVwXzVkMzRiNWNhZDI2YzQzOGQ5N2ZiYTAyZDU2NTg3ZmRiKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lYjU4ZDYxZGU1YjU0MWI0YTFmNGY4MzZlMzgyZmExMSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2NTg1OTksIC03OS4zODMxNTk5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9mYzAyZTZmZjk0MTA0MGUyYjYyODcwZTlmMTI5MmZjYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYWU5NjA1ZjM5NjY1NDBiZmEzMWVjNzU5N2E3MDhjMWMgPSAkKGA8ZGl2IGlkPSJodG1sX2FlOTYwNWYzOTY2NTQwYmZhMzFlYzc1OTdhNzA4YzFjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DaHVyY2ggYW5kIFdlbGxlc2xleSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9mYzAyZTZmZjk0MTA0MGUyYjYyODcwZTlmMTI5MmZjYS5zZXRDb250ZW50KGh0bWxfYWU5NjA1ZjM5NjY1NDBiZmEzMWVjNzU5N2E3MDhjMWMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ViNThkNjFkZTViNTQxYjRhMWY0ZjgzNmUzODJmYTExLmJpbmRQb3B1cChwb3B1cF9mYzAyZTZmZjk0MTA0MGUyYjYyODcwZTlmMTI5MmZjYSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTRkY2Y2YzZhNjU4NDExMDhmMDM0ZjU4YjQ1MTRmZTQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTQyNTk5LCAtNzkuMzYwNjM1OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF84ZTgzYTAyOThlMjc0MmYwODE3OGJlMDM2NzA1YTlmNyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfN2U0YTEzN2U0NzY5NDc4YmJmM2MyZThjNDJiNGJiZjcgPSAkKGA8ZGl2IGlkPSJodG1sXzdlNGExMzdlNDc2OTQ3OGJiZjNjMmU4YzQyYjRiYmY3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IYXJib3VyZnJvbnQsIFJlZ2VudCBQYXJrLCBEb3dudG93biBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzhlODNhMDI5OGUyNzQyZjA4MTc4YmUwMzY3MDVhOWY3LnNldENvbnRlbnQoaHRtbF83ZTRhMTM3ZTQ3Njk0NzhiYmYzYzJlOGM0MmI0YmJmNyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMTRkY2Y2YzZhNjU4NDExMDhmMDM0ZjU4YjQ1MTRmZTQuYmluZFBvcHVwKHBvcHVwXzhlODNhMDI5OGUyNzQyZjA4MTc4YmUwMzY3MDVhOWY3KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83YWIwYTI3ZDVhZGI0OWJmOTQxNDk3MTI4MmM5MWZmMSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1NzE2MTgsIC03OS4zNzg5MzcwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hMDY4NDM2OTM5MjY0ODk1OWY5ODY5MmQ1OTA1MjE0MyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNTU3NGZjMWFlNmYyNDNiZmFlZTA3N2NmODNhNjgxMTkgPSAkKGA8ZGl2IGlkPSJodG1sXzU1NzRmYzFhZTZmMjQzYmZhZWUwNzdjZjgzYTY4MTE5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5SeWVyc29uLCBHYXJkZW4gRGlzdHJpY3QsIERvd250b3duIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYTA2ODQzNjkzOTI2NDg5NTlmOTg2OTJkNTkwNTIxNDMuc2V0Q29udGVudChodG1sXzU1NzRmYzFhZTZmMjQzYmZhZWUwNzdjZjgzYTY4MTE5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl83YWIwYTI3ZDVhZGI0OWJmOTQxNDk3MTI4MmM5MWZmMS5iaW5kUG9wdXAocG9wdXBfYTA2ODQzNjkzOTI2NDg5NTlmOTg2OTJkNTkwNTIxNDMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzgwNDhiYmE2OTQ0YjQwOTZhM2MzZWY0Mjk4Y2RmM2Q5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUxNDkzOSwgLTc5LjM3NTQxNzldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOWE1MDI3MGRmYzM1NGJhODhiYzRkZThmMmQwMWVhNmIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzk0Nzk5NzM1NzQzMjRiYmRhNGFjN2EwNWI4ZGFiYTVhID0gJChgPGRpdiBpZD0iaHRtbF85NDc5OTczNTc0MzI0YmJkYTRhYzdhMDViOGRhYmE1YSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U3QuIEphbWVzIFRvd24sIERvd250b3duIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOWE1MDI3MGRmYzM1NGJhODhiYzRkZThmMmQwMWVhNmIuc2V0Q29udGVudChodG1sXzk0Nzk5NzM1NzQzMjRiYmRhNGFjN2EwNWI4ZGFiYTVhKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl84MDQ4YmJhNjk0NGI0MDk2YTNjM2VmNDI5OGNkZjNkOS5iaW5kUG9wdXAocG9wdXBfOWE1MDI3MGRmYzM1NGJhODhiYzRkZThmMmQwMWVhNmIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y4ZjAyYmM2OTc1NjRhMjlhNDhkMTQwNzc5N2M2NDEzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ0NzcwNzk5OTk5OTk2LCAtNzkuMzczMzA2NF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80OTUzOTIzMDdkNWM0ZTE0YTRhYzYxNzAyODZkYTM5NiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYjRlOWRlZWYzNzhjNDA3MDhhZmE3OGUzMTRkMTYwOTIgPSAkKGA8ZGl2IGlkPSJodG1sX2I0ZTlkZWVmMzc4YzQwNzA4YWZhNzhlMzE0ZDE2MDkyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CZXJjenkgUGFyaywgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80OTUzOTIzMDdkNWM0ZTE0YTRhYzYxNzAyODZkYTM5Ni5zZXRDb250ZW50KGh0bWxfYjRlOWRlZWYzNzhjNDA3MDhhZmE3OGUzMTRkMTYwOTIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2Y4ZjAyYmM2OTc1NjRhMjlhNDhkMTQwNzc5N2M2NDEzLmJpbmRQb3B1cChwb3B1cF80OTUzOTIzMDdkNWM0ZTE0YTRhYzYxNzAyODZkYTM5NikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOGM5NmJhMmVlNTMxNDUwYWIzNzQyZjQ5Nzc4MWU4ZmYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTc5NTI0LCAtNzkuMzg3MzgyNl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hZmM4MWFhMTFjNjQ0ZWMwOWU4ZTY3M2ZiMDAzNjEzMiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMWQ1MzNiMjUyOTZhNDIyMTg3NDUxYTA3ODcxZjA5Y2UgPSAkKGA8ZGl2IGlkPSJodG1sXzFkNTMzYjI1Mjk2YTQyMjE4NzQ1MWEwNzg3MWYwOWNlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DZW50cmFsIEJheSBTdHJlZXQsIERvd250b3duIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYWZjODFhYTExYzY0NGVjMDllOGU2NzNmYjAwMzYxMzIuc2V0Q29udGVudChodG1sXzFkNTMzYjI1Mjk2YTQyMjE4NzQ1MWEwNzg3MWYwOWNlKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl84Yzk2YmEyZWU1MzE0NTBhYjM3NDJmNDk3NzgxZThmZi5iaW5kUG9wdXAocG9wdXBfYWZjODFhYTExYzY0NGVjMDllOGU2NzNmYjAwMzYxMzIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzQxNDIwNjQyZWY2NTRkOGI4NzNjYTRlODUyYzc5MzI0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUwNTcxMjAwMDAwMDEsIC03OS4zODQ1Njc1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzczOTI2NWE4ZGFiYzQ3YmNiZTc5ZGVjNDU3NDI1ZjJkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF84YTNmYWI1ZmQxNGM0N2IyYmYwOGFkNjM1MTQ0NDEzOSA9ICQoYDxkaXYgaWQ9Imh0bWxfOGEzZmFiNWZkMTRjNDdiMmJmMDhhZDYzNTE0NDQxMzkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkFkZWxhaWRlLCBLaW5nLCBSaWNobW9uZCwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83MzkyNjVhOGRhYmM0N2JjYmU3OWRlYzQ1NzQyNWYyZC5zZXRDb250ZW50KGh0bWxfOGEzZmFiNWZkMTRjNDdiMmJmMDhhZDYzNTE0NDQxMzkpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzQxNDIwNjQyZWY2NTRkOGI4NzNjYTRlODUyYzc5MzI0LmJpbmRQb3B1cChwb3B1cF83MzkyNjVhOGRhYmM0N2JjYmU3OWRlYzQ1NzQyNWYyZCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmU1MGFkNzk2NjM1NGJkN2JjZWNhZjAwNzcxNDRmZmQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDA4MTU3LCAtNzkuMzgxNzUyMjk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZDY5ZGU2MzJlZTAyNDQxNGFiNGEwOWZlNTg0NjExODEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzg1Zjc3ODlkNjM1ODQ3NTViOWM0NmI0MjY5Yjc5MTJiID0gJChgPGRpdiBpZD0iaHRtbF84NWY3Nzg5ZDYzNTg0NzU1YjljNDZiNDI2OWI3OTEyYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SGFyYm91cmZyb250IEVhc3QsIFRvcm9udG8gSXNsYW5kcywgVW5pb24gU3RhdGlvbiwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kNjlkZTYzMmVlMDI0NDE0YWI0YTA5ZmU1ODQ2MTE4MS5zZXRDb250ZW50KGh0bWxfODVmNzc4OWQ2MzU4NDc1NWI5YzQ2YjQyNjliNzkxMmIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2JlNTBhZDc5NjYzNTRiZDdiY2VjYWYwMDc3MTQ0ZmZkLmJpbmRQb3B1cChwb3B1cF9kNjlkZTYzMmVlMDI0NDE0YWI0YTA5ZmU1ODQ2MTE4MSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZTcxNTIwNzIyNmViNGZhMzg0OTY1MjQzNDY3ZjZlNDEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDcxNzY4LCAtNzkuMzgxNTc2NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYTg3NWZmNTkwZWQ5NDRlYmE1MjU5NzFjYzc5NDllOTYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzNjMTExOTNkNTAwMjQyZTFhMTMwMWE4NzAwNzYwMmY4ID0gJChgPGRpdiBpZD0iaHRtbF8zYzExMTkzZDUwMDI0MmUxYTEzMDFhODcwMDc2MDJmOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RGVzaWduIEV4Y2hhbmdlLCBUb3JvbnRvIERvbWluaW9uIENlbnRyZSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hODc1ZmY1OTBlZDk0NGViYTUyNTk3MWNjNzk0OWU5Ni5zZXRDb250ZW50KGh0bWxfM2MxMTE5M2Q1MDAyNDJlMWExMzAxYTg3MDA3NjAyZjgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U3MTUyMDcyMjZlYjRmYTM4NDk2NTI0MzQ2N2Y2ZTQxLmJpbmRQb3B1cChwb3B1cF9hODc1ZmY1OTBlZDk0NGViYTUyNTk3MWNjNzk0OWU5NikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDc2YzhlNTBmMzMyNDcyZTkzZTU0YTM1ODIxNDYwMmYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDgxOTg1LCAtNzkuMzc5ODE2OTAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZTI1MTdhOGQ3MWJmNDk1MzlmYmI4MTkyNjEwZTkyOTAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2JmZGU0Y2I3MmFiNDQ0ZDFiYWQ0MTE4OTk2OGFiNzNmID0gJChgPGRpdiBpZD0iaHRtbF9iZmRlNGNiNzJhYjQ0NGQxYmFkNDExODk5NjhhYjczZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q29tbWVyY2UgQ291cnQsIFZpY3RvcmlhIEhvdGVsLCBEb3dudG93biBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2UyNTE3YThkNzFiZjQ5NTM5ZmJiODE5MjYxMGU5MjkwLnNldENvbnRlbnQoaHRtbF9iZmRlNGNiNzJhYjQ0NGQxYmFkNDExODk5NjhhYjczZik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDc2YzhlNTBmMzMyNDcyZTkzZTU0YTM1ODIxNDYwMmYuYmluZFBvcHVwKHBvcHVwX2UyNTE3YThkNzFiZjQ5NTM5ZmJiODE5MjYxMGU5MjkwKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mMWUzNjRkMGU2Mjg0MTVmOGQ4OTk3Mzc2ZmEzMDllZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjczMzI4MjUsIC03OS40MTk3NDk3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzkwMDk3YWMzNTRhNTRmZTA5YjcxODU3MGJjNjM2MzVhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wODZmNzE1ZmEwMmQ0MDdkOWQ4MTFkNDI3M2JhMDZiOCA9ICQoYDxkaXYgaWQ9Imh0bWxfMDg2ZjcxNWZhMDJkNDA3ZDlkODExZDQyNzNiYTA2YjgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJlZGZvcmQgUGFyaywgTGF3cmVuY2UgTWFub3IgRWFzdCwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85MDA5N2FjMzU0YTU0ZmUwOWI3MTg1NzBiYzYzNjM1YS5zZXRDb250ZW50KGh0bWxfMDg2ZjcxNWZhMDJkNDA3ZDlkODExZDQyNzNiYTA2YjgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2YxZTM2NGQwZTYyODQxNWY4ZDg5OTczNzZmYTMwOWVlLmJpbmRQb3B1cChwb3B1cF85MDA5N2FjMzU0YTU0ZmUwOWI3MTg1NzBiYzYzNjM1YSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZjA3YjU0NGUxMjRiNDM5OGI5ZmZkMzIxZGUyN2I2NjcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTE2OTQ4LCAtNzkuNDE2OTM1NTk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMjdmNWIxZjVhMjUzNDBhNTliZjUwY2ExOTBiZDNiZTQgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzVhM2ZhOTcyOTFhZTQ0YjliNTgzNDllMmM4NjY5MzRiID0gJChgPGRpdiBpZD0iaHRtbF81YTNmYTk3MjkxYWU0NGI5YjU4MzQ5ZTJjODY2OTM0YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Um9zZWxhd24sIENlbnRyYWwgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yN2Y1YjFmNWEyNTM0MGE1OWJmNTBjYTE5MGJkM2JlNC5zZXRDb250ZW50KGh0bWxfNWEzZmE5NzI5MWFlNDRiOWI1ODM0OWUyYzg2NjkzNGIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2YwN2I1NDRlMTI0YjQzOThiOWZmZDMyMWRlMjdiNjY3LmJpbmRQb3B1cChwb3B1cF8yN2Y1YjFmNWEyNTM0MGE1OWJmNTBjYTE5MGJkM2JlNCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYWIwMTY4MDliZjNhNDljNDhlOWQ2MmRiNDI4N2UwYjggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42OTY5NDc2LCAtNzkuNDExMzA3MjAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfM2VhM2RhYTQ4ZjU5NDA4NThjNTE3MzZhNzgzMDE3MTMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzJhMDI2NjU1YTQ2YTRiN2FiZDQ1ZDg4ZTFmYTIzYTUyID0gJChgPGRpdiBpZD0iaHRtbF8yYTAyNjY1NWE0NmE0YjdhYmQ0NWQ4OGUxZmEyM2E1MiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Rm9yZXN0IEhpbGwgTm9ydGgsIEZvcmVzdCBIaWxsIFdlc3QsIENlbnRyYWwgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zZWEzZGFhNDhmNTk0MDg1OGM1MTczNmE3ODMwMTcxMy5zZXRDb250ZW50KGh0bWxfMmEwMjY2NTVhNDZhNGI3YWJkNDVkODhlMWZhMjNhNTIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2FiMDE2ODA5YmYzYTQ5YzQ4ZTlkNjJkYjQyODdlMGI4LmJpbmRQb3B1cChwb3B1cF8zZWEzZGFhNDhmNTk0MDg1OGM1MTczNmE3ODMwMTcxMykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjhlNjhkNTBhMzIyNDBiNjk4YTFkZmJjN2QzOWJhNzcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NzI3MDk3LCAtNzkuNDA1Njc4NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfODBkMmNhNzNkYmE0NDFhOWE4OTYzYzgwNjI4NzgzN2EgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzI3YjhhYmU2Y2YwYzQxNGI4ZDRhZDE5N2Q2OGQ5MzhlID0gJChgPGRpdiBpZD0iaHRtbF8yN2I4YWJlNmNmMGM0MTRiOGQ0YWQxOTdkNjhkOTM4ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEFubmV4LCBOb3J0aCBNaWR0b3duLCBZb3JrdmlsbGUsIENlbnRyYWwgVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84MGQyY2E3M2RiYTQ0MWE5YTg5NjNjODA2Mjg3ODM3YS5zZXRDb250ZW50KGh0bWxfMjdiOGFiZTZjZjBjNDE0YjhkNGFkMTk3ZDY4ZDkzOGUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2I4ZTY4ZDUwYTMyMjQwYjY5OGExZGZiYzdkMzliYTc3LmJpbmRQb3B1cChwb3B1cF84MGQyY2E3M2RiYTQ0MWE5YTg5NjNjODA2Mjg3ODM3YSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYTc1ZWMwMmIxNDgyNDMzNTg2Yzc0MjViNjRhMDE3MGIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjI2OTU2LCAtNzkuNDAwMDQ5M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hM2ZhMGU1MmZiZTc0NGE1YTQxNDNjZjgxZTNmZGNmZiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYzZjMjkxNjhmYTY3NDlhYzk1MzYyMWFlNDgxNGQxNTggPSAkKGA8ZGl2IGlkPSJodG1sX2M2YzI5MTY4ZmE2NzQ5YWM5NTM2MjFhZTQ4MTRkMTU4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IYXJib3JkLCBVbml2ZXJzaXR5IG9mIFRvcm9udG8sIERvd250b3duIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYTNmYTBlNTJmYmU3NDRhNWE0MTQzY2Y4MWUzZmRjZmYuc2V0Q29udGVudChodG1sX2M2YzI5MTY4ZmE2NzQ5YWM5NTM2MjFhZTQ4MTRkMTU4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9hNzVlYzAyYjE0ODI0MzM1ODZjNzQyNWI2NGEwMTcwYi5iaW5kUG9wdXAocG9wdXBfYTNmYTBlNTJmYmU3NDRhNWE0MTQzY2Y4MWUzZmRjZmYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzMwZjA5ZjdiYWZlNjQyMjI4MmI5YTE5NTczNGY5MDE0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUzMjA1NywgLTc5LjQwMDA0OTNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOWM3MjZjOWNiNjVjNGQyNjg1NWMxZDQ3N2MyMmY2NWIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzAxNTNkZGRmYTY4NTRiZmI5NjA1Mzk2ZTA4MTM4MDg2ID0gJChgPGRpdiBpZD0iaHRtbF8wMTUzZGRkZmE2ODU0YmZiOTYwNTM5NmUwODEzODA4NiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2hpbmF0b3duLCBHcmFuZ2UgUGFyaywgS2Vuc2luZ3RvbiBNYXJrZXQsIERvd250b3duIFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOWM3MjZjOWNiNjVjNGQyNjg1NWMxZDQ3N2MyMmY2NWIuc2V0Q29udGVudChodG1sXzAxNTNkZGRmYTY4NTRiZmI5NjA1Mzk2ZTA4MTM4MDg2KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zMGYwOWY3YmFmZTY0MjIyODJiOWExOTU3MzRmOTAxNC5iaW5kUG9wdXAocG9wdXBfOWM3MjZjOWNiNjVjNGQyNjg1NWMxZDQ3N2MyMmY2NWIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2VmYmM3OWI1YzcyMDQwM2RiM2QwZDY2YzA5NTRiZTZiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjI4OTQ2NywgLTc5LjM5NDQxOTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTU1ODljNmM1YjhmNDk3NmJkNzU0NTYwMTdkZjQxNGEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzVmNWE1NTY2NmE1NDQ0YmE4NjcyNzVjZjA0YTk0MGMyID0gJChgPGRpdiBpZD0iaHRtbF81ZjVhNTU2NjZhNTQ0NGJhODY3Mjc1Y2YwNGE5NDBjMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q04gVG93ZXIsIEJhdGh1cnN0IFF1YXksIElzbGFuZCBhaXJwb3J0LCBIYXJib3VyZnJvbnQgV2VzdCwgS2luZyBhbmQgU3BhZGluYSwgUmFpbHdheSBMYW5kcywgU291dGggTmlhZ2FyYSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85NTU4OWM2YzViOGY0OTc2YmQ3NTQ1NjAxN2RmNDE0YS5zZXRDb250ZW50KGh0bWxfNWY1YTU1NjY2YTU0NDRiYTg2NzI3NWNmMDRhOTQwYzIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2VmYmM3OWI1YzcyMDQwM2RiM2QwZDY2YzA5NTRiZTZiLmJpbmRQb3B1cChwb3B1cF85NTU4OWM2YzViOGY0OTc2YmQ3NTQ1NjAxN2RmNDE0YSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfODA2YWE5OTg4MzhmNDkzZjhmZjYzMmY5MjFiMmUxNTAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDY0MzUyLCAtNzkuMzc0ODQ1OTk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfM2NmZTc3NTI3NTRhNGJlMDhlNzEzYzIyZTg0NDc0ZTkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2NjY2FlNjZjMzVlZDQ3Y2M5ODM2MjFlNWY3ZjRiOTk0ID0gJChgPGRpdiBpZD0iaHRtbF9jY2NhZTY2YzM1ZWQ0N2NjOTgzNjIxZTVmN2Y0Yjk5NCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U3RuIEEgUE8gQm94ZXMgMjUgVGhlIEVzcGxhbmFkZSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zY2ZlNzc1Mjc1NGE0YmUwOGU3MTNjMjJlODQ0NzRlOS5zZXRDb250ZW50KGh0bWxfY2NjYWU2NmMzNWVkNDdjYzk4MzYyMWU1ZjdmNGI5OTQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzgwNmFhOTk4ODM4ZjQ5M2Y4ZmY2MzJmOTIxYjJlMTUwLmJpbmRQb3B1cChwb3B1cF8zY2ZlNzc1Mjc1NGE0YmUwOGU3MTNjMjJlODQ0NzRlOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGRlZWM4MzI5N2JiNDkwZTgxNWQ2ZTEyMmU0Y2JmZDMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDg0MjkyLCAtNzkuMzgyMjgwMl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8xZjJhMDFmYWQ5NDI0NzMxODA2MmEwNTkzMDBkNjQzNiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNmJkNWY5ODcyOWRmNDIwYTkzMzE4M2JhYzBjYWEyMTYgPSAkKGA8ZGl2IGlkPSJodG1sXzZiZDVmOTg3MjlkZjQyMGE5MzMxODNiYWMwY2FhMjE2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5GaXJzdCBDYW5hZGlhbiBQbGFjZSwgVW5kZXJncm91bmQgY2l0eSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xZjJhMDFmYWQ5NDI0NzMxODA2MmEwNTkzMDBkNjQzNi5zZXRDb250ZW50KGh0bWxfNmJkNWY5ODcyOWRmNDIwYTkzMzE4M2JhYzBjYWEyMTYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2RkZWVjODMyOTdiYjQ5MGU4MTVkNmUxMjJlNGNiZmQzLmJpbmRQb3B1cChwb3B1cF8xZjJhMDFmYWQ5NDI0NzMxODA2MmEwNTkzMDBkNjQzNikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjhiNjY4ZTAxMzdkNGNlYzljZGJiMmJkMzhiZDRhYTQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTg1MTc5OTk5OTk5OTYsIC03OS40NjQ3NjMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hNTM2OGRlMTdiZGM0N2U1YjZjNDNlODFmMTk1ZWE4MiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYzdiMzI2NmNlNTNjNGUzNWFjYzIzYmMxMjgyZTkzMmIgPSAkKGA8ZGl2IGlkPSJodG1sX2M3YjMyNjZjZTUzYzRlMzVhY2MyM2JjMTI4MmU5MzJiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5MYXdyZW5jZSBIZWlnaHRzLCBMYXdyZW5jZSBNYW5vciwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hNTM2OGRlMTdiZGM0N2U1YjZjNDNlODFmMTk1ZWE4Mi5zZXRDb250ZW50KGh0bWxfYzdiMzI2NmNlNTNjNGUzNWFjYzIzYmMxMjgyZTkzMmIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzI4YjY2OGUwMTM3ZDRjZWM5Y2RiYjJiZDM4YmQ0YWE0LmJpbmRQb3B1cChwb3B1cF9hNTM2OGRlMTdiZGM0N2U1YjZjNDNlODFmMTk1ZWE4MikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDFiY2MwZmVjZWM0NDQxMmI1MjUwOGNmMjgyZmFlMDQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDk1NzcsIC03OS40NDUwNzI1OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9iNjI1NWU1ZDcyNDI0YTMwOGEwZTFkNWYyN2U5NTQ5MSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOWU1N2ZkMmZlZDE1NGI3NGFkMjA4MTQwMmQ3NmIwZTcgPSAkKGA8ZGl2IGlkPSJodG1sXzllNTdmZDJmZWQxNTRiNzRhZDIwODE0MDJkNzZiMGU3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5HbGVuY2Fpcm4sIE5vcnRoIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYjYyNTVlNWQ3MjQyNGEzMDhhMGUxZDVmMjdlOTU0OTEuc2V0Q29udGVudChodG1sXzllNTdmZDJmZWQxNTRiNzRhZDIwODE0MDJkNzZiMGU3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl80MWJjYzBmZWNlYzQ0NDEyYjUyNTA4Y2YyODJmYWUwNC5iaW5kUG9wdXAocG9wdXBfYjYyNTVlNWQ3MjQyNGEzMDhhMGUxZDVmMjdlOTU0OTEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2VhYjJjMjBkN2EyMDRkZjk4N2Q3ZTgyMmZhMDEwNDY1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjkzNzgxMywgLTc5LjQyODE5MTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2E0Y2Y2MDRjNGM3ODQ0MGQ4M2MxMGY3ZjUyYWY2NzAzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9kZmQyODQ1MDc2N2I0ODQwYmVjM2Q5NTc4YjNkYmFmYSA9ICQoYDxkaXYgaWQ9Imh0bWxfZGZkMjg0NTA3NjdiNDg0MGJlYzNkOTU3OGIzZGJhZmEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkh1bWV3b29kLUNlZGFydmFsZSwgWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hNGNmNjA0YzRjNzg0NDBkODNjMTBmN2Y1MmFmNjcwMy5zZXRDb250ZW50KGh0bWxfZGZkMjg0NTA3NjdiNDg0MGJlYzNkOTU3OGIzZGJhZmEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2VhYjJjMjBkN2EyMDRkZjk4N2Q3ZTgyMmZhMDEwNDY1LmJpbmRQb3B1cChwb3B1cF9hNGNmNjA0YzRjNzg0NDBkODNjMTBmN2Y1MmFmNjcwMykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNjAyMzhhN2E2MTQ2NGQ3YTgzZjc2ODExMzA0ZjdkMzcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODkwMjU2LCAtNzkuNDUzNTEyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzZjYzcyZDk2OGY1ZTQyN2ViMTA2ODg2ZWZiYjk3N2NhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9lNzZmNzZiOTE3ZjM0ZWMxODMxYTAwNWU2NzQ2NTVjYSA9ICQoYDxkaXYgaWQ9Imh0bWxfZTc2Zjc2YjkxN2YzNGVjMTgzMWEwMDVlNjc0NjU1Y2EiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNhbGVkb25pYS1GYWlyYmFua3MsIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNmNjNzJkOTY4ZjVlNDI3ZWIxMDY4ODZlZmJiOTc3Y2Euc2V0Q29udGVudChodG1sX2U3NmY3NmI5MTdmMzRlYzE4MzFhMDA1ZTY3NDY1NWNhKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82MDIzOGE3YTYxNDY0ZDdhODNmNzY4MTEzMDRmN2QzNy5iaW5kUG9wdXAocG9wdXBfNmNjNzJkOTY4ZjVlNDI3ZWIxMDY4ODZlZmJiOTc3Y2EpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzlmMjAxMmFlMzBkMTQ2ZWNiNTJiOTkxYjU1MmI2NTdhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjY5NTQyLCAtNzkuNDIyNTYzN10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9jMzQxZWRhYzgyNTc0Yjk3YjZmMTg3ZTQwZjgzOWFjZiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfY2MxZTgwNzM0MTAzNDM3OWIyOTA2NzI4NjFiODI3NDEgPSAkKGA8ZGl2IGlkPSJodG1sX2NjMWU4MDczNDEwMzQzNzliMjkwNjcyODYxYjgyNzQxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DaHJpc3RpZSwgRG93bnRvd24gVG9yb250bzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9jMzQxZWRhYzgyNTc0Yjk3YjZmMTg3ZTQwZjgzOWFjZi5zZXRDb250ZW50KGh0bWxfY2MxZTgwNzM0MTAzNDM3OWIyOTA2NzI4NjFiODI3NDEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzlmMjAxMmFlMzBkMTQ2ZWNiNTJiOTkxYjU1MmI2NTdhLmJpbmRQb3B1cChwb3B1cF9jMzQxZWRhYzgyNTc0Yjk3YjZmMTg3ZTQwZjgzOWFjZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDhjNmQyNmI4M2FmNDA1ZGFlNzgzM2U0YzkzZTgyZTcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjkwMDUxMDAwMDAwMSwgLTc5LjQ0MjI1OTNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZWIwOWMxNTgzMzU2NDhmMjlhMGVlYjE2MjNmNTBjNzEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzI5ODI0NGUyOTBiZjQwYzA4NDEwMjc1ZDA5MGQwYTBjID0gJChgPGRpdiBpZD0iaHRtbF8yOTgyNDRlMjkwYmY0MGMwODQxMDI3NWQwOTBkMGEwYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG92ZXJjb3VydCBWaWxsYWdlLCBEdWZmZXJpbiwgV2VzdCBUb3JvbnRvPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2ViMDljMTU4MzM1NjQ4ZjI5YTBlZWIxNjIzZjUwYzcxLnNldENvbnRlbnQoaHRtbF8yOTgyNDRlMjkwYmY0MGMwODQxMDI3NWQwOTBkMGEwYyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDhjNmQyNmI4M2FmNDA1ZGFlNzgzM2U0YzkzZTgyZTcuYmluZFBvcHVwKHBvcHVwX2ViMDljMTU4MzM1NjQ4ZjI5YTBlZWIxNjIzZjUwYzcxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hNjRmYjQ5NTI2ZGI0ZGJmODYyNjQwYTQ3ODc2MmU2ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NzkyNjcwMDAwMDAwNiwgLTc5LjQxOTc0OTddLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZjBmNTM0M2MyOTA3NGY1NjgxMTg0NDU2YmU1OGY1MTggPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzUzYzA2YTg3MzQ5MDRmMzJhMjgwNmUzM2FlMDhkODg1ID0gJChgPGRpdiBpZD0iaHRtbF81M2MwNmE4NzM0OTA0ZjMyYTI4MDZlMzNhZTA4ZDg4NSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TGl0dGxlIFBvcnR1Z2FsLCBUcmluaXR5LCBXZXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZjBmNTM0M2MyOTA3NGY1NjgxMTg0NDU2YmU1OGY1MTguc2V0Q29udGVudChodG1sXzUzYzA2YTg3MzQ5MDRmMzJhMjgwNmUzM2FlMDhkODg1KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9hNjRmYjQ5NTI2ZGI0ZGJmODYyNjQwYTQ3ODc2MmU2ZC5iaW5kUG9wdXAocG9wdXBfZjBmNTM0M2MyOTA3NGY1NjgxMTg0NDU2YmU1OGY1MTgpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM4NWU5ZjA4MjQyNjRjN2U5Njg5YmY1NjYwOTM2ZmRhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjM2ODQ3MiwgLTc5LjQyODE5MTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2UzNWIyYTU5MDEwMTRjZGI4MDRlOGE0OTAxMTc0NWE2ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8xMzAwMjk3YThmODc0NmE4ODFiMDViNTQzZTA0YzdiMiA9ICQoYDxkaXYgaWQ9Imh0bWxfMTMwMDI5N2E4Zjg3NDZhODgxYjA1YjU0M2UwNGM3YjIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJyb2NrdG9uLCBFeGhpYml0aW9uIFBsYWNlLCBQYXJrZGFsZSBWaWxsYWdlLCBXZXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZTM1YjJhNTkwMTAxNGNkYjgwNGU4YTQ5MDExNzQ1YTYuc2V0Q29udGVudChodG1sXzEzMDAyOTdhOGY4NzQ2YTg4MWIwNWI1NDNlMDRjN2IyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zODVlOWYwODI0MjY0YzdlOTY4OWJmNTY2MDkzNmZkYS5iaW5kUG9wdXAocG9wdXBfZTM1YjJhNTkwMTAxNGNkYjgwNGU4YTQ5MDExNzQ1YTYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IxNmUwZjFlY2VkMzQwNmJhMjI5MThjNTBlNjg3ZjdkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzEzNzU2MjAwMDAwMDA2LCAtNzkuNDkwMDczOF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81OGU0ZmM2Mjc0MTI0NTVhYjQzZTcxMjFiNmFlM2RmNCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjAyYTkzMDZlOWU3NDliOGI1ZmVjNDEwNjQyZjAwNDcgPSAkKGA8ZGl2IGlkPSJodG1sXzIwMmE5MzA2ZTllNzQ5YjhiNWZlYzQxMDY0MmYwMDQ3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3duc3ZpZXcsIE5vcnRoIFBhcmssIFVwd29vZCBQYXJrLCBOb3J0aCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzU4ZTRmYzYyNzQxMjQ1NWFiNDNlNzEyMWI2YWUzZGY0LnNldENvbnRlbnQoaHRtbF8yMDJhOTMwNmU5ZTc0OWI4YjVmZWM0MTA2NDJmMDA0Nyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYjE2ZTBmMWVjZWQzNDA2YmEyMjkxOGM1MGU2ODdmN2QuYmluZFBvcHVwKHBvcHVwXzU4ZTRmYzYyNzQxMjQ1NWFiNDNlNzEyMWI2YWUzZGY0KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wOGM4NDcxYmRiMGQ0MmFlODc2NThiOTM0MGVhMDIwNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY5MTExNTgsIC03OS40NzYwMTMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81Y2Q5ZjI5NWNiZTU0YzU0OWY4Nzk4NzVkYzJmN2U4NCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZTk3OGMyY2Y2YmJjNDQ1MWExYTUyNTYwNjcyMzUxMmIgPSAkKGA8ZGl2IGlkPSJodG1sX2U5NzhjMmNmNmJiYzQ0NTFhMWE1MjU2MDY3MjM1MTJiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EZWwgUmF5LCBLZWVsZXNkYWxlLCBNb3VudCBEZW5uaXMsIFNpbHZlcnRob3JuLCBZb3JrPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzVjZDlmMjk1Y2JlNTRjNTQ5Zjg3OTg3NWRjMmY3ZTg0LnNldENvbnRlbnQoaHRtbF9lOTc4YzJjZjZiYmM0NDUxYTFhNTI1NjA2NzIzNTEyYik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMDhjODQ3MWJkYjBkNDJhZTg3NjU4YjkzNDBlYTAyMDYuYmluZFBvcHVwKHBvcHVwXzVjZDlmMjk1Y2JlNTRjNTQ5Zjg3OTg3NWRjMmY3ZTg0KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kNzU2YzRiZGY0N2I0NGJjOTA5MDcxYzAyMzhmZjM3YyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3MzE4NTI5OTk5OTk5LCAtNzkuNDg3MjYxOTAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZmY1ZjU2ZDNkZTFmNDJjODgwNTQ5ZjI5ZWM3ZjE5NDkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzc5YWVlYjc4M2RlMDQ0NzJiMDJhMTQ2NzM4NjI4YjFmID0gJChgPGRpdiBpZD0iaHRtbF83OWFlZWI3ODNkZTA0NDcyYjAyYTE0NjczODYyOGIxZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEp1bmN0aW9uIE5vcnRoLCBSdW5ueW1lZGUsIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZmY1ZjU2ZDNkZTFmNDJjODgwNTQ5ZjI5ZWM3ZjE5NDkuc2V0Q29udGVudChodG1sXzc5YWVlYjc4M2RlMDQ0NzJiMDJhMTQ2NzM4NjI4YjFmKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kNzU2YzRiZGY0N2I0NGJjOTA5MDcxYzAyMzhmZjM3Yy5iaW5kUG9wdXAocG9wdXBfZmY1ZjU2ZDNkZTFmNDJjODgwNTQ5ZjI5ZWM3ZjE5NDkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y5ZGQ3ZTU5ZWFkODQzZTg5NzFmODFiNGQ5MzhhOTA4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjYxNjA4MywgLTc5LjQ2NDc2MzI5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2I5NGM0YzhhYzNhMzQ2ODRiZjRiYjQyNzYwN2FlYjIwID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iNzk3YzM3MmRkYWM0ZjU3YjJjOTRhOGVmOTcwMTU3ZiA9ICQoYDxkaXYgaWQ9Imh0bWxfYjc5N2MzNzJkZGFjNGY1N2IyYzk0YThlZjk3MDE1N2YiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhpZ2ggUGFyaywgVGhlIEp1bmN0aW9uIFNvdXRoLCBXZXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYjk0YzRjOGFjM2EzNDY4NGJmNGJiNDI3NjA3YWViMjAuc2V0Q29udGVudChodG1sX2I3OTdjMzcyZGRhYzRmNTdiMmM5NGE4ZWY5NzAxNTdmKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9mOWRkN2U1OWVhZDg0M2U4OTcxZjgxYjRkOTM4YTkwOC5iaW5kUG9wdXAocG9wdXBfYjk0YzRjOGFjM2EzNDY4NGJmNGJiNDI3NjA3YWViMjApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzI1ZDljY2EwYWFlZTRmMzk5ZDdiNGNlNzY2MDFjMGVkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ4OTU5NywgLTc5LjQ1NjMyNV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81YmZmYjA0MjhhMzc0ODU3ODRiNGY4YThjNGE5OTBmNSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfY2IwOWIzMjBhNzdkNDdiOGIzOTBhODIzNWQ3Y2EwMWMgPSAkKGA8ZGl2IGlkPSJodG1sX2NiMDliMzIwYTc3ZDQ3YjhiMzkwYTgyMzVkN2NhMDFjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5QYXJrZGFsZSwgUm9uY2VzdmFsbGVzLCBXZXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNWJmZmIwNDI4YTM3NDg1Nzg0YjRmOGE4YzRhOTkwZjUuc2V0Q29udGVudChodG1sX2NiMDliMzIwYTc3ZDQ3YjhiMzkwYTgyMzVkN2NhMDFjKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yNWQ5Y2NhMGFhZWU0ZjM5OWQ3YjRjZTc2NjAxYzBlZC5iaW5kUG9wdXAocG9wdXBfNWJmZmIwNDI4YTM3NDg1Nzg0YjRmOGE4YzRhOTkwZjUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzUyNWU5YjliZWVhNjRiNWE5OTRkNTZmZWRjZDk1MDQ5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUxNTcwNiwgLTc5LjQ4NDQ0OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTQzNzYzOTk0ZmNlNGJkN2IzNjE5NDc2NzAwNjVjNTcgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzUzNjI4ZmNiMDY3YzQ3N2M5YmJiMGMwNTRlYzM3ZDNjID0gJChgPGRpdiBpZD0iaHRtbF81MzYyOGZjYjA2N2M0NzdjOWJiYjBjMDU0ZWMzN2QzYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UnVubnltZWRlLCBTd2Fuc2VhLCBXZXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTQzNzYzOTk0ZmNlNGJkN2IzNjE5NDc2NzAwNjVjNTcuc2V0Q29udGVudChodG1sXzUzNjI4ZmNiMDY3YzQ3N2M5YmJiMGMwNTRlYzM3ZDNjKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl81MjVlOWI5YmVlYTY0YjVhOTk0ZDU2ZmVkY2Q5NTA0OS5iaW5kUG9wdXAocG9wdXBfOTQzNzYzOTk0ZmNlNGJkN2IzNjE5NDc2NzAwNjVjNTcpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NkZDk5YjcwY2EwNDQwNDVhZjc3NjlhOTM1OGQ4OWM4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjYyMzAxNSwgLTc5LjM4OTQ5MzhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZDRiZTY5YzAzMDY5NDllYWFiOTBiZmRiMmVmNDVkMWIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzE1ZjE4ZDU3ZGRmNzQ3YjZhZWMzYmFhNGRiNWU4NzQzID0gJChgPGRpdiBpZD0iaHRtbF8xNWYxOGQ1N2RkZjc0N2I2YWVjM2JhYTRkYjVlODc0MyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UXVlZW4mIzM5O3MgUGFyaywgUXVlZW4mIzM5O3MgUGFyazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kNGJlNjljMDMwNjk0OWVhYWI5MGJmZGIyZWY0NWQxYi5zZXRDb250ZW50KGh0bWxfMTVmMThkNTdkZGY3NDdiNmFlYzNiYWE0ZGI1ZTg3NDMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2NkZDk5YjcwY2EwNDQwNDVhZjc3NjlhOTM1OGQ4OWM4LmJpbmRQb3B1cChwb3B1cF9kNGJlNjljMDMwNjk0OWVhYWI5MGJmZGIyZWY0NWQxYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjAyM2I0YmJhNTgzNGJlOWJlYzgwZjE0ZjgxMTRmZDAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42MzY5NjU2LCAtNzkuNjE1ODE4OTk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOGM4MTNjMDUxODQwNDgwZGE1OTJjYmZhNjJlMjM0MTkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzNjNzI5YzYzZmZhYTRlZWQ5ZTY4N2YyMGI4MmJkOWM4ID0gJChgPGRpdiBpZD0iaHRtbF8zYzcyOWM2M2ZmYWE0ZWVkOWU2ODdmMjBiODJiZDljOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2FuYWRhIFBvc3QgR2F0ZXdheSBQcm9jZXNzaW5nIENlbnRyZSwgTWlzc2lzc2F1Z2E8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOGM4MTNjMDUxODQwNDgwZGE1OTJjYmZhNjJlMjM0MTkuc2V0Q29udGVudChodG1sXzNjNzI5YzYzZmZhYTRlZWQ5ZTY4N2YyMGI4MmJkOWM4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yMDIzYjRiYmE1ODM0YmU5YmVjODBmMTRmODExNGZkMC5iaW5kUG9wdXAocG9wdXBfOGM4MTNjMDUxODQwNDgwZGE1OTJjYmZhNjJlMjM0MTkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2RhMDMyOGM1ZjQ3MDRlMDNhMDY0MDViZTRkNDI4MDVkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjYyNzQzOSwgLTc5LjMyMTU1OF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82YzIxYTkxZjE5Yzk0NjdlYjNmYmRjZjE3NGIzNDQ4ZiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfN2RhYjJiNTFhZDE0NDliZDgwMDhmNjg4OWRkOGQzNzIgPSAkKGA8ZGl2IGlkPSJodG1sXzdkYWIyYjUxYWQxNDQ5YmQ4MDA4ZjY4ODlkZDhkMzcyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CdXNpbmVzcyBSZXBseSBNYWlsIFByb2Nlc3NpbmcgQ2VudHJlIDk2OSBFYXN0ZXJuLCBFYXN0IFRvcm9udG88L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNmMyMWE5MWYxOWM5NDY3ZWIzZmJkY2YxNzRiMzQ0OGYuc2V0Q29udGVudChodG1sXzdkYWIyYjUxYWQxNDQ5YmQ4MDA4ZjY4ODlkZDhkMzcyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kYTAzMjhjNWY0NzA0ZTAzYTA2NDA1YmU0ZDQyODA1ZC5iaW5kUG9wdXAocG9wdXBfNmMyMWE5MWYxOWM5NDY3ZWIzZmJkY2YxNzRiMzQ0OGYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzczOTdjODNhY2Q2ZjQ0ZGZhYTM2YTcxM2Y5ZDcyY2JmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjA1NjQ2NiwgLTc5LjUwMTMyMDcwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzdmYWVmN2ViNzNhNzQ0Njk4OTg4Y2U4YTQ5MGJkNDQ1ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8zM2YzNDcyMjMzZDg0OThkODNmZjJiOTk2MjU1Nzg4MSA9ICQoYDxkaXYgaWQ9Imh0bWxfMzNmMzQ3MjIzM2Q4NDk4ZDgzZmYyYjk5NjI1NTc4ODEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkh1bWJlciBCYXkgU2hvcmVzLCBNaW1pY28gU291dGgsIE5ldyBUb3JvbnRvLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfN2ZhZWY3ZWI3M2E3NDQ2OTg5ODhjZThhNDkwYmQ0NDUuc2V0Q29udGVudChodG1sXzMzZjM0NzIyMzNkODQ5OGQ4M2ZmMmI5OTYyNTU3ODgxKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl83Mzk3YzgzYWNkNmY0NGRmYWEzNmE3MTNmOWQ3MmNiZi5iaW5kUG9wdXAocG9wdXBfN2ZhZWY3ZWI3M2E3NDQ2OTg5ODhjZThhNDkwYmQ0NDUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2YyZDlhZGEzMDhjMTRkNTg4ZTEwYTAwYjAxMTBlYTRiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjAyNDEzNzAwMDAwMDEsIC03OS41NDM0ODQwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kMWM0MmU0MDY3Yjk0MGMwYmY2YzI1OTdlODNiN2NmMCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjYxNWQyZTY1MWYwNDI0NTg4ODNjN2JmNGVlZDQ1YmQgPSAkKGA8ZGl2IGlkPSJodG1sXzY2MTVkMmU2NTFmMDQyNDU4ODgzYzdiZjRlZWQ0NWJkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5BbGRlcndvb2QsIExvbmcgQnJhbmNoLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZDFjNDJlNDA2N2I5NDBjMGJmNmMyNTk3ZTgzYjdjZjAuc2V0Q29udGVudChodG1sXzY2MTVkMmU2NTFmMDQyNDU4ODgzYzdiZjRlZWQ0NWJkKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9mMmQ5YWRhMzA4YzE0ZDU4OGUxMGEwMGIwMTEwZWE0Yi5iaW5kUG9wdXAocG9wdXBfZDFjNDJlNDA2N2I5NDBjMGJmNmMyNTk3ZTgzYjdjZjApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U4YjMxODY3OTkyOTQ0NWFhN2UwMGJjYjM1ZWQxNDdkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUzNjUzNjAwMDAwMDA1LCAtNzkuNTA2OTQzNl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83ZTE4ZjQxZDcwZTM0ZDBjYmIzNjY4ZTE3OTNmM2E0NCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMDUxYWY4YTM4NDUwNGYyZjlhNTczNjNlOTE4MzI1ZmMgPSAkKGA8ZGl2IGlkPSJodG1sXzA1MWFmOGEzODQ1MDRmMmY5YTU3MzYzZTkxODMyNWZjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5UaGUgS2luZ3N3YXksIE1vbnRnb21lcnkgUm9hZCwgT2xkIE1pbGwgTm9ydGgsIEV0b2JpY29rZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83ZTE4ZjQxZDcwZTM0ZDBjYmIzNjY4ZTE3OTNmM2E0NC5zZXRDb250ZW50KGh0bWxfMDUxYWY4YTM4NDUwNGYyZjlhNTczNjNlOTE4MzI1ZmMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U4YjMxODY3OTkyOTQ0NWFhN2UwMGJjYjM1ZWQxNDdkLmJpbmRQb3B1cChwb3B1cF83ZTE4ZjQxZDcwZTM0ZDBjYmIzNjY4ZTE3OTNmM2E0NCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZTkyNjQxZDVmYWYyNDk0Njg5NDQ5ZjI4MGZlYmMwOTYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42MzYyNTc5LCAtNzkuNDk4NTA5MDk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZjBhZWRlNjRkMWI5NDQ5ZmJkMzgyZTUyODRiN2M5ZjEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzAyN2UwZTE2MDI2OTQ2YjRiYTUzMWFlNTcwMWUyZDYyID0gJChgPGRpdiBpZD0iaHRtbF8wMjdlMGUxNjAyNjk0NmI0YmE1MzFhZTU3MDFlMmQ2MiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SHVtYmVyIEJheSwgS2luZyYjMzk7cyBNaWxsIFBhcmssIEtpbmdzd2F5IFBhcmsgU291dGggRWFzdCwgTWltaWNvIE5FLCBPbGQgTWlsbCBTb3V0aCwgVGhlIFF1ZWVuc3dheSBFYXN0LCBSb3lhbCBZb3JrIFNvdXRoIEVhc3QsIFN1bm55bGVhLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZjBhZWRlNjRkMWI5NDQ5ZmJkMzgyZTUyODRiN2M5ZjEuc2V0Q29udGVudChodG1sXzAyN2UwZTE2MDI2OTQ2YjRiYTUzMWFlNTcwMWUyZDYyKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9lOTI2NDFkNWZhZjI0OTQ2ODk0NDlmMjgwZmViYzA5Ni5iaW5kUG9wdXAocG9wdXBfZjBhZWRlNjRkMWI5NDQ5ZmJkMzgyZTUyODRiN2M5ZjEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2QxNTgxZTBjNmVkZDQ1ZDE4ZDk4YTcxODFiZTliODU2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjI4ODQwOCwgLTc5LjUyMDk5OTQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzRhYzdhY2YyMzc3NTRiOGE4MDE3NzRmM2JmZTk1OWM1ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iZmY3ZTc1YTlkM2E0YjU5OGVkYWJlYmY5YWFkNDU5NiA9ICQoYDxkaXYgaWQ9Imh0bWxfYmZmN2U3NWE5ZDNhNGI1OThlZGFiZWJmOWFhZDQ1OTYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPktpbmdzd2F5IFBhcmsgU291dGggV2VzdCwgTWltaWNvIE5XLCBUaGUgUXVlZW5zd2F5IFdlc3QsIFJveWFsIFlvcmsgU291dGggV2VzdCwgU291dGggb2YgQmxvb3IsIEV0b2JpY29rZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80YWM3YWNmMjM3NzU0YjhhODAxNzc0ZjNiZmU5NTljNS5zZXRDb250ZW50KGh0bWxfYmZmN2U3NWE5ZDNhNGI1OThlZGFiZWJmOWFhZDQ1OTYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2QxNTgxZTBjNmVkZDQ1ZDE4ZDk4YTcxODFiZTliODU2LmJpbmRQb3B1cChwb3B1cF80YWM3YWNmMjM3NzU0YjhhODAxNzc0ZjNiZmU5NTljNSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfODNkMjU1MmZhOGUzNDYxMDk5NTE4YTIxNzNiZGMyMGMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Njc4NTU2LCAtNzkuNTMyMjQyNDAwMDAwMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYjM3Yzc5ZmY0YjE0NGY3ZTljMGU0ZjljYmI5ZTM3OGYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzU0MWE4YTViOGI5YzQ4NDA5NGRiNTJmNDk3Yjg4N2Y5ID0gJChgPGRpdiBpZD0iaHRtbF81NDFhOGE1YjhiOWM0ODQwOTRkYjUyZjQ5N2I4ODdmOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SXNsaW5ndG9uIEF2ZW51ZSwgRXRvYmljb2tlPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2IzN2M3OWZmNGIxNDRmN2U5YzBlNGY5Y2JiOWUzNzhmLnNldENvbnRlbnQoaHRtbF81NDFhOGE1YjhiOWM0ODQwOTRkYjUyZjQ5N2I4ODdmOSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfODNkMjU1MmZhOGUzNDYxMDk5NTE4YTIxNzNiZGMyMGMuYmluZFBvcHVwKHBvcHVwX2IzN2M3OWZmNGIxNDRmN2U5YzBlNGY5Y2JiOWUzNzhmKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yMDE4YmYzZjY3YjY0YjU3YWRlNTExZDk2NDUwMDQ0OSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MDk0MzIsIC03OS41NTQ3MjQ0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81MDA4OGYzNWY1NWU0YTlkOTg4ZDZjNWM0NmM2Mzc1MiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMGYxNmRlNTZmYjc0NGE0NjgwM2IxNTBmZmU2N2FlOTEgPSAkKGA8ZGl2IGlkPSJodG1sXzBmMTZkZTU2ZmI3NDRhNDY4MDNiMTUwZmZlNjdhZTkxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbG92ZXJkYWxlLCBJc2xpbmd0b24sIE1hcnRpbiBHcm92ZSwgUHJpbmNlc3MgR2FyZGVucywgV2VzdCBEZWFuZSBQYXJrLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNTAwODhmMzVmNTVlNGE5ZDk4OGQ2YzVjNDZjNjM3NTIuc2V0Q29udGVudChodG1sXzBmMTZkZTU2ZmI3NDRhNDY4MDNiMTUwZmZlNjdhZTkxKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yMDE4YmYzZjY3YjY0YjU3YWRlNTExZDk2NDUwMDQ0OS5iaW5kUG9wdXAocG9wdXBfNTAwODhmMzVmNTVlNGE5ZDk4OGQ2YzVjNDZjNjM3NTIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U2YjgxMWUyZjc5ODRiZWRiMDNhNGFmODgyMGQxZWU0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQzNTE1MiwgLTc5LjU3NzIwMDc5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzFmZDRlZDZmZjAwMDQ4Yjc5NzBlNzRlMDZkMDhhZjkyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80Y2NiZGFlMTM0NmY0MmEyYWEyZWY2MTYzNWZhNzIwOSA9ICQoYDxkaXYgaWQ9Imh0bWxfNGNjYmRhZTEzNDZmNDJhMmFhMmVmNjE2MzVmYTcyMDkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJsb29yZGFsZSBHYXJkZW5zLCBFcmluZ2F0ZSwgTWFya2xhbmQgV29vZCwgT2xkIEJ1cm5oYW10aG9ycGUsIEV0b2JpY29rZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xZmQ0ZWQ2ZmYwMDA0OGI3OTcwZTc0ZTA2ZDA4YWY5Mi5zZXRDb250ZW50KGh0bWxfNGNjYmRhZTEzNDZmNDJhMmFhMmVmNjE2MzVmYTcyMDkpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U2YjgxMWUyZjc5ODRiZWRiMDNhNGFmODgyMGQxZWU0LmJpbmRQb3B1cChwb3B1cF8xZmQ0ZWQ2ZmYwMDA0OGI3OTcwZTc0ZTA2ZDA4YWY5MikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzNlOTJlNzI0NmQ4NDQ3ODlkNmYwNzNjNzBkNDA4NjIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NTYzMDMzLCAtNzkuNTY1OTYzMjk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzVmNWI4NThjOGQyNGE3Y2JiZDA5OTkyNWU5NjY5MWIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzY4OGZkYzk5NTJjNDQ0MTdiNDY3MzFlNjZkNDMyM2ExID0gJChgPGRpdiBpZD0iaHRtbF82ODhmZGM5OTUyYzQ0NDE3YjQ2NzMxZTY2ZDQzMjNhMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SHVtYmVyIFN1bW1pdCwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83NWY1Yjg1OGM4ZDI0YTdjYmJkMDk5OTI1ZTk2NjkxYi5zZXRDb250ZW50KGh0bWxfNjg4ZmRjOTk1MmM0NDQxN2I0NjczMWU2NmQ0MzIzYTEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2MzZTkyZTcyNDZkODQ0Nzg5ZDZmMDczYzcwZDQwODYyLmJpbmRQb3B1cChwb3B1cF83NWY1Yjg1OGM4ZDI0YTdjYmJkMDk5OTI1ZTk2NjkxYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWU3YzMxNjJlMmE3NDA5Yzk4M2RmNWViMjVlZTYzMjIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MjQ3NjU5LCAtNzkuNTMyMjQyNDAwMDAwMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYzExMWUxZTI2YTFlNDJjYTgzZjUwMDgwYzk1NGIzM2YgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzQ5YmNkNGY2OWNmOTQ1NzM4MTRlNzBlYTAxYzRlOGNkID0gJChgPGRpdiBpZD0iaHRtbF80OWJjZDRmNjljZjk0NTczODE0ZTcwZWEwMWM0ZThjZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RW1lcnksIEh1bWJlcmxlYSwgTm9ydGggWW9yazwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9jMTExZTFlMjZhMWU0MmNhODNmNTAwODBjOTU0YjMzZi5zZXRDb250ZW50KGh0bWxfNDliY2Q0ZjY5Y2Y5NDU3MzgxNGU3MGVhMDFjNGU4Y2QpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2VlN2MzMTYyZTJhNzQwOWM5ODNkZjVlYjI1ZWU2MzIyLmJpbmRQb3B1cChwb3B1cF9jMTExZTFlMjZhMWU0MmNhODNmNTAwODBjOTU0YjMzZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZTU5MmE0NzYzZTA5NGRiMDhmODRhZjBkZGRjM2Y2YmUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDY4NzYsIC03OS41MTgxODg0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9mNDVhMTY4ZGY3MTE0ODY3OWRkYzNjMmUxZWVlNDA2MyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYTVlYzYwNjQ4MGMxNDNlMmExMDczMzZmYjM0ZDc3ZGUgPSAkKGA8ZGl2IGlkPSJodG1sX2E1ZWM2MDY0ODBjMTQzZTJhMTA3MzM2ZmIzNGQ3N2RlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5XZXN0b24sIFlvcms8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZjQ1YTE2OGRmNzExNDg2NzlkZGMzYzJlMWVlZTQwNjMuc2V0Q29udGVudChodG1sX2E1ZWM2MDY0ODBjMTQzZTJhMTA3MzM2ZmIzNGQ3N2RlKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9lNTkyYTQ3NjNlMDk0ZGIwOGY4NGFmMGRkZGMzZjZiZS5iaW5kUG9wdXAocG9wdXBfZjQ1YTE2OGRmNzExNDg2NzlkZGMzYzJlMWVlZTQwNjMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NlMTJlOWE0MjM1ODQ4Mjc5NWMzMTA4M2M4ZjllNTFhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjk2MzE5LCAtNzkuNTMyMjQyNDAwMDAwMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogImJsdWUiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzMyODdjZCIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogOSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF9iOWJkZGU1MzBjNmE0NzcwODM2MTVjY2FjZjk3NjgxYyk7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYjIyZjkwMzQ2MTY0NDRiNTg3Y2QyNjA4ZDA3MTM3YmUgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzVlNjdhZDk2MjM2MzRlMjU4ZjZlYzliYmNhYjNlMGFjID0gJChgPGRpdiBpZD0iaHRtbF81ZTY3YWQ5NjIzNjM0ZTI1OGY2ZWM5YmJjYWIzZTBhYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdG1vdW50LCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYjIyZjkwMzQ2MTY0NDRiNTg3Y2QyNjA4ZDA3MTM3YmUuc2V0Q29udGVudChodG1sXzVlNjdhZDk2MjM2MzRlMjU4ZjZlYzliYmNhYjNlMGFjKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9jZTEyZTlhNDIzNTg0ODI3OTVjMzEwODNjOGY5ZTUxYS5iaW5kUG9wdXAocG9wdXBfYjIyZjkwMzQ2MTY0NDRiNTg3Y2QyNjA4ZDA3MTM3YmUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzIxOTBkNTcwZDJhZTQ0ZDdhOTMwMTU4OWNiNDY1OWZlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjg4OTA1NCwgLTc5LjU1NDcyNDQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICJibHVlIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMzMjg3Y2QiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDksICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjliZGRlNTMwYzZhNDc3MDgzNjE1Y2NhY2Y5NzY4MWMpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2IxNTVmMzM4YmI2MjQyZjJiNzgzOWMxZTFkYjQ2OGI2ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9kNGExODA3OGFkMmQ0NDhmYWE4ODJiYzVlNTBlNmZiNyA9ICQoYDxkaXYgaWQ9Imh0bWxfZDRhMTgwNzhhZDJkNDQ4ZmFhODgyYmM1ZTUwZTZmYjciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPktpbmdzdmlldyBWaWxsYWdlLCBNYXJ0aW4gR3JvdmUgR2FyZGVucywgUmljaHZpZXcgR2FyZGVucywgU3QuIFBoaWxsaXBzLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYjE1NWYzMzhiYjYyNDJmMmI3ODM5YzFlMWRiNDY4YjYuc2V0Q29udGVudChodG1sX2Q0YTE4MDc4YWQyZDQ0OGZhYTg4MmJjNWU1MGU2ZmI3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yMTkwZDU3MGQyYWU0NGQ3YTkzMDE1ODljYjQ2NTlmZS5iaW5kUG9wdXAocG9wdXBfYjE1NWYzMzhiYjYyNDJmMmI3ODM5YzFlMWRiNDY4YjYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzY3ZDk2NmE3YTU5NjRiZmZhYjFjNTEyYzNjYzlkNjU1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzM5NDE2Mzk5OTk5OTk2LCAtNzkuNTg4NDM2OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hYjE0NDU2ZjUwZDQ0MDUwODhhMzgxN2Q3NDhlODJjNyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMzE0MmVlMDRlMWViNGY2OGI4NTdlNTVmY2M0OWMwMzkgPSAkKGA8ZGl2IGlkPSJodG1sXzMxNDJlZTA0ZTFlYjRmNjhiODU3ZTU1ZmNjNDljMDM5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5BbGJpb24gR2FyZGVucywgQmVhdW1vbmQgSGVpZ2h0cywgSHVtYmVyZ2F0ZSwgSmFtZXN0b3duLCBNb3VudCBPbGl2ZSwgU2lsdmVyc3RvbmUsIFNvdXRoIFN0ZWVsZXMsIFRoaXN0bGV0b3duLCBFdG9iaWNva2U8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYWIxNDQ1NmY1MGQ0NDA1MDg4YTM4MTdkNzQ4ZTgyYzcuc2V0Q29udGVudChodG1sXzMxNDJlZTA0ZTFlYjRmNjhiODU3ZTU1ZmNjNDljMDM5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82N2Q5NjZhN2E1OTY0YmZmYWIxYzUxMmMzY2M5ZDY1NS5iaW5kUG9wdXAocG9wdXBfYWIxNDQ1NmY1MGQ0NDA1MDg4YTM4MTdkNzQ4ZTgyYzcpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzUwZmQ0OTdiMDU3NTQwMDlhYTk0ZTlhMDI4NTQ1NTlmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzA2NzQ4Mjk5OTk5OTk0LCAtNzkuNTk0MDU0NF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiYmx1ZSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMzI4N2NkIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiA5LCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwX2I5YmRkZTUzMGM2YTQ3NzA4MzYxNWNjYWNmOTc2ODFjKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wMjkxOWUwNTk0NjI0YmRjYWExMjIxODNiM2VlZDViMiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMzc0MzliYjkxMjQzNDVjNTkyNjA1M2ZmZDk1NTM2N2IgPSAkKGA8ZGl2IGlkPSJodG1sXzM3NDM5YmI5MTI0MzQ1YzU5MjYwNTNmZmQ5NTUzNjdiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ob3J0aHdlc3QsIEV0b2JpY29rZTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8wMjkxOWUwNTk0NjI0YmRjYWExMjIxODNiM2VlZDViMi5zZXRDb250ZW50KGh0bWxfMzc0MzliYjkxMjQzNDVjNTkyNjA1M2ZmZDk1NTM2N2IpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzUwZmQ0OTdiMDU3NTQwMDlhYTk0ZTlhMDI4NTQ1NTlmLmJpbmRQb3B1cChwb3B1cF8wMjkxOWUwNTk0NjI0YmRjYWExMjIxODNiM2VlZDViMikKICAgICAgICA7CgogICAgICAgIAogICAgCjwvc2NyaXB0Pg==\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
],
"text/plain": [
"<folium.folium.Map at 0x7f89b7274eb8>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# create map of Toronto using latitude and longitude values\n",
"map_toronto = folium.Map(location=[latitude, longitude], zoom_start=11)\n",
"\n",
"# add markers to map\n",
"for lat, lng, borough, neighborhood in zip(mydf_post['Latitude'], mydf_post['Longitude'], mydf_post['Borough'], mydf_post['Neighbourhood']):\n",
" label = '{}, {}'.format(neighborhood, borough)\n",
" label = folium.Popup(label, parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lng],\n",
" radius=9,\n",
" popup=label,\n",
" color='blue',\n",
" fill=True,\n",
" fill_color='#3287cd',\n",
" fill_opacity=0.5,\n",
" parse_html=False).add_to(map_toronto) \n",
" \n",
"map_toronto"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Get Foursquare data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First off, we need to enter our credentials in order to access the Foursquare API."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"outputs": [],
"source": [
"CLIENT_ID = 'EOGS2ZA3IH1DZAGOT0G0MLFHMRLQSAV1TMGAIW4N2EJEGPFG' # your Foursquare ID\n",
"CLIENT_SECRET = 'M2QXMSBBAOTLRW5RCOSNJUGYM0SRZB3WMT3QMR4SB1HVOYIT' # your Foursquare Secret\n",
"VERSION = '20180605' # Foursquare API version\n",
"\n",
"#print('Your credentails:')\n",
"#print('CLIENT_ID: ' + CLIENT_ID)\n",
"#print('CLIENT_SECRET:' + CLIENT_SECRET)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, let's set some sensible defaults to limit the amount of data we are pulling from Foursquare."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"LIMIT = 100 # limit of number of venues returned by Foursquare API\n",
"radius = 500 # define radius"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To make gathering the nearby venues more efficient, let's create a function to pull the relevant data for all the Boroughs that returns the data in a neat data frame."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def getNearbyVenues(names, latitudes, longitudes, radius=500):\n",
" \n",
" venues_list=[]\n",
" for name, lat, lng in zip(names, latitudes, longitudes):\n",
" print(name)\n",
" \n",
" # create the API request URL\n",
" url = 'https://api.foursquare.com/v2/venues/explore?&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}'.format(\n",
" CLIENT_ID, \n",
" CLIENT_SECRET, \n",
" VERSION, \n",
" lat, \n",
" lng, \n",
" radius, \n",
" LIMIT)\n",
" \n",
" # make the GET request\n",
" results = requests.get(url).json()[\"response\"]['groups'][0]['items']\n",
" \n",
" # return only relevant information for each nearby venue\n",
" venues_list.append([(\n",
" name, \n",
" lat, \n",
" lng, \n",
" v['venue']['name'], \n",
" v['venue']['location']['lat'], \n",
" v['venue']['location']['lng'], \n",
" v['venue']['categories'][0]['name']) for v in results])\n",
"\n",
" nearby_venues = pd.DataFrame([item for venue_list in venues_list for item in venue_list])\n",
" nearby_venues.columns = ['Neighbourhood', \n",
" 'Neighbourhood Latitude', \n",
" 'Neighbourhood Longitude', \n",
" 'Venue', \n",
" 'Venue Latitude', \n",
" 'Venue Longitude', \n",
" 'Venue Category']\n",
" \n",
" return(nearby_venues)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's call the function with our data as parameter."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Rouge, Malvern\n",
"Highland Creek, Rouge Hill, Port Union\n",
"Guildwood, Morningside, West Hill\n",
"Woburn\n",
"Cedarbrae\n",
"Scarborough Village\n",
"East Birchmount Park, Ionview, Kennedy Park\n",
"Clairlea, Golden Mile, Oakridge\n",
"Cliffcrest, Cliffside, Scarborough Village West\n",
"Birch Cliff, Cliffside West\n",
"Dorset Park, Scarborough Town Centre, Wexford Heights\n",
"Maryvale, Wexford\n",
"Agincourt\n",
"Clarks Corners, Sullivan, Tam O'Shanter\n",
"Agincourt North, L'Amoreaux East, Milliken, Steeles East\n",
"L'Amoreaux West\n",
"Upper Rouge\n",
"Hillcrest Village\n",
"Fairview, Henry Farm, Oriole\n",
"Bayview Village\n",
"Silver Hills, York Mills\n",
"Newtonbrook, Willowdale\n",
"Willowdale South\n",
"York Mills West\n",
"Willowdale West\n",
"Parkwoods\n",
"Don Mills North\n",
"Flemingdon Park, Don Mills South\n",
"Bathurst Manor, Downsview North, Wilson Heights\n",
"Northwood Park, York University\n",
"CFB Toronto, Downsview East\n",
"Downsview West\n",
"Downsview Central\n",
"Downsview Northwest\n",
"Victoria Village\n",
"Woodbine Gardens, Parkview Hill\n",
"Woodbine Heights\n",
"The Beaches\n",
"Leaside\n",
"Thorncliffe Park\n",
"East Toronto\n",
"The Danforth West, Riverdale\n",
"The Beaches West, India Bazaar\n",
"Studio District\n",
"Lawrence Park\n",
"Davisville North\n",
"North Toronto West\n",
"Davisville\n",
"Moore Park, Summerhill East\n",
"Deer Park, Forest Hill SE, Rathnelly, South Hill, Summerhill West\n",
"Rosedale\n",
"Cabbagetown, St. James Town\n",
"Church and Wellesley\n",
"Harbourfront, Regent Park\n",
"Ryerson, Garden District\n",
"St. James Town\n",
"Berczy Park\n",
"Central Bay Street\n",
"Adelaide, King, Richmond\n",
"Harbourfront East, Toronto Islands, Union Station\n",
"Design Exchange, Toronto Dominion Centre\n",
"Commerce Court, Victoria Hotel\n",
"Bedford Park, Lawrence Manor East\n",
"Roselawn\n",
"Forest Hill North, Forest Hill West\n",
"The Annex, North Midtown, Yorkville\n",
"Harbord, University of Toronto\n",
"Chinatown, Grange Park, Kensington Market\n",
"CN Tower, Bathurst Quay, Island airport, Harbourfront West, King and Spadina, Railway Lands, South Niagara\n",
"Stn A PO Boxes 25 The Esplanade\n",
"First Canadian Place, Underground city\n",
"Lawrence Heights, Lawrence Manor\n",
"Glencairn\n",
"Humewood-Cedarvale\n",
"Caledonia-Fairbanks\n",
"Christie\n",
"Dovercourt Village, Dufferin\n",
"Little Portugal, Trinity\n",
"Brockton, Exhibition Place, Parkdale Village\n",
"Downsview, North Park, Upwood Park\n",
"Del Ray, Keelesdale, Mount Dennis, Silverthorn\n",
"The Junction North, Runnymede\n",
"High Park, The Junction South\n",
"Parkdale, Roncesvalles\n",
"Runnymede, Swansea\n",
"Queen's Park\n",
"Canada Post Gateway Processing Centre\n",
"Business Reply Mail Processing Centre 969 Eastern\n",
"Humber Bay Shores, Mimico South, New Toronto\n",
"Alderwood, Long Branch\n",
"The Kingsway, Montgomery Road, Old Mill North\n",
"Humber Bay, King's Mill Park, Kingsway Park South East, Mimico NE, Old Mill South, The Queensway East, Royal York South East, Sunnylea\n",
"Kingsway Park South West, Mimico NW, The Queensway West, Royal York South West, South of Bloor\n",
"Islington Avenue\n",
"Cloverdale, Islington, Martin Grove, Princess Gardens, West Deane Park\n",
"Bloordale Gardens, Eringate, Markland Wood, Old Burnhamthorpe\n",
"Humber Summit\n",
"Emery, Humberlea\n",
"Weston\n",
"Westmount\n",
"Kingsview Village, Martin Grove Gardens, Richview Gardens, St. Phillips\n",
"Albion Gardens, Beaumond Heights, Humbergate, Jamestown, Mount Olive, Silverstone, South Steeles, Thistletown\n",
"Northwest\n"
]
}
],
"source": [
"toronto_venues = getNearbyVenues(names=mydf_post['Neighbourhood'],\n",
" latitudes=mydf_post['Latitude'],\n",
" longitudes=mydf_post['Longitude']\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's inspect how much data we got back."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(2244, 7)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Neighbourhood</th>\n",
" <th>Neighbourhood Latitude</th>\n",
" <th>Neighbourhood Longitude</th>\n",
" <th>Venue</th>\n",
" <th>Venue Latitude</th>\n",
" <th>Venue Longitude</th>\n",
" <th>Venue Category</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Rouge, Malvern</td>\n",
" <td>43.806686</td>\n",
" <td>-79.194353</td>\n",
" <td>Wendy's</td>\n",
" <td>43.807448</td>\n",
" <td>-79.199056</td>\n",
" <td>Fast Food Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" <td>43.784535</td>\n",
" <td>-79.160497</td>\n",
" <td>Royal Canadian Legion</td>\n",
" <td>43.782533</td>\n",
" <td>-79.163085</td>\n",
" <td>Bar</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" <td>Swiss Chalet Rotisserie &amp; Grill</td>\n",
" <td>43.767697</td>\n",
" <td>-79.189914</td>\n",
" <td>Pizza Place</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" <td>G &amp; G Electronics</td>\n",
" <td>43.765309</td>\n",
" <td>-79.191537</td>\n",
" <td>Electronics Store</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" <td>Big Bite Burrito</td>\n",
" <td>43.766299</td>\n",
" <td>-79.190720</td>\n",
" <td>Mexican Restaurant</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Neighbourhood Neighbourhood Latitude \\\n",
"0 Rouge, Malvern 43.806686 \n",
"1 Highland Creek, Rouge Hill, Port Union 43.784535 \n",
"2 Guildwood, Morningside, West Hill 43.763573 \n",
"3 Guildwood, Morningside, West Hill 43.763573 \n",
"4 Guildwood, Morningside, West Hill 43.763573 \n",
"\n",
" Neighbourhood Longitude Venue Venue Latitude \\\n",
"0 -79.194353 Wendy's 43.807448 \n",
"1 -79.160497 Royal Canadian Legion 43.782533 \n",
"2 -79.188711 Swiss Chalet Rotisserie & Grill 43.767697 \n",
"3 -79.188711 G & G Electronics 43.765309 \n",
"4 -79.188711 Big Bite Burrito 43.766299 \n",
"\n",
" Venue Longitude Venue Category \n",
"0 -79.199056 Fast Food Restaurant \n",
"1 -79.163085 Bar \n",
"2 -79.189914 Pizza Place \n",
"3 -79.191537 Electronics Store \n",
"4 -79.190720 Mexican Restaurant "
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(toronto_venues.shape)\n",
"toronto_venues.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Analyze Neighbourhoods"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With the venue data from Foursquare, we are now ready to analyze the neighborhoods. Since we are interested in the frequency of the venue categories in each neighbourhood, we'll first one-hot encode those features and proceed with calculating the relative frequencies."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<bound method Series.unique of 0 Rouge, Malvern\n",
"1 Highland Creek, Rouge Hill, Port Union\n",
"2 Guildwood, Morningside, West Hill\n",
"3 Guildwood, Morningside, West Hill\n",
"4 Guildwood, Morningside, West Hill\n",
" ... \n",
"2239 Albion Gardens, Beaumond Heights, Humbergate, ...\n",
"2240 Albion Gardens, Beaumond Heights, Humbergate, ...\n",
"2241 Northwest\n",
"2242 Northwest\n",
"2243 Northwest\n",
"Name: Neighbourhood, Length: 2244, dtype: object>"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_venues['Neighbourhood'].unique"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(2244, 280)\n",
"(2244, 281)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Neighbourhood</th>\n",
" <th>Accessories Store</th>\n",
" <th>Afghan Restaurant</th>\n",
" <th>Airport</th>\n",
" <th>Airport Food Court</th>\n",
" <th>Airport Gate</th>\n",
" <th>Airport Lounge</th>\n",
" <th>Airport Service</th>\n",
" <th>Airport Terminal</th>\n",
" <th>American Restaurant</th>\n",
" <th>Antique Shop</th>\n",
" <th>Aquarium</th>\n",
" <th>Art Gallery</th>\n",
" <th>Art Museum</th>\n",
" <th>Arts &amp; Crafts Store</th>\n",
" <th>Asian Restaurant</th>\n",
" <th>Athletics &amp; Sports</th>\n",
" <th>Auto Garage</th>\n",
" <th>Auto Workshop</th>\n",
" <th>BBQ Joint</th>\n",
" <th>Baby Store</th>\n",
" <th>Bagel Shop</th>\n",
" <th>Bakery</th>\n",
" <th>Bank</th>\n",
" <th>Bar</th>\n",
" <th>Baseball Field</th>\n",
" <th>Baseball Stadium</th>\n",
" <th>Basketball Court</th>\n",
" <th>Basketball Stadium</th>\n",
" <th>Beach</th>\n",
" <th>Beer Bar</th>\n",
" <th>Beer Store</th>\n",
" <th>Bike Shop</th>\n",
" <th>Bistro</th>\n",
" <th>Boat or Ferry</th>\n",
" <th>Bookstore</th>\n",
" <th>Boutique</th>\n",
" <th>Brazilian Restaurant</th>\n",
" <th>Breakfast Spot</th>\n",
" <th>Brewery</th>\n",
" <th>Bridal Shop</th>\n",
" <th>Bubble Tea Shop</th>\n",
" <th>Building</th>\n",
" <th>Burger Joint</th>\n",
" <th>Burrito Place</th>\n",
" <th>Bus Line</th>\n",
" <th>Bus Station</th>\n",
" <th>Bus Stop</th>\n",
" <th>Butcher</th>\n",
" <th>Cafeteria</th>\n",
" <th>...</th>\n",
" <th>Salon / Barbershop</th>\n",
" <th>Sandwich Place</th>\n",
" <th>Scenic Lookout</th>\n",
" <th>Sculpture Garden</th>\n",
" <th>Seafood Restaurant</th>\n",
" <th>Shoe Store</th>\n",
" <th>Shopping Mall</th>\n",
" <th>Shopping Plaza</th>\n",
" <th>Skate Park</th>\n",
" <th>Skating Rink</th>\n",
" <th>Smoke Shop</th>\n",
" <th>Smoothie Shop</th>\n",
" <th>Snack Place</th>\n",
" <th>Soccer Field</th>\n",
" <th>Soup Place</th>\n",
" <th>Southern / Soul Food Restaurant</th>\n",
" <th>Spa</th>\n",
" <th>Speakeasy</th>\n",
" <th>Sporting Goods Shop</th>\n",
" <th>Sports Bar</th>\n",
" <th>Stadium</th>\n",
" <th>Stationery Store</th>\n",
" <th>Steakhouse</th>\n",
" <th>Strip Club</th>\n",
" <th>Supermarket</th>\n",
" <th>Supplement Shop</th>\n",
" <th>Sushi Restaurant</th>\n",
" <th>Swim School</th>\n",
" <th>Taco Place</th>\n",
" <th>Tailor Shop</th>\n",
" <th>Taiwanese Restaurant</th>\n",
" <th>Tanning Salon</th>\n",
" <th>Tapas Restaurant</th>\n",
" <th>Tea Room</th>\n",
" <th>Thai Restaurant</th>\n",
" <th>Theater</th>\n",
" <th>Theme Restaurant</th>\n",
" <th>Thrift / Vintage Store</th>\n",
" <th>Toy / Game Store</th>\n",
" <th>Trail</th>\n",
" <th>Train Station</th>\n",
" <th>Vegetarian / Vegan Restaurant</th>\n",
" <th>Video Game Store</th>\n",
" <th>Video Store</th>\n",
" <th>Vietnamese Restaurant</th>\n",
" <th>Warehouse Store</th>\n",
" <th>Wine Bar</th>\n",
" <th>Wings Joint</th>\n",
" <th>Women's Store</th>\n",
" <th>Yoga Studio</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Rouge, Malvern</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>...</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 281 columns</p>\n",
"</div>"
],
"text/plain": [
" Neighbourhood Accessories Store \\\n",
"0 Rouge, Malvern 0 \n",
"1 Highland Creek, Rouge Hill, Port Union 0 \n",
"2 Guildwood, Morningside, West Hill 0 \n",
"3 Guildwood, Morningside, West Hill 0 \n",
"4 Guildwood, Morningside, West Hill 0 \n",
"\n",
" Afghan Restaurant Airport Airport Food Court Airport Gate \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Airport Lounge Airport Service Airport Terminal American Restaurant \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Antique Shop Aquarium Art Gallery Art Museum Arts & Crafts Store \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Asian Restaurant Athletics & Sports Auto Garage Auto Workshop \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" BBQ Joint Baby Store Bagel Shop Bakery Bank Bar Baseball Field \\\n",
"0 0 0 0 0 0 0 0 \n",
"1 0 0 0 0 0 1 0 \n",
"2 0 0 0 0 0 0 0 \n",
"3 0 0 0 0 0 0 0 \n",
"4 0 0 0 0 0 0 0 \n",
"\n",
" Baseball Stadium Basketball Court Basketball Stadium Beach Beer Bar \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Beer Store Bike Shop Bistro Boat or Ferry Bookstore Boutique \\\n",
"0 0 0 0 0 0 0 \n",
"1 0 0 0 0 0 0 \n",
"2 0 0 0 0 0 0 \n",
"3 0 0 0 0 0 0 \n",
"4 0 0 0 0 0 0 \n",
"\n",
" Brazilian Restaurant Breakfast Spot Brewery Bridal Shop \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Bubble Tea Shop Building Burger Joint Burrito Place Bus Line \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Bus Station Bus Stop Butcher Cafeteria ... Salon / Barbershop \\\n",
"0 0 0 0 0 ... 0 \n",
"1 0 0 0 0 ... 0 \n",
"2 0 0 0 0 ... 0 \n",
"3 0 0 0 0 ... 0 \n",
"4 0 0 0 0 ... 0 \n",
"\n",
" Sandwich Place Scenic Lookout Sculpture Garden Seafood Restaurant \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Shoe Store Shopping Mall Shopping Plaza Skate Park Skating Rink \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Smoke Shop Smoothie Shop Snack Place Soccer Field Soup Place \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Southern / Soul Food Restaurant Spa Speakeasy Sporting Goods Shop \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Sports Bar Stadium Stationery Store Steakhouse Strip Club Supermarket \\\n",
"0 0 0 0 0 0 0 \n",
"1 0 0 0 0 0 0 \n",
"2 0 0 0 0 0 0 \n",
"3 0 0 0 0 0 0 \n",
"4 0 0 0 0 0 0 \n",
"\n",
" Supplement Shop Sushi Restaurant Swim School Taco Place Tailor Shop \\\n",
"0 0 0 0 0 0 \n",
"1 0 0 0 0 0 \n",
"2 0 0 0 0 0 \n",
"3 0 0 0 0 0 \n",
"4 0 0 0 0 0 \n",
"\n",
" Taiwanese Restaurant Tanning Salon Tapas Restaurant Tea Room \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Thai Restaurant Theater Theme Restaurant Thrift / Vintage Store \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Toy / Game Store Trail Train Station Vegetarian / Vegan Restaurant \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Video Game Store Video Store Vietnamese Restaurant Warehouse Store \\\n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
" Wine Bar Wings Joint Women's Store Yoga Studio \n",
"0 0 0 0 0 \n",
"1 0 0 0 0 \n",
"2 0 0 0 0 \n",
"3 0 0 0 0 \n",
"4 0 0 0 0 \n",
"\n",
"[5 rows x 281 columns]"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# one hot encoding\n",
"toronto_onehot = pd.get_dummies(toronto_venues[['Venue Category']], prefix=\"\", prefix_sep=\"\")\n",
"print(toronto_onehot.shape)\n",
"\n",
"# add neighborhood column back to dataframe\n",
"toronto_onehot['Neighbourhood'] = toronto_venues['Neighbourhood'] \n",
"print(toronto_onehot.shape)\n",
"\n",
"# move neighborhood column to the first column\n",
"fixed_columns = [toronto_onehot.columns[-1]] + list(toronto_onehot.columns[:-1])\n",
"toronto_onehot = toronto_onehot[fixed_columns]\n",
"\n",
"toronto_onehot.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's group by Neighbourhood to determine the frequencies of the venue types."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(101, 281)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Neighbourhood</th>\n",
" <th>Accessories Store</th>\n",
" <th>Afghan Restaurant</th>\n",
" <th>Airport</th>\n",
" <th>Airport Food Court</th>\n",
" <th>Airport Gate</th>\n",
" <th>Airport Lounge</th>\n",
" <th>Airport Service</th>\n",
" <th>Airport Terminal</th>\n",
" <th>American Restaurant</th>\n",
" <th>Antique Shop</th>\n",
" <th>Aquarium</th>\n",
" <th>Art Gallery</th>\n",
" <th>Art Museum</th>\n",
" <th>Arts &amp; Crafts Store</th>\n",
" <th>Asian Restaurant</th>\n",
" <th>Athletics &amp; Sports</th>\n",
" <th>Auto Garage</th>\n",
" <th>Auto Workshop</th>\n",
" <th>BBQ Joint</th>\n",
" <th>Baby Store</th>\n",
" <th>Bagel Shop</th>\n",
" <th>Bakery</th>\n",
" <th>Bank</th>\n",
" <th>Bar</th>\n",
" <th>Baseball Field</th>\n",
" <th>Baseball Stadium</th>\n",
" <th>Basketball Court</th>\n",
" <th>Basketball Stadium</th>\n",
" <th>Beach</th>\n",
" <th>Beer Bar</th>\n",
" <th>Beer Store</th>\n",
" <th>Bike Shop</th>\n",
" <th>Bistro</th>\n",
" <th>Boat or Ferry</th>\n",
" <th>Bookstore</th>\n",
" <th>Boutique</th>\n",
" <th>Brazilian Restaurant</th>\n",
" <th>Breakfast Spot</th>\n",
" <th>Brewery</th>\n",
" <th>Bridal Shop</th>\n",
" <th>Bubble Tea Shop</th>\n",
" <th>Building</th>\n",
" <th>Burger Joint</th>\n",
" <th>Burrito Place</th>\n",
" <th>Bus Line</th>\n",
" <th>Bus Station</th>\n",
" <th>Bus Stop</th>\n",
" <th>Butcher</th>\n",
" <th>Cafeteria</th>\n",
" <th>...</th>\n",
" <th>Salon / Barbershop</th>\n",
" <th>Sandwich Place</th>\n",
" <th>Scenic Lookout</th>\n",
" <th>Sculpture Garden</th>\n",
" <th>Seafood Restaurant</th>\n",
" <th>Shoe Store</th>\n",
" <th>Shopping Mall</th>\n",
" <th>Shopping Plaza</th>\n",
" <th>Skate Park</th>\n",
" <th>Skating Rink</th>\n",
" <th>Smoke Shop</th>\n",
" <th>Smoothie Shop</th>\n",
" <th>Snack Place</th>\n",
" <th>Soccer Field</th>\n",
" <th>Soup Place</th>\n",
" <th>Southern / Soul Food Restaurant</th>\n",
" <th>Spa</th>\n",
" <th>Speakeasy</th>\n",
" <th>Sporting Goods Shop</th>\n",
" <th>Sports Bar</th>\n",
" <th>Stadium</th>\n",
" <th>Stationery Store</th>\n",
" <th>Steakhouse</th>\n",
" <th>Strip Club</th>\n",
" <th>Supermarket</th>\n",
" <th>Supplement Shop</th>\n",
" <th>Sushi Restaurant</th>\n",
" <th>Swim School</th>\n",
" <th>Taco Place</th>\n",
" <th>Tailor Shop</th>\n",
" <th>Taiwanese Restaurant</th>\n",
" <th>Tanning Salon</th>\n",
" <th>Tapas Restaurant</th>\n",
" <th>Tea Room</th>\n",
" <th>Thai Restaurant</th>\n",
" <th>Theater</th>\n",
" <th>Theme Restaurant</th>\n",
" <th>Thrift / Vintage Store</th>\n",
" <th>Toy / Game Store</th>\n",
" <th>Trail</th>\n",
" <th>Train Station</th>\n",
" <th>Vegetarian / Vegan Restaurant</th>\n",
" <th>Video Game Store</th>\n",
" <th>Video Store</th>\n",
" <th>Vietnamese Restaurant</th>\n",
" <th>Warehouse Store</th>\n",
" <th>Wine Bar</th>\n",
" <th>Wings Joint</th>\n",
" <th>Women's Store</th>\n",
" <th>Yoga Studio</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Adelaide, King, Richmond</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.03</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.03</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.02</td>\n",
" <td>0.0</td>\n",
" <td>0.04</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.03</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.02</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>0.01</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.04</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.02</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.04</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" <td>0.01</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Agincourt</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.20</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>0.00</td>\n",
" <td>0.200000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.200000</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Agincourt North, L'Amoreaux East, Milliken, St...</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>0.00</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Albion Gardens, Beaumond Heights, Humbergate, ...</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.111111</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>0.00</td>\n",
" <td>0.111111</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Alderwood, Long Branch</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>...</td>\n",
" <td>0.00</td>\n",
" <td>0.111111</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.111111</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" <td>0.00</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 281 columns</p>\n",
"</div>"
],
"text/plain": [
" Neighbourhood Accessories Store \\\n",
"0 Adelaide, King, Richmond 0.0 \n",
"1 Agincourt 0.0 \n",
"2 Agincourt North, L'Amoreaux East, Milliken, St... 0.0 \n",
"3 Albion Gardens, Beaumond Heights, Humbergate, ... 0.0 \n",
"4 Alderwood, Long Branch 0.0 \n",
"\n",
" Afghan Restaurant Airport Airport Food Court Airport Gate \\\n",
"0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 \n",
"\n",
" Airport Lounge Airport Service Airport Terminal American Restaurant \\\n",
"0 0.0 0.0 0.0 0.03 \n",
"1 0.0 0.0 0.0 0.00 \n",
"2 0.0 0.0 0.0 0.00 \n",
"3 0.0 0.0 0.0 0.00 \n",
"4 0.0 0.0 0.0 0.00 \n",
"\n",
" Antique Shop Aquarium Art Gallery Art Museum Arts & Crafts Store \\\n",
"0 0.0 0.0 0.01 0.01 0.0 \n",
"1 0.0 0.0 0.00 0.00 0.0 \n",
"2 0.0 0.0 0.00 0.00 0.0 \n",
"3 0.0 0.0 0.00 0.00 0.0 \n",
"4 0.0 0.0 0.00 0.00 0.0 \n",
"\n",
" Asian Restaurant Athletics & Sports Auto Garage Auto Workshop \\\n",
"0 0.03 0.0 0.0 0.0 \n",
"1 0.00 0.0 0.0 0.0 \n",
"2 0.00 0.0 0.0 0.0 \n",
"3 0.00 0.0 0.0 0.0 \n",
"4 0.00 0.0 0.0 0.0 \n",
"\n",
" BBQ Joint Baby Store Bagel Shop Bakery Bank Bar Baseball Field \\\n",
"0 0.0 0.0 0.0 0.02 0.0 0.04 0.0 \n",
"1 0.0 0.0 0.0 0.00 0.0 0.00 0.0 \n",
"2 0.0 0.0 0.0 0.00 0.0 0.00 0.0 \n",
"3 0.0 0.0 0.0 0.00 0.0 0.00 0.0 \n",
"4 0.0 0.0 0.0 0.00 0.0 0.00 0.0 \n",
"\n",
" Baseball Stadium Basketball Court Basketball Stadium Beach Beer Bar \\\n",
"0 0.0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
" Beer Store Bike Shop Bistro Boat or Ferry Bookstore Boutique \\\n",
"0 0.000000 0.0 0.0 0.0 0.01 0.0 \n",
"1 0.000000 0.0 0.0 0.0 0.00 0.0 \n",
"2 0.000000 0.0 0.0 0.0 0.00 0.0 \n",
"3 0.111111 0.0 0.0 0.0 0.00 0.0 \n",
"4 0.000000 0.0 0.0 0.0 0.00 0.0 \n",
"\n",
" Brazilian Restaurant Breakfast Spot Brewery Bridal Shop \\\n",
"0 0.01 0.03 0.0 0.0 \n",
"1 0.00 0.20 0.0 0.0 \n",
"2 0.00 0.00 0.0 0.0 \n",
"3 0.00 0.00 0.0 0.0 \n",
"4 0.00 0.00 0.0 0.0 \n",
"\n",
" Bubble Tea Shop Building Burger Joint Burrito Place Bus Line \\\n",
"0 0.0 0.01 0.02 0.01 0.0 \n",
"1 0.0 0.00 0.00 0.00 0.0 \n",
"2 0.0 0.00 0.00 0.00 0.0 \n",
"3 0.0 0.00 0.00 0.00 0.0 \n",
"4 0.0 0.00 0.00 0.00 0.0 \n",
"\n",
" Bus Station Bus Stop Butcher Cafeteria ... Salon / Barbershop \\\n",
"0 0.0 0.0 0.0 0.0 ... 0.01 \n",
"1 0.0 0.0 0.0 0.0 ... 0.00 \n",
"2 0.0 0.0 0.0 0.0 ... 0.00 \n",
"3 0.0 0.0 0.0 0.0 ... 0.00 \n",
"4 0.0 0.0 0.0 0.0 ... 0.00 \n",
"\n",
" Sandwich Place Scenic Lookout Sculpture Garden Seafood Restaurant \\\n",
"0 0.000000 0.0 0.0 0.01 \n",
"1 0.200000 0.0 0.0 0.00 \n",
"2 0.000000 0.0 0.0 0.00 \n",
"3 0.111111 0.0 0.0 0.00 \n",
"4 0.111111 0.0 0.0 0.00 \n",
"\n",
" Shoe Store Shopping Mall Shopping Plaza Skate Park Skating Rink \\\n",
"0 0.0 0.0 0.0 0.0 0.000000 \n",
"1 0.0 0.0 0.0 0.0 0.200000 \n",
"2 0.0 0.0 0.0 0.0 0.000000 \n",
"3 0.0 0.0 0.0 0.0 0.000000 \n",
"4 0.0 0.0 0.0 0.0 0.111111 \n",
"\n",
" Smoke Shop Smoothie Shop Snack Place Soccer Field Soup Place \\\n",
"0 0.01 0.0 0.0 0.0 0.0 \n",
"1 0.00 0.0 0.0 0.0 0.0 \n",
"2 0.00 0.0 0.0 0.0 0.0 \n",
"3 0.00 0.0 0.0 0.0 0.0 \n",
"4 0.00 0.0 0.0 0.0 0.0 \n",
"\n",
" Southern / Soul Food Restaurant Spa Speakeasy Sporting Goods Shop \\\n",
"0 0.0 0.0 0.01 0.0 \n",
"1 0.0 0.0 0.00 0.0 \n",
"2 0.0 0.0 0.00 0.0 \n",
"3 0.0 0.0 0.00 0.0 \n",
"4 0.0 0.0 0.00 0.0 \n",
"\n",
" Sports Bar Stadium Stationery Store Steakhouse Strip Club Supermarket \\\n",
"0 0.0 0.0 0.0 0.04 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.00 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.00 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.00 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.00 0.0 0.0 \n",
"\n",
" Supplement Shop Sushi Restaurant Swim School Taco Place Tailor Shop \\\n",
"0 0.0 0.02 0.0 0.0 0.0 \n",
"1 0.0 0.00 0.0 0.0 0.0 \n",
"2 0.0 0.00 0.0 0.0 0.0 \n",
"3 0.0 0.00 0.0 0.0 0.0 \n",
"4 0.0 0.00 0.0 0.0 0.0 \n",
"\n",
" Taiwanese Restaurant Tanning Salon Tapas Restaurant Tea Room \\\n",
"0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 \n",
"\n",
" Thai Restaurant Theater Theme Restaurant Thrift / Vintage Store \\\n",
"0 0.04 0.01 0.0 0.0 \n",
"1 0.00 0.00 0.0 0.0 \n",
"2 0.00 0.00 0.0 0.0 \n",
"3 0.00 0.00 0.0 0.0 \n",
"4 0.00 0.00 0.0 0.0 \n",
"\n",
" Toy / Game Store Trail Train Station Vegetarian / Vegan Restaurant \\\n",
"0 0.0 0.0 0.0 0.01 \n",
"1 0.0 0.0 0.0 0.00 \n",
"2 0.0 0.0 0.0 0.00 \n",
"3 0.0 0.0 0.0 0.00 \n",
"4 0.0 0.0 0.0 0.00 \n",
"\n",
" Video Game Store Video Store Vietnamese Restaurant Warehouse Store \\\n",
"0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 \n",
"\n",
" Wine Bar Wings Joint Women's Store Yoga Studio \n",
"0 0.01 0.0 0.01 0.0 \n",
"1 0.00 0.0 0.00 0.0 \n",
"2 0.00 0.0 0.00 0.0 \n",
"3 0.00 0.0 0.00 0.0 \n",
"4 0.00 0.0 0.00 0.0 \n",
"\n",
"[5 rows x 281 columns]"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_grouped = toronto_onehot.groupby('Neighbourhood').mean().reset_index()\n",
"print(toronto_grouped.shape)\n",
"toronto_grouped.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Obviously, we're dealing with a very sparse data set here, so let's determine the top 10 most frequent venue types per neighbourhood. First, let's create a function that sorts the venue frequencies in descending order."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"def return_most_common_venues(row, num_top_venues):\n",
" row_categories = row.iloc[1:]\n",
" row_categories_sorted = row_categories.sort_values(ascending=False)\n",
" \n",
" return row_categories_sorted.index.values[0:num_top_venues]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's create the new dataframe containing the top 10 venues for each neighborhood."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Neighbourhood</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Adelaide, King, Richmond</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Café</td>\n",
" <td>Thai Restaurant</td>\n",
" <td>Bar</td>\n",
" <td>Steakhouse</td>\n",
" <td>Gym</td>\n",
" <td>Restaurant</td>\n",
" <td>American Restaurant</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Hotel</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Agincourt</td>\n",
" <td>Lounge</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Skating Rink</td>\n",
" <td>Chinese Restaurant</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Agincourt North, L'Amoreaux East, Milliken, St...</td>\n",
" <td>Park</td>\n",
" <td>Playground</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Albion Gardens, Beaumond Heights, Humbergate, ...</td>\n",
" <td>Grocery Store</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Pizza Place</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Beer Store</td>\n",
" <td>Pharmacy</td>\n",
" <td>Fried Chicken Joint</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Electronics Store</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Alderwood, Long Branch</td>\n",
" <td>Pizza Place</td>\n",
" <td>Gym</td>\n",
" <td>Pool</td>\n",
" <td>Skating Rink</td>\n",
" <td>Pharmacy</td>\n",
" <td>Pub</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Diner</td>\n",
" <td>Discount Store</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Neighbourhood 1st Most Common Venue \\\n",
"0 Adelaide, King, Richmond Coffee Shop \n",
"1 Agincourt Lounge \n",
"2 Agincourt North, L'Amoreaux East, Milliken, St... Park \n",
"3 Albion Gardens, Beaumond Heights, Humbergate, ... Grocery Store \n",
"4 Alderwood, Long Branch Pizza Place \n",
"\n",
" 2nd Most Common Venue 3rd Most Common Venue 4th Most Common Venue \\\n",
"0 Café Thai Restaurant Bar \n",
"1 Breakfast Spot Skating Rink Chinese Restaurant \n",
"2 Playground Yoga Studio Eastern European Restaurant \n",
"3 Fast Food Restaurant Pizza Place Sandwich Place \n",
"4 Gym Pool Skating Rink \n",
"\n",
" 5th Most Common Venue 6th Most Common Venue 7th Most Common Venue \\\n",
"0 Steakhouse Gym Restaurant \n",
"1 Sandwich Place Eastern European Restaurant Doner Restaurant \n",
"2 Dive Bar Dog Run Doner Restaurant \n",
"3 Coffee Shop Beer Store Pharmacy \n",
"4 Pharmacy Pub Coffee Shop \n",
"\n",
" 8th Most Common Venue 9th Most Common Venue 10th Most Common Venue \n",
"0 American Restaurant Breakfast Spot Hotel \n",
"1 Donut Shop Drugstore Dumpling Restaurant \n",
"2 Donut Shop Drugstore Dumpling Restaurant \n",
"3 Fried Chicken Joint Empanada Restaurant Electronics Store \n",
"4 Sandwich Place Diner Discount Store "
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"num_top_venues = 10\n",
"\n",
"indicators = ['st', 'nd', 'rd']\n",
"\n",
"# create columns according to number of top venues\n",
"columns = ['Neighbourhood']\n",
"for ind in np.arange(num_top_venues):\n",
" try:\n",
" columns.append('{}{} Most Common Venue'.format(ind+1, indicators[ind]))\n",
" except:\n",
" columns.append('{}th Most Common Venue'.format(ind+1))\n",
"\n",
"# create a new dataframe\n",
"neighborhoods_venues_sorted = pd.DataFrame(columns=columns)\n",
"neighborhoods_venues_sorted['Neighbourhood'] = toronto_grouped['Neighbourhood']\n",
"\n",
"for ind in np.arange(toronto_grouped.shape[0]):\n",
" neighborhoods_venues_sorted.iloc[ind, 1:] = return_most_common_venues(toronto_grouped.iloc[ind, :], num_top_venues)\n",
"\n",
"neighborhoods_venues_sorted.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Neighbourhood clustering"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're now ready to cluster the neighbourhoods based on the prevalence of venue types. \n",
"\n",
"### Finding k\n",
"\n",
"One question that always comes up is how to choose k for the clustering. We solve this by looking at the inertia of the clusters and applying the elbox rule."
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"# remove Neighbourhood column\n",
"toronto_grouped_clustering = toronto_grouped.drop('Neighbourhood', 1)\n",
"\n",
"\n",
"# set number of clusters to test\n",
"maxk = 8\n",
"cost = np.zeros((maxk-1))\n",
"\n",
"for n in range(1, maxk):\n",
" # run k-means clustering\n",
" kmeans = KMeans(n_clusters=n, random_state=0).fit(toronto_grouped_clustering)\n",
" cost[n-1] = kmeans.inertia_\n",
" #print(cost[n-1])\n",
"\n",
"# plot inertia to find best value for K\n",
"plt.plot(range(2, maxk), cost[1:maxk], 'g')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Performing the clustering\n",
"\n",
"Judging from the plot above, it looks like setting k to 7 will be the best balance, so let's run the final clustering like this."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 0, 6, 5, 5, 0, 3, 0, 0, 0], dtype=int32)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"kclusters = 7\n",
"kmeans = KMeans(n_clusters=kclusters, random_state=0).fit(toronto_grouped_clustering)\n",
"# check cluster labels generated for each row in the dataframe\n",
"kmeans.labels_[0:10] "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's create a new dataframe that includes the cluster as well as the top 10 venues for each neighborhood."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Postcode</th>\n",
" <th>Borough</th>\n",
" <th>Neighbourhood</th>\n",
" <th>Latitude</th>\n",
" <th>Longitude</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>M1B</td>\n",
" <td>Scarborough</td>\n",
" <td>Rouge, Malvern</td>\n",
" <td>43.806686</td>\n",
" <td>-79.194353</td>\n",
" <td>5</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>M1C</td>\n",
" <td>Scarborough</td>\n",
" <td>Highland Creek, Rouge Hill, Port Union</td>\n",
" <td>43.784535</td>\n",
" <td>-79.160497</td>\n",
" <td>0</td>\n",
" <td>Bar</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>M1E</td>\n",
" <td>Scarborough</td>\n",
" <td>Guildwood, Morningside, West Hill</td>\n",
" <td>43.763573</td>\n",
" <td>-79.188711</td>\n",
" <td>0</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Rental Car Location</td>\n",
" <td>Intersection</td>\n",
" <td>Pizza Place</td>\n",
" <td>Electronics Store</td>\n",
" <td>Medical Center</td>\n",
" <td>Mexican Restaurant</td>\n",
" <td>Drugstore</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>M1G</td>\n",
" <td>Scarborough</td>\n",
" <td>Woburn</td>\n",
" <td>43.770992</td>\n",
" <td>-79.216917</td>\n",
" <td>0</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Korean Restaurant</td>\n",
" <td>Electronics Store</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Yoga Studio</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>M1H</td>\n",
" <td>Scarborough</td>\n",
" <td>Cedarbrae</td>\n",
" <td>43.773136</td>\n",
" <td>-79.239476</td>\n",
" <td>0</td>\n",
" <td>Hakka Restaurant</td>\n",
" <td>Thai Restaurant</td>\n",
" <td>Fried Chicken Joint</td>\n",
" <td>Bank</td>\n",
" <td>Bakery</td>\n",
" <td>Athletics &amp; Sports</td>\n",
" <td>Caribbean Restaurant</td>\n",
" <td>Cuban Restaurant</td>\n",
" <td>Costume Shop</td>\n",
" <td>Farmers Market</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Postcode Borough Neighbourhood Latitude \\\n",
"0 M1B Scarborough Rouge, Malvern 43.806686 \n",
"1 M1C Scarborough Highland Creek, Rouge Hill, Port Union 43.784535 \n",
"2 M1E Scarborough Guildwood, Morningside, West Hill 43.763573 \n",
"3 M1G Scarborough Woburn 43.770992 \n",
"4 M1H Scarborough Cedarbrae 43.773136 \n",
"\n",
" Longitude Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"0 -79.194353 5 Fast Food Restaurant Yoga Studio \n",
"1 -79.160497 0 Bar Yoga Studio \n",
"2 -79.188711 0 Breakfast Spot Rental Car Location \n",
"3 -79.216917 0 Coffee Shop Korean Restaurant \n",
"4 -79.239476 0 Hakka Restaurant Thai Restaurant \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"0 Electronics Store Dog Run Doner Restaurant \n",
"1 Electronics Store Doner Restaurant Donut Shop \n",
"2 Intersection Pizza Place Electronics Store \n",
"3 Electronics Store Dog Run Doner Restaurant \n",
"4 Fried Chicken Joint Bank Bakery \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"0 Donut Shop Drugstore Dumpling Restaurant \n",
"1 Drugstore Dumpling Restaurant Eastern European Restaurant \n",
"2 Medical Center Mexican Restaurant Drugstore \n",
"3 Donut Shop Drugstore Dumpling Restaurant \n",
"4 Athletics & Sports Caribbean Restaurant Cuban Restaurant \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"0 Eastern European Restaurant Empanada Restaurant \n",
"1 Empanada Restaurant Dive Bar \n",
"2 Dog Run Doner Restaurant \n",
"3 Eastern European Restaurant Yoga Studio \n",
"4 Costume Shop Farmers Market "
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# add clustering labels\n",
"#neighborhoods_venues_sorted.drop('Cluster Labels', axis=1, inplace=True)\n",
"neighborhoods_venues_sorted.insert(0, 'Cluster Labels', kmeans.labels_)\n",
"\n",
"toronto_merged = mydf_post\n",
"\n",
"# inner join toronto_merged with neighborhood_venues_sorted to add latitude/longitude for each neighbourhood\n",
"toronto_labeled = pd.merge(toronto_merged, neighborhoods_venues_sorted, how='inner', on='Neighbourhood')\n",
"\n",
"toronto_labeled.head() # check the last columns!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Clustering results\n",
"\n",
"Finally, let's visualize the resulting clusters of similar neighbourhoods. Let's start by counting the number of neighbourhoods in each cluster."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Cluster Labels\n",
"0 72\n",
"1 1\n",
"2 1\n",
"3 2\n",
"4 1\n",
"5 10\n",
"6 14\n",
"Name: Neighbourhood, dtype: int64"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.groupby('Cluster Labels').count()['Neighbourhood']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is very interesting, as it appears that there are 3 main clusters accompanied by 4 outliers. \n",
"\n",
"## Mapping the clusters\n",
"\n",
"Let's see how this looks on the map using Folium."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgCiAgICAgICAgPHNjcmlwdD4KICAgICAgICAgICAgTF9OT19UT1VDSCA9IGZhbHNlOwogICAgICAgICAgICBMX0RJU0FCTEVfM0QgPSBmYWxzZTsKICAgICAgICA8L3NjcmlwdD4KICAgIAogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbGVhZmxldEAxLjUuMS9kaXN0L2xlYWZsZXQuanMiPjwvc2NyaXB0PgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY29kZS5qcXVlcnkuY29tL2pxdWVyeS0xLjEyLjQubWluLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9qcy9ib290c3RyYXAubWluLmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5qcyI+PC9zY3JpcHQ+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbGVhZmxldEAxLjUuMS9kaXN0L2xlYWZsZXQuY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vYm9vdHN0cmFwLzMuMi4wL2Nzcy9ib290c3RyYXAubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLXRoZW1lLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9mb250LWF3ZXNvbWUvNC42LjMvY3NzL2ZvbnQtYXdlc29tZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL0xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLzIuMC4yL2xlYWZsZXQuYXdlc29tZS1tYXJrZXJzLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL3Jhd2Nkbi5naXRoYWNrLmNvbS9weXRob24tdmlzdWFsaXphdGlvbi9mb2xpdW0vbWFzdGVyL2ZvbGl1bS90ZW1wbGF0ZXMvbGVhZmxldC5hd2Vzb21lLnJvdGF0ZS5jc3MiLz4KICAgIDxzdHlsZT5odG1sLCBib2R5IHt3aWR0aDogMTAwJTtoZWlnaHQ6IDEwMCU7bWFyZ2luOiAwO3BhZGRpbmc6IDA7fTwvc3R5bGU+CiAgICA8c3R5bGU+I21hcCB7cG9zaXRpb246YWJzb2x1dGU7dG9wOjA7Ym90dG9tOjA7cmlnaHQ6MDtsZWZ0OjA7fTwvc3R5bGU+CiAgICAKICAgICAgICAgICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwKICAgICAgICAgICAgICAgIGluaXRpYWwtc2NhbGU9MS4wLCBtYXhpbXVtLXNjYWxlPTEuMCwgdXNlci1zY2FsYWJsZT1ubyIgLz4KICAgICAgICAgICAgPHN0eWxlPgogICAgICAgICAgICAgICAgI21hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZiB7CiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlOwogICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAuMCU7CiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICAgICAgbGVmdDogMC4wJTsKICAgICAgICAgICAgICAgICAgICB0b3A6IDAuMCU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIDwvc3R5bGU+CiAgICAgICAgCjwvaGVhZD4KPGJvZHk+ICAgIAogICAgCiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZvbGl1bS1tYXAiIGlkPSJtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YiID48L2Rpdj4KICAgICAgICAKPC9ib2R5Pgo8c2NyaXB0PiAgICAKICAgIAogICAgICAgICAgICB2YXIgbWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmID0gTC5tYXAoCiAgICAgICAgICAgICAgICAibWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmIiwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBjZW50ZXI6IFs0My42NTM5NjMsIC03OS4zODcyMDddLAogICAgICAgICAgICAgICAgICAgIGNyczogTC5DUlMuRVBTRzM4NTcsCiAgICAgICAgICAgICAgICAgICAgem9vbTogMTEsCiAgICAgICAgICAgICAgICAgICAgem9vbUNvbnRyb2w6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgcHJlZmVyQ2FudmFzOiBmYWxzZSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIAoKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl9hZGNjZDM3N2U0MmI0NTEyOWNiZDU3MzA0N2EwNWM4ZCA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgImh0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nIiwKICAgICAgICAgICAgICAgIHsiYXR0cmlidXRpb24iOiAiRGF0YSBieSBcdTAwMjZjb3B5OyBcdTAwM2NhIGhyZWY9XCJodHRwOi8vb3BlbnN0cmVldG1hcC5vcmdcIlx1MDAzZU9wZW5TdHJlZXRNYXBcdTAwM2MvYVx1MDAzZSwgdW5kZXIgXHUwMDNjYSBocmVmPVwiaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIlx1MDAzZU9EYkxcdTAwM2MvYVx1MDAzZS4iLCAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsICJtYXhOYXRpdmVab29tIjogMTgsICJtYXhab29tIjogMTgsICJtaW5ab29tIjogMCwgIm5vV3JhcCI6IGZhbHNlLCAib3BhY2l0eSI6IDEsICJzdWJkb21haW5zIjogImFiYyIsICJ0bXMiOiBmYWxzZX0KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzRjNDRmYzY4ZjQ5ZjQ3YzE5MDM2ZDM0NTNmODI2NTcyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuODA2Njg2Mjk5OTk5OTk2LCAtNzkuMTk0MzUzNDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiMwMDhmZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzAwOGZmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzgzZGRiYzM4MmZlYjQxYzNhMDM1NWU5OWRmNzliZjU2ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9kZDhlNzQxOGViMDc0NWE2YjBmMjFhMGMyYWY3N2U5ZiA9ICQoYDxkaXYgaWQ9Imh0bWxfZGQ4ZTc0MThlYjA3NDVhNmIwZjIxYTBjMmFmNzdlOWYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJvdWdlLCBNYWx2ZXJuIENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84M2RkYmMzODJmZWI0MWMzYTAzNTVlOTlkZjc5YmY1Ni5zZXRDb250ZW50KGh0bWxfZGQ4ZTc0MThlYjA3NDVhNmIwZjIxYTBjMmFmNzdlOWYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzRjNDRmYzY4ZjQ5ZjQ3YzE5MDM2ZDM0NTNmODI2NTcyLmJpbmRQb3B1cChwb3B1cF84M2RkYmMzODJmZWI0MWMzYTAzNTVlOTlkZjc5YmY1NikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzM4NjNjN2QxN2U2NGM2ODk0ZDljMmI1NjhlMGQxNjIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43ODQ1MzUxLCAtNzkuMTYwNDk3MDk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzhhYzJkNTc0NzUzZDRlZmZhODFjOTZjYTYyMDJjMzJiID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8xZTQ2YjRlYmUyMTA0ZDRhOGM2OGFkNmU4YjhkOTkyZCA9ICQoYDxkaXYgaWQ9Imh0bWxfMWU0NmI0ZWJlMjEwNGQ0YThjNjhhZDZlOGI4ZDk5MmQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhpZ2hsYW5kIENyZWVrLCBSb3VnZSBIaWxsLCBQb3J0IFVuaW9uIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84YWMyZDU3NDc1M2Q0ZWZmYTgxYzk2Y2E2MjAyYzMyYi5zZXRDb250ZW50KGh0bWxfMWU0NmI0ZWJlMjEwNGQ0YThjNjhhZDZlOGI4ZDk5MmQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzczODYzYzdkMTdlNjRjNjg5NGQ5YzJiNTY4ZTBkMTYyLmJpbmRQb3B1cChwb3B1cF84YWMyZDU3NDc1M2Q0ZWZmYTgxYzk2Y2E2MjAyYzMyYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGEwOWJlMjM4NzgzNGY4NWFjNzlkODA4NTM1MWU0NDkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NjM1NzI2LCAtNzkuMTg4NzExNV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYTljZDlmNDkwMjY4NDVkZTkxOWJmN2Y2YWUxYmI2M2QgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzcwNTJiNmIxZjVkMTRiZjFiOTdkZDA4ZDgwYjljZmE5ID0gJChgPGRpdiBpZD0iaHRtbF83MDUyYjZiMWY1ZDE0YmYxYjk3ZGQwOGQ4MGI5Y2ZhOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+R3VpbGR3b29kLCBNb3JuaW5nc2lkZSwgV2VzdCBIaWxsIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hOWNkOWY0OTAyNjg0NWRlOTE5YmY3ZjZhZTFiYjYzZC5zZXRDb250ZW50KGh0bWxfNzA1MmI2YjFmNWQxNGJmMWI5N2RkMDhkODBiOWNmYTkpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzRhMDliZTIzODc4MzRmODVhYzc5ZDgwODUzNTFlNDQ5LmJpbmRQb3B1cChwb3B1cF9hOWNkOWY0OTAyNjg0NWRlOTE5YmY3ZjZhZTFiYjYzZCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzU3ODljMWI5NDAxNDkwOTkxZDgzOGI5Y2E0MzdiODMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NzA5OTIxLCAtNzkuMjE2OTE3NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzVhMDk2Y2Y0MjQ1OTQ3OTViOWZkODI2ODAzZjA4YWY3ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF85NmE0MGJhMTU1OGQ0MDM3YWU5YTQyODFjOGMyMmJlMCA9ICQoYDxkaXYgaWQ9Imh0bWxfOTZhNDBiYTE1NThkNDAzN2FlOWE0MjgxYzhjMjJiZTAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldvYnVybiBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNWEwOTZjZjQyNDU5NDc5NWI5ZmQ4MjY4MDNmMDhhZjcuc2V0Q29udGVudChodG1sXzk2YTQwYmExNTU4ZDQwMzdhZTlhNDI4MWM4YzIyYmUwKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl83NTc4OWMxYjk0MDE0OTA5OTFkODM4YjljYTQzN2I4My5iaW5kUG9wdXAocG9wdXBfNWEwOTZjZjQyNDU5NDc5NWI5ZmQ4MjY4MDNmMDhhZjcpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzhhNTlkYTZiZjkxZTQ5NGJiNGI1MmY2ZDc2YTRhNDc0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzczMTM2LCAtNzkuMjM5NDc2MDk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzQ2ZDY2MTliZjI2YjRiNGNhYTc5ZDE0OTQ2MDhiOTYwID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iMGM1ZmIxM2UxZmU0NmEwOWNlNGNlNDYzZjBjNmZlOSA9ICQoYDxkaXYgaWQ9Imh0bWxfYjBjNWZiMTNlMWZlNDZhMDljZTRjZTQ2M2YwYzZmZTkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlZGFyYnJhZSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNDZkNjYxOWJmMjZiNGI0Y2FhNzlkMTQ5NDYwOGI5NjAuc2V0Q29udGVudChodG1sX2IwYzVmYjEzZTFmZTQ2YTA5Y2U0Y2U0NjNmMGM2ZmU5KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl84YTU5ZGE2YmY5MWU0OTRiYjRiNTJmNmQ3NmE0YTQ3NC5iaW5kUG9wdXAocG9wdXBfNDZkNjYxOWJmMjZiNGI0Y2FhNzlkMTQ5NDYwOGI5NjApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzk1ZTMyYmM3ZWFiYzQ5YjM4YzQyNTM1NmM3MjM5YWIxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzQ0NzM0MiwgLTc5LjIzOTQ3NjA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9lNmNmMDdhZDYyZjY0NTY0YjhjYjY4M2YzMjFiMTkzYiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNGZmZDg2YWY0ZGY4NDdlMGE5YTdiODU3MmZjYjQ4MDIgPSAkKGA8ZGl2IGlkPSJodG1sXzRmZmQ4NmFmNGRmODQ3ZTBhOWE3Yjg1NzJmY2I0ODAyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TY2FyYm9yb3VnaCBWaWxsYWdlIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9lNmNmMDdhZDYyZjY0NTY0YjhjYjY4M2YzMjFiMTkzYi5zZXRDb250ZW50KGh0bWxfNGZmZDg2YWY0ZGY4NDdlMGE5YTdiODU3MmZjYjQ4MDIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzk1ZTMyYmM3ZWFiYzQ5YjM4YzQyNTM1NmM3MjM5YWIxLmJpbmRQb3B1cChwb3B1cF9lNmNmMDdhZDYyZjY0NTY0YjhjYjY4M2YzMjFiMTkzYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfM2NiM2VlNzcxMDgyNDEzMDk5NTkwMWQ3NWVmNmY4NWQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Mjc5MjkyLCAtNzkuMjYyMDI5NDAwMDAwMDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzY3YjljNDljNDcwZTQzMGQ4NTYzZGQzOGYwYjIzZmRhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80OTJmNWM4NjQzOTA0NmUzYTM2MTY4NmU4YTUxOGEwZCA9ICQoYDxkaXYgaWQ9Imh0bWxfNDkyZjVjODY0MzkwNDZlM2EzNjE2ODZlOGE1MThhMGQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgQmlyY2htb3VudCBQYXJrLCBJb252aWV3LCBLZW5uZWR5IFBhcmsgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzY3YjljNDljNDcwZTQzMGQ4NTYzZGQzOGYwYjIzZmRhLnNldENvbnRlbnQoaHRtbF80OTJmNWM4NjQzOTA0NmUzYTM2MTY4NmU4YTUxOGEwZCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfM2NiM2VlNzcxMDgyNDEzMDk5NTkwMWQ3NWVmNmY4NWQuYmluZFBvcHVwKHBvcHVwXzY3YjljNDljNDcwZTQzMGQ4NTYzZGQzOGYwYjIzZmRhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hNTliZjJmNzE0NDg0M2IzODkwOWJiMjdkYjc3MmFjYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxMTExMTcwMDAwMDAwNCwgLTc5LjI4NDU3NzJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzg3NjE4YzE5ZjFkZDQ5ZWFiZmZmNjYyYWY4NDA5NjUxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80MzZjMDAyNjc0YTM0MTJlYjEyMGQyOGNmYWQzMjk0OCA9ICQoYDxkaXYgaWQ9Imh0bWxfNDM2YzAwMjY3NGEzNDEyZWIxMjBkMjhjZmFkMzI5NDgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNsYWlybGVhLCBHb2xkZW4gTWlsZSwgT2FrcmlkZ2UgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzg3NjE4YzE5ZjFkZDQ5ZWFiZmZmNjYyYWY4NDA5NjUxLnNldENvbnRlbnQoaHRtbF80MzZjMDAyNjc0YTM0MTJlYjEyMGQyOGNmYWQzMjk0OCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYTU5YmYyZjcxNDQ4NDNiMzg5MDliYjI3ZGI3NzJhY2IuYmluZFBvcHVwKHBvcHVwXzg3NjE4YzE5ZjFkZDQ5ZWFiZmZmNjYyYWY4NDA5NjUxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85OTY3MjkzMmUxMGM0Njc1YmU0MmJiZGI4OGFlYmQzOCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxNjMxNiwgLTc5LjIzOTQ3NjA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yMTMwNzI2Zjg3Zjg0ZWFjYWRlNmI3ZGFlNjY4YWZjZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMTE0NGJlMzA1ZTViNDYyN2FkMGE5NmRlNDU5MGQ2NTMgPSAkKGA8ZGl2IGlkPSJodG1sXzExNDRiZTMwNWU1YjQ2MjdhZDBhOTZkZTQ1OTBkNjUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbGlmZmNyZXN0LCBDbGlmZnNpZGUsIFNjYXJib3JvdWdoIFZpbGxhZ2UgV2VzdCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMjEzMDcyNmY4N2Y4NGVhY2FkZTZiN2RhZTY2OGFmY2Quc2V0Q29udGVudChodG1sXzExNDRiZTMwNWU1YjQ2MjdhZDBhOTZkZTQ1OTBkNjUzKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85OTY3MjkzMmUxMGM0Njc1YmU0MmJiZGI4OGFlYmQzOC5iaW5kUG9wdXAocG9wdXBfMjEzMDcyNmY4N2Y4NGVhY2FkZTZiN2RhZTY2OGFmY2QpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Q3Mzc5ZGIzM2Q1YzQ1ZThhMWZjMmEwYWY0ZmQ4YjNiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjkyNjU3MDAwMDAwMDA0LCAtNzkuMjY0ODQ4MV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfODI4ZTE5YzFhMGRjNDY5YjgwZTgxMGI2OWE2MTk1YTEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzBmYTE0YTg1YmY0ZTRhZmE4NjZkODljNDQ3ZmM3MDE1ID0gJChgPGRpdiBpZD0iaHRtbF8wZmExNGE4NWJmNGU0YWZhODY2ZDg5YzQ0N2ZjNzAxNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QmlyY2ggQ2xpZmYsIENsaWZmc2lkZSBXZXN0IENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84MjhlMTljMWEwZGM0NjliODBlODEwYjY5YTYxOTVhMS5zZXRDb250ZW50KGh0bWxfMGZhMTRhODViZjRlNGFmYTg2NmQ4OWM0NDdmYzcwMTUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2Q3Mzc5ZGIzM2Q1YzQ1ZThhMWZjMmEwYWY0ZmQ4YjNiLmJpbmRQb3B1cChwb3B1cF84MjhlMTljMWEwZGM0NjliODBlODEwYjY5YTYxOTVhMSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYWNiNTg5ZDUyM2ViNDVmMjg1OWMwMDkyNTU0NjQzOTggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NTc0MDk2LCAtNzkuMjczMzA0MDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2QzOGEyZTM3Y2UxMTQzYzZhYjBiZTNhNTg1NzQ2YjFjID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9kY2VmZTg2ODA0NGQ0NDBlYmFlODQ4OTMzNTBiYzJlNyA9ICQoYDxkaXYgaWQ9Imh0bWxfZGNlZmU4NjgwNDRkNDQwZWJhZTg0ODkzMzUwYmMyZTciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvcnNldCBQYXJrLCBTY2FyYm9yb3VnaCBUb3duIENlbnRyZSwgV2V4Zm9yZCBIZWlnaHRzIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kMzhhMmUzN2NlMTE0M2M2YWIwYmUzYTU4NTc0NmIxYy5zZXRDb250ZW50KGh0bWxfZGNlZmU4NjgwNDRkNDQwZWJhZTg0ODkzMzUwYmMyZTcpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2FjYjU4OWQ1MjNlYjQ1ZjI4NTljMDA5MjU1NDY0Mzk4LmJpbmRQb3B1cChwb3B1cF9kMzhhMmUzN2NlMTE0M2M2YWIwYmUzYTU4NTc0NmIxYykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzQ1OGNjNDBlODE0NDY4NzhkMjY3MzdlYmY1NTkxZjMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NTAwNzE1MDAwMDAwMDQsIC03OS4yOTU4NDkxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80ODA2NjgyN2NkZDk0NWM4OGMzMmU4NWU1NjhkOWE1YyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjg2NDM3MDUwOGI1NGM2ZDkzZGM0YmRiZmNmMjdhZTEgPSAkKGA8ZGl2IGlkPSJodG1sXzI4NjQzNzA1MDhiNTRjNmQ5M2RjNGJkYmZjZjI3YWUxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5NYXJ5dmFsZSwgV2V4Zm9yZCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNDgwNjY4MjdjZGQ5NDVjODhjMzJlODVlNTY4ZDlhNWMuc2V0Q29udGVudChodG1sXzI4NjQzNzA1MDhiNTRjNmQ5M2RjNGJkYmZjZjI3YWUxKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9jNDU4Y2M0MGU4MTQ0Njg3OGQyNjczN2ViZjU1OTFmMy5iaW5kUG9wdXAocG9wdXBfNDgwNjY4MjdjZGQ5NDVjODhjMzJlODVlNTY4ZDlhNWMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2YxMGY4YzQzNTY3YjQ0Yjk5MjUyNjUyMGYwNDhlMjVlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzk0MjAwMywgLTc5LjI2MjAyOTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kZTdiZDJiNDZmZTU0ODU4OGRjMGNhY2Q5MWQxZTdmYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfN2NjODY3ODljY2E4NDI0M2I2YmI5ZDVlYTJkY2E4Y2EgPSAkKGA8ZGl2IGlkPSJodG1sXzdjYzg2Nzg5Y2NhODQyNDNiNmJiOWQ1ZWEyZGNhOGNhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5BZ2luY291cnQgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2RlN2JkMmI0NmZlNTQ4NTg4ZGMwY2FjZDkxZDFlN2ZhLnNldENvbnRlbnQoaHRtbF83Y2M4Njc4OWNjYTg0MjQzYjZiYjlkNWVhMmRjYThjYSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZjEwZjhjNDM1NjdiNDRiOTkyNTI2NTIwZjA0OGUyNWUuYmluZFBvcHVwKHBvcHVwX2RlN2JkMmI0NmZlNTQ4NTg4ZGMwY2FjZDkxZDFlN2ZhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81OGQzZDljMTFjZjM0NzQ0OTBhMTAxMWRkMzcwMThjMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc4MTYzNzUsIC03OS4zMDQzMDIxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjMDA4ZmZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMwMDhmZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81NTIwN2IwZDg4MzY0OWI3YmRkNGM4YjBiM2E0YWJhYiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfODcyMDY4NWVmNDdiNDNmNmFlMjY0OTRhMDAxMGU3YmQgPSAkKGA8ZGl2IGlkPSJodG1sXzg3MjA2ODVlZjQ3YjQzZjZhZTI2NDk0YTAwMTBlN2JkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbGFya3MgQ29ybmVycywgU3VsbGl2YW4sIFRhbSBPJiMzOTtTaGFudGVyIENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81NTIwN2IwZDg4MzY0OWI3YmRkNGM4YjBiM2E0YWJhYi5zZXRDb250ZW50KGh0bWxfODcyMDY4NWVmNDdiNDNmNmFlMjY0OTRhMDAxMGU3YmQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzU4ZDNkOWMxMWNmMzQ3NDQ5MGExMDExZGQzNzAxOGMyLmJpbmRQb3B1cChwb3B1cF81NTIwN2IwZDg4MzY0OWI3YmRkNGM4YjBiM2E0YWJhYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZmE1MDE5NDczZmZlNDNjYjgyYzRjMDEzZmI2Mzk4ZjggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My44MTUyNTIyLCAtNzkuMjg0NTc3Ml0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzVhMDBmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjNWEwMGZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZDFkMjhmZmFlOGZjNGRiOTkzYjdkYTk0ODQ0YWYzNTMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzM4NjI4YTAyMjQ3YzQ0YmViOTJkNzBmMmVhMThmZTI4ID0gJChgPGRpdiBpZD0iaHRtbF8zODYyOGEwMjI0N2M0NGJlYjkyZDcwZjJlYTE4ZmUyOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QWdpbmNvdXJ0IE5vcnRoLCBMJiMzOTtBbW9yZWF1eCBFYXN0LCBNaWxsaWtlbiwgU3RlZWxlcyBFYXN0IENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kMWQyOGZmYWU4ZmM0ZGI5OTNiN2RhOTQ4NDRhZjM1My5zZXRDb250ZW50KGh0bWxfMzg2MjhhMDIyNDdjNDRiZWI5MmQ3MGYyZWExOGZlMjgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ZhNTAxOTQ3M2ZmZTQzY2I4MmM0YzAxM2ZiNjM5OGY4LmJpbmRQb3B1cChwb3B1cF9kMWQyOGZmYWU4ZmM0ZGI5OTNiN2RhOTQ4NDRhZjM1MykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfN2JjN2I3MDNmM2I3NGYxOWFlOTAyY2FhM2U3MDc1NDMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43OTk1MjUyMDAwMDAwMDUsIC03OS4zMTgzODg3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjMDA4ZmZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMwMDhmZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83NDI5Mzg5NGMxYzU0Mjc3OTQ4NzIzNDQwNjNlYjRlNSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZjI3YTE3OTJjMWJmNGIwMWI1NDAzM2MxMGZkNzMzYTYgPSAkKGA8ZGl2IGlkPSJodG1sX2YyN2ExNzkyYzFiZjRiMDFiNTQwMzNjMTBmZDczM2E2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5MJiMzOTtBbW9yZWF1eCBXZXN0IENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83NDI5Mzg5NGMxYzU0Mjc3OTQ4NzIzNDQwNjNlYjRlNS5zZXRDb250ZW50KGh0bWxfZjI3YTE3OTJjMWJmNGIwMWI1NDAzM2MxMGZkNzMzYTYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzdiYzdiNzAzZjNiNzRmMTlhZTkwMmNhYTNlNzA3NTQzLmJpbmRQb3B1cChwb3B1cF83NDI5Mzg5NGMxYzU0Mjc3OTQ4NzIzNDQwNjNlYjRlNSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDM0NzYxM2I5OGQ5NDlhOTgyYWFmMmRlZjgyNGFjODUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My44MDM3NjIyLCAtNzkuMzYzNDUxN10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZGZiYWUzN2ZhYzkzNDdhNTkzNWVkYzIzMjAyZTY0NDggPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzMyNTQxNGFiNTUwNDQ1MmI5YThhN2E1Mzg5MWI1NGQ2ID0gJChgPGRpdiBpZD0iaHRtbF8zMjU0MTRhYjU1MDQ0NTJiOWE4YTdhNTM4OTFiNTRkNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SGlsbGNyZXN0IFZpbGxhZ2UgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2RmYmFlMzdmYWM5MzQ3YTU5MzVlZGMyMzIwMmU2NDQ4LnNldENvbnRlbnQoaHRtbF8zMjU0MTRhYjU1MDQ0NTJiOWE4YTdhNTM4OTFiNTRkNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDM0NzYxM2I5OGQ5NDlhOTgyYWFmMmRlZjgyNGFjODUuYmluZFBvcHVwKHBvcHVwX2RmYmFlMzdmYWM5MzQ3YTU5MzVlZGMyMzIwMmU2NDQ4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xMzY0ZTA5MDM4Mzk0ZWUwYTRhNTYxNWFlMTYyYzIzNCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc3ODUxNzUsIC03OS4zNDY1NTU3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kNzljOThiYTRmNzc0YWRiYTZiZGYwMWM0MTcwMjkwMCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYWQ2ODBlOGQ3NTMyNDJjN2FlMGU2OWQ1MzAzYTk3ZmYgPSAkKGA8ZGl2IGlkPSJodG1sX2FkNjgwZThkNzUzMjQyYzdhZTBlNjlkNTMwM2E5N2ZmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5GYWlydmlldywgSGVucnkgRmFybSwgT3Jpb2xlIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kNzljOThiYTRmNzc0YWRiYTZiZGYwMWM0MTcwMjkwMC5zZXRDb250ZW50KGh0bWxfYWQ2ODBlOGQ3NTMyNDJjN2FlMGU2OWQ1MzAzYTk3ZmYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzEzNjRlMDkwMzgzOTRlZTBhNGE1NjE1YWUxNjJjMjM0LmJpbmRQb3B1cChwb3B1cF9kNzljOThiYTRmNzc0YWRiYTZiZGYwMWM0MTcwMjkwMCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjI0MTUxYzQ4ZjBlNDlmMzk1MTA0NjA3MDNhYmI1Y2QgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43ODY5NDczLCAtNzkuMzg1OTc1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWNmZjAwIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1Y2ZmMDAiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF84NjQ3YjVhMDczN2U0MzM5YjEyYzM1MDBlMGU4YmQ1MSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOGUxYmUxNmQxYWZmNDg4MWIxYmQ4MTNiNTFmOTMxNzkgPSAkKGA8ZGl2IGlkPSJodG1sXzhlMWJlMTZkMWFmZjQ4ODFiMWJkODEzYjUxZjkzMTc5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CYXl2aWV3IFZpbGxhZ2UgQ2x1c3RlciAzPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzg2NDdiNWEwNzM3ZTQzMzliMTJjMzUwMGUwZThiZDUxLnNldENvbnRlbnQoaHRtbF84ZTFiZTE2ZDFhZmY0ODgxYjFiZDgxM2I1MWY5MzE3OSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYjI0MTUxYzQ4ZjBlNDlmMzk1MTA0NjA3MDNhYmI1Y2QuYmluZFBvcHVwKHBvcHVwXzg2NDdiNWEwNzM3ZTQzMzliMTJjMzUwMGUwZThiZDUxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85NzFmNGFlZDU0YTM0OTgzYTk3NDA3ZDEyMTgxNzFmYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1NzQ5MDIsIC03OS4zNzQ3MTQwOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzAwZmY4YyIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMDBmZjhjIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTk5YWJjNDIzNzViNDA4YmI3Y2EzYjU1YTFkNGUyMzkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2NkZjU2NTRlNGEyMDQ0MjA4ZTk2NzRmYzk5YzczZjVlID0gJChgPGRpdiBpZD0iaHRtbF9jZGY1NjU0ZTRhMjA0NDIwOGU5Njc0ZmM5OWM3M2Y1ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U2lsdmVyIEhpbGxzLCBZb3JrIE1pbGxzIENsdXN0ZXIgNDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85OTlhYmM0MjM3NWI0MDhiYjdjYTNiNTVhMWQ0ZTIzOS5zZXRDb250ZW50KGh0bWxfY2RmNTY1NGU0YTIwNDQyMDhlOTY3NGZjOTljNzNmNWUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzk3MWY0YWVkNTRhMzQ5ODNhOTc0MDdkMTIxODE3MWZiLmJpbmRQb3B1cChwb3B1cF85OTlhYmM0MjM3NWI0MDhiYjdjYTNiNTVhMWQ0ZTIzOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGVkYjVlMWQ3YTI3NDkwYWJhZTc0ZGExODY2OGM3MjUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43ODkwNTMsIC03OS40MDg0OTI3OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDAyOSIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMDI5IiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOGUyNDJmYTUwMmE1NDVhMzliYTNkN2JmZjlmNjlkNTIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2I3ZDI2YTlkMzJlMDRmNjViZDE1M2ViNzI5ZmI3Nzk5ID0gJChgPGRpdiBpZD0iaHRtbF9iN2QyNmE5ZDMyZTA0ZjY1YmQxNTNlYjcyOWZiNzc5OSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TmV3dG9uYnJvb2ssIFdpbGxvd2RhbGUgQ2x1c3RlciAxPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzhlMjQyZmE1MDJhNTQ1YTM5YmEzZDdiZmY5ZjY5ZDUyLnNldENvbnRlbnQoaHRtbF9iN2QyNmE5ZDMyZTA0ZjY1YmQxNTNlYjcyOWZiNzc5OSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZGVkYjVlMWQ3YTI3NDkwYWJhZTc0ZGExODY2OGM3MjUuYmluZFBvcHVwKHBvcHVwXzhlMjQyZmE1MDJhNTQ1YTM5YmEzZDdiZmY5ZjY5ZDUyKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lYTc2ZjhkMWE2Mzc0ODg5YWRjOGQ3ODVjYzg3NWQyYSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc3MDExOTksIC03OS40MDg0OTI3OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMWEzYjVkOTNhNDZkNGQ5OWJkMTRjNWM3YTE1ZjM4ZWUgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2Q1MDhmZWRjNzcwZTQ5NTdhMzgyYTA1MTQ2YjYxMTQ1ID0gJChgPGRpdiBpZD0iaHRtbF9kNTA4ZmVkYzc3MGU0OTU3YTM4MmEwNTE0NmI2MTE0NSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2lsbG93ZGFsZSBTb3V0aCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMWEzYjVkOTNhNDZkNGQ5OWJkMTRjNWM3YTE1ZjM4ZWUuc2V0Q29udGVudChodG1sX2Q1MDhmZWRjNzcwZTQ5NTdhMzgyYTA1MTQ2YjYxMTQ1KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9lYTc2ZjhkMWE2Mzc0ODg5YWRjOGQ3ODVjYzg3NWQyYS5iaW5kUG9wdXAocG9wdXBfMWEzYjVkOTNhNDZkNGQ5OWJkMTRjNWM3YTE1ZjM4ZWUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2NhODczYjVkZDgxNzQ3MGE5OWIxODZkYThiMjgwMmEzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzUyNzU4Mjk5OTk5OTk2LCAtNzkuNDAwMDQ5M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzVhMDBmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjNWEwMGZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNDNiY2EzNTY1ZGUxNGZlYzlmYWE3OThhYjYxNGJlNTAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzFkMDZiNjcyNDA1NzRjYTFiNTI0ZTVhODBlMWY2YzU4ID0gJChgPGRpdiBpZD0iaHRtbF8xZDA2YjY3MjQwNTc0Y2ExYjUyNGU1YTgwZTFmNmM1OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+WW9yayBNaWxscyBXZXN0IENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80M2JjYTM1NjVkZTE0ZmVjOWZhYTc5OGFiNjE0YmU1MC5zZXRDb250ZW50KGh0bWxfMWQwNmI2NzI0MDU3NGNhMWI1MjRlNWE4MGUxZjZjNTgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2NhODczYjVkZDgxNzQ3MGE5OWIxODZkYThiMjgwMmEzLmJpbmRQb3B1cChwb3B1cF80M2JjYTM1NjVkZTE0ZmVjOWZhYTc5OGFiNjE0YmU1MCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZmQ3NzY5NmU2MzU3NDYzNmE5ZmFkZDk4MWUwYzZiZDcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43ODI3MzY0LCAtNzkuNDQyMjU5M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMTEwODk1MzQ3OTc2NDcxNTgyZGE1MjgyY2IyY2ZkODEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzliYmRkNzhiM2JkNjQzZTdiNTAxY2EwZWUwMjU5MDYyID0gJChgPGRpdiBpZD0iaHRtbF85YmJkZDc4YjNiZDY0M2U3YjUwMWNhMGVlMDI1OTA2MiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2lsbG93ZGFsZSBXZXN0IENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xMTA4OTUzNDc5NzY0NzE1ODJkYTUyODJjYjJjZmQ4MS5zZXRDb250ZW50KGh0bWxfOWJiZGQ3OGIzYmQ2NDNlN2I1MDFjYTBlZTAyNTkwNjIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ZkNzc2OTZlNjM1NzQ2MzZhOWZhZGQ5ODFlMGM2YmQ3LmJpbmRQb3B1cChwb3B1cF8xMTA4OTUzNDc5NzY0NzE1ODJkYTUyODJjYjJjZmQ4MSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZjg0ZmExNGRmODRjNDdhMDg0YWU4YzZiZTM1MzkwMTcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NTMyNTg2LCAtNzkuMzI5NjU2NV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzVhMDBmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjNWEwMGZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMWNjOWY4NmM3MjA5NGY1YWIwMTMyZmM3NTYzZmRlMjkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2UwZWYwMjMzNjU2MDRiZGU5YzkzNTQ0OTVmMjhlMDA4ID0gJChgPGRpdiBpZD0iaHRtbF9lMGVmMDIzMzY1NjA0YmRlOWM5MzU0NDk1ZjI4ZTAwOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UGFya3dvb2RzIENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xY2M5Zjg2YzcyMDk0ZjVhYjAxMzJmYzc1NjNmZGUyOS5zZXRDb250ZW50KGh0bWxfZTBlZjAyMzM2NTYwNGJkZTljOTM1NDQ5NWYyOGUwMDgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2Y4NGZhMTRkZjg0YzQ3YTA4NGFlOGM2YmUzNTM5MDE3LmJpbmRQb3B1cChwb3B1cF8xY2M5Zjg2YzcyMDk0ZjVhYjAxMzJmYzc1NjNmZGUyOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWMwZDBiMmVkYWNlNGNhOTlhY2Q2MWY3MzY1ZDJmZmYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NDU5MDU3OTk5OTk5OTYsIC03OS4zNTIxODhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzMwZThlNTIzNTM0YTRmNTlhNjMxMDBlZWQzOTFiYWMyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82Y2E4YTJmNWJlYTY0MTU2YTM0NDY5YzFmZDdkNTlhOCA9ICQoYDxkaXYgaWQ9Imh0bWxfNmNhOGEyZjViZWE2NDE1NmEzNDQ2OWMxZmQ3ZDU5YTgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvbiBNaWxscyBOb3J0aCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMzBlOGU1MjM1MzRhNGY1OWE2MzEwMGVlZDM5MWJhYzIuc2V0Q29udGVudChodG1sXzZjYThhMmY1YmVhNjQxNTZhMzQ0NjljMWZkN2Q1OWE4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8xYzBkMGIyZWRhY2U0Y2E5OWFjZDYxZjczNjVkMmZmZi5iaW5kUG9wdXAocG9wdXBfMzBlOGU1MjM1MzRhNGY1OWE2MzEwMGVlZDM5MWJhYzIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzA3MDFhYmQ5MWEzYTQ0NjZiMzY0MTM3ODI4MjExZDg2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzI1ODk5NzAwMDAwMDEsIC03OS4zNDA5MjNdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzUyNmRjYThiNDhhNzQwZDM5MTFjZTAwZTRhZWU4M2YyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iZDM5NjQ1ODQ0Mjk0Mjc4ODVmYzNkNTJiZmVjODVkZCA9ICQoYDxkaXYgaWQ9Imh0bWxfYmQzOTY0NTg0NDI5NDI3ODg1ZmMzZDUyYmZlYzg1ZGQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkZsZW1pbmdkb24gUGFyaywgRG9uIE1pbGxzIFNvdXRoIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81MjZkY2E4YjQ4YTc0MGQzOTExY2UwMGU0YWVlODNmMi5zZXRDb250ZW50KGh0bWxfYmQzOTY0NTg0NDI5NDI3ODg1ZmMzZDUyYmZlYzg1ZGQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzA3MDFhYmQ5MWEzYTQ0NjZiMzY0MTM3ODI4MjExZDg2LmJpbmRQb3B1cChwb3B1cF81MjZkY2E4YjQ4YTc0MGQzOTExY2UwMGU0YWVlODNmMikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNWRiOWM4ZDRhNDE1NDMxZWFmMjgyNTI3ZTkzYzg5MjkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NTQzMjgzLCAtNzkuNDQyMjU5M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfODc5N2UxYWZmNmY3NDUzOThmMDQ4ZmNhMTA4MmIxMzEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzU0NGY5NWY2ODk0MzQyYTJhMDUzZDNhYzg5N2UzZGNjID0gJChgPGRpdiBpZD0iaHRtbF81NDRmOTVmNjg5NDM0MmEyYTA1M2QzYWM4OTdlM2RjYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QmF0aHVyc3QgTWFub3IsIERvd25zdmlldyBOb3J0aCwgV2lsc29uIEhlaWdodHMgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzg3OTdlMWFmZjZmNzQ1Mzk4ZjA0OGZjYTEwODJiMTMxLnNldENvbnRlbnQoaHRtbF81NDRmOTVmNjg5NDM0MmEyYTA1M2QzYWM4OTdlM2RjYyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNWRiOWM4ZDRhNDE1NDMxZWFmMjgyNTI3ZTkzYzg5MjkuYmluZFBvcHVwKHBvcHVwXzg3OTdlMWFmZjZmNzQ1Mzk4ZjA0OGZjYTEwODJiMTMxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yNDBhMGFlNDgwMWU0MDM0YjJiNTFiMmM4ZjViMGM4YiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc2Nzk4MDMsIC03OS40ODcyNjE5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMzJhMDVlOTY5ZjQ5NDVlYmIzMmYzZDU3MzhjMjgwYmYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzA0NTRjODk5NWVlMzQwMmJhYjhiMzUxY2FlODI4MThmID0gJChgPGRpdiBpZD0iaHRtbF8wNDU0Yzg5OTVlZTM0MDJiYWI4YjM1MWNhZTgyODE4ZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Tm9ydGh3b29kIFBhcmssIFlvcmsgVW5pdmVyc2l0eSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMzJhMDVlOTY5ZjQ5NDVlYmIzMmYzZDU3MzhjMjgwYmYuc2V0Q29udGVudChodG1sXzA0NTRjODk5NWVlMzQwMmJhYjhiMzUxY2FlODI4MThmKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yNDBhMGFlNDgwMWU0MDM0YjJiNTFiMmM4ZjViMGM4Yi5iaW5kUG9wdXAocG9wdXBfMzJhMDVlOTY5ZjQ5NDVlYmIzMmYzZDU3MzhjMjgwYmYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzk5NmM5NDNiYmZiYTQ5NzZiYjlmYzBjYTY1MGFjZTFhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzM3NDczMjAwMDAwMDA0LCAtNzkuNDY0NzYzMjk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiM1YTAwZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzVhMDBmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2FhOTZiZGM5MTg3ZTQzNzU5ZTI4NjBmYzBlNjlkYmViID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF82OTRjOWZjNzc4MjM0OTc0YjVlNzhhYmJiMzNmZDI4NyA9ICQoYDxkaXYgaWQ9Imh0bWxfNjk0YzlmYzc3ODIzNDk3NGI1ZTc4YWJiYjMzZmQyODciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNGQiBUb3JvbnRvLCBEb3duc3ZpZXcgRWFzdCBDbHVzdGVyIDY8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYWE5NmJkYzkxODdlNDM3NTllMjg2MGZjMGU2OWRiZWIuc2V0Q29udGVudChodG1sXzY5NGM5ZmM3NzgyMzQ5NzRiNWU3OGFiYmIzM2ZkMjg3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85OTZjOTQzYmJmYmE0OTc2YmI5ZmMwY2E2NTBhY2UxYS5iaW5kUG9wdXAocG9wdXBfYWE5NmJkYzkxODdlNDM3NTllMjg2MGZjMGU2OWRiZWIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzMyNjU5YzMxYTkxNzQ5MTU5NzVkOTZiNzNlMzI4Y2UzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzM5MDE0NiwgLTc5LjUwNjk0MzZdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzgzNzBmMmZkNGZhNTQyZGI4NzU5ZmEwMGNmYTY2NzgzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9lNGMzNDdkMmY2N2Y0OGI4ODAxY2M4MDg1YTkwZWZjNSA9ICQoYDxkaXYgaWQ9Imh0bWxfZTRjMzQ3ZDJmNjdmNDhiODgwMWNjODA4NWE5MGVmYzUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd25zdmlldyBXZXN0IENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84MzcwZjJmZDRmYTU0MmRiODc1OWZhMDBjZmE2Njc4My5zZXRDb250ZW50KGh0bWxfZTRjMzQ3ZDJmNjdmNDhiODgwMWNjODA4NWE5MGVmYzUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzMyNjU5YzMxYTkxNzQ5MTU5NzVkOTZiNzNlMzI4Y2UzLmJpbmRQb3B1cChwb3B1cF84MzcwZjJmZDRmYTU0MmRiODc1OWZhMDBjZmE2Njc4MykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOTllNzJmNThmNGNhNGRmOWI2MmQwNWFmOTAwMjBjNzQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Mjg0OTY0LCAtNzkuNDk1Njk3NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2RkZWNlZGZhYWMzYzQzNjlhNDA0YjlhOGI0NGNlMzNjID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mM2M1Y2Q1Y2I0Y2M0M2I5YTZiYzcyNzRmYWFiZmQ3OCA9ICQoYDxkaXYgaWQ9Imh0bWxfZjNjNWNkNWNiNGNjNDNiOWE2YmM3Mjc0ZmFhYmZkNzgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd25zdmlldyBDZW50cmFsIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9kZGVjZWRmYWFjM2M0MzY5YTQwNGI5YThiNDRjZTMzYy5zZXRDb250ZW50KGh0bWxfZjNjNWNkNWNiNGNjNDNiOWE2YmM3Mjc0ZmFhYmZkNzgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzk5ZTcyZjU4ZjRjYTRkZjliNjJkMDVhZjkwMDIwYzc0LmJpbmRQb3B1cChwb3B1cF9kZGVjZWRmYWFjM2M0MzY5YTQwNGI5YThiNDRjZTMzYykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOGMxOTAwNGM1OGMyNGQzMzgxNTliODkwNGVkZDAzM2UgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43NjE2MzEzLCAtNzkuNTIwOTk5NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzZkY2RkM2EwMzgwYTQ1Y2I4NDk5Y2EyMjdkZWU2NDNmID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8yMTQyYTYxMmRkZmQ0NGZjYTE1ZjBhNzYyMmE2MGU5MyA9ICQoYDxkaXYgaWQ9Imh0bWxfMjE0MmE2MTJkZGZkNDRmY2ExNWYwYTc2MjJhNjBlOTMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd25zdmlldyBOb3J0aHdlc3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzZkY2RkM2EwMzgwYTQ1Y2I4NDk5Y2EyMjdkZWU2NDNmLnNldENvbnRlbnQoaHRtbF8yMTQyYTYxMmRkZmQ0NGZjYTE1ZjBhNzYyMmE2MGU5Myk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfOGMxOTAwNGM1OGMyNGQzMzgxNTliODkwNGVkZDAzM2UuYmluZFBvcHVwKHBvcHVwXzZkY2RkM2EwMzgwYTQ1Y2I4NDk5Y2EyMjdkZWU2NDNmKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wOWUwNjJlYzJmZGU0ZDZjYWM5OGM5NTlmMDY4YjgzMyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcyNTg4MjI5OTk5OTk5NSwgLTc5LjMxNTU3MTU5OTk5OTk4XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9hNDgwYWI5M2Q1NDQ0YTk3ODU5ZDQyYzFjYTA0MGVmYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOGIyZWI3Y2VkYWVlNDA3Yjg1MzBkNjk5NjhiZWE1ZGYgPSAkKGA8ZGl2IGlkPSJodG1sXzhiMmViN2NlZGFlZTQwN2I4NTMwZDY5OTY4YmVhNWRmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5WaWN0b3JpYSBWaWxsYWdlIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9hNDgwYWI5M2Q1NDQ0YTk3ODU5ZDQyYzFjYTA0MGVmYS5zZXRDb250ZW50KGh0bWxfOGIyZWI3Y2VkYWVlNDA3Yjg1MzBkNjk5NjhiZWE1ZGYpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzA5ZTA2MmVjMmZkZTRkNmNhYzk4Yzk1OWYwNjhiODMzLmJpbmRQb3B1cChwb3B1cF9hNDgwYWI5M2Q1NDQ0YTk3ODU5ZDQyYzFjYTA0MGVmYSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGY5MmZjMDI2M2M3NGJmNDhhZTZlMWU3ODk5MGJhZDUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDYzOTcyLCAtNzkuMzA5OTM3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjMDA4ZmZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMwMDhmZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF82OGI3Y2MzMDE2YTc0NjBkYTdiMjBmOWQyNWY1Y2U1OCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOGEwNzM2NTM2MGM2NDMxNjg0YmZjMWFlNWY0ZTQyZTMgPSAkKGA8ZGl2IGlkPSJodG1sXzhhMDczNjUzNjBjNjQzMTY4NGJmYzFhZTVmNGU0MmUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Xb29kYmluZSBHYXJkZW5zLCBQYXJrdmlldyBIaWxsIENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF82OGI3Y2MzMDE2YTc0NjBkYTdiMjBmOWQyNWY1Y2U1OC5zZXRDb250ZW50KGh0bWxfOGEwNzM2NTM2MGM2NDMxNjg0YmZjMWFlNWY0ZTQyZTMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2RmOTJmYzAyNjNjNzRiZjQ4YWU2ZTFlNzg5OTBiYWQ1LmJpbmRQb3B1cChwb3B1cF82OGI3Y2MzMDE2YTc0NjBkYTdiMjBmOWQyNWY1Y2U1OCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWQ4MjFmOWY0NGFjNGEwMWJjNjdkN2I4YjNmZTAzMGUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42OTUzNDM5MDAwMDAwMDUsIC03OS4zMTgzODg3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85YzEwYTZkNTEwNzU0ZmM5YWQ1YzlhNzBmNzViOGQwNCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNDYyYjFkODlmZDE5NGQ5MDk0YmRiNzdjM2MyZWQyNGMgPSAkKGA8ZGl2IGlkPSJodG1sXzQ2MmIxZDg5ZmQxOTRkOTA5NGJkYjc3YzNjMmVkMjRjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Xb29kYmluZSBIZWlnaHRzIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85YzEwYTZkNTEwNzU0ZmM5YWQ1YzlhNzBmNzViOGQwNC5zZXRDb250ZW50KGh0bWxfNDYyYjFkODlmZDE5NGQ5MDk0YmRiNzdjM2MyZWQyNGMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzFkODIxZjlmNDRhYzRhMDFiYzY3ZDdiOGIzZmUwMzBlLmJpbmRQb3B1cChwb3B1cF85YzEwYTZkNTEwNzU0ZmM5YWQ1YzlhNzBmNzViOGQwNCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGUzNjZkM2NjOWYzNDkxNDkxZjVlZDBlMmZhMjVhZTAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NzYzNTczOTk5OTk5OSwgLTc5LjI5MzAzMTJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzc4NTYxNzNiZjY0ZTQ4ZGQ4MWRkMzEwMDc4ZTU5NTlmID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80YzkyYTI2ZGM2Njg0ZGUzYTRjMDJlYzYyZWJiMWVmOCA9ICQoYDxkaXYgaWQ9Imh0bWxfNGM5MmEyNmRjNjY4NGRlM2E0YzAyZWM2MmViYjFlZjgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRoZSBCZWFjaGVzIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83ODU2MTczYmY2NGU0OGRkODFkZDMxMDA3OGU1OTU5Zi5zZXRDb250ZW50KGh0bWxfNGM5MmEyNmRjNjY4NGRlM2E0YzAyZWM2MmViYjFlZjgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzRlMzY2ZDNjYzlmMzQ5MTQ5MWY1ZWQwZTJmYTI1YWUwLmJpbmRQb3B1cChwb3B1cF83ODU2MTczYmY2NGU0OGRkODFkZDMxMDA3OGU1OTU5ZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOWNmODgzMmMyMDhjNGQ3YzhmYTUzOWMzNGQxZmZlZWIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDkwNjA0LCAtNzkuMzYzNDUxN10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMTZkY2FkY2Y2ZGUwNDMxYTg1OGZiYjM4NDcyYjQ0NGIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzcyNjBkMjE1NzBlODRjMzZiZjI3MGQ3MmZkMTFhZmU0ID0gJChgPGRpdiBpZD0iaHRtbF83MjYwZDIxNTcwZTg0YzM2YmYyNzBkNzJmZDExYWZlNCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TGVhc2lkZSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMTZkY2FkY2Y2ZGUwNDMxYTg1OGZiYjM4NDcyYjQ0NGIuc2V0Q29udGVudChodG1sXzcyNjBkMjE1NzBlODRjMzZiZjI3MGQ3MmZkMTFhZmU0KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85Y2Y4ODMyYzIwOGM0ZDdjOGZhNTM5YzM0ZDFmZmVlYi5iaW5kUG9wdXAocG9wdXBfMTZkY2FkY2Y2ZGUwNDMxYTg1OGZiYjM4NDcyYjQ0NGIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2ZiYjQ2YjMwMDEzYTQxNDc4ZmNjY2E2NDgyZTBiNDM0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzA1MzY4OSwgLTc5LjM0OTM3MTkwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83ZDdjNDUzMGNiNWU0YzRlYWQzNzUyZmQ2MGQ1MmE1YSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNTI5Y2U5YmY0ZDY5NGViM2E5NWQxYTE3YTc2NTJlYjggPSAkKGA8ZGl2IGlkPSJodG1sXzUyOWNlOWJmNGQ2OTRlYjNhOTVkMWExN2E3NjUyZWI4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5UaG9ybmNsaWZmZSBQYXJrIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83ZDdjNDUzMGNiNWU0YzRlYWQzNzUyZmQ2MGQ1MmE1YS5zZXRDb250ZW50KGh0bWxfNTI5Y2U5YmY0ZDY5NGViM2E5NWQxYTE3YTc2NTJlYjgpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2ZiYjQ2YjMwMDEzYTQxNDc4ZmNjY2E2NDgyZTBiNDM0LmJpbmRQb3B1cChwb3B1cF83ZDdjNDUzMGNiNWU0YzRlYWQzNzUyZmQ2MGQ1MmE1YSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMmExZDdmZTJkOTQ3NGZlMzlmMzRiMmFkMGY1MDJkZDcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODUzNDcsIC03OS4zMzgxMDY1XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWEwMGZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1YTAwZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81NDkwMTYxNzk2YzE0Y2VmYTU0YTVmYzQ3OTQ2NGE3MyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMTBjZWM4NGU2MjA4NGY2N2EyMjJhNzE0Zjg3ZTkxMmQgPSAkKGA8ZGl2IGlkPSJodG1sXzEwY2VjODRlNjIwODRmNjdhMjIyYTcxNGY4N2U5MTJkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FYXN0IFRvcm9udG8gQ2x1c3RlciA2PC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzU0OTAxNjE3OTZjMTRjZWZhNTRhNWZjNDc5NDY0YTczLnNldENvbnRlbnQoaHRtbF8xMGNlYzg0ZTYyMDg0ZjY3YTIyMmE3MTRmODdlOTEyZCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMmExZDdmZTJkOTQ3NGZlMzlmMzRiMmFkMGY1MDJkZDcuYmluZFBvcHVwKHBvcHVwXzU0OTAxNjE3OTZjMTRjZWZhNTRhNWZjNDc5NDY0YTczKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83NjFkMDhiOWUzZjY0M2RkOTZiYmExNTBiMmQ0ZDU2NSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3OTU1NzEsIC03OS4zNTIxODhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzZlNTBkMjQzZDYyNTQyMmJiNWIxN2UyMzRlYmM4NjYzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8xM2U5ZTdmODBjOTE0ZWY4YTY2ZDNmZDdmMDllMzg5ZSA9ICQoYDxkaXYgaWQ9Imh0bWxfMTNlOWU3ZjgwYzkxNGVmOGE2NmQzZmQ3ZjA5ZTM4OWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRoZSBEYW5mb3J0aCBXZXN0LCBSaXZlcmRhbGUgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzZlNTBkMjQzZDYyNTQyMmJiNWIxN2UyMzRlYmM4NjYzLnNldENvbnRlbnQoaHRtbF8xM2U5ZTdmODBjOTE0ZWY4YTY2ZDNmZDdmMDllMzg5ZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNzYxZDA4YjllM2Y2NDNkZDk2YmJhMTUwYjJkNGQ1NjUuYmluZFBvcHVwKHBvcHVwXzZlNTBkMjQzZDYyNTQyMmJiNWIxN2UyMzRlYmM4NjYzKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82NGY3NzlkNWNmYzc0OTkzOTYwNDk1MTg1NzE5ZmY5MyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2ODk5ODUsIC03OS4zMTU1NzE1OTk5OTk5OF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOWE2OWEwN2NjNWEwNDJjNWFmMGEyMzEyZjExMjliZjUgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2YwODcwZGE2OTRkOTQ3MTg4MDlkNjA1MWRjOTlkMTVjID0gJChgPGRpdiBpZD0iaHRtbF9mMDg3MGRhNjk0ZDk0NzE4ODA5ZDYwNTFkYzk5ZDE1YyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEJlYWNoZXMgV2VzdCwgSW5kaWEgQmF6YWFyIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85YTY5YTA3Y2M1YTA0MmM1YWYwYTIzMTJmMTEyOWJmNS5zZXRDb250ZW50KGh0bWxfZjA4NzBkYTY5NGQ5NDcxODgwOWQ2MDUxZGM5OWQxNWMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzY0Zjc3OWQ1Y2ZjNzQ5OTM5NjA0OTUxODU3MTlmZjkzLmJpbmRQb3B1cChwb3B1cF85YTY5YTA3Y2M1YTA0MmM1YWYwYTIzMTJmMTEyOWJmNSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZTM0N2YzNDIyNzI2NGU4MDk5MzU1ZmFkYTJhMDJkYTIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTk1MjU1LCAtNzkuMzQwOTIzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83MDA2OTllY2I1YWM0YzJlOTZjMjRlMzhkMDJlY2MxOCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNGRhOWM4NGE1MjJmNDg4MWE2MDQ0ZmU3MjQ2MjNkZDMgPSAkKGA8ZGl2IGlkPSJodG1sXzRkYTljODRhNTIyZjQ4ODFhNjA0NGZlNzI0NjIzZGQzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TdHVkaW8gRGlzdHJpY3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzcwMDY5OWVjYjVhYzRjMmU5NmMyNGUzOGQwMmVjYzE4LnNldENvbnRlbnQoaHRtbF80ZGE5Yzg0YTUyMmY0ODgxYTYwNDRmZTcyNDYyM2RkMyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZTM0N2YzNDIyNzI2NGU4MDk5MzU1ZmFkYTJhMDJkYTIuYmluZFBvcHVwKHBvcHVwXzcwMDY5OWVjYjVhYzRjMmU5NmMyNGUzOGQwMmVjYzE4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xMTU3ZmIyZTI3NDQ0MTljYjhmZjExN2MzOTJjNjhmNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcyODAyMDUsIC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWEwMGZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1YTAwZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81ZTQ2OWNmODI4ZGQ0MjY5YjU0OTc3OGE2ZThkZjRhMCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZmY4MmZlNjhmNWE0NGVhYjk5NTA1ZDNlYjU3YmQ4MmEgPSAkKGA8ZGl2IGlkPSJodG1sX2ZmODJmZTY4ZjVhNDRlYWI5OTUwNWQzZWI1N2JkODJhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5MYXdyZW5jZSBQYXJrIENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81ZTQ2OWNmODI4ZGQ0MjY5YjU0OTc3OGE2ZThkZjRhMC5zZXRDb250ZW50KGh0bWxfZmY4MmZlNjhmNWE0NGVhYjk5NTA1ZDNlYjU3YmQ4MmEpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzExNTdmYjJlMjc0NDQxOWNiOGZmMTE3YzM5MmM2OGY2LmJpbmRQb3B1cChwb3B1cF81ZTQ2OWNmODI4ZGQ0MjY5YjU0OTc3OGE2ZThkZjRhMCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGZkYmQ3YzQwODZiNDcyYjliOTg2OWU4NWQyMGNiZjMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTI3NTExLCAtNzkuMzkwMTk3NV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzY2ZmJkM2FjZjQ1NDM3M2I2NzNmYTBkNzFiMzExNGIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzkyOTBlOGRkZWJhZDQ5ODQ5NGNiZTFkZGY3OWYxYjZiID0gJChgPGRpdiBpZD0iaHRtbF85MjkwZThkZGViYWQ0OTg0OTRjYmUxZGRmNzlmMWI2YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RGF2aXN2aWxsZSBOb3J0aCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNzY2ZmJkM2FjZjQ1NDM3M2I2NzNmYTBkNzFiMzExNGIuc2V0Q29udGVudChodG1sXzkyOTBlOGRkZWJhZDQ5ODQ5NGNiZTFkZGY3OWYxYjZiKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kZmRiZDdjNDA4NmI0NzJiOWI5ODY5ZTg1ZDIwY2JmMy5iaW5kUG9wdXAocG9wdXBfNzY2ZmJkM2FjZjQ1NDM3M2I2NzNmYTBkNzFiMzExNGIpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2FlMDg2ODdjZWExMDRiMTI5ZGEzMzdjMmNmNDkzMmVmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzE1MzgzNCwgLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF81YWNiNzhjYjhmY2Q0YjAyYmIzYTE1YjRhYjUxMzVmOCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNWU2MDNmOTVlZWFiNDFjZWFjMmNjZWVkNzJiMWMxZTAgPSAkKGA8ZGl2IGlkPSJodG1sXzVlNjAzZjk1ZWVhYjQxY2VhYzJjY2VlZDcyYjFjMWUwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ob3J0aCBUb3JvbnRvIFdlc3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzVhY2I3OGNiOGZjZDRiMDJiYjNhMTViNGFiNTEzNWY4LnNldENvbnRlbnQoaHRtbF81ZTYwM2Y5NWVlYWI0MWNlYWMyY2NlZWQ3MmIxYzFlMCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYWUwODY4N2NlYTEwNGIxMjlkYTMzN2MyY2Y0OTMyZWYuYmluZFBvcHVwKHBvcHVwXzVhY2I3OGNiOGZjZDRiMDJiYjNhMTViNGFiNTEzNWY4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jYjliZDUxMDA5ZDg0MTc4YTBmYzJiNDI4OWY0Yjk4OSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcwNDMyNDQsIC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83YTE1ZDI3MTdkYTM0ODUwODA2YzQyZWZiYWUyNzBiZSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYjhkNTFhZjEyNDY2NDc5ZTllZWViOTNkYzU5MDBlMWQgPSAkKGA8ZGl2IGlkPSJodG1sX2I4ZDUxYWYxMjQ2NjQ3OWU5ZWVlYjkzZGM1OTAwZTFkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EYXZpc3ZpbGxlIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83YTE1ZDI3MTdkYTM0ODUwODA2YzQyZWZiYWUyNzBiZS5zZXRDb250ZW50KGh0bWxfYjhkNTFhZjEyNDY2NDc5ZTllZWViOTNkYzU5MDBlMWQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2NiOWJkNTEwMDlkODQxNzhhMGZjMmI0Mjg5ZjRiOTg5LmJpbmRQb3B1cChwb3B1cF83YTE1ZDI3MTdkYTM0ODUwODA2YzQyZWZiYWUyNzBiZSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDQ2MjQ4NzA2NWEyNDhjOTg0MDMwNWRhMGMzNTY0OTUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODk1NzQzLCAtNzkuMzgzMTU5OTAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiM1YTAwZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzVhMDBmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzNkNzBmMDZiMzc3NjQ5YTlhMmRkZTQwYWFhOGYzODA2ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF81MWZhYzcwNGFmYjc0NjAyOWQzZGU1Mzg3ODE4YWFkNSA9ICQoYDxkaXYgaWQ9Imh0bWxfNTFmYWM3MDRhZmI3NDYwMjlkM2RlNTM4NzgxOGFhZDUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPk1vb3JlIFBhcmssIFN1bW1lcmhpbGwgRWFzdCBDbHVzdGVyIDY8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfM2Q3MGYwNmIzNzc2NDlhOWEyZGRlNDBhYWE4ZjM4MDYuc2V0Q29udGVudChodG1sXzUxZmFjNzA0YWZiNzQ2MDI5ZDNkZTUzODc4MThhYWQ1KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9kNDYyNDg3MDY1YTI0OGM5ODQwMzA1ZGEwYzM1NjQ5NS5iaW5kUG9wdXAocG9wdXBfM2Q3MGYwNmIzNzc2NDlhOWEyZGRlNDBhYWE4ZjM4MDYpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM2MzQ5NTNkZWRiYTRlNzJhYjA5YzZjMTFhMjc3MzFkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjg2NDEyMjk5OTk5OTksIC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85MmYxMmVmODMzZjc0NWIwODhjODBiYmIxOTEyYTRkZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNTVmNmVhMDNhZGMxNGMwNGI1YmIxZGFjYzMzMWU5YjMgPSAkKGA8ZGl2IGlkPSJodG1sXzU1ZjZlYTAzYWRjMTRjMDRiNWJiMWRhY2MzMzFlOWIzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EZWVyIFBhcmssIEZvcmVzdCBIaWxsIFNFLCBSYXRobmVsbHksIFNvdXRoIEhpbGwsIFN1bW1lcmhpbGwgV2VzdCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTJmMTJlZjgzM2Y3NDViMDg4YzgwYmJiMTkxMmE0ZGQuc2V0Q29udGVudChodG1sXzU1ZjZlYTAzYWRjMTRjMDRiNWJiMWRhY2MzMzFlOWIzKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zNjM0OTUzZGVkYmE0ZTcyYWIwOWM2YzExYTI3NzMxZC5iaW5kUG9wdXAocG9wdXBfOTJmMTJlZjgzM2Y3NDViMDg4YzgwYmJiMTkxMmE0ZGQpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzllMmRjOWRmNGU4YTRlZTliNzAzNzE1Y2EyZDk1MjIxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjc5NTYyNiwgLTc5LjM3NzUyOTQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWEwMGZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1YTAwZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wY2RjYmM2YjQwM2Q0NGU3YmQ0MWM5YjIwOWM2MjE0YSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYTQ3ZDMzZmJmYWYwNDY0NmFjYzU3NzE1MTVlODMxZGIgPSAkKGA8ZGl2IGlkPSJodG1sX2E0N2QzM2ZiZmFmMDQ2NDZhY2M1NzcxNTE1ZTgzMWRiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Sb3NlZGFsZSBDbHVzdGVyIDY8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMGNkY2JjNmI0MDNkNDRlN2JkNDFjOWIyMDljNjIxNGEuc2V0Q29udGVudChodG1sX2E0N2QzM2ZiZmFmMDQ2NDZhY2M1NzcxNTE1ZTgzMWRiKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl85ZTJkYzlkZjRlOGE0ZWU5YjcwMzcxNWNhMmQ5NTIyMS5iaW5kUG9wdXAocG9wdXBfMGNkY2JjNmI0MDNkNDRlN2JkNDFjOWIyMDljNjIxNGEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U0MGMxZDkzYTU2ZDRmYjRiZGM0NzAzOWIwYjY3NzdmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjY3OTY3LCAtNzkuMzY3Njc1M10sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzNiZTcwODc3MWQ0NGU1OWIyMDk5M2YwYWIxNzQwNWMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2Y2YTZkODc4NzNkZTQ1Zjg4ZGIxY2Y0NzM4MTE3MGM5ID0gJChgPGRpdiBpZD0iaHRtbF9mNmE2ZDg3ODczZGU0NWY4OGRiMWNmNDczODExNzBjOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2FiYmFnZXRvd24sIFN0LiBKYW1lcyBUb3duIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83M2JlNzA4NzcxZDQ0ZTU5YjIwOTkzZjBhYjE3NDA1Yy5zZXRDb250ZW50KGh0bWxfZjZhNmQ4Nzg3M2RlNDVmODhkYjFjZjQ3MzgxMTcwYzkpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U0MGMxZDkzYTU2ZDRmYjRiZGM0NzAzOWIwYjY3NzdmLmJpbmRQb3B1cChwb3B1cF83M2JlNzA4NzcxZDQ0ZTU5YjIwOTkzZjBhYjE3NDA1YykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMDI5NjFlMmE4NDMxNDhjMWI2MTIwMDYwMGMzNDc2N2YgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjU4NTk5LCAtNzkuMzgzMTU5OTAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzNjY2E3MDBiZTE2NTRmNjE5MzAxZGE0OGIzM2Y1NTAyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iZjE4NjA1MTNjZWE0OTk1OWYxZjdiMzY0MzFiNmY0NCA9ICQoYDxkaXYgaWQ9Imh0bWxfYmYxODYwNTEzY2VhNDk5NTlmMWY3YjM2NDMxYjZmNDQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNodXJjaCBhbmQgV2VsbGVzbGV5IENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8zY2NhNzAwYmUxNjU0ZjYxOTMwMWRhNDhiMzNmNTUwMi5zZXRDb250ZW50KGh0bWxfYmYxODYwNTEzY2VhNDk5NTlmMWY3YjM2NDMxYjZmNDQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzAyOTYxZTJhODQzMTQ4YzFiNjEyMDA2MDBjMzQ3NjdmLmJpbmRQb3B1cChwb3B1cF8zY2NhNzAwYmUxNjU0ZjYxOTMwMWRhNDhiMzNmNTUwMikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjZkNDRkODdlMjI1NGU3ZDgxYzc5ZDUxY2RhM2U0MjQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTQyNTk5LCAtNzkuMzYwNjM1OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjBkMWExN2ZlY2VhNDFiZDk1OTc1YjI5YThhMGMxZmEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzgwNDU4YzVhZmU4MDRlNjVhZjQ3ZThlYzI2N2I1ZjA3ID0gJChgPGRpdiBpZD0iaHRtbF84MDQ1OGM1YWZlODA0ZTY1YWY0N2U4ZWMyNjdiNWYwNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SGFyYm91cmZyb250LCBSZWdlbnQgUGFyayBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfNjBkMWExN2ZlY2VhNDFiZDk1OTc1YjI5YThhMGMxZmEuc2V0Q29udGVudChodG1sXzgwNDU4YzVhZmU4MDRlNjVhZjQ3ZThlYzI2N2I1ZjA3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9iNmQ0NGQ4N2UyMjU0ZTdkODFjNzlkNTFjZGEzZTQyNC5iaW5kUG9wdXAocG9wdXBfNjBkMWExN2ZlY2VhNDFiZDk1OTc1YjI5YThhMGMxZmEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzEzNTc1NjFjM2YxNDRiZmE5NWNhYzI4OTU2OWM1NWM5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjU3MTYxOCwgLTc5LjM3ODkzNzA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9lOTA1NGVjNDZhOTM0Njk2ODFkYzlkNWI3MDQxNmMyOCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOThiZDE4NDE2NjRiNGE1YTg5NGM3MzBhM2M3NzE1MTYgPSAkKGA8ZGl2IGlkPSJodG1sXzk4YmQxODQxNjY0YjRhNWE4OTRjNzMwYTNjNzcxNTE2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5SeWVyc29uLCBHYXJkZW4gRGlzdHJpY3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2U5MDU0ZWM0NmE5MzQ2OTY4MWRjOWQ1YjcwNDE2YzI4LnNldENvbnRlbnQoaHRtbF85OGJkMTg0MTY2NGI0YTVhODk0YzczMGEzYzc3MTUxNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMTM1NzU2MWMzZjE0NGJmYTk1Y2FjMjg5NTY5YzU1YzkuYmluZFBvcHVwKHBvcHVwX2U5MDU0ZWM0NmE5MzQ2OTY4MWRjOWQ1YjcwNDE2YzI4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zNjQyZGRjNGNkYTg0YTcwODYzODE5MmE1OWE4NmM5ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MTQ5MzksIC03OS4zNzU0MTc5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wY2JjNmJhYzI1MjQ0ZWQ2ODUyOWJjMTk0YTMyMTc1MCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfYzBkOGUyYjZjYmViNDZjYWExZWRlMjc1ZDEwNmYwODMgPSAkKGA8ZGl2IGlkPSJodG1sX2MwZDhlMmI2Y2JlYjQ2Y2FhMWVkZTI3NWQxMDZmMDgzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TdC4gSmFtZXMgVG93biBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMGNiYzZiYWMyNTI0NGVkNjg1MjliYzE5NGEzMjE3NTAuc2V0Q29udGVudChodG1sX2MwZDhlMmI2Y2JlYjQ2Y2FhMWVkZTI3NWQxMDZmMDgzKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8zNjQyZGRjNGNkYTg0YTcwODYzODE5MmE1OWE4NmM5ZC5iaW5kUG9wdXAocG9wdXBfMGNiYzZiYWMyNTI0NGVkNjg1MjliYzE5NGEzMjE3NTApCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzQ3ZWUxNjgwMjc3MjQxNTViMGFmMTQxNTM4ZTljZDM4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ0NzcwNzk5OTk5OTk2LCAtNzkuMzczMzA2NF0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfN2VkNjMwNjg3NTM0NGI3OTgzMTlkZjVkMDRlNWFhMTMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2MwMTY5OWVhZjRlYTRjNzc5ZDgxZTg4MjAzZmQ2NDMwID0gJChgPGRpdiBpZD0iaHRtbF9jMDE2OTllYWY0ZWE0Yzc3OWQ4MWU4ODIwM2ZkNjQzMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QmVyY3p5IFBhcmsgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzdlZDYzMDY4NzUzNDRiNzk4MzE5ZGY1ZDA0ZTVhYTEzLnNldENvbnRlbnQoaHRtbF9jMDE2OTllYWY0ZWE0Yzc3OWQ4MWU4ODIwM2ZkNjQzMCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDdlZTE2ODAyNzcyNDE1NWIwYWYxNDE1MzhlOWNkMzguYmluZFBvcHVwKHBvcHVwXzdlZDYzMDY4NzUzNDRiNzk4MzE5ZGY1ZDA0ZTVhYTEzKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wYWQxOTJmYWU1ZTE0MzQ2YjE4MDkyNWQ2YmJjOTA0ZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1Nzk1MjQsIC03OS4zODczODI2XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80YmNkNTcxZGIyZmY0ZDkxOWE5Njc4MGJkMDQwNTM4NiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfY2UyZDU1NGZkNDRjNDY2ODg2ZDM1ZmNlNmY4NDI0MWUgPSAkKGA8ZGl2IGlkPSJodG1sX2NlMmQ1NTRmZDQ0YzQ2Njg4NmQzNWZjZTZmODQyNDFlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DZW50cmFsIEJheSBTdHJlZXQgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzRiY2Q1NzFkYjJmZjRkOTE5YTk2NzgwYmQwNDA1Mzg2LnNldENvbnRlbnQoaHRtbF9jZTJkNTU0ZmQ0NGM0NjY4ODZkMzVmY2U2Zjg0MjQxZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMGFkMTkyZmFlNWUxNDM0NmIxODA5MjVkNmJiYzkwNGYuYmluZFBvcHVwKHBvcHVwXzRiY2Q1NzFkYjJmZjRkOTE5YTk2NzgwYmQwNDA1Mzg2KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jNmE3NjNlYmE5ZjA0N2M4YmM4NGNlYTc2YWY3NjBiYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MDU3MTIwMDAwMDAxLCAtNzkuMzg0NTY3NV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZTc5MmQyZDBiYzM4NGRiOTgwZDljODI4NzQ3MGIzNGYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzI2OTVjZWUxOGRiZTRhZDJiNDI1ZmVjZmQzYjM2MGQwID0gJChgPGRpdiBpZD0iaHRtbF8yNjk1Y2VlMThkYmU0YWQyYjQyNWZlY2ZkM2IzNjBkMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QWRlbGFpZGUsIEtpbmcsIFJpY2htb25kIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9lNzkyZDJkMGJjMzg0ZGI5ODBkOWM4Mjg3NDcwYjM0Zi5zZXRDb250ZW50KGh0bWxfMjY5NWNlZTE4ZGJlNGFkMmI0MjVmZWNmZDNiMzYwZDApOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2M2YTc2M2ViYTlmMDQ3YzhiYzg0Y2VhNzZhZjc2MGJjLmJpbmRQb3B1cChwb3B1cF9lNzkyZDJkMGJjMzg0ZGI5ODBkOWM4Mjg3NDcwYjM0ZikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDkxYjFiNTQ1YmJkNDNjYTg1YmQ5YmM2Y2JmM2M4NmIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDA4MTU3LCAtNzkuMzgxNzUyMjk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2ExMzU5MTRlZjM2ZjRlZTBhMDkyNmNjYTdlNjc1ZTAxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wNTc0OTg4M2VjY2I0M2FkYTEwNTVjZTI2N2Y0MmFjNSA9ICQoYDxkaXYgaWQ9Imh0bWxfMDU3NDk4ODNlY2NiNDNhZGExMDU1Y2UyNjdmNDJhYzUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhhcmJvdXJmcm9udCBFYXN0LCBUb3JvbnRvIElzbGFuZHMsIFVuaW9uIFN0YXRpb24gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2ExMzU5MTRlZjM2ZjRlZTBhMDkyNmNjYTdlNjc1ZTAxLnNldENvbnRlbnQoaHRtbF8wNTc0OTg4M2VjY2I0M2FkYTEwNTVjZTI2N2Y0MmFjNSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDkxYjFiNTQ1YmJkNDNjYTg1YmQ5YmM2Y2JmM2M4NmIuYmluZFBvcHVwKHBvcHVwX2ExMzU5MTRlZjM2ZjRlZTBhMDkyNmNjYTdlNjc1ZTAxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82YmZhODNlNmQzNmY0YzA4YWM0MTY3NzhkNTA0YTFmOSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NzE3NjgsIC03OS4zODE1NzY0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYWZiZjViMmQ0NzdjNDU1ZmE3NTQ0ZDYwM2NmNmNmYjMgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2M4ZjhmMTk5YThhZDQ4NDJhODYzODZhMjVlNGJhYWUzID0gJChgPGRpdiBpZD0iaHRtbF9jOGY4ZjE5OWE4YWQ0ODQyYTg2Mzg2YTI1ZTRiYWFlMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RGVzaWduIEV4Y2hhbmdlLCBUb3JvbnRvIERvbWluaW9uIENlbnRyZSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYWZiZjViMmQ0NzdjNDU1ZmE3NTQ0ZDYwM2NmNmNmYjMuc2V0Q29udGVudChodG1sX2M4ZjhmMTk5YThhZDQ4NDJhODYzODZhMjVlNGJhYWUzKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82YmZhODNlNmQzNmY0YzA4YWM0MTY3NzhkNTA0YTFmOS5iaW5kUG9wdXAocG9wdXBfYWZiZjViMmQ0NzdjNDU1ZmE3NTQ0ZDYwM2NmNmNmYjMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzI5ZDdiYTg0ZDI5MTRjMzE5M2VjZDZkYTBlNWU3Y2FmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ4MTk4NSwgLTc5LjM3OTgxNjkwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8yOTdhNjEyNGZmZTc0NDEzYjc2ZGJjMzMxNzlkMmU5ZiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZjdlZGJmMWIwNmI2NDliM2E1ODhjMjFmYmY2OWM4YTUgPSAkKGA8ZGl2IGlkPSJodG1sX2Y3ZWRiZjFiMDZiNjQ5YjNhNTg4YzIxZmJmNjljOGE1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Db21tZXJjZSBDb3VydCwgVmljdG9yaWEgSG90ZWwgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzI5N2E2MTI0ZmZlNzQ0MTNiNzZkYmMzMzE3OWQyZTlmLnNldENvbnRlbnQoaHRtbF9mN2VkYmYxYjA2YjY0OWIzYTU4OGMyMWZiZjY5YzhhNSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMjlkN2JhODRkMjkxNGMzMTkzZWNkNmRhMGU1ZTdjYWYuYmluZFBvcHVwKHBvcHVwXzI5N2E2MTI0ZmZlNzQ0MTNiNzZkYmMzMzE3OWQyZTlmKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zMzAzY2M5M2NkMTU0MmI0YmJmNjJkOGU0MjYxZTI5ZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjczMzI4MjUsIC03OS40MTk3NDk3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8zYTQxMTMxNGRmMjQ0M2Y0YWRiODVlMmY5YmMxMThlZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfY2EyNWZjNzg4ZmEwNDBmYzkxMWU1NjQyYTUxMzZiNDkgPSAkKGA8ZGl2IGlkPSJodG1sX2NhMjVmYzc4OGZhMDQwZmM5MTFlNTY0MmE1MTM2YjQ5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CZWRmb3JkIFBhcmssIExhd3JlbmNlIE1hbm9yIEVhc3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzNhNDExMzE0ZGYyNDQzZjRhZGI4NWUyZjliYzExOGVkLnNldENvbnRlbnQoaHRtbF9jYTI1ZmM3ODhmYTA0MGZjOTExZTU2NDJhNTEzNmI0OSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMzMwM2NjOTNjZDE1NDJiNGJiZjYyZDhlNDI2MWUyOWYuYmluZFBvcHVwKHBvcHVwXzNhNDExMzE0ZGYyNDQzZjRhZGI4NWUyZjliYzExOGVkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xMmU3NGFjNDAxMDg0NjhlYTE2NTU3MDEzMThkOWE3YyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxMTY5NDgsIC03OS40MTY5MzU1OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjk2OTMwOTBhMmU2NDI3NGIyM2IzZjUyYWRjNzBlZTEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2E4ZDM5NmI1MGNmYjQ0MDU4ZGEwY2EzNjMyZjE0ZTg0ID0gJChgPGRpdiBpZD0iaHRtbF9hOGQzOTZiNTBjZmI0NDA1OGRhMGNhMzYzMmYxNGU4NCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Um9zZWxhd24gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzY5NjkzMDkwYTJlNjQyNzRiMjNiM2Y1MmFkYzcwZWUxLnNldENvbnRlbnQoaHRtbF9hOGQzOTZiNTBjZmI0NDA1OGRhMGNhMzYzMmYxNGU4NCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMTJlNzRhYzQwMTA4NDY4ZWExNjU1NzAxMzE4ZDlhN2MuYmluZFBvcHVwKHBvcHVwXzY5NjkzMDkwYTJlNjQyNzRiMjNiM2Y1MmFkYzcwZWUxKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83YzI0ZjdlZDMyZmQ0MTQzYjY1ODYwNWNiMDg0MzkxYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY5Njk0NzYsIC03OS40MTEzMDcyMDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzVhMDBmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjNWEwMGZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNzRmMTVmMTZhNGYwNDRkY2FhMzE5OGIxYTAxMmM5YzAgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzAxYWQ4NWU1M2I2MTRjZjliZGRhNjU2ZjA4Y2M4MWEwID0gJChgPGRpdiBpZD0iaHRtbF8wMWFkODVlNTNiNjE0Y2Y5YmRkYTY1NmYwOGNjODFhMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Rm9yZXN0IEhpbGwgTm9ydGgsIEZvcmVzdCBIaWxsIFdlc3QgQ2x1c3RlciA2PC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzc0ZjE1ZjE2YTRmMDQ0ZGNhYTMxOThiMWEwMTJjOWMwLnNldENvbnRlbnQoaHRtbF8wMWFkODVlNTNiNjE0Y2Y5YmRkYTY1NmYwOGNjODFhMCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfN2MyNGY3ZWQzMmZkNDE0M2I2NTg2MDVjYjA4NDM5MWIuYmluZFBvcHVwKHBvcHVwXzc0ZjE1ZjE2YTRmMDQ0ZGNhYTMxOThiMWEwMTJjOWMwKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83ZjM4NjEzYzE5NDY0MGY4OTY3ZjY1MWY0NDI5NTQxOCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3MjcwOTcsIC03OS40MDU2Nzg0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNjZlOTM3MmU5MTMxNDY2NWFmZDUyNzI5YmZiYjg3OGEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzE2Y2U3MzkyM2IzMzRjZDNiNzJhZjQ1YTQ2MjIwMzFmID0gJChgPGRpdiBpZD0iaHRtbF8xNmNlNzM5MjNiMzM0Y2QzYjcyYWY0NWE0NjIyMDMxZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEFubmV4LCBOb3J0aCBNaWR0b3duLCBZb3JrdmlsbGUgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzY2ZTkzNzJlOTEzMTQ2NjVhZmQ1MjcyOWJmYmI4NzhhLnNldENvbnRlbnQoaHRtbF8xNmNlNzM5MjNiMzM0Y2QzYjcyYWY0NWE0NjIyMDMxZik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfN2YzODYxM2MxOTQ2NDBmODk2N2Y2NTFmNDQyOTU0MTguYmluZFBvcHVwKHBvcHVwXzY2ZTkzNzJlOTEzMTQ2NjVhZmQ1MjcyOWJmYmI4NzhhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84ZWNhM2RjMThhMDc0YTRmOGZkNjgwMjY2YjA0MmQwYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2MjY5NTYsIC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85ZDI2Y2VjZmNlNTM0ZmZmYmQ1MDE5YjU5YzQ5ZGFkOSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZGNhOWEyOTVlZjg3NDZmMDg3OTAyYTdkZDc1MDVkOWMgPSAkKGA8ZGl2IGlkPSJodG1sX2RjYTlhMjk1ZWY4NzQ2ZjA4NzkwMmE3ZGQ3NTA1ZDljIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IYXJib3JkLCBVbml2ZXJzaXR5IG9mIFRvcm9udG8gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzlkMjZjZWNmY2U1MzRmZmZiZDUwMTliNTljNDlkYWQ5LnNldENvbnRlbnQoaHRtbF9kY2E5YTI5NWVmODc0NmYwODc5MDJhN2RkNzUwNWQ5Yyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfOGVjYTNkYzE4YTA3NGE0ZjhmZDY4MDI2NmIwNDJkMGMuYmluZFBvcHVwKHBvcHVwXzlkMjZjZWNmY2U1MzRmZmZiZDUwMTliNTljNDlkYWQ5KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82MjgyZjBmNWU1MmQ0ZTBmYTNiOTlhYzg2ODMwN2I5YSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MzIwNTcsIC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9lYzM2YTQ3N2I5ZDU0YzQwYTFjMzk3YzNhNTZlZDdkYyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMWUzZjEzOTkwYTE1NDBkN2JiYjc4OTUwNmE4YTMyMTEgPSAkKGA8ZGl2IGlkPSJodG1sXzFlM2YxMzk5MGExNTQwZDdiYmI3ODk1MDZhOGEzMjExIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DaGluYXRvd24sIEdyYW5nZSBQYXJrLCBLZW5zaW5ndG9uIE1hcmtldCBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZWMzNmE0NzdiOWQ1NGM0MGExYzM5N2MzYTU2ZWQ3ZGMuc2V0Q29udGVudChodG1sXzFlM2YxMzk5MGExNTQwZDdiYmI3ODk1MDZhOGEzMjExKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82MjgyZjBmNWU1MmQ0ZTBmYTNiOTlhYzg2ODMwN2I5YS5iaW5kUG9wdXAocG9wdXBfZWMzNmE0NzdiOWQ1NGM0MGExYzM5N2MzYTU2ZWQ3ZGMpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzdlZTE2YzI1ZWM4NjQ1NGQ5ZWM0ZDBlYWYxMjAxMDA5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjI4OTQ2NywgLTc5LjM5NDQxOTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2EwYTM2Mzk0ZGNiNjRlNGM4YmVkNjk1ZWJhMDEwNmUzID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8yMWVhMWY5OGNhNGI0MmI2OGIzZmQzN2JiYzQzODg0ZSA9ICQoYDxkaXYgaWQ9Imh0bWxfMjFlYTFmOThjYTRiNDJiNjhiM2ZkMzdiYmM0Mzg4NGUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNOIFRvd2VyLCBCYXRodXJzdCBRdWF5LCBJc2xhbmQgYWlycG9ydCwgSGFyYm91cmZyb250IFdlc3QsIEtpbmcgYW5kIFNwYWRpbmEsIFJhaWx3YXkgTGFuZHMsIFNvdXRoIE5pYWdhcmEgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2EwYTM2Mzk0ZGNiNjRlNGM4YmVkNjk1ZWJhMDEwNmUzLnNldENvbnRlbnQoaHRtbF8yMWVhMWY5OGNhNGI0MmI2OGIzZmQzN2JiYzQzODg0ZSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfN2VlMTZjMjVlYzg2NDU0ZDllYzRkMGVhZjEyMDEwMDkuYmluZFBvcHVwKHBvcHVwX2EwYTM2Mzk0ZGNiNjRlNGM4YmVkNjk1ZWJhMDEwNmUzKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iZWM0MmI4YjdmNDA0N2QzYmUwODVmOGM3YWMyZTkzZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NjQzNTIsIC03OS4zNzQ4NDU5OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYmI0Nzc3Y2E1MTFlNDg1YjkyZDJlNTAyNzJlOTViMWEgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2YwMWE2ZDU5YjliODRlZWY4Nzg2Y2Y4NWIxYWMwZjc4ID0gJChgPGRpdiBpZD0iaHRtbF9mMDFhNmQ1OWI5Yjg0ZWVmODc4NmNmODViMWFjMGY3OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U3RuIEEgUE8gQm94ZXMgMjUgVGhlIEVzcGxhbmFkZSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYmI0Nzc3Y2E1MTFlNDg1YjkyZDJlNTAyNzJlOTViMWEuc2V0Q29udGVudChodG1sX2YwMWE2ZDU5YjliODRlZWY4Nzg2Y2Y4NWIxYWMwZjc4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9iZWM0MmI4YjdmNDA0N2QzYmUwODVmOGM3YWMyZTkzZC5iaW5kUG9wdXAocG9wdXBfYmI0Nzc3Y2E1MTFlNDg1YjkyZDJlNTAyNzJlOTViMWEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U4Njc5NjAwOGQxMDRlNGE5MDY5Y2NiMGZhODE3ZTQzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ4NDI5MiwgLTc5LjM4MjI4MDJdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzVmODEwYzYwNGRlOTQzODY4NjhkOGE1NTYxMWI4N2JhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8yM2IzMzdiNmE5MmU0NGY1ODA0MmZlYzdjNTdlMmFmMCA9ICQoYDxkaXYgaWQ9Imh0bWxfMjNiMzM3YjZhOTJlNDRmNTgwNDJmZWM3YzU3ZTJhZjAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkZpcnN0IENhbmFkaWFuIFBsYWNlLCBVbmRlcmdyb3VuZCBjaXR5IENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF81ZjgxMGM2MDRkZTk0Mzg2ODY4ZDhhNTU2MTFiODdiYS5zZXRDb250ZW50KGh0bWxfMjNiMzM3YjZhOTJlNDRmNTgwNDJmZWM3YzU3ZTJhZjApOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2U4Njc5NjAwOGQxMDRlNGE5MDY5Y2NiMGZhODE3ZTQzLmJpbmRQb3B1cChwb3B1cF81ZjgxMGM2MDRkZTk0Mzg2ODY4ZDhhNTU2MTFiODdiYSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDQxODE5M2U5NDNiNDliNjg1YzRjYWQ5ZDYyNmEwNTggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTg1MTc5OTk5OTk5OTYsIC03OS40NjQ3NjMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYmNlNjVlNzAyOGMyNGUzMWJhMjk0ZWJmNmY2MzQyY2UgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2RiNjgzYWVlODQzOTQ0NDk5MWZkM2Y4YjU1M2E5YTJiID0gJChgPGRpdiBpZD0iaHRtbF9kYjY4M2FlZTg0Mzk0NDQ5OTFmZDNmOGI1NTNhOWEyYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TGF3cmVuY2UgSGVpZ2h0cywgTGF3cmVuY2UgTWFub3IgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2JjZTY1ZTcwMjhjMjRlMzFiYTI5NGViZjZmNjM0MmNlLnNldENvbnRlbnQoaHRtbF9kYjY4M2FlZTg0Mzk0NDQ5OTFmZDNmOGI1NTNhOWEyYik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNDQxODE5M2U5NDNiNDliNjg1YzRjYWQ5ZDYyNmEwNTguYmluZFBvcHVwKHBvcHVwX2JjZTY1ZTcwMjhjMjRlMzFiYTI5NGViZjZmNjM0MmNlKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yMzgxODA2Yzg2MDM0NmY2YWJkYWFjZWE0ODAwZmFiMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcwOTU3NywgLTc5LjQ0NTA3MjU5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9kNGMzMTllY2M5Mzc0NDMyYTljYzFjYTY4ZmUzNjVlZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNWVjYzE2YTM3ZWY0NDU2NzkxMzVmMmVkOTZmNjRmYTAgPSAkKGA8ZGl2IGlkPSJodG1sXzVlY2MxNmEzN2VmNDQ1Njc5MTM1ZjJlZDk2ZjY0ZmEwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5HbGVuY2Fpcm4gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2Q0YzMxOWVjYzkzNzQ0MzJhOWNjMWNhNjhmZTM2NWVkLnNldENvbnRlbnQoaHRtbF81ZWNjMTZhMzdlZjQ0NTY3OTEzNWYyZWQ5NmY2NGZhMCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMjM4MTgwNmM4NjAzNDZmNmFiZGFhY2VhNDgwMGZhYjIuYmluZFBvcHVwKHBvcHVwX2Q0YzMxOWVjYzkzNzQ0MzJhOWNjMWNhNjhmZTM2NWVkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82M2FkNDNmYjllZWY0ZmNhOTc2MWZkZjRkZDJlZjZhNyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY5Mzc4MTMsIC03OS40MjgxOTE0MDAwMDAwMl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTQ2OGZmYWFiYzE0NGZmZmIwYzM2NTM2OWEyNjU5ZjIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzhlZDYwNzllOTc3NDQyZmU5MjA0M2ZkZDhiMzdkMTYyID0gJChgPGRpdiBpZD0iaHRtbF84ZWQ2MDc5ZTk3NzQ0MmZlOTIwNDNmZGQ4YjM3ZDE2MiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SHVtZXdvb2QtQ2VkYXJ2YWxlIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF85NDY4ZmZhYWJjMTQ0ZmZmYjBjMzY1MzY5YTI2NTlmMi5zZXRDb250ZW50KGh0bWxfOGVkNjA3OWU5Nzc0NDJmZTkyMDQzZmRkOGIzN2QxNjIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzYzYWQ0M2ZiOWVlZjRmY2E5NzYxZmRmNGRkMmVmNmE3LmJpbmRQb3B1cChwb3B1cF85NDY4ZmZhYWJjMTQ0ZmZmYjBjMzY1MzY5YTI2NTlmMikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNjlhMWM2YTRiOGEzNDMxOThhMGI3NjUwMjUwZTNkYjEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODkwMjU2LCAtNzkuNDUzNTEyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWEwMGZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1YTAwZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83ZTE1MDk2NWEwMzA0Yzc1OGVlMTQ3YWY0YWUzNDYyNiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfOTQ5MTQ1ZGUzOTFhNDI2OGE2ODliZTIxZjA3MDAxMTMgPSAkKGA8ZGl2IGlkPSJodG1sXzk0OTE0NWRlMzkxYTQyNjhhNjg5YmUyMWYwNzAwMTEzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DYWxlZG9uaWEtRmFpcmJhbmtzIENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF83ZTE1MDk2NWEwMzA0Yzc1OGVlMTQ3YWY0YWUzNDYyNi5zZXRDb250ZW50KGh0bWxfOTQ5MTQ1ZGUzOTFhNDI2OGE2ODliZTIxZjA3MDAxMTMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzY5YTFjNmE0YjhhMzQzMTk4YTBiNzY1MDI1MGUzZGIxLmJpbmRQb3B1cChwb3B1cF83ZTE1MDk2NWEwMzA0Yzc1OGVlMTQ3YWY0YWUzNDYyNikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNjg1NWZlNWEyY2JlNDE2YzlmMTQwMDJjMjc5OTU4ODAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Njk1NDIsIC03OS40MjI1NjM3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9jNjUzMjJlOThhMWU0ZmQwOTg0ZjBhZmI5NDk2ODVjNSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNzg4MTllMDY0NmZkNDQ5YmJkNDJmN2U5OTQ3MjIyMzAgPSAkKGA8ZGl2IGlkPSJodG1sXzc4ODE5ZTA2NDZmZDQ0OWJiZDQyZjdlOTk0NzIyMjMwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DaHJpc3RpZSBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYzY1MzIyZTk4YTFlNGZkMDk4NGYwYWZiOTQ5Njg1YzUuc2V0Q29udGVudChodG1sXzc4ODE5ZTA2NDZmZDQ0OWJiZDQyZjdlOTk0NzIyMjMwKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl82ODU1ZmU1YTJjYmU0MTZjOWYxNDAwMmMyNzk5NTg4MC5iaW5kUG9wdXAocG9wdXBfYzY1MzIyZTk4YTFlNGZkMDk4NGYwYWZiOTQ5Njg1YzUpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzdlNWEyMDVmMDY1ZDRlMjk5NTZmZTViYjMyMjVhZjBkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjY5MDA1MTAwMDAwMDEsIC03OS40NDIyNTkzXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF84YzMzMmJlM2ExM2Q0NWVmYmYwZDk4MjQ0ODU4ODY5NyA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjBlNTAzYmIyMTkzNDNkYzhiMTYwZTcwZmY0ZWM0MGIgPSAkKGA8ZGl2IGlkPSJodG1sXzYwZTUwM2JiMjE5MzQzZGM4YjE2MGU3MGZmNGVjNDBiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3ZlcmNvdXJ0IFZpbGxhZ2UsIER1ZmZlcmluIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84YzMzMmJlM2ExM2Q0NWVmYmYwZDk4MjQ0ODU4ODY5Ny5zZXRDb250ZW50KGh0bWxfNjBlNTAzYmIyMTkzNDNkYzhiMTYwZTcwZmY0ZWM0MGIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzdlNWEyMDVmMDY1ZDRlMjk5NTZmZTViYjMyMjVhZjBkLmJpbmRQb3B1cChwb3B1cF84YzMzMmJlM2ExM2Q0NWVmYmYwZDk4MjQ0ODU4ODY5NykKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWRlODhmNWIzM2JiNGFiMTljYmM3ZjBlNmFkNzUyNTcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDc5MjY3MDAwMDAwMDYsIC03OS40MTk3NDk3XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9iZDk0NzQxN2E4MDA0YjE2YjgzYWE1ZDNiNGY1ZTE4MiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNDRlYTZiOWIwNDdiNGQyZmIyNTU4ZjNhNDIxMmNlMzEgPSAkKGA8ZGl2IGlkPSJodG1sXzQ0ZWE2YjliMDQ3YjRkMmZiMjU1OGYzYTQyMTJjZTMxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5MaXR0bGUgUG9ydHVnYWwsIFRyaW5pdHkgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2JkOTQ3NDE3YTgwMDRiMTZiODNhYTVkM2I0ZjVlMTgyLnNldENvbnRlbnQoaHRtbF80NGVhNmI5YjA0N2I0ZDJmYjI1NThmM2E0MjEyY2UzMSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZWRlODhmNWIzM2JiNGFiMTljYmM3ZjBlNmFkNzUyNTcuYmluZFBvcHVwKHBvcHVwX2JkOTQ3NDE3YTgwMDRiMTZiODNhYTVkM2I0ZjVlMTgyKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kY2FhOTFhZDNmZmI0NTQ0YTYxMjc0YmNiOTIzYWE4YiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYzNjg0NzIsIC03OS40MjgxOTE0MDAwMDAwMl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMzMxZTNlODI5NmY0NDc2ZGIxNzZjMmMzYjZkYmY5YjcgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2QwYzQ2ZDNlNTRjZTQ3ZmQ5YjgxZjFhYjI3NTllM2M0ID0gJChgPGRpdiBpZD0iaHRtbF9kMGM0NmQzZTU0Y2U0N2ZkOWI4MWYxYWIyNzU5ZTNjNCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QnJvY2t0b24sIEV4aGliaXRpb24gUGxhY2UsIFBhcmtkYWxlIFZpbGxhZ2UgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzMzMWUzZTgyOTZmNDQ3NmRiMTc2YzJjM2I2ZGJmOWI3LnNldENvbnRlbnQoaHRtbF9kMGM0NmQzZTU0Y2U0N2ZkOWI4MWYxYWIyNzU5ZTNjNCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZGNhYTkxYWQzZmZiNDU0NGE2MTI3NGJjYjkyM2FhOGIuYmluZFBvcHVwKHBvcHVwXzMzMWUzZTgyOTZmNDQ3NmRiMTc2YzJjM2I2ZGJmOWI3KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85ODAxZDRmODBjYzg0NzNiOWY3M2Y2Njg3MGQwZTUwZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxMzc1NjIwMDAwMDAwNiwgLTc5LjQ5MDA3MzhdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiM1YTAwZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzVhMDBmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzBlZWY4NDAyOGFlNzQ2NGU4OTI0NDY1YjA4ZTg2NWE4ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9iOTQ4ZGMxYmYyMTY0NTMzYWI1NzdhMWQ2ODE3MDgyYyA9ICQoYDxkaXYgaWQ9Imh0bWxfYjk0OGRjMWJmMjE2NDUzM2FiNTc3YTFkNjgxNzA4MmMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd25zdmlldywgTm9ydGggUGFyaywgVXB3b29kIFBhcmsgQ2x1c3RlciA2PC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzBlZWY4NDAyOGFlNzQ2NGU4OTI0NDY1YjA4ZTg2NWE4LnNldENvbnRlbnQoaHRtbF9iOTQ4ZGMxYmYyMTY0NTMzYWI1NzdhMWQ2ODE3MDgyYyk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfOTgwMWQ0ZjgwY2M4NDczYjlmNzNmNjY4NzBkMGU1MGYuYmluZFBvcHVwKHBvcHVwXzBlZWY4NDAyOGFlNzQ2NGU4OTI0NDY1YjA4ZTg2NWE4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wZWQ3NTU3ODNkZmU0MGRlODZiMzY2ZWEwOTNhZjk1NiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY5MTExNTgsIC03OS40NzYwMTMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzAwOGZmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMDA4ZmZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZmE1NzE5OTE2MzE4NDdiOGFiYjU2MDg1OWYyNTgyOWQgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzFhZTNlZjk1OWJmZTRhZmVhNDc0NWQ5Y2M0ODBmNTM4ID0gJChgPGRpdiBpZD0iaHRtbF8xYWUzZWY5NTliZmU0YWZlYTQ3NDVkOWNjNDgwZjUzOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RGVsIFJheSwgS2VlbGVzZGFsZSwgTW91bnQgRGVubmlzLCBTaWx2ZXJ0aG9ybiBDbHVzdGVyIDU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfZmE1NzE5OTE2MzE4NDdiOGFiYjU2MDg1OWYyNTgyOWQuc2V0Q29udGVudChodG1sXzFhZTNlZjk1OWJmZTRhZmVhNDc0NWQ5Y2M0ODBmNTM4KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8wZWQ3NTU3ODNkZmU0MGRlODZiMzY2ZWEwOTNhZjk1Ni5iaW5kUG9wdXAocG9wdXBfZmE1NzE5OTE2MzE4NDdiOGFiYjU2MDg1OWYyNTgyOWQpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzU2N2E3YmQ2ZWQxOTRlZGE5MGU3YzA1MmI1YTY1NWRiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjczMTg1Mjk5OTk5OTksIC03OS40ODcyNjE5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzAwOGZmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMDA4ZmZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNDZkMTM3ZDU5ZDBiNGVkYWJlYTQ3YzA5MjY4NDU2NGQgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzNmMzU3YmVlYThlMjRjYTE4MzJkZWZjNjQzODgwYWJiID0gJChgPGRpdiBpZD0iaHRtbF8zZjM1N2JlZWE4ZTI0Y2ExODMyZGVmYzY0Mzg4MGFiYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIEp1bmN0aW9uIE5vcnRoLCBSdW5ueW1lZGUgQ2x1c3RlciA1PC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzQ2ZDEzN2Q1OWQwYjRlZGFiZWE0N2MwOTI2ODQ1NjRkLnNldENvbnRlbnQoaHRtbF8zZjM1N2JlZWE4ZTI0Y2ExODMyZGVmYzY0Mzg4MGFiYik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNTY3YTdiZDZlZDE5NGVkYTkwZTdjMDUyYjVhNjU1ZGIuYmluZFBvcHVwKHBvcHVwXzQ2ZDEzN2Q1OWQwYjRlZGFiZWE0N2MwOTI2ODQ1NjRkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xNjcyNWIwYzY1NTE0MzBjYTIwODEwNWFmMzZlNmQ5MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2MTYwODMsIC03OS40NjQ3NjMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfY2E4MzBmYTlmODlkNGQ4ODkzNWJhNDJlYWNiOGM2NDkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2RlNjcxYmY1MjZhNDRhNzZiYmU0MWFlMWJmZTMzNGE5ID0gJChgPGRpdiBpZD0iaHRtbF9kZTY3MWJmNTI2YTQ0YTc2YmJlNDFhZTFiZmUzMzRhOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SGlnaCBQYXJrLCBUaGUgSnVuY3Rpb24gU291dGggQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2NhODMwZmE5Zjg5ZDRkODg5MzViYTQyZWFjYjhjNjQ5LnNldENvbnRlbnQoaHRtbF9kZTY3MWJmNTI2YTQ0YTc2YmJlNDFhZTFiZmUzMzRhOSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMTY3MjViMGM2NTUxNDMwY2EyMDgxMDVhZjM2ZTZkOTEuYmluZFBvcHVwKHBvcHVwX2NhODMwZmE5Zjg5ZDRkODg5MzViYTQyZWFjYjhjNjQ5KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lY2Q2NTA4NjY0NWU0Yzc4YTBhNjAwYTI3NWExMjU4NiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0ODk1OTcsIC03OS40NTYzMjVdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzMzYzMzMmZhODlkNjQwM2I4Y2ZjY2E1YTA2ZjViZDdmID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8wMGYxYWVkMjBkODM0NmM0ODU3OGFlOWJkNmY4ZTY4YiA9ICQoYDxkaXYgaWQ9Imh0bWxfMDBmMWFlZDIwZDgzNDZjNDg1NzhhZTliZDZmOGU2OGIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlBhcmtkYWxlLCBSb25jZXN2YWxsZXMgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzMzYzMzMmZhODlkNjQwM2I4Y2ZjY2E1YTA2ZjViZDdmLnNldENvbnRlbnQoaHRtbF8wMGYxYWVkMjBkODM0NmM0ODU3OGFlOWJkNmY4ZTY4Yik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZWNkNjUwODY2NDVlNGM3OGEwYTYwMGEyNzVhMTI1ODYuYmluZFBvcHVwKHBvcHVwXzMzYzMzMmZhODlkNjQwM2I4Y2ZjY2E1YTA2ZjViZDdmKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81ZjY1ZDVhMjJjZDQ0NGI3ODhhYTc0NGQ0NDM0Yjk5OSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MTU3MDYsIC03OS40ODQ0NDk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF85ZTI4NTI3ZWVmMzI0YmQxYTM1YTVjZTExZGI2OGQxMSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjA5YzllN2E3MWI1NDAzYzk3Yzg5NjhkMDAxYmUyMjYgPSAkKGA8ZGl2IGlkPSJodG1sXzYwOWM5ZTdhNzFiNTQwM2M5N2M4OTY4ZDAwMWJlMjI2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5SdW5ueW1lZGUsIFN3YW5zZWEgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzllMjg1MjdlZWYzMjRiZDFhMzVhNWNlMTFkYjY4ZDExLnNldENvbnRlbnQoaHRtbF82MDljOWU3YTcxYjU0MDNjOTdjODk2OGQwMDFiZTIyNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNWY2NWQ1YTIyY2Q0NDRiNzg4YWE3NDRkNDQzNGI5OTkuYmluZFBvcHVwKHBvcHVwXzllMjg1MjdlZWYzMjRiZDFhMzVhNWNlMTFkYjY4ZDExKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84YmM4YWFhOTY2NjE0ZWI0YTIyYWNkNjk2MDdjOWU2MiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2MjMwMTUsIC03OS4zODk0OTM4XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF80Njg3MWZjMDY4MDc0YTU5ODEwZjBkNTZlZWZjNWFjNCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMWUyMGYyODI0NDY2NDc0YWFhOTEwMGMxMDdmNTAyMmMgPSAkKGA8ZGl2IGlkPSJodG1sXzFlMjBmMjgyNDQ2NjQ3NGFhYTkxMDBjMTA3ZjUwMjJjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5RdWVlbiYjMzk7cyBQYXJrIENsdXN0ZXIgMDwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF80Njg3MWZjMDY4MDc0YTU5ODEwZjBkNTZlZWZjNWFjNC5zZXRDb250ZW50KGh0bWxfMWUyMGYyODI0NDY2NDc0YWFhOTEwMGMxMDdmNTAyMmMpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzhiYzhhYWE5NjY2MTRlYjRhMjJhY2Q2OTYwN2M5ZTYyLmJpbmRQb3B1cChwb3B1cF80Njg3MWZjMDY4MDc0YTU5ODEwZjBkNTZlZWZjNWFjNCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZTdkNDQyNWE5ZmYzNDZjZThmNzg0NzkwZDA4YTJlM2EgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42MzY5NjU2LCAtNzkuNjE1ODE4OTk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzkyZmNmZjA3ZTc1MTRmZTFhNjIwNDE4YmRmNGY5ZGJiID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9hZTMxNzM3MmU5NzM0MTZjODcxODRiNzFlOGM5NWIwMSA9ICQoYDxkaXYgaWQ9Imh0bWxfYWUzMTczNzJlOTczNDE2Yzg3MTg0YjcxZThjOTViMDEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNhbmFkYSBQb3N0IEdhdGV3YXkgUHJvY2Vzc2luZyBDZW50cmUgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzkyZmNmZjA3ZTc1MTRmZTFhNjIwNDE4YmRmNGY5ZGJiLnNldENvbnRlbnQoaHRtbF9hZTMxNzM3MmU5NzM0MTZjODcxODRiNzFlOGM5NWIwMSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZTdkNDQyNWE5ZmYzNDZjZThmNzg0NzkwZDA4YTJlM2EuYmluZFBvcHVwKHBvcHVwXzkyZmNmZjA3ZTc1MTRmZTFhNjIwNDE4YmRmNGY5ZGJiKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83MjgwNmU1YWMxMDk0ZTExOWI4MDk3NWI2MjE4Zjk5MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2Mjc0MzksIC03OS4zMjE1NThdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzViMTU4MWVkMGQ5YTQ0YmJiY2RlZTBiZTQ2MzJjYjc4ID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8zMDEyNzVkMWU1MGU0MzUwODQyMDIwMDBkMzQ5Y2EyYSA9ICQoYDxkaXYgaWQ9Imh0bWxfMzAxMjc1ZDFlNTBlNDM1MDg0MjAyMDAwZDM0OWNhMmEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJ1c2luZXNzIFJlcGx5IE1haWwgUHJvY2Vzc2luZyBDZW50cmUgOTY5IEVhc3Rlcm4gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzViMTU4MWVkMGQ5YTQ0YmJiY2RlZTBiZTQ2MzJjYjc4LnNldENvbnRlbnQoaHRtbF8zMDEyNzVkMWU1MGU0MzUwODQyMDIwMDBkMzQ5Y2EyYSk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfNzI4MDZlNWFjMTA5NGUxMTliODA5NzViNjIxOGY5OTEuYmluZFBvcHVwKHBvcHVwXzViMTU4MWVkMGQ5YTQ0YmJiY2RlZTBiZTQ2MzJjYjc4KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mZDVjNWFjOTNjYTE0NTJjOTM2NzM2OWZkZmM3Y2RlNyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYwNTY0NjYsIC03OS41MDEzMjA3MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfNTFhNWM0ZTBhZGU4NDQwOTkxYmRhYmNkNGVhMzBjNDYgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzkxNTA2OTY5OTZlNzRlMzlhMGM0MDQ1MWMyYzkxNmU0ID0gJChgPGRpdiBpZD0iaHRtbF85MTUwNjk2OTk2ZTc0ZTM5YTBjNDA0NTFjMmM5MTZlNCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SHVtYmVyIEJheSBTaG9yZXMsIE1pbWljbyBTb3V0aCwgTmV3IFRvcm9udG8gQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzUxYTVjNGUwYWRlODQ0MDk5MWJkYWJjZDRlYTMwYzQ2LnNldENvbnRlbnQoaHRtbF85MTUwNjk2OTk2ZTc0ZTM5YTBjNDA0NTFjMmM5MTZlNCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZmQ1YzVhYzkzY2ExNDUyYzkzNjczNjlmZGZjN2NkZTcuYmluZFBvcHVwKHBvcHVwXzUxYTVjNGUwYWRlODQ0MDk5MWJkYWJjZDRlYTMwYzQ2KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jNWE5NmI2NDcxZjA0MTQwODJkYTAyZWYzYzIwZGUxNCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYwMjQxMzcwMDAwMDAxLCAtNzkuNTQzNDg0MDk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiMwMDhmZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzAwOGZmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2YyZjNhYjVhZDg3MjRiOWU4OWJjNTU1MDk0YzVmY2JkID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF80MzU0ZWZlMzg5ZGQ0YjZmYWQ2YmU3NjU3MTBiYjhhMiA9ICQoYDxkaXYgaWQ9Imh0bWxfNDM1NGVmZTM4OWRkNGI2ZmFkNmJlNzY1NzEwYmI4YTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkFsZGVyd29vZCwgTG9uZyBCcmFuY2ggQ2x1c3RlciA1PC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2YyZjNhYjVhZDg3MjRiOWU4OWJjNTU1MDk0YzVmY2JkLnNldENvbnRlbnQoaHRtbF80MzU0ZWZlMzg5ZGQ0YjZmYWQ2YmU3NjU3MTBiYjhhMik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYzVhOTZiNjQ3MWYwNDE0MDgyZGEwMmVmM2MyMGRlMTQuYmluZFBvcHVwKHBvcHVwX2YyZjNhYjVhZDg3MjRiOWU4OWJjNTU1MDk0YzVmY2JkKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iMjhkYmZlMzA1NWI0YTc4YjhiNWQ1ODY3YWM3YjZlYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MzY1MzYwMDAwMDAwNSwgLTc5LjUwNjk0MzZdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiM1YTAwZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzVhMDBmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzI0MjQ5ZTlkYzdmNjQ2ODRhZTk0ZjgxYWYyN2U2ZDZhID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF8zNjM2ODA2Nzc0NjE0M2FkOTNmMjZlYTcxOThlMWI1YiA9ICQoYDxkaXYgaWQ9Imh0bWxfMzYzNjgwNjc3NDYxNDNhZDkzZjI2ZWE3MTk4ZTFiNWIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRoZSBLaW5nc3dheSwgTW9udGdvbWVyeSBSb2FkLCBPbGQgTWlsbCBOb3J0aCBDbHVzdGVyIDY8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfMjQyNDllOWRjN2Y2NDY4NGFlOTRmODFhZjI3ZTZkNmEuc2V0Q29udGVudChodG1sXzM2MzY4MDY3NzQ2MTQzYWQ5M2YyNmVhNzE5OGUxYjViKTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl9iMjhkYmZlMzA1NWI0YTc4YjhiNWQ1ODY3YWM3YjZlYy5iaW5kUG9wdXAocG9wdXBfMjQyNDllOWRjN2Y2NDY4NGFlOTRmODFhZjI3ZTZkNmEpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2JmY2VjYTFiNzFkMjQzYTA5MjVhNWQ2NDg2MDNhMjcyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjM2MjU3OSwgLTc5LjQ5ODUwOTA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8wNzk5NzhkZjc2YzU0YTI3OWJlYTc1MzRkYzhiZDYwNiA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZmZlZDQzMWEyM2IwNDA5NGIzYzFmNTJjM2M0NTE3N2QgPSAkKGA8ZGl2IGlkPSJodG1sX2ZmZWQ0MzFhMjNiMDQwOTRiM2MxZjUyYzNjNDUxNzdkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IdW1iZXIgQmF5LCBLaW5nJiMzOTtzIE1pbGwgUGFyaywgS2luZ3N3YXkgUGFyayBTb3V0aCBFYXN0LCBNaW1pY28gTkUsIE9sZCBNaWxsIFNvdXRoLCBUaGUgUXVlZW5zd2F5IEVhc3QsIFJveWFsIFlvcmsgU291dGggRWFzdCwgU3VubnlsZWEgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzA3OTk3OGRmNzZjNTRhMjc5YmVhNzUzNGRjOGJkNjA2LnNldENvbnRlbnQoaHRtbF9mZmVkNDMxYTIzYjA0MDk0YjNjMWY1MmMzYzQ1MTc3ZCk7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfYmZjZWNhMWI3MWQyNDNhMDkyNWE1ZDY0ODYwM2EyNzIuYmluZFBvcHVwKHBvcHVwXzA3OTk3OGRmNzZjNTRhMjc5YmVhNzUzNGRjOGJkNjA2KQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xMTI2Y2Y5Y2NkOTc0MjFmYTA1N2RlNTM5ZjVlZTJjYSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYyODg0MDgsIC03OS41MjA5OTk0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiI2ZmMDBiZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjZmYwMGJmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfOTI0ODJiMmE4M2Q3NGQxMWI2ZGRmOWRkOTY0MDg1NTkgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2ZiMzk1OWY2NTY3MTRmNWE5ZTVhMDM2OGE0Yjg1MTI3ID0gJChgPGRpdiBpZD0iaHRtbF9mYjM5NTlmNjU2NzE0ZjVhOWU1YTAzNjhhNGI4NTEyNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+S2luZ3N3YXkgUGFyayBTb3V0aCBXZXN0LCBNaW1pY28gTlcsIFRoZSBRdWVlbnN3YXkgV2VzdCwgUm95YWwgWW9yayBTb3V0aCBXZXN0LCBTb3V0aCBvZiBCbG9vciBDbHVzdGVyIDA8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfOTI0ODJiMmE4M2Q3NGQxMWI2ZGRmOWRkOTY0MDg1NTkuc2V0Q29udGVudChodG1sX2ZiMzk1OWY2NTY3MTRmNWE5ZTVhMDM2OGE0Yjg1MTI3KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8xMTI2Y2Y5Y2NkOTc0MjFmYTA1N2RlNTM5ZjVlZTJjYS5iaW5kUG9wdXAocG9wdXBfOTI0ODJiMmE4M2Q3NGQxMWI2ZGRmOWRkOTY0MDg1NTkpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzU2ZDFlM2FiMzE1YzQ1YjdhYjhmN2I1MDI1YjgxODkxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUwOTQzMiwgLTc5LjU1NDcyNDQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjNWNmZjAwIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiM1Y2ZmMDAiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF8xZjNkMzljYzk4ZDc0YTk2YmVhYzgwMzczYjNmODcxOSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfZjhmZTk4NWNlNjJjNGRjMGIxZDNiYjZmNjIwZWVhMjIgPSAkKGA8ZGl2IGlkPSJodG1sX2Y4ZmU5ODVjZTYyYzRkYzBiMWQzYmI2ZjYyMGVlYTIyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DbG92ZXJkYWxlLCBJc2xpbmd0b24sIE1hcnRpbiBHcm92ZSwgUHJpbmNlc3MgR2FyZGVucywgV2VzdCBEZWFuZSBQYXJrIENsdXN0ZXIgMzwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xZjNkMzljYzk4ZDc0YTk2YmVhYzgwMzczYjNmODcxOS5zZXRDb250ZW50KGh0bWxfZjhmZTk4NWNlNjJjNGRjMGIxZDNiYjZmNjIwZWVhMjIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzU2ZDFlM2FiMzE1YzQ1YjdhYjhmN2I1MDI1YjgxODkxLmJpbmRQb3B1cChwb3B1cF8xZjNkMzljYzk4ZDc0YTk2YmVhYzgwMzczYjNmODcxOSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZjJjMmZlNTUwYzYzNDAzOWFlMzA1OWI1MzljMzc5ODIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDM1MTUyLCAtNzkuNTc3MjAwNzk5OTk5OTldLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiNmZjAwYmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiI2ZmMDBiZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwX2Q1NDQ5N2VjMWUzNTQ2YjQ4OTVlMjFlMTAwMDlhMDIyID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF9mMGI3ZmQ4ZjEwNjY0NmZiOWU4OThiYmI0YzI5NjhiNiA9ICQoYDxkaXYgaWQ9Imh0bWxfZjBiN2ZkOGYxMDY2NDZmYjllODk4YmJiNGMyOTY4YjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkJsb29yZGFsZSBHYXJkZW5zLCBFcmluZ2F0ZSwgTWFya2xhbmQgV29vZCwgT2xkIEJ1cm5oYW10aG9ycGUgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwX2Q1NDQ5N2VjMWUzNTQ2YjQ4OTVlMjFlMTAwMDlhMDIyLnNldENvbnRlbnQoaHRtbF9mMGI3ZmQ4ZjEwNjY0NmZiOWU4OThiYmI0YzI5NjhiNik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfZjJjMmZlNTUwYzYzNDAzOWFlMzA1OWI1MzljMzc5ODIuYmluZFBvcHVwKHBvcHVwX2Q1NDQ5N2VjMWUzNTQ2YjQ4OTVlMjFlMTAwMDlhMDIyKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yODU3ZGJmODhkOWY0ZTJmYWE1OTE2MzJjOGFlOWZmNSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjc1NjMwMzMsIC03OS41NjU5NjMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzAwOGZmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMDA4ZmZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfYTFkN2ZmYTMzNmVhNDk0MmJiNTRiODQ1NGJhNDEwMTcgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sXzcwN2RmYjdlZWRhZTQwZmZiNTEwZWU4MmUzOTBkYjU2ID0gJChgPGRpdiBpZD0iaHRtbF83MDdkZmI3ZWVkYWU0MGZmYjUxMGVlODJlMzkwZGI1NiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SHVtYmVyIFN1bW1pdCBDbHVzdGVyIDU8L2Rpdj5gKVswXTsKICAgICAgICAgICAgcG9wdXBfYTFkN2ZmYTMzNmVhNDk0MmJiNTRiODQ1NGJhNDEwMTcuc2V0Q29udGVudChodG1sXzcwN2RmYjdlZWRhZTQwZmZiNTEwZWU4MmUzOTBkYjU2KTsKICAgICAgICAKCiAgICAgICAgY2lyY2xlX21hcmtlcl8yODU3ZGJmODhkOWY0ZTJmYWE1OTE2MzJjOGFlOWZmNS5iaW5kUG9wdXAocG9wdXBfYTFkN2ZmYTMzNmVhNDk0MmJiNTRiODQ1NGJhNDEwMTcpCiAgICAgICAgOwoKICAgICAgICAKICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzM1N2NjYzNiMzhiMDRhMDE5MWNmNmQ4ZDAzOGE2YTY3ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzI0NzY1OSwgLTc5LjUzMjI0MjQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmZiYTAwIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZmJhMDAiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF9mMDQyMmM0YjEzNmU0OTk4ODUyYzhhOWI1MjQ1N2IxZCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNjY3ZDhlMTNlMjliNDc0NWJjYWM3NDRlYjNmMjM4YTQgPSAkKGA8ZGl2IGlkPSJodG1sXzY2N2Q4ZTEzZTI5YjQ3NDViY2FjNzQ0ZWIzZjIzOGE0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FbWVyeSwgSHVtYmVybGVhIENsdXN0ZXIgMjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9mMDQyMmM0YjEzNmU0OTk4ODUyYzhhOWI1MjQ1N2IxZC5zZXRDb250ZW50KGh0bWxfNjY3ZDhlMTNlMjliNDc0NWJjYWM3NDRlYjNmMjM4YTQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzM1N2NjYzNiMzhiMDRhMDE5MWNmNmQ4ZDAzOGE2YTY3LmJpbmRQb3B1cChwb3B1cF9mMDQyMmM0YjEzNmU0OTk4ODUyYzhhOWI1MjQ1N2IxZCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDJkZmQ4OTMxNTBmNGUxMTk1NDY3Y2Y0NDBmMzNjNjQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDY4NzYsIC03OS41MTgxODg0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzVhMDBmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjNWEwMGZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfMThlMTJkZDM2ZWJlNDIzNzllYjMxMGJiNTBiOWRkNTIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2E2MTMzYzg1Y2E5YTQ1MzNiMGJkNzBmNGNlZTViZDI1ID0gJChgPGRpdiBpZD0iaHRtbF9hNjEzM2M4NWNhOWE0NTMzYjBiZDcwZjRjZWU1YmQyNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdG9uIENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8xOGUxMmRkMzZlYmU0MjM3OWViMzEwYmI1MGI5ZGQ1Mi5zZXRDb250ZW50KGh0bWxfYTYxMzNjODVjYTlhNDUzM2IwYmQ3MGY0Y2VlNWJkMjUpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzQyZGZkODkzMTUwZjRlMTE5NTQ2N2NmNDQwZjMzYzY0LmJpbmRQb3B1cChwb3B1cF8xOGUxMmRkMzZlYmU0MjM3OWViMzEwYmI1MGI5ZGQ1MikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzVmNzJmZDc5ZTkxNDQ2OTg1YjU2OGU0ZjIzM2MwNDkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42OTYzMTksIC03OS41MzIyNDI0MDAwMDAwMl0sCiAgICAgICAgICAgICAgICB7ImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLCAiY29sb3IiOiAiIzAwOGZmZiIsICJkYXNoQXJyYXkiOiBudWxsLCAiZGFzaE9mZnNldCI6IG51bGwsICJmaWxsIjogdHJ1ZSwgImZpbGxDb2xvciI6ICIjMDA4ZmZmIiwgImZpbGxPcGFjaXR5IjogMC41LCAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsICJsaW5lQ2FwIjogInJvdW5kIiwgImxpbmVKb2luIjogInJvdW5kIiwgIm9wYWNpdHkiOiAxLjAsICJyYWRpdXMiOiAxMSwgInN0cm9rZSI6IHRydWUsICJ3ZWlnaHQiOiAzfQogICAgICAgICAgICApLmFkZFRvKG1hcF80YTExZWNkY2Y1ZGM0YjFjYjYyN2RiOTJlMWU2NTYzZik7CiAgICAgICAgCiAgICAKICAgICAgICB2YXIgcG9wdXBfZWUyMmNlYmJkNGQyNGQwYWI5MmRmZTYyNzgyNGY2YWIgPSBMLnBvcHVwKHsibWF4V2lkdGgiOiAiMTAwJSJ9KTsKCiAgICAgICAgCiAgICAgICAgICAgIHZhciBodG1sX2RhMTZjNDkyYTRiYzQwYTJiNDAzOGI0ZjE1NjUwNGJiID0gJChgPGRpdiBpZD0iaHRtbF9kYTE2YzQ5MmE0YmM0MGEyYjQwMzhiNGYxNTY1MDRiYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdG1vdW50IENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF9lZTIyY2ViYmQ0ZDI0ZDBhYjkyZGZlNjI3ODI0ZjZhYi5zZXRDb250ZW50KGh0bWxfZGExNmM0OTJhNGJjNDBhMmI0MDM4YjRmMTU2NTA0YmIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2M1ZjcyZmQ3OWU5MTQ0Njk4NWI1NjhlNGYyMzNjMDQ5LmJpbmRQb3B1cChwb3B1cF9lZTIyY2ViYmQ0ZDI0ZDBhYjkyZGZlNjI3ODI0ZjZhYikKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMzdkNmQ4NTQyOThhNDNiZGI0NjkxOTFjZDVhNzAxZTUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODg5MDU0LCAtNzkuNTU0NzI0NDAwMDAwMDFdLAogICAgICAgICAgICAgICAgeyJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwgImNvbG9yIjogIiM1YTAwZmYiLCAiZGFzaEFycmF5IjogbnVsbCwgImRhc2hPZmZzZXQiOiBudWxsLCAiZmlsbCI6IHRydWUsICJmaWxsQ29sb3IiOiAiIzVhMDBmZiIsICJmaWxsT3BhY2l0eSI6IDAuNSwgImZpbGxSdWxlIjogImV2ZW5vZGQiLCAibGluZUNhcCI6ICJyb3VuZCIsICJsaW5lSm9pbiI6ICJyb3VuZCIsICJvcGFjaXR5IjogMS4wLCAicmFkaXVzIjogMTEsICJzdHJva2UiOiB0cnVlLCAid2VpZ2h0IjogM30KICAgICAgICAgICAgKS5hZGRUbyhtYXBfNGExMWVjZGNmNWRjNGIxY2I2MjdkYjkyZTFlNjU2M2YpOwogICAgICAgIAogICAgCiAgICAgICAgdmFyIHBvcHVwXzI3ZWVkYzg2NWI3NzQ2NTRhODUxNGQ0ODFkYzEwNGQxID0gTC5wb3B1cCh7Im1heFdpZHRoIjogIjEwMCUifSk7CgogICAgICAgIAogICAgICAgICAgICB2YXIgaHRtbF84MTAwYzE5NTA0NDY0ZmM5YjE1YWMyNzdiNWNlZjAxZCA9ICQoYDxkaXYgaWQ9Imh0bWxfODEwMGMxOTUwNDQ2NGZjOWIxNWFjMjc3YjVjZWYwMWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPktpbmdzdmlldyBWaWxsYWdlLCBNYXJ0aW4gR3JvdmUgR2FyZGVucywgUmljaHZpZXcgR2FyZGVucywgU3QuIFBoaWxsaXBzIENsdXN0ZXIgNjwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF8yN2VlZGM4NjViNzc0NjU0YTg1MTRkNDgxZGMxMDRkMS5zZXRDb250ZW50KGh0bWxfODEwMGMxOTUwNDQ2NGZjOWIxNWFjMjc3YjVjZWYwMWQpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyXzM3ZDZkODU0Mjk4YTQzYmRiNDY5MTkxY2Q1YTcwMWU1LmJpbmRQb3B1cChwb3B1cF8yN2VlZGM4NjViNzc0NjU0YTg1MTRkNDgxZGMxMDRkMSkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzA3NDg4NDI4ZjE3NGFkZGJjODQ3ZTRlNTA0NzExOGMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43Mzk0MTYzOTk5OTk5OTYsIC03OS41ODg0MzY5XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjMDA4ZmZmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiMwMDhmZmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF84MGZlMDhmOWZlN2Y0ZGRmOGJiODFmYjNlZTg4ZjI5MCA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfNGMzYjczZWIxYzU0NDMzNDlmMTIzYjQ1ZDljMjVjMTIgPSAkKGA8ZGl2IGlkPSJodG1sXzRjM2I3M2ViMWM1NDQzMzQ5ZjEyM2I0NWQ5YzI1YzEyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5BbGJpb24gR2FyZGVucywgQmVhdW1vbmQgSGVpZ2h0cywgSHVtYmVyZ2F0ZSwgSmFtZXN0b3duLCBNb3VudCBPbGl2ZSwgU2lsdmVyc3RvbmUsIFNvdXRoIFN0ZWVsZXMsIFRoaXN0bGV0b3duIENsdXN0ZXIgNTwvZGl2PmApWzBdOwogICAgICAgICAgICBwb3B1cF84MGZlMDhmOWZlN2Y0ZGRmOGJiODFmYjNlZTg4ZjI5MC5zZXRDb250ZW50KGh0bWxfNGMzYjczZWIxYzU0NDMzNDlmMTIzYjQ1ZDljMjVjMTIpOwogICAgICAgIAoKICAgICAgICBjaXJjbGVfbWFya2VyX2MwNzQ4ODQyOGYxNzRhZGRiYzg0N2U0ZTUwNDcxMThjLmJpbmRQb3B1cChwb3B1cF84MGZlMDhmOWZlN2Y0ZGRmOGJiODFmYjNlZTg4ZjI5MCkKICAgICAgICA7CgogICAgICAgIAogICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTJhY2ViNGQwZmNmNDRlMGJjMzIxNjlhYjEwNWM5MzUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDY3NDgyOTk5OTk5OTQsIC03OS41OTQwNTQ0XSwKICAgICAgICAgICAgICAgIHsiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsICJjb2xvciI6ICIjZmYwMGJmIiwgImRhc2hBcnJheSI6IG51bGwsICJkYXNoT2Zmc2V0IjogbnVsbCwgImZpbGwiOiB0cnVlLCAiZmlsbENvbG9yIjogIiNmZjAwYmYiLCAiZmlsbE9wYWNpdHkiOiAwLjUsICJmaWxsUnVsZSI6ICJldmVub2RkIiwgImxpbmVDYXAiOiAicm91bmQiLCAibGluZUpvaW4iOiAicm91bmQiLCAib3BhY2l0eSI6IDEuMCwgInJhZGl1cyI6IDExLCAic3Ryb2tlIjogdHJ1ZSwgIndlaWdodCI6IDN9CiAgICAgICAgICAgICkuYWRkVG8obWFwXzRhMTFlY2RjZjVkYzRiMWNiNjI3ZGI5MmUxZTY1NjNmKTsKICAgICAgICAKICAgIAogICAgICAgIHZhciBwb3B1cF83OWQzOWM2YTM0Y2U0NjhhYWU1M2FhNzNiZGJkZDVkYSA9IEwucG9wdXAoeyJtYXhXaWR0aCI6ICIxMDAlIn0pOwoKICAgICAgICAKICAgICAgICAgICAgdmFyIGh0bWxfMjg2NWZiMDhkNTU1NDA3OTgxZDBhYWQ5YmUxZTI4NGIgPSAkKGA8ZGl2IGlkPSJodG1sXzI4NjVmYjA4ZDU1NTQwNzk4MWQwYWFkOWJlMWUyODRiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ob3J0aHdlc3QgQ2x1c3RlciAwPC9kaXY+YClbMF07CiAgICAgICAgICAgIHBvcHVwXzc5ZDM5YzZhMzRjZTQ2OGFhZTUzYWE3M2JkYmRkNWRhLnNldENvbnRlbnQoaHRtbF8yODY1ZmIwOGQ1NTU0MDc5ODFkMGFhZDliZTFlMjg0Yik7CiAgICAgICAgCgogICAgICAgIGNpcmNsZV9tYXJrZXJfMTJhY2ViNGQwZmNmNDRlMGJjMzIxNjlhYjEwNWM5MzUuYmluZFBvcHVwKHBvcHVwXzc5ZDM5YzZhMzRjZTQ2OGFhZTUzYWE3M2JkYmRkNWRhKQogICAgICAgIDsKCiAgICAgICAgCiAgICAKPC9zY3JpcHQ+\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
],
"text/plain": [
"<folium.folium.Map at 0x7f89b40225f8>"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# create map\n",
"map_clusters = folium.Map(location=[latitude, longitude], zoom_start=11)\n",
"\n",
"# set color scheme for the clusters\n",
"x = np.arange(kclusters)\n",
"ys = [i + x + (i*x)**2 for i in range(kclusters)]\n",
"#colors_array = cm.rainbow(np.linspace(0, 1, len(ys)))\n",
"colors_array = cm.gist_rainbow(np.linspace(0, 1, len(ys)))\n",
"rainbow = [colors.rgb2hex(i) for i in colors_array]\n",
"\n",
"# add markers to the map\n",
"markers_colors = []\n",
"for lat, lon, poi, cluster in zip(toronto_labeled['Latitude'], toronto_labeled['Longitude'], toronto_labeled['Neighbourhood'], toronto_labeled['Cluster Labels']):\n",
" label = folium.Popup(str(poi) + ' Cluster ' + str(cluster), parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lon],\n",
" radius=11,\n",
" popup=label,\n",
" color=rainbow[cluster-1],\n",
" fill=True,\n",
" fill_color=rainbow[cluster-1],\n",
" fill_opacity=0.5).add_to(map_clusters)\n",
" \n",
"map_clusters"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analysis of the clusters\n",
"\n",
"Now, we are ready to examine each cluster and determine the discriminating venue categories that distinguish each cluster. Based on the defining categories, we can assign a name to each cluster."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 1: Coffee to go"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>North York</td>\n",
" <td>0</td>\n",
" <td>Clothing Store</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Shoe Store</td>\n",
" <td>Cosmetics Shop</td>\n",
" <td>Japanese Restaurant</td>\n",
" <td>Bakery</td>\n",
" <td>Chinese Restaurant</td>\n",
" <td>Pharmacy</td>\n",
" <td>Sporting Goods Shop</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Scarborough</td>\n",
" <td>0</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Rental Car Location</td>\n",
" <td>Intersection</td>\n",
" <td>Pizza Place</td>\n",
" <td>Electronics Store</td>\n",
" <td>Medical Center</td>\n",
" <td>Mexican Restaurant</td>\n",
" <td>Drugstore</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>77</th>\n",
" <td>West Toronto</td>\n",
" <td>0</td>\n",
" <td>Café</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Italian Restaurant</td>\n",
" <td>Bar</td>\n",
" <td>Intersection</td>\n",
" <td>Bakery</td>\n",
" <td>Stadium</td>\n",
" <td>Restaurant</td>\n",
" <td>Climbing Gym</td>\n",
" </tr>\n",
" <tr>\n",
" <th>57</th>\n",
" <td>Downtown Toronto</td>\n",
" <td>0</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Café</td>\n",
" <td>Thai Restaurant</td>\n",
" <td>Bar</td>\n",
" <td>Steakhouse</td>\n",
" <td>Gym</td>\n",
" <td>Restaurant</td>\n",
" <td>American Restaurant</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Hotel</td>\n",
" </tr>\n",
" <tr>\n",
" <th>32</th>\n",
" <td>North York</td>\n",
" <td>0</td>\n",
" <td>Gym / Fitness Center</td>\n",
" <td>Grocery Store</td>\n",
" <td>Liquor Store</td>\n",
" <td>Athletics &amp; Sports</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue \\\n",
"17 North York 0 Clothing Store \n",
"2 Scarborough 0 Breakfast Spot \n",
"77 West Toronto 0 Café \n",
"57 Downtown Toronto 0 Coffee Shop \n",
"32 North York 0 Gym / Fitness Center \n",
"\n",
" 2nd Most Common Venue 3rd Most Common Venue 4th Most Common Venue \\\n",
"17 Fast Food Restaurant Coffee Shop Shoe Store \n",
"2 Rental Car Location Intersection Pizza Place \n",
"77 Breakfast Spot Coffee Shop Italian Restaurant \n",
"57 Café Thai Restaurant Bar \n",
"32 Grocery Store Liquor Store Athletics & Sports \n",
"\n",
" 5th Most Common Venue 6th Most Common Venue 7th Most Common Venue \\\n",
"17 Cosmetics Shop Japanese Restaurant Bakery \n",
"2 Electronics Store Medical Center Mexican Restaurant \n",
"77 Bar Intersection Bakery \n",
"57 Steakhouse Gym Restaurant \n",
"32 Yoga Studio Eastern European Restaurant Dog Run \n",
"\n",
" 8th Most Common Venue 9th Most Common Venue 10th Most Common Venue \n",
"17 Chinese Restaurant Pharmacy Sporting Goods Shop \n",
"2 Drugstore Dog Run Doner Restaurant \n",
"77 Stadium Restaurant Climbing Gym \n",
"57 American Restaurant Breakfast Spot Hotel \n",
"32 Doner Restaurant Donut Shop Drugstore "
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 0, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]].sample(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 2: Mixed bag"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>North York</td>\n",
" <td>1</td>\n",
" <td>Park</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Electronics Store</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"20 North York 1 Park Yoga Studio \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"20 Eastern European Restaurant Dive Bar Dog Run \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"20 Doner Restaurant Donut Shop Drugstore \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"20 Dumpling Restaurant Electronics Store "
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 1, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 3: Sports"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>95</th>\n",
" <td>North York</td>\n",
" <td>2</td>\n",
" <td>Baseball Field</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"95 North York 2 Baseball Field Yoga Studio \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"95 Electronics Store Doner Restaurant Donut Shop \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"95 Drugstore Dumpling Restaurant Eastern European Restaurant \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"95 Empanada Restaurant Dive Bar "
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 2, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 4: Banking"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>North York</td>\n",
" <td>3</td>\n",
" <td>Café</td>\n",
" <td>Chinese Restaurant</td>\n",
" <td>Japanese Restaurant</td>\n",
" <td>Bank</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Dog Run</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>92</th>\n",
" <td>Etobicoke</td>\n",
" <td>3</td>\n",
" <td>Bank</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"18 North York 3 Café Chinese Restaurant \n",
"92 Etobicoke 3 Bank Yoga Studio \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"18 Japanese Restaurant Bank Yoga Studio \n",
"92 Electronics Store Doner Restaurant Donut Shop \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"18 Dog Run Donut Shop Drugstore \n",
"92 Drugstore Dumpling Restaurant Eastern European Restaurant \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"18 Dumpling Restaurant Eastern European Restaurant \n",
"92 Empanada Restaurant Dive Bar "
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 3, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 5: Oddball"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>North York</td>\n",
" <td>4</td>\n",
" <td>Cafeteria</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"19 North York 4 Cafeteria Yoga Studio \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"19 Electronics Store Doner Restaurant Donut Shop \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"19 Drugstore Dumpling Restaurant Eastern European Restaurant \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"19 Empanada Restaurant Dive Bar "
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 4, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 6: Food & Shopping"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>34</th>\n",
" <td>East York</td>\n",
" <td>5</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Pizza Place</td>\n",
" <td>Gastropub</td>\n",
" <td>Bank</td>\n",
" <td>Intersection</td>\n",
" <td>Athletics &amp; Sports</td>\n",
" <td>Gym / Fitness Center</td>\n",
" <td>Pharmacy</td>\n",
" <td>Pet Store</td>\n",
" <td>Cosmetics Shop</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>Scarborough</td>\n",
" <td>5</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Chinese Restaurant</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Nail Salon</td>\n",
" <td>Grocery Store</td>\n",
" <td>Pharmacy</td>\n",
" <td>Pizza Place</td>\n",
" <td>Breakfast Spot</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Thrift / Vintage Store</td>\n",
" </tr>\n",
" <tr>\n",
" <th>88</th>\n",
" <td>Etobicoke</td>\n",
" <td>5</td>\n",
" <td>Pizza Place</td>\n",
" <td>Gym</td>\n",
" <td>Pool</td>\n",
" <td>Skating Rink</td>\n",
" <td>Pharmacy</td>\n",
" <td>Pub</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Diner</td>\n",
" <td>Discount Store</td>\n",
" </tr>\n",
" <tr>\n",
" <th>97</th>\n",
" <td>Etobicoke</td>\n",
" <td>5</td>\n",
" <td>Pizza Place</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Discount Store</td>\n",
" <td>Chinese Restaurant</td>\n",
" <td>Middle Eastern Restaurant</td>\n",
" <td>Sandwich Place</td>\n",
" <td>Intersection</td>\n",
" <td>Electronics Store</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dumpling Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Scarborough</td>\n",
" <td>5</td>\n",
" <td>Fast Food Restaurant</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue 2nd Most Common Venue \\\n",
"34 East York 5 Fast Food Restaurant Pizza Place \n",
"15 Scarborough 5 Fast Food Restaurant Chinese Restaurant \n",
"88 Etobicoke 5 Pizza Place Gym \n",
"97 Etobicoke 5 Pizza Place Coffee Shop \n",
"0 Scarborough 5 Fast Food Restaurant Yoga Studio \n",
"\n",
" 3rd Most Common Venue 4th Most Common Venue 5th Most Common Venue \\\n",
"34 Gastropub Bank Intersection \n",
"15 Coffee Shop Nail Salon Grocery Store \n",
"88 Pool Skating Rink Pharmacy \n",
"97 Discount Store Chinese Restaurant Middle Eastern Restaurant \n",
"0 Electronics Store Dog Run Doner Restaurant \n",
"\n",
" 6th Most Common Venue 7th Most Common Venue 8th Most Common Venue \\\n",
"34 Athletics & Sports Gym / Fitness Center Pharmacy \n",
"15 Pharmacy Pizza Place Breakfast Spot \n",
"88 Pub Coffee Shop Sandwich Place \n",
"97 Sandwich Place Intersection Electronics Store \n",
"0 Donut Shop Drugstore Dumpling Restaurant \n",
"\n",
" 9th Most Common Venue 10th Most Common Venue \n",
"34 Pet Store Cosmetics Shop \n",
"15 Sandwich Place Thrift / Vintage Store \n",
"88 Diner Discount Store \n",
"97 Eastern European Restaurant Dumpling Restaurant \n",
"0 Eastern European Restaurant Empanada Restaurant "
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 5, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]].sample(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cluster 7: Rest & Relaxation"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Borough</th>\n",
" <th>Cluster Labels</th>\n",
" <th>1st Most Common Venue</th>\n",
" <th>2nd Most Common Venue</th>\n",
" <th>3rd Most Common Venue</th>\n",
" <th>4th Most Common Venue</th>\n",
" <th>5th Most Common Venue</th>\n",
" <th>6th Most Common Venue</th>\n",
" <th>7th Most Common Venue</th>\n",
" <th>8th Most Common Venue</th>\n",
" <th>9th Most Common Venue</th>\n",
" <th>10th Most Common Venue</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>47</th>\n",
" <td>Central Toronto</td>\n",
" <td>6</td>\n",
" <td>Park</td>\n",
" <td>Playground</td>\n",
" <td>Restaurant</td>\n",
" <td>Gym</td>\n",
" <td>Comic Shop</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Discount Store</td>\n",
" <td>Dive Bar</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>98</th>\n",
" <td>Etobicoke</td>\n",
" <td>6</td>\n",
" <td>Park</td>\n",
" <td>Bus Line</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Electronics Store</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>North York</td>\n",
" <td>6</td>\n",
" <td>Park</td>\n",
" <td>Convenience Store</td>\n",
" <td>Bank</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Electronics Store</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" <td>Eastern European Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>Scarborough</td>\n",
" <td>6</td>\n",
" <td>Park</td>\n",
" <td>Playground</td>\n",
" <td>Yoga Studio</td>\n",
" <td>Eastern European Restaurant</td>\n",
" <td>Dive Bar</td>\n",
" <td>Dog Run</td>\n",
" <td>Doner Restaurant</td>\n",
" <td>Donut Shop</td>\n",
" <td>Drugstore</td>\n",
" <td>Dumpling Restaurant</td>\n",
" </tr>\n",
" <tr>\n",
" <th>39</th>\n",
" <td>East York</td>\n",
" <td>6</td>\n",
" <td>Park</td>\n",
" <td>Pizza Place</td>\n",
" <td>Convenience Store</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Falafel Restaurant</td>\n",
" <td>Farm</td>\n",
" <td>Event Space</td>\n",
" <td>Ethiopian Restaurant</td>\n",
" <td>Empanada Restaurant</td>\n",
" <td>Diner</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Borough Cluster Labels 1st Most Common Venue \\\n",
"47 Central Toronto 6 Park \n",
"98 Etobicoke 6 Park \n",
"22 North York 6 Park \n",
"14 Scarborough 6 Park \n",
"39 East York 6 Park \n",
"\n",
" 2nd Most Common Venue 3rd Most Common Venue 4th Most Common Venue \\\n",
"47 Playground Restaurant Gym \n",
"98 Bus Line Yoga Studio Eastern European Restaurant \n",
"22 Convenience Store Bank Yoga Studio \n",
"14 Playground Yoga Studio Eastern European Restaurant \n",
"39 Pizza Place Convenience Store Coffee Shop \n",
"\n",
" 5th Most Common Venue 6th Most Common Venue 7th Most Common Venue \\\n",
"47 Comic Shop Dumpling Restaurant Discount Store \n",
"98 Dog Run Doner Restaurant Donut Shop \n",
"22 Electronics Store Doner Restaurant Donut Shop \n",
"14 Dive Bar Dog Run Doner Restaurant \n",
"39 Falafel Restaurant Farm Event Space \n",
"\n",
" 8th Most Common Venue 9th Most Common Venue 10th Most Common Venue \n",
"47 Dive Bar Dog Run Doner Restaurant \n",
"98 Drugstore Dumpling Restaurant Electronics Store \n",
"22 Drugstore Dumpling Restaurant Eastern European Restaurant \n",
"14 Donut Shop Drugstore Dumpling Restaurant \n",
"39 Ethiopian Restaurant Empanada Restaurant Diner "
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toronto_labeled.loc[toronto_labeled['Cluster Labels'] == 6, toronto_labeled.columns[[1] + list(range(5, toronto_labeled.shape[1]))]].sample(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Conclusion\n",
"\n",
"As we already suspected, the map is dominated by the majority cluster 0, while the other two big clusters (5 & 6) only start appearing once you leave the center of Toronto city. As for the remaining 4 outlier clusters, they appear on the outskirts of the Toronto city area and only have one or two members in them. \n",
"\n",
"Looking at the clusters more closely, there seems to be an abundance of fast food & beverage venues found in the biggest cluster. The 2nd and 3rd biggest clusters seem to address the needs of people in search of places to have lunch and/or dinner, or places to get outdoors and/or relax respectively. The rest of the clusters seem to be in neighbourhoods that cater to more specific needs, like electronics shopping or banking, which explains the low number of member neighbourhoods in them.\n",
"\n",
"Overall, the visualization on the map accompanied by the inspection of the data reveals that there are mainly to types of areas in Toronto. The first is the downtown city life while the other appears to be more work related on the outskirts of the city. This is important information for people considering moving to or within Toronto."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python",
"language": "python",
"name": "conda-env-python-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment