First part of assignment
Second part of assignment
Third part of assignment
Let us download all the dependencies and libraries that we need for this assignment
import numpy as np
import pandas as pd # library for data analsysis
pd .set_option ('display.max_columns' , None )
pd .set_option ('display.max_rows' , None )
import json # library to handle JSON files
!conda install - c conda - forge lxml - - yes #helps in scraping the web for data
import requests # library to handle requests
from pandas .io .json import json_normalize # tranform JSON file into a pandas dataframe
# Matplotlib and associated plotting modules
import matplotlib .cm as cm
import matplotlib .colors as colors
# import k-means from clustering stage
from sklearn .cluster import KMeans
!conda install - c conda - forge folium = 0.5 .0 - - yes
import folium # map rendering library
print ('Libraries imported.' )
Solving environment: done
## Package Plan ##
environment location: /opt/conda/envs/Python36
added / updated specs:
- lxml
The following packages will be downloaded:
package | build
---------------------------|-----------------
certifi-2019.9.11 | py36_0 147 KB conda-forge
ca-certificates-2019.9.11 | hecc5488_0 144 KB conda-forge
lxml-4.4.1 | py36h7ec2d77_0 1.6 MB conda-forge
openssl-1.1.1d | h516909a_0 2.1 MB conda-forge
------------------------------------------------------------
Total: 3.9 MB
The following packages will be UPDATED:
certifi: 2019.9.11-py36_0 --> 2019.9.11-py36_0 conda-forge
lxml: 4.3.1-py36hefd8a0e_0 --> 4.4.1-py36h7ec2d77_0 conda-forge
The following packages will be DOWNGRADED:
ca-certificates: 2019.10.16-0 --> 2019.9.11-hecc5488_0 conda-forge
openssl: 1.1.1d-h7b6447c_3 --> 1.1.1d-h516909a_0 conda-forge
Downloading and Extracting Packages
certifi-2019.9.11 | 147 KB | ##################################### | 100%
ca-certificates-2019 | 144 KB | ##################################### | 100%
lxml-4.4.1 | 1.6 MB | ##################################### | 100%
openssl-1.1.1d | 2.1 MB | ##################################### | 100%
Preparing transaction: done
Verifying transaction: done
Executing transaction: done
Solving environment: done
## Package Plan ##
environment location: /opt/conda/envs/Python36
added / updated specs:
- folium=0.5.0
The following packages will be downloaded:
package | build
---------------------------|-----------------
altair-3.2.0 | py36_0 770 KB conda-forge
branca-0.3.1 | py_0 25 KB conda-forge
vincent-0.4.4 | py_1 28 KB conda-forge
folium-0.5.0 | py_0 45 KB conda-forge
------------------------------------------------------------
Total: 868 KB
The following NEW packages will be INSTALLED:
altair: 3.2.0-py36_0 conda-forge
branca: 0.3.1-py_0 conda-forge
folium: 0.5.0-py_0 conda-forge
vincent: 0.4.4-py_1 conda-forge
Downloading and Extracting Packages
altair-3.2.0 | 770 KB | ##################################### | 100%
branca-0.3.1 | 25 KB | ##################################### | 100%
vincent-0.4.4 | 28 KB | ##################################### | 100%
folium-0.5.0 | 45 KB | ##################################### | 100%
Preparing transaction: done
Verifying transaction: done
Executing transaction: done
Libraries imported.
1. First part of the assignment
Extracting data from a website
We are going to download and clean the Toronto neighborhoods in cells below
df = pd .read_html ("https://en.wikipedia.org/wiki/List_of_postal_codes_of_Canada:_M" )
df = df [0 ] # Taking the dataframe with the required data
df = df [df .Borough != 'Not assigned' ] #ignoring the rows with the non-assigned rows
df .reset_index (inplace = True )
df .drop (columns = 'index' , inplace = True )
df .Neighbourhood [df .Neighbourhood == 'Not assigned' ]= df .Borough [df .Neighbourhood == 'Not assigned' ] #Naming the non-assigned neighborhoods
#with the borough names
#Grouping neighborhoods with same postal codes and separting them with a comma
df_table = df .groupby (['Postcode' ,'Borough' ])['Neighbourhood' ].apply (', ' .join ).reset_index ()
df_table .columns = ['PostalCode' , 'Borough' , 'Neighborhood' ]
df_table .head (20 )
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
PostalCode
Borough
Neighborhood
0
M1B
Scarborough
Rouge, Malvern
1
M1C
Scarborough
Highland Creek, Rouge Hill, Port Union
2
M1E
Scarborough
Guildwood, Morningside, West Hill
3
M1G
Scarborough
Woburn
4
M1H
Scarborough
Cedarbrae
5
M1J
Scarborough
Scarborough Village
6
M1K
Scarborough
East Birchmount Park, Ionview, Kennedy Park
7
M1L
Scarborough
Clairlea, Golden Mile, Oakridge
8
M1M
Scarborough
Cliffcrest, Cliffside, Scarborough Village West
9
M1N
Scarborough
Birch Cliff, Cliffside West
10
M1P
Scarborough
Dorset Park, Scarborough Town Centre, Wexford ...
11
M1R
Scarborough
Maryvale, Wexford
12
M1S
Scarborough
Agincourt
13
M1T
Scarborough
Clarks Corners, Sullivan, Tam O'Shanter
14
M1V
Scarborough
Agincourt North, L'Amoreaux East, Milliken, St...
15
M1W
Scarborough
L'Amoreaux West
16
M1X
Scarborough
Upper Rouge
17
M2H
North York
Hillcrest Village
18
M2J
North York
Fairview, Henry Farm, Oriole
19
M2K
North York
Bayview Village
shape = df_table .shape
print ("The number of rows in the above dataframe is" ,shape [0 ])
The number of rows in the above dataframe is 103
2. Second part of the assignment
Finding out the coordinates of the neighborhoods
We will download the coordinates values based on the Postal Codes and merge them with the above table in the cells below
coord = pd .read_csv ("https://cocl.us/Geospatial_data" ) #Extracting the data from the given website
coord .set_index ('Postal Code' , inplace = True )
coord .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Latitude
Longitude
Postal Code
M1B
43.806686
-79.194353
M1C
43.784535
-79.160497
M1E
43.763573
-79.188711
M1G
43.770992
-79.216917
M1H
43.773136
-79.239476
#Merging the coordinates data with the borough and neighborhood data
temp = coord .loc [df_table .PostalCode ]
temp .reset_index (inplace = True )
temp .head ()
df_table [['Latitude' ,'Longitude' ]]= temp [['Latitude' ,'Longitude' ]]
df_table .head (20 )
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
PostalCode
Borough
Neighborhood
Latitude
Longitude
0
M1B
Scarborough
Rouge, Malvern
43.806686
-79.194353
1
M1C
Scarborough
Highland Creek, Rouge Hill, Port Union
43.784535
-79.160497
2
M1E
Scarborough
Guildwood, Morningside, West Hill
43.763573
-79.188711
3
M1G
Scarborough
Woburn
43.770992
-79.216917
4
M1H
Scarborough
Cedarbrae
43.773136
-79.239476
5
M1J
Scarborough
Scarborough Village
43.744734
-79.239476
6
M1K
Scarborough
East Birchmount Park, Ionview, Kennedy Park
43.727929
-79.262029
7
M1L
Scarborough
Clairlea, Golden Mile, Oakridge
43.711112
-79.284577
8
M1M
Scarborough
Cliffcrest, Cliffside, Scarborough Village West
43.716316
-79.239476
9
M1N
Scarborough
Birch Cliff, Cliffside West
43.692657
-79.264848
10
M1P
Scarborough
Dorset Park, Scarborough Town Centre, Wexford ...
43.757410
-79.273304
11
M1R
Scarborough
Maryvale, Wexford
43.750072
-79.295849
12
M1S
Scarborough
Agincourt
43.794200
-79.262029
13
M1T
Scarborough
Clarks Corners, Sullivan, Tam O'Shanter
43.781638
-79.304302
14
M1V
Scarborough
Agincourt North, L'Amoreaux East, Milliken, St...
43.815252
-79.284577
15
M1W
Scarborough
L'Amoreaux West
43.799525
-79.318389
16
M1X
Scarborough
Upper Rouge
43.836125
-79.205636
17
M2H
North York
Hillcrest Village
43.803762
-79.363452
18
M2J
North York
Fairview, Henry Farm, Oriole
43.778517
-79.346556
19
M2K
North York
Bayview Village
43.786947
-79.385975
3. Third part of the assignment
We will be exploring and clustering the neighborhoods whose boroughs' have the word "Toronto" in them
#Separating the above dataframe such that the borough's have the word "Toronto" in them
df_toronto = df_table [df_table ['Borough' ].str .find ('Toronto' )> 0 ]
df_toronto .reset_index (inplace = True )
df_toronto = df_toronto .drop ('index' , axis = 1 )
df_toronto .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
PostalCode
Borough
Neighborhood
Latitude
Longitude
0
M4E
East Toronto
The Beaches
43.676357
-79.293031
1
M4K
East Toronto
The Danforth West, Riverdale
43.679557
-79.352188
2
M4L
East Toronto
The Beaches West, India Bazaar
43.668999
-79.315572
3
M4M
East Toronto
Studio District
43.659526
-79.340923
4
M4N
Central Toronto
Lawrence Park
43.728020
-79.388790
We will display the above neighborhoods on a map in the cells below
#Obtaining the coordnitaes for centering the map
latitude = df_toronto ['Latitude' ].mean ()
longitude = df_toronto ['Longitude' ].mean ()
print ('The central geographical coordinate for Boroughs which contain the word toronto are {}, {}.' .format (latitude , longitude ))
The central geographical coordinate for Boroughs which contain the word toronto are 43.66726218421052, -79.38988323421053.
# create map of Toronto using latitude and longitude values
map_toronto = folium .Map (location = [latitude , longitude ], zoom_start = 12 )
# add markers to map
for lat , lng , borough , neighborhood in zip (df_toronto ['Latitude' ], df_toronto ['Longitude' ], df_toronto ['Borough' ], df_toronto ['Neighborhood' ]):
label = borough + ": " + neighborhood #'{}, {}'.format(neighborhood, borough)
label = folium .Popup (label , parse_html = True )
folium .CircleMarker (
[lat , lng ],
radius = 5 ,
popup = label ,
color = 'blue' ,
fill = True ,
fill_color = '#3186cc' ,
fill_opacity = 0.7 ,
parse_html = False ).add_to (map_toronto )
map_toronto
<iframe src="data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdnaXQuY29tL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9tYXN0ZXIvZm9saXVtL3RlbXBsYXRlcy9sZWFmbGV0LmF3ZXNvbWUucm90YXRlLmNzcyIvPgogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIAogICAgICAgICAgICA8c3R5bGU+ICNtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUgewogICAgICAgICAgICAgICAgcG9zaXRpb24gOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgIHdpZHRoIDogMTAwLjAlOwogICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1IiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IG51bGw7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgdmFyIG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSA9IEwubWFwKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2VudGVyOiBbNDMuNjY3MjYyMTg0MjEwNTIsLTc5LjM4OTg4MzIzNDIxMDUzXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHpvb206IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Qm91bmRzOiBib3VuZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXllcnM6IFtdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGRDb3B5SnVtcDogZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnM6IEwuQ1JTLkVQU0czODU3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl83MGNjNTRiYTg5YmY0MDg2OTQ0Y2U0M2NmMmZmNzM0OCA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgJ2h0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nJywKICAgICAgICAgICAgICAgIHsKICAiYXR0cmlidXRpb24iOiBudWxsLAogICJkZXRlY3RSZXRpbmEiOiBmYWxzZSwKICAibWF4Wm9vbSI6IDE4LAogICJtaW5ab29tIjogMSwKICAibm9XcmFwIjogZmFsc2UsCiAgInN1YmRvbWFpbnMiOiAiYWJjIgp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOWM3NzAxMzYwN2Y1NGNjZmI1MGVjODM5YmVhMDRjMGMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NzYzNTczOTk5OTk5OSwtNzkuMjkzMDMxMl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82NmJlNWU5YmFhMjE0YWU1OWNiZGI5YzE4MWQ2N2I0YSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kZWQ0MTMwZDBhZWU0YjRkYTZjOGVhYjE4ZDc2MzlmZiA9ICQoJzxkaXYgaWQ9Imh0bWxfZGVkNDEzMGQwYWVlNGI0ZGE2YzhlYWIxOGQ3NjM5ZmYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgVG9yb250bzogVGhlIEJlYWNoZXM8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzY2YmU1ZTliYWEyMTRhZTU5Y2JkYjljMTgxZDY3YjRhLnNldENvbnRlbnQoaHRtbF9kZWQ0MTMwZDBhZWU0YjRkYTZjOGVhYjE4ZDc2MzlmZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl85Yzc3MDEzNjA3ZjU0Y2NmYjUwZWM4MzliZWEwNGMwYy5iaW5kUG9wdXAocG9wdXBfNjZiZTVlOWJhYTIxNGFlNTljYmRiOWMxODFkNjdiNGEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWEwNjZkZGY1MDEwNGJhNWJhZDE2NDRmNDVjMmYzYzUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Nzk1NTcxLC03OS4zNTIxODhdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYWM4ZTdmZmIxYzZiNGJlOWI0NzM2MzhmNTljMDlkOWQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNTljNzM3MWU2Y2MwNDY5OWEzOGY4YzNjMjUxMTFhM2YgPSAkKCc8ZGl2IGlkPSJodG1sXzU5YzczNzFlNmNjMDQ2OTlhMzhmOGMzYzI1MTExYTNmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FYXN0IFRvcm9udG86IFRoZSBEYW5mb3J0aCBXZXN0LCBSaXZlcmRhbGU8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2FjOGU3ZmZiMWM2YjRiZTliNDczNjM4ZjU5YzA5ZDlkLnNldENvbnRlbnQoaHRtbF81OWM3MzcxZTZjYzA0Njk5YTM4ZjhjM2MyNTExMWEzZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9lYTA2NmRkZjUwMTA0YmE1YmFkMTY0NGY0NWMyZjNjNS5iaW5kUG9wdXAocG9wdXBfYWM4ZTdmZmIxYzZiNGJlOWI0NzM2MzhmNTljMDlkOWQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNTNkM2YzZjMzY2Q5NGY3N2JkYzQxNmE5NTNkOTc0NzYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Njg5OTg1LC03OS4zMTU1NzE1OTk5OTk5OF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81MjkzZTBhMjFkYjM0OWM5YTIzM2FlNzBhYjJiZmM2YSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kYjM0MzA5M2ZiNzM0NmUxOWRmNWNmYTRhMWQ4YmIyOCA9ICQoJzxkaXYgaWQ9Imh0bWxfZGIzNDMwOTNmYjczNDZlMTlkZjVjZmE0YTFkOGJiMjgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgVG9yb250bzogVGhlIEJlYWNoZXMgV2VzdCwgSW5kaWEgQmF6YWFyPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF81MjkzZTBhMjFkYjM0OWM5YTIzM2FlNzBhYjJiZmM2YS5zZXRDb250ZW50KGh0bWxfZGIzNDMwOTNmYjczNDZlMTlkZjVjZmE0YTFkOGJiMjgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNTNkM2YzZjMzY2Q5NGY3N2JkYzQxNmE5NTNkOTc0NzYuYmluZFBvcHVwKHBvcHVwXzUyOTNlMGEyMWRiMzQ5YzlhMjMzYWU3MGFiMmJmYzZhKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzg2NmFmN2VjODU3OTQyMTViN2NiZDU5OWQ2ZTUxYjIxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjU5NTI1NSwtNzkuMzQwOTIzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzNjZWY3NTQyMTFiODRiMzI5MGZiMDhjY2I5YWE0YjkyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2Y4YjY3ZGI4NjhlNDRmNWU4MWQ5NTZjN2U1MzJjYzQ4ID0gJCgnPGRpdiBpZD0iaHRtbF9mOGI2N2RiODY4ZTQ0ZjVlODFkOTU2YzdlNTMyY2M0OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RWFzdCBUb3JvbnRvOiBTdHVkaW8gRGlzdHJpY3Q8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzNjZWY3NTQyMTFiODRiMzI5MGZiMDhjY2I5YWE0YjkyLnNldENvbnRlbnQoaHRtbF9mOGI2N2RiODY4ZTQ0ZjVlODFkOTU2YzdlNTMyY2M0OCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl84NjZhZjdlYzg1Nzk0MjE1YjdjYmQ1OTlkNmU1MWIyMS5iaW5kUG9wdXAocG9wdXBfM2NlZjc1NDIxMWI4NGIzMjkwZmIwOGNjYjlhYTRiOTIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMDEzMjEzODc4Y2Y5NDVlMDk1NzMzMjQzMmM1MzIwMzQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MjgwMjA1LC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2QxNzViZTExYjI4NzRkYTM5NzkwMjhlZmRkMzNhMDZiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzA2ZGUzMGE0NDhhNjRiODA5MzBiMjY3NWU4ODU3YjM1ID0gJCgnPGRpdiBpZD0iaHRtbF8wNmRlMzBhNDQ4YTY0YjgwOTMwYjI2NzVlODg1N2IzNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBMYXdyZW5jZSBQYXJrPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kMTc1YmUxMWIyODc0ZGEzOTc5MDI4ZWZkZDMzYTA2Yi5zZXRDb250ZW50KGh0bWxfMDZkZTMwYTQ0OGE2NGI4MDkzMGIyNjc1ZTg4NTdiMzUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDEzMjEzODc4Y2Y5NDVlMDk1NzMzMjQzMmM1MzIwMzQuYmluZFBvcHVwKHBvcHVwX2QxNzViZTExYjI4NzRkYTM5NzkwMjhlZmRkMzNhMDZiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2M1N2VkMDAwNTUzNzQ2ZWJiZTM1NjVjMjNhODIyYWU5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzEyNzUxMSwtNzkuMzkwMTk3NV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82ZDg4ZmZlYTFhZWY0ZDVhOWNjY2U1ZGMzY2JkNzBmMSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83NjY1YjY2NjY4ODY0MmU0OTdlZWM2YWJmYjQyM2RmYyA9ICQoJzxkaXYgaWQ9Imh0bWxfNzY2NWI2NjY2ODg2NDJlNDk3ZWVjNmFiZmI0MjNkZmMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlbnRyYWwgVG9yb250bzogRGF2aXN2aWxsZSBOb3J0aDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmQ4OGZmZWExYWVmNGQ1YTljY2NlNWRjM2NiZDcwZjEuc2V0Q29udGVudChodG1sXzc2NjViNjY2Njg4NjQyZTQ5N2VlYzZhYmZiNDIzZGZjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2M1N2VkMDAwNTUzNzQ2ZWJiZTM1NjVjMjNhODIyYWU5LmJpbmRQb3B1cChwb3B1cF82ZDg4ZmZlYTFhZWY0ZDVhOWNjY2U1ZGMzY2JkNzBmMSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83NTcyNDRiZTY2ZGE0MTU5OWIxMjdkMjAwOTgwMmU2NCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxNTM4MzQsLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzJiNWFmMDA5MTI2NzQ4NzhhYzMwYjkyMmYyMzAyOWE2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzY3NmEwNDA5MmMxZTQ5YTk5OWE4MmE2N2UwYTE2MWJmID0gJCgnPGRpdiBpZD0iaHRtbF82NzZhMDQwOTJjMWU0OWE5OTlhODJhNjdlMGExNjFiZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBOb3J0aCBUb3JvbnRvIFdlc3Q8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzJiNWFmMDA5MTI2NzQ4NzhhYzMwYjkyMmYyMzAyOWE2LnNldENvbnRlbnQoaHRtbF82NzZhMDQwOTJjMWU0OWE5OTlhODJhNjdlMGExNjFiZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl83NTcyNDRiZTY2ZGE0MTU5OWIxMjdkMjAwOTgwMmU2NC5iaW5kUG9wdXAocG9wdXBfMmI1YWYwMDkxMjY3NDg3OGFjMzBiOTIyZjIzMDI5YTYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMmEyNzViOTQ3MzEzNGViYmI1ZjQ1ZWNhNjM4MTg3NmMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MDQzMjQ0LC03OS4zODg3OTAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2FmYzMzMDJhOWQ2MDQzMzNhMTNlZGEwZDM5MzE1NTI0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2Q1Yzk3ZDg4YzBiNjQyNThhYjM3Y2EyMzMxYmU0ZDFmID0gJCgnPGRpdiBpZD0iaHRtbF9kNWM5N2Q4OGMwYjY0MjU4YWIzN2NhMjMzMWJlNGQxZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBEYXZpc3ZpbGxlPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hZmMzMzAyYTlkNjA0MzMzYTEzZWRhMGQzOTMxNTUyNC5zZXRDb250ZW50KGh0bWxfZDVjOTdkODhjMGI2NDI1OGFiMzdjYTIzMzFiZTRkMWYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMmEyNzViOTQ3MzEzNGViYmI1ZjQ1ZWNhNjM4MTg3NmMuYmluZFBvcHVwKHBvcHVwX2FmYzMzMDJhOWQ2MDQzMzNhMTNlZGEwZDM5MzE1NTI0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2VkNjFkYzRhYzg4ZjRhNzE4MTRiNzRlOTI1ZTZkYmFlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjg5NTc0MywtNzkuMzgzMTU5OTAwMDAwMDFdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZjI0MTA5NDU5Y2I1NGIwNWIxMzg5NWUzNWUyYjBkNTggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZDY3ZTU2MTY3MmM2NDdmNWEzMTg4NDlkMDFlNzU3OGIgPSAkKCc8ZGl2IGlkPSJodG1sX2Q2N2U1NjE2NzJjNjQ3ZjVhMzE4ODQ5ZDAxZTc1NzhiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DZW50cmFsIFRvcm9udG86IE1vb3JlIFBhcmssIFN1bW1lcmhpbGwgRWFzdDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZjI0MTA5NDU5Y2I1NGIwNWIxMzg5NWUzNWUyYjBkNTguc2V0Q29udGVudChodG1sX2Q2N2U1NjE2NzJjNjQ3ZjVhMzE4ODQ5ZDAxZTc1NzhiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2VkNjFkYzRhYzg4ZjRhNzE4MTRiNzRlOTI1ZTZkYmFlLmJpbmRQb3B1cChwb3B1cF9mMjQxMDk0NTljYjU0YjA1YjEzODk1ZTM1ZTJiMGQ1OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mNjQ0YThmMmZlZjg0NmM5OWVjZjVkY2IyNWI3NWVlZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY4NjQxMjI5OTk5OTk5LC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2ZjN2ZkYTRkMzViZTRiNjU5ZjljMGNiYTY4NDA2NjVlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2QyZDk0NjcwNWM2YzQ0YWNhZWUxNDc0YzQwMDU2MWM2ID0gJCgnPGRpdiBpZD0iaHRtbF9kMmQ5NDY3MDVjNmM0NGFjYWVlMTQ3NGM0MDA1NjFjNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBEZWVyIFBhcmssIEZvcmVzdCBIaWxsIFNFLCBSYXRobmVsbHksIFNvdXRoIEhpbGwsIFN1bW1lcmhpbGwgV2VzdDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZmM3ZmRhNGQzNWJlNGI2NTlmOWMwY2JhNjg0MDY2NWUuc2V0Q29udGVudChodG1sX2QyZDk0NjcwNWM2YzQ0YWNhZWUxNDc0YzQwMDU2MWM2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2Y2NDRhOGYyZmVmODQ2Yzk5ZWNmNWRjYjI1Yjc1ZWVkLmJpbmRQb3B1cChwb3B1cF9mYzdmZGE0ZDM1YmU0YjY1OWY5YzBjYmE2ODQwNjY1ZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mMWU1MDVhZmJkNmY0YjQ0YjYxNTE5NzBhNWU4YzgxZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3OTU2MjYsLTc5LjM3NzUyOTQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Y4ZDE0OTEzMmUwNDQ2NjViZTY1ZTg2YzQ5ZjMxNGNkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzgyOGE2OGMyNDVkMTQ4YmQ4MzcxNGNiNjhlMTcyNzllID0gJCgnPGRpdiBpZD0iaHRtbF84MjhhNjhjMjQ1ZDE0OGJkODM3MTRjYjY4ZTE3Mjc5ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogUm9zZWRhbGU8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2Y4ZDE0OTEzMmUwNDQ2NjViZTY1ZTg2YzQ5ZjMxNGNkLnNldENvbnRlbnQoaHRtbF84MjhhNjhjMjQ1ZDE0OGJkODM3MTRjYjY4ZTE3Mjc5ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9mMWU1MDVhZmJkNmY0YjQ0YjYxNTE5NzBhNWU4YzgxZS5iaW5kUG9wdXAocG9wdXBfZjhkMTQ5MTMyZTA0NDY2NWJlNjVlODZjNDlmMzE0Y2QpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOGIyMWQ5MGM3ZDU1NDQwM2JhMGQ3N2ZmNDk5ZTVkYTYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Njc5NjcsLTc5LjM2NzY3NTNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZWZmN2RlMTAzMjIyNDZlYzhlOGFhMGI5N2FlZjlkODEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYjg2N2MzMWE1ZmNmNDc5MzhkMmY1NWUwZGJiZjcyOTIgPSAkKCc8ZGl2IGlkPSJodG1sX2I4NjdjMzFhNWZjZjQ3OTM4ZDJmNTVlMGRiYmY3MjkyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBDYWJiYWdldG93biwgU3QuIEphbWVzIFRvd248L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2VmZjdkZTEwMzIyMjQ2ZWM4ZThhYTBiOTdhZWY5ZDgxLnNldENvbnRlbnQoaHRtbF9iODY3YzMxYTVmY2Y0NzkzOGQyZjU1ZTBkYmJmNzI5Mik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl84YjIxZDkwYzdkNTU0NDAzYmEwZDc3ZmY0OTllNWRhNi5iaW5kUG9wdXAocG9wdXBfZWZmN2RlMTAzMjIyNDZlYzhlOGFhMGI5N2FlZjlkODEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYTBhZmM3Mjk5YjQ2NDJmOWI1NWExZTVkOTdkZDJjMDggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjU4NTk5LC03OS4zODMxNTk5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83ZjYyMjM0YzU4MzE0MmZkODYwOGE4ZWI3NTdlOGY2MCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kMDBiM2UxOWU3ZDg0ZGJhOWNkMjA0MThlNmYyMDdjYyA9ICQoJzxkaXYgaWQ9Imh0bWxfZDAwYjNlMTllN2Q4NGRiYTljZDIwNDE4ZTZmMjA3Y2MiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENodXJjaCBhbmQgV2VsbGVzbGV5PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83ZjYyMjM0YzU4MzE0MmZkODYwOGE4ZWI3NTdlOGY2MC5zZXRDb250ZW50KGh0bWxfZDAwYjNlMTllN2Q4NGRiYTljZDIwNDE4ZTZmMjA3Y2MpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYTBhZmM3Mjk5YjQ2NDJmOWI1NWExZTVkOTdkZDJjMDguYmluZFBvcHVwKHBvcHVwXzdmNjIyMzRjNTgzMTQyZmQ4NjA4YThlYjc1N2U4ZjYwKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzUxZTM3NjI3Mjk1ZDQ1MTNhNWEwOWE2Yjk5YTA0MjU4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjU0MjU5OSwtNzkuMzYwNjM1OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF85N2UzMTIzOWVlNzk0ZWYxYjBmNTJjYzg5MzA4NzkzZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81YzI5NWFkMzIyMGQ0YjRiOTQyNTA1MzNhOGZjNzc5NCA9ICQoJzxkaXYgaWQ9Imh0bWxfNWMyOTVhZDMyMjBkNGI0Yjk0MjUwNTMzYThmYzc3OTQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IEhhcmJvdXJmcm9udDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOTdlMzEyMzllZTc5NGVmMWIwZjUyY2M4OTMwODc5M2Quc2V0Q29udGVudChodG1sXzVjMjk1YWQzMjIwZDRiNGI5NDI1MDUzM2E4ZmM3Nzk0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzUxZTM3NjI3Mjk1ZDQ1MTNhNWEwOWE2Yjk5YTA0MjU4LmJpbmRQb3B1cChwb3B1cF85N2UzMTIzOWVlNzk0ZWYxYjBmNTJjYzg5MzA4NzkzZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83NTYwMGI0Njk4NWI0NTI1OGUwZDJkN2U0ZWJmYjY2MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1NzE2MTgsLTc5LjM3ODkzNzA5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzgzYzRkNjRlM2M5YTQ2ZTNiODQ4MzEzNjdlODA3YTZmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzllOTBiMGQ1OWM2MDQ0ODU5MDg1MGZmY2UxMDlhMTYwID0gJCgnPGRpdiBpZD0iaHRtbF85ZTkwYjBkNTljNjA0NDg1OTA4NTBmZmNlMTA5YTE2MCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogUnllcnNvbiwgR2FyZGVuIERpc3RyaWN0PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84M2M0ZDY0ZTNjOWE0NmUzYjg0ODMxMzY3ZTgwN2E2Zi5zZXRDb250ZW50KGh0bWxfOWU5MGIwZDU5YzYwNDQ4NTkwODUwZmZjZTEwOWExNjApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNzU2MDBiNDY5ODViNDUyNThlMGQyZDdlNGViZmI2NjEuYmluZFBvcHVwKHBvcHVwXzgzYzRkNjRlM2M5YTQ2ZTNiODQ4MzEzNjdlODA3YTZmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzgyZWE0YTMyYjcxNTQyNGI5ZWZkOGQwZjZlNWUwOTRhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUxNDkzOSwtNzkuMzc1NDE3OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xYzFmNjk3ZGJjOTk0Mjc1YmI0N2QwNzcxZjY3ZGYzMyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jM2EzNWZmZDg1MDE0Y2MwYmYwYTc0MjgwZDU2ZWUxYSA9ICQoJzxkaXYgaWQ9Imh0bWxfYzNhMzVmZmQ4NTAxNGNjMGJmMGE3NDI4MGQ1NmVlMWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IFN0LiBKYW1lcyBUb3duPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xYzFmNjk3ZGJjOTk0Mjc1YmI0N2QwNzcxZjY3ZGYzMy5zZXRDb250ZW50KGh0bWxfYzNhMzVmZmQ4NTAxNGNjMGJmMGE3NDI4MGQ1NmVlMWEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfODJlYTRhMzJiNzE1NDI0YjllZmQ4ZDBmNmU1ZTA5NGEuYmluZFBvcHVwKHBvcHVwXzFjMWY2OTdkYmM5OTQyNzViYjQ3ZDA3NzFmNjdkZjMzKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IyNjYwZmViYjg1NDQxZjg5MWRmM2VhMjBhYjhlNDhlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ0NzcwNzk5OTk5OTk2LC03OS4zNzMzMDY0XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2IxZDg3ODNhMDhjMjQxNGE4ZGJlNjMwZGM1ZTM1OTIyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2EzZWExZjZiYmJkMzRhN2NhNWM5Nzc1M2IzNzZmYjliID0gJCgnPGRpdiBpZD0iaHRtbF9hM2VhMWY2YmJiZDM0YTdjYTVjOTc3NTNiMzc2ZmI5YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogQmVyY3p5IFBhcms8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2IxZDg3ODNhMDhjMjQxNGE4ZGJlNjMwZGM1ZTM1OTIyLnNldENvbnRlbnQoaHRtbF9hM2VhMWY2YmJiZDM0YTdjYTVjOTc3NTNiMzc2ZmI5Yik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9iMjY2MGZlYmI4NTQ0MWY4OTFkZjNlYTIwYWI4ZTQ4ZS5iaW5kUG9wdXAocG9wdXBfYjFkODc4M2EwOGMyNDE0YThkYmU2MzBkYzVlMzU5MjIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmIyNjNhZTRjYTEwNGYxYzhlNmYzNjY4ZmE4YzhjZTkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTc5NTI0LC03OS4zODczODI2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2JlNjU3Y2I1ODJkMTQ5YzBiYTU4YmY4NjQxZTVjMGE2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzNkMGJmOWFjNjk1MjQ0OGI5ODFlZDcwNWI3MDU4YzJjID0gJCgnPGRpdiBpZD0iaHRtbF8zZDBiZjlhYzY5NTI0NDhiOTgxZWQ3MDViNzA1OGMyYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogQ2VudHJhbCBCYXkgU3RyZWV0PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9iZTY1N2NiNTgyZDE0OWMwYmE1OGJmODY0MWU1YzBhNi5zZXRDb250ZW50KGh0bWxfM2QwYmY5YWM2OTUyNDQ4Yjk4MWVkNzA1YjcwNThjMmMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYmIyNjNhZTRjYTEwNGYxYzhlNmYzNjY4ZmE4YzhjZTkuYmluZFBvcHVwKHBvcHVwX2JlNjU3Y2I1ODJkMTQ5YzBiYTU4YmY4NjQxZTVjMGE2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2YyOGUzY2JhMjk5YzRmMWQ5ZjhkOWY0NjM0OWJiM2M3ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUwNTcxMjAwMDAwMDEsLTc5LjM4NDU2NzVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZmIwOWE5OWZkYmMwNGJkN2EyZjk0YjU5ZDFhMTJlZTIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOGE5ZDQ1M2RlMTMyNGIxODhmM2E4YmQ3ZmYzY2ZiNzMgPSAkKCc8ZGl2IGlkPSJodG1sXzhhOWQ0NTNkZTEzMjRiMTg4ZjNhOGJkN2ZmM2NmYjczIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBBZGVsYWlkZSwgS2luZywgUmljaG1vbmQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2ZiMDlhOTlmZGJjMDRiZDdhMmY5NGI1OWQxYTEyZWUyLnNldENvbnRlbnQoaHRtbF84YTlkNDUzZGUxMzI0YjE4OGYzYThiZDdmZjNjZmI3Myk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9mMjhlM2NiYTI5OWM0ZjFkOWY4ZDlmNDYzNDliYjNjNy5iaW5kUG9wdXAocG9wdXBfZmIwOWE5OWZkYmMwNGJkN2EyZjk0YjU5ZDFhMTJlZTIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfM2E3YjgzNDIyNjRmNGU4MjkwYjBlZjU0OWQ1OWRhODQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDA4MTU3LC03OS4zODE3NTIyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zMTM2MTJkOWE5ZTg0NzdiOTAzNWNhZDNmNDYxOGNhNCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83NjJmMWU5ZDA0MjA0NmNkYWI3MWYxZDBhMzQ0MThlMyA9ICQoJzxkaXYgaWQ9Imh0bWxfNzYyZjFlOWQwNDIwNDZjZGFiNzFmMWQwYTM0NDE4ZTMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IEhhcmJvdXJmcm9udCBFYXN0LCBUb3JvbnRvIElzbGFuZHMsIFVuaW9uIFN0YXRpb248L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzMxMzYxMmQ5YTllODQ3N2I5MDM1Y2FkM2Y0NjE4Y2E0LnNldENvbnRlbnQoaHRtbF83NjJmMWU5ZDA0MjA0NmNkYWI3MWYxZDBhMzQ0MThlMyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8zYTdiODM0MjI2NGY0ZTgyOTBiMGVmNTQ5ZDU5ZGE4NC5iaW5kUG9wdXAocG9wdXBfMzEzNjEyZDlhOWU4NDc3YjkwMzVjYWQzZjQ2MThjYTQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWY3YzZkMjQ1ZGNmNDNjY2JkMDBhZWMyNjJmOWZhZmMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDcxNzY4LC03OS4zODE1NzY0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9iOWIxYzEwYjdhZjU0MzQyYTY3NmEzY2FhNDA0Yjk0MCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9lY2NhMzUwODYyMDc0MmM4YWQwOGI4YTBjZmQ0N2VkZSA9ICQoJzxkaXYgaWQ9Imh0bWxfZWNjYTM1MDg2MjA3NDJjOGFkMDhiOGEwY2ZkNDdlZGUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IERlc2lnbiBFeGNoYW5nZSwgVG9yb250byBEb21pbmlvbiBDZW50cmU8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2I5YjFjMTBiN2FmNTQzNDJhNjc2YTNjYWE0MDRiOTQwLnNldENvbnRlbnQoaHRtbF9lY2NhMzUwODYyMDc0MmM4YWQwOGI4YTBjZmQ0N2VkZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8xZjdjNmQyNDVkY2Y0M2NjYmQwMGFlYzI2MmY5ZmFmYy5iaW5kUG9wdXAocG9wdXBfYjliMWMxMGI3YWY1NDM0MmE2NzZhM2NhYTQwNGI5NDApOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMWNkNjdhMmIyOTZhNDE1OTg4ZjEzYTYwODYzOTRjY2IgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDgxOTg1LC03OS4zNzk4MTY5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xMTBhMmMyNTFiNjE0MTlhYmNjYzY4ZTgzYWIwM2JhNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF84MjcxMGY1NTBlZmQ0YmNhYjUwZTU4NzA3ODM0YzAzMiA9ICQoJzxkaXYgaWQ9Imh0bWxfODI3MTBmNTUwZWZkNGJjYWI1MGU1ODcwNzgzNGMwMzIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENvbW1lcmNlIENvdXJ0LCBWaWN0b3JpYSBIb3RlbDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMTEwYTJjMjUxYjYxNDE5YWJjY2M2OGU4M2FiMDNiYTUuc2V0Q29udGVudChodG1sXzgyNzEwZjU1MGVmZDRiY2FiNTBlNTg3MDc4MzRjMDMyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzFjZDY3YTJiMjk2YTQxNTk4OGYxM2E2MDg2Mzk0Y2NiLmJpbmRQb3B1cChwb3B1cF8xMTBhMmMyNTFiNjE0MTlhYmNjYzY4ZTgzYWIwM2JhNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xNzJkY2RkYWY0MDU0NjVhOWNmMWRiNjhhZGFlZjhjZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxMTY5NDgsLTc5LjQxNjkzNTU5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI1ZmEwMzdhNmViNDRhYTA4M2VlMGE0NzYwMDhiNmU4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2I2YjI3N2JjZjRiODQzZDJiMTRlYTE5OTVjY2UxZWVkID0gJCgnPGRpdiBpZD0iaHRtbF9iNmIyNzdiY2Y0Yjg0M2QyYjE0ZWExOTk1Y2NlMWVlZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBSb3NlbGF3bjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjVmYTAzN2E2ZWI0NGFhMDgzZWUwYTQ3NjAwOGI2ZTguc2V0Q29udGVudChodG1sX2I2YjI3N2JjZjRiODQzZDJiMTRlYTE5OTVjY2UxZWVkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzE3MmRjZGRhZjQwNTQ2NWE5Y2YxZGI2OGFkYWVmOGNmLmJpbmRQb3B1cChwb3B1cF8yNWZhMDM3YTZlYjQ0YWEwODNlZTBhNDc2MDA4YjZlOCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kYjM2ZWZlN2EyNjg0ODUyODdmMzI2YTEzOTg5NzEyYSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY5Njk0NzYsLTc5LjQxMTMwNzIwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Y3OTZjOTJkZjE0NTRjZDU5MWVjZTM2MWYwYjY1ZWYzID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzZlOTNjNDdiMmNlOTRkMjdiZmM2OGU2MGZmZTZlNGIyID0gJCgnPGRpdiBpZD0iaHRtbF82ZTkzYzQ3YjJjZTk0ZDI3YmZjNjhlNjBmZmU2ZTRiMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBGb3Jlc3QgSGlsbCBOb3J0aCwgRm9yZXN0IEhpbGwgV2VzdDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZjc5NmM5MmRmMTQ1NGNkNTkxZWNlMzYxZjBiNjVlZjMuc2V0Q29udGVudChodG1sXzZlOTNjNDdiMmNlOTRkMjdiZmM2OGU2MGZmZTZlNGIyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2RiMzZlZmU3YTI2ODQ4NTI4N2YzMjZhMTM5ODk3MTJhLmJpbmRQb3B1cChwb3B1cF9mNzk2YzkyZGYxNDU0Y2Q1OTFlY2UzNjFmMGI2NWVmMyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yYWZkOTFhNDEzODA0NGY3OGM2OWNhNjQyZjZlOTVhZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3MjcwOTcsLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2JjYmI0N2FmZWM1NDRlMjViZmY4MmU4NDEzNmZlZjhjID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2I4NDg1ZGNjZTI3NzQ4ODQ5Mzc4MWNjNWExYjNiODZiID0gJCgnPGRpdiBpZD0iaHRtbF9iODQ4NWRjY2UyNzc0ODg0OTM3ODFjYzVhMWIzYjg2YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBUaGUgQW5uZXgsIE5vcnRoIE1pZHRvd24sIFlvcmt2aWxsZTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmNiYjQ3YWZlYzU0NGUyNWJmZjgyZTg0MTM2ZmVmOGMuc2V0Q29udGVudChodG1sX2I4NDg1ZGNjZTI3NzQ4ODQ5Mzc4MWNjNWExYjNiODZiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzJhZmQ5MWE0MTM4MDQ0Zjc4YzY5Y2E2NDJmNmU5NWFmLmJpbmRQb3B1cChwb3B1cF9iY2JiNDdhZmVjNTQ0ZTI1YmZmODJlODQxMzZmZWY4Yyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kZmM5OGVjNDcyYmY0MDQ4OWNjMDkxYmUwMDQyYTcwOSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2MjY5NTYsLTc5LjQwMDA0OTNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZmIwZmUwM2JhNWIzNDQ1OThjNWRjOGI3Yzc3ZDczZTUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZjM5NGM0N2RhYTJiNDg0Yzg4YWE2ZGIyYjU4ZDI1MTAgPSAkKCc8ZGl2IGlkPSJodG1sX2YzOTRjNDdkYWEyYjQ4NGM4OGFhNmRiMmI1OGQyNTEwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBIYXJib3JkLCBVbml2ZXJzaXR5IG9mIFRvcm9udG88L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2ZiMGZlMDNiYTViMzQ0NTk4YzVkYzhiN2M3N2Q3M2U1LnNldENvbnRlbnQoaHRtbF9mMzk0YzQ3ZGFhMmI0ODRjODhhYTZkYjJiNThkMjUxMCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9kZmM5OGVjNDcyYmY0MDQ4OWNjMDkxYmUwMDQyYTcwOS5iaW5kUG9wdXAocG9wdXBfZmIwZmUwM2JhNWIzNDQ1OThjNWRjOGI3Yzc3ZDczZTUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmFlNDNhNDQ4NzEyNGJkNWE1YzFiODUzYTc0ZTQyM2EgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NTMyMDU3LC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzJlNzg1OTY1N2UyODQ1NDM5NTEyN2RkNmRhNmM0OGJlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzY0NjVjMDE5ZWI5NjRjMzY4N2E4MmZiNGU5YmNmYjRlID0gJCgnPGRpdiBpZD0iaHRtbF82NDY1YzAxOWViOTY0YzM2ODdhODJmYjRlOWJjZmI0ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogQ2hpbmF0b3duLCBHcmFuZ2UgUGFyaywgS2Vuc2luZ3RvbiBNYXJrZXQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzJlNzg1OTY1N2UyODQ1NDM5NTEyN2RkNmRhNmM0OGJlLnNldENvbnRlbnQoaHRtbF82NDY1YzAxOWViOTY0YzM2ODdhODJmYjRlOWJjZmI0ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9iYWU0M2E0NDg3MTI0YmQ1YTVjMWI4NTNhNzRlNDIzYS5iaW5kUG9wdXAocG9wdXBfMmU3ODU5NjU3ZTI4NDU0Mzk1MTI3ZGQ2ZGE2YzQ4YmUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDMzNzU2YWUyNDY0NGRjMGI4MjRiYWNmY2E2NmM4NWIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Mjg5NDY3LC03OS4zOTQ0MTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzNlYTkxZTc1OTViZjRhMWRiNTA3MTE4Y2I0YjBkMDFlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJmMTkwOTA4OTBlZjQ0YzJhNjgwOGM2NjcwN2M3NmFiID0gJCgnPGRpdiBpZD0iaHRtbF8yZjE5MDkwODkwZWY0NGMyYTY4MDhjNjY3MDdjNzZhYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogQ04gVG93ZXIsIEJhdGh1cnN0IFF1YXksIElzbGFuZCBhaXJwb3J0LCBIYXJib3VyZnJvbnQgV2VzdCwgS2luZyBhbmQgU3BhZGluYSwgUmFpbHdheSBMYW5kcywgU291dGggTmlhZ2FyYTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfM2VhOTFlNzU5NWJmNGExZGI1MDcxMThjYjRiMGQwMWUuc2V0Q29udGVudChodG1sXzJmMTkwOTA4OTBlZjQ0YzJhNjgwOGM2NjcwN2M3NmFiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2QzMzc1NmFlMjQ2NDRkYzBiODI0YmFjZmNhNjZjODViLmJpbmRQb3B1cChwb3B1cF8zZWE5MWU3NTk1YmY0YTFkYjUwNzExOGNiNGIwZDAxZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82MDNhOWM5NjI5YTM0YTZhOTY5YjYyYjNjZDdhMGQ4MyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NjQzNTIsLTc5LjM3NDg0NTk5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2JiMzk2M2FkNWZlZTQzMmFhZmIzYzQ4MzM5ZTY5OGZiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2ExZjM3NGJmZGQyZTRmMzU5OTI3MDBkYzU0MmQ2NjdjID0gJCgnPGRpdiBpZD0iaHRtbF9hMWYzNzRiZmRkMmU0ZjM1OTkyNzAwZGM1NDJkNjY3YyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogU3RuIEEgUE8gQm94ZXMgMjUgVGhlIEVzcGxhbmFkZTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmIzOTYzYWQ1ZmVlNDMyYWFmYjNjNDgzMzllNjk4ZmIuc2V0Q29udGVudChodG1sX2ExZjM3NGJmZGQyZTRmMzU5OTI3MDBkYzU0MmQ2NjdjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzYwM2E5Yzk2MjlhMzRhNmE5NjliNjJiM2NkN2EwZDgzLmJpbmRQb3B1cChwb3B1cF9iYjM5NjNhZDVmZWU0MzJhYWZiM2M0ODMzOWU2OThmYik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kNmVkOTQ4YjMzZDA0M2I3OGM5NmRmYThjMjRiYTI5ZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0ODQyOTIsLTc5LjM4MjI4MDJdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTk1MmNhNDQ3OWNlNDIwOTk2YmI0NTZhYzk1MjkwZjAgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWJiZWRhZjE1ZjQ3NGVlZjljZjJlMWRiYWJmM2I5OTUgPSAkKCc8ZGl2IGlkPSJodG1sXzFiYmVkYWYxNWY0NzRlZWY5Y2YyZTFkYmFiZjNiOTk1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBGaXJzdCBDYW5hZGlhbiBQbGFjZSwgVW5kZXJncm91bmQgY2l0eTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTk1MmNhNDQ3OWNlNDIwOTk2YmI0NTZhYzk1MjkwZjAuc2V0Q29udGVudChodG1sXzFiYmVkYWYxNWY0NzRlZWY5Y2YyZTFkYmFiZjNiOTk1KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2Q2ZWQ5NDhiMzNkMDQzYjc4Yzk2ZGZhOGMyNGJhMjllLmJpbmRQb3B1cChwb3B1cF9hOTUyY2E0NDc5Y2U0MjA5OTZiYjQ1NmFjOTUyOTBmMCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wYTc1YzgyY2RkNjA0NzQ4YmYyZWI0ZWIwZjdkNGU4OCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2OTU0MiwtNzkuNDIyNTYzN10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83ZmQzMmM3NWIzNGE0ZTBiOTdkYjE4NDI4MTEyY2M0MiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kYjNhYzlhMDBmZjY0YmE5YWM3OGMzMTcwZTU3MmFlNCA9ICQoJzxkaXYgaWQ9Imh0bWxfZGIzYWM5YTAwZmY2NGJhOWFjNzhjMzE3MGU1NzJhZTQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENocmlzdGllPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83ZmQzMmM3NWIzNGE0ZTBiOTdkYjE4NDI4MTEyY2M0Mi5zZXRDb250ZW50KGh0bWxfZGIzYWM5YTAwZmY2NGJhOWFjNzhjMzE3MGU1NzJhZTQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMGE3NWM4MmNkZDYwNDc0OGJmMmViNGViMGY3ZDRlODguYmluZFBvcHVwKHBvcHVwXzdmZDMyYzc1YjM0YTRlMGI5N2RiMTg0MjgxMTJjYzQyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzBlMzljMDhjYjVjZDRiMDhhYTAxMzg3OTY4MjhjZDJkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjY5MDA1MTAwMDAwMDEsLTc5LjQ0MjI1OTNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZDM4NTNiZGQ3NDM4NDM3OGI0Y2VmM2Y1NGEyNGM1MDMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNmE4MTNiMGQxMGQ4NGU0ZmJhYzZhMjNkZTQ2Yjc5ZWMgPSAkKCc8ZGl2IGlkPSJodG1sXzZhODEzYjBkMTBkODRlNGZiYWM2YTIzZGU0NmI3OWVjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5XZXN0IFRvcm9udG86IERvdmVyY291cnQgVmlsbGFnZSwgRHVmZmVyaW48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2QzODUzYmRkNzQzODQzNzhiNGNlZjNmNTRhMjRjNTAzLnNldENvbnRlbnQoaHRtbF82YTgxM2IwZDEwZDg0ZTRmYmFjNmEyM2RlNDZiNzllYyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8wZTM5YzA4Y2I1Y2Q0YjA4YWEwMTM4Nzk2ODI4Y2QyZC5iaW5kUG9wdXAocG9wdXBfZDM4NTNiZGQ3NDM4NDM3OGI0Y2VmM2Y1NGEyNGM1MDMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNTZiZGQ1NjdhMmE1NDk0ODk1YWM3YzkwMWUzOTM4YjEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDc5MjY3MDAwMDAwMDYsLTc5LjQxOTc0OTddLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZDg4OWQ1NmY4OGM5NDFhYjllNDhmN2ViOGQ0NGQ1ZjYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2ZlOTRhOGQxZTUyNDg0ZGE4MzBjOTIxYmRkYTg0MWIgPSAkKCc8ZGl2IGlkPSJodG1sXzdmZTk0YThkMWU1MjQ4NGRhODMwYzkyMWJkZGE4NDFiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5XZXN0IFRvcm9udG86IExpdHRsZSBQb3J0dWdhbCwgVHJpbml0eTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZDg4OWQ1NmY4OGM5NDFhYjllNDhmN2ViOGQ0NGQ1ZjYuc2V0Q29udGVudChodG1sXzdmZTk0YThkMWU1MjQ4NGRhODMwYzkyMWJkZGE4NDFiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzU2YmRkNTY3YTJhNTQ5NDg5NWFjN2M5MDFlMzkzOGIxLmJpbmRQb3B1cChwb3B1cF9kODg5ZDU2Zjg4Yzk0MWFiOWU0OGY3ZWI4ZDQ0ZDVmNik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yZTg0Njg5ODA5MTQ0MDdkODc5YjNiNmEwZWJiMmQ0YyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYzNjg0NzIsLTc5LjQyODE5MTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2EwZWNlZTJkZDAyYzQyZWQ4MWU4YzI1NmE3NTAxM2NiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2MxZDA2NGQyZDQ3MzQyYWU4YzQyNzkxMWVhNTEzNmE4ID0gJCgnPGRpdiBpZD0iaHRtbF9jMWQwNjRkMmQ0NzM0MmFlOGM0Mjc5MTFlYTUxMzZhOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdCBUb3JvbnRvOiBCcm9ja3RvbiwgRXhoaWJpdGlvbiBQbGFjZSwgUGFya2RhbGUgVmlsbGFnZTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTBlY2VlMmRkMDJjNDJlZDgxZThjMjU2YTc1MDEzY2Iuc2V0Q29udGVudChodG1sX2MxZDA2NGQyZDQ3MzQyYWU4YzQyNzkxMWVhNTEzNmE4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzJlODQ2ODk4MDkxNDQwN2Q4NzliM2I2YTBlYmIyZDRjLmJpbmRQb3B1cChwb3B1cF9hMGVjZWUyZGQwMmM0MmVkODFlOGMyNTZhNzUwMTNjYik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84MjgyZDk1ODE0Y2E0M2QzYWNlMDZiOTdhZjc4ZDA5MiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2MTYwODMsLTc5LjQ2NDc2MzI5OTk5OTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjMzE4NmNjIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2NlOThjM2YzYjhjMjQ5ZDNiZGNhYWE3Yjk3MTk4ODY1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzNmNzJiYWRlMjhkODRkNTViM2Y4YTk0NDk4Njk2MTk2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzYyMzYzYjkyNGI2MTRmMDdiY2ExZjg4MTI1ZjE2YzAzID0gJCgnPGRpdiBpZD0iaHRtbF82MjM2M2I5MjRiNjE0ZjA3YmNhMWY4ODEyNWYxNmMwMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdCBUb3JvbnRvOiBIaWdoIFBhcmssIFRoZSBKdW5jdGlvbiBTb3V0aDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfM2Y3MmJhZGUyOGQ4NGQ1NWIzZjhhOTQ0OTg2OTYxOTYuc2V0Q29udGVudChodG1sXzYyMzYzYjkyNGI2MTRmMDdiY2ExZjg4MTI1ZjE2YzAzKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzgyODJkOTU4MTRjYTQzZDNhY2UwNmI5N2FmNzhkMDkyLmJpbmRQb3B1cChwb3B1cF8zZjcyYmFkZTI4ZDg0ZDU1YjNmOGE5NDQ5ODY5NjE5Nik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jZGQwZjJjZTMzZGM0MzI1OGZhODU5NjYzNGJiMWQ2ZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0ODk1OTcsLTc5LjQ1NjMyNV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jOTBjNWUwZmFmNzc0M2RhYjg4Mjk0Y2JhZWYwZTQ3YSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zZmMyYTdmZTk3Y2Q0ODFmYjhmNzNlYjYzYjZmMjhlNCA9ICQoJzxkaXYgaWQ9Imh0bWxfM2ZjMmE3ZmU5N2NkNDgxZmI4ZjczZWI2M2I2ZjI4ZTQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldlc3QgVG9yb250bzogUGFya2RhbGUsIFJvbmNlc3ZhbGxlczwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYzkwYzVlMGZhZjc3NDNkYWI4ODI5NGNiYWVmMGU0N2Euc2V0Q29udGVudChodG1sXzNmYzJhN2ZlOTdjZDQ4MWZiOGY3M2ViNjNiNmYyOGU0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2NkZDBmMmNlMzNkYzQzMjU4ZmE4NTk2NjM0YmIxZDZlLmJpbmRQb3B1cChwb3B1cF9jOTBjNWUwZmFmNzc0M2RhYjg4Mjk0Y2JhZWYwZTQ3YSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84OGFiNzUyZDY0NDY0MDlmYTEwYWRiZmM0N2I3ZTFkYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MTU3MDYsLTc5LjQ4NDQ0OTldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiMzMTg2Y2MiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfY2U5OGMzZjNiOGMyNDlkM2JkY2FhYTdiOTcxOTg4NjUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMjU2YzVkYTA3ZDVkNGNlODhkODU4ZmNkNTkzODA5MmUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfM2U5YzRmYmVmNjcxNGFjY2FhNTc3YjI1YTYwM2Y3Y2QgPSAkKCc8ZGl2IGlkPSJodG1sXzNlOWM0ZmJlZjY3MTRhY2NhYTU3N2IyNWE2MDNmN2NkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5XZXN0IFRvcm9udG86IFJ1bm55bWVkZSwgU3dhbnNlYTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjU2YzVkYTA3ZDVkNGNlODhkODU4ZmNkNTkzODA5MmUuc2V0Q29udGVudChodG1sXzNlOWM0ZmJlZjY3MTRhY2NhYTU3N2IyNWE2MDNmN2NkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzg4YWI3NTJkNjQ0NjQwOWZhMTBhZGJmYzQ3YjdlMWRiLmJpbmRQb3B1cChwb3B1cF8yNTZjNWRhMDdkNWQ0Y2U4OGQ4NThmY2Q1OTM4MDkyZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lNDA5MzU2ZDIxMWY0ZWEzOGVkNGM0MDY1YTY5YjRkMyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2Mjc0MzksLTc5LjMyMTU1OF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzMxODZjYyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9jZTk4YzNmM2I4YzI0OWQzYmRjYWFhN2I5NzE5ODg2NSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82MzkzN2Q0MTE1M2E0Y2I5YmM5ODIzMTUwY2FhNjRkNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kN2VhZWEwOGYyMzQ0MmQxYTIzZGVjNDAwY2MzYzVlNCA9ICQoJzxkaXYgaWQ9Imh0bWxfZDdlYWVhMDhmMjM0NDJkMWEyM2RlYzQwMGNjM2M1ZTQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgVG9yb250bzogQnVzaW5lc3MgUmVwbHkgTWFpbCBQcm9jZXNzaW5nIENlbnRyZSA5NjkgRWFzdGVybjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjM5MzdkNDExNTNhNGNiOWJjOTgyMzE1MGNhYTY0ZDUuc2V0Q29udGVudChodG1sX2Q3ZWFlYTA4ZjIzNDQyZDFhMjNkZWM0MDBjYzNjNWU0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2U0MDkzNTZkMjExZjRlYTM4ZWQ0YzQwNjVhNjliNGQzLmJpbmRQb3B1cChwb3B1cF82MzkzN2Q0MTE1M2E0Y2I5YmM5ODIzMTUwY2FhNjRkNSk7CgogICAgICAgICAgICAKICAgICAgICAKPC9zY3JpcHQ+" style="position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe>
CLIENT_ID = 'FROUNNKNE2NFNJ3DPMSVCFHY5322WYELMEGST2E22VVQCDCN' # your Foursquare ID
CLIENT_SECRET = 'Z30WRUBMICAZU4NBL4UOTJTKB3LWTDVTRAXJU3AFIX3ONRA0' # your Foursquare Secret
VERSION = '20180605' # Foursquare API version
print ('Your credentails:' )
print ('CLIENT_SECRET:' + CLIENT_SECRET )
print ('CLIENT_ID: ' + CLIENT_ID )
Your credentails:
CLIENT_SECRET:Z30WRUBMICAZU4NBL4UOTJTKB3LWTDVTRAXJU3AFIX3ONRA0
CLIENT_ID: FROUNNKNE2NFNJ3DPMSVCFHY5322WYELMEGST2E22VVQCDCN
We will explore the neighborhoods using the Foursquare API in the following cells
#creating a function to get the near by venues of a given neighborhood using the Foursquare API
def getNearbyVenues (names , latitudes , longitudes , radius = 500 ):
venues_list = []
for name , lat , lng in zip (names , latitudes , longitudes ):
#print(name)
# create the API request URL
url = 'https://api.foursquare.com/v2/venues/explore?&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}' .format (
CLIENT_ID ,
CLIENT_SECRET ,
VERSION ,
lat ,
lng ,
radius ,
LIMIT )
# make the GET request
results = requests .get (url ).json ()["response" ]['groups' ][0 ]['items' ]
# return only relevant information for each nearby venue
venues_list .append ([(
name ,
lat ,
lng ,
v ['venue' ]['name' ],
v ['venue' ]['location' ]['lat' ],
v ['venue' ]['location' ]['lng' ],
v ['venue' ]['categories' ][0 ]['name' ]) for v in results ])
nearby_venues = pd .DataFrame ([item for venue_list in venues_list for item in venue_list ])
nearby_venues .columns = ['Neighborhood' ,
'Neighborhood Latitude' ,
'Neighborhood Longitude' ,
'Venue' ,
'Venue Latitude' ,
'Venue Longitude' ,
'Venue Category' ]
return (nearby_venues )
#Obtaining venues within 500m of each neighborhood with a limit of 100 venues per neighborhood
LIMIT = 100
toronto_venues = getNearbyVenues (names = df_toronto ['Neighborhood' ],
latitudes = df_toronto ['Latitude' ],
longitudes = df_toronto ['Longitude' ]
)
toronto_venues .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Neighborhood Latitude
Neighborhood Longitude
Venue
Venue Latitude
Venue Longitude
Venue Category
0
The Beaches
43.676357
-79.293031
Glen Manor Ravine
43.676821
-79.293942
Trail
1
The Beaches
43.676357
-79.293031
The Big Carrot Natural Food Market
43.678879
-79.297734
Health Food Store
2
The Beaches
43.676357
-79.293031
Grover Pub and Grub
43.679181
-79.297215
Pub
3
The Beaches
43.676357
-79.293031
Upper Beaches
43.680563
-79.292869
Neighborhood
4
The Danforth West, Riverdale
43.679557
-79.352188
Pantheon
43.677621
-79.351434
Greek Restaurant
We will check how many venues were obtained per neighborhood below
toronto_venues .groupby ('Neighborhood' ).count ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood Latitude
Neighborhood Longitude
Venue
Venue Latitude
Venue Longitude
Venue Category
Neighborhood
Adelaide, King, Richmond
100
100
100
100
100
100
Berczy Park
57
57
57
57
57
57
Brockton, Exhibition Place, Parkdale Village
21
21
21
21
21
21
Business Reply Mail Processing Centre 969 Eastern
18
18
18
18
18
18
CN Tower, Bathurst Quay, Island airport, Harbourfront West, King and Spadina, Railway Lands, South Niagara
16
16
16
16
16
16
Cabbagetown, St. James Town
43
43
43
43
43
43
Central Bay Street
82
82
82
82
82
82
Chinatown, Grange Park, Kensington Market
96
96
96
96
96
96
Christie
17
17
17
17
17
17
Church and Wellesley
89
89
89
89
89
89
Commerce Court, Victoria Hotel
100
100
100
100
100
100
Davisville
38
38
38
38
38
38
Davisville North
7
7
7
7
7
7
Deer Park, Forest Hill SE, Rathnelly, South Hill, Summerhill West
16
16
16
16
16
16
Design Exchange, Toronto Dominion Centre
100
100
100
100
100
100
Dovercourt Village, Dufferin
18
18
18
18
18
18
First Canadian Place, Underground city
100
100
100
100
100
100
Forest Hill North, Forest Hill West
4
4
4
4
4
4
Harbord, University of Toronto
36
36
36
36
36
36
Harbourfront
48
48
48
48
48
48
Harbourfront East, Toronto Islands, Union Station
100
100
100
100
100
100
High Park, The Junction South
27
27
27
27
27
27
Lawrence Park
3
3
3
3
3
3
Little Portugal, Trinity
64
64
64
64
64
64
Moore Park, Summerhill East
4
4
4
4
4
4
North Toronto West
21
21
21
21
21
21
Parkdale, Roncesvalles
15
15
15
15
15
15
Rosedale
4
4
4
4
4
4
Roselawn
2
2
2
2
2
2
Runnymede, Swansea
34
34
34
34
34
34
Ryerson, Garden District
100
100
100
100
100
100
St. James Town
100
100
100
100
100
100
Stn A PO Boxes 25 The Esplanade
99
99
99
99
99
99
Studio District
38
38
38
38
38
38
The Annex, North Midtown, Yorkville
21
21
21
21
21
21
The Beaches
4
4
4
4
4
4
The Beaches West, India Bazaar
21
21
21
21
21
21
The Danforth West, Riverdale
42
42
42
42
42
42
#Checking how many unique venue categories were obtained
print ('There are {} uniques categories.' .format (len (toronto_venues ['Venue Category' ].unique ())))
There are 234 uniques categories.
We will analyse each neigborhood in the cells below
# one hot encoding
toronto_onehot = pd .get_dummies (toronto_venues [['Venue Category' ]], prefix = "" , prefix_sep = "" )
# add neighborhood column back to dataframe
toronto_onehot ['Neighborhoods' ] = toronto_venues ['Neighborhood' ]
# move neighborhood column to the first column
fixed_columns = [toronto_onehot .columns [- 1 ]] + list (toronto_onehot .columns [:- 1 ])
toronto_onehot = toronto_onehot [fixed_columns ]
toronto_onehot .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhoods
Afghan Restaurant
Airport
Airport Food Court
Airport Gate
Airport Lounge
Airport Service
Airport Terminal
American Restaurant
Antique Shop
Aquarium
Art Gallery
Arts & Crafts Store
Asian Restaurant
Athletics & Sports
Auto Workshop
BBQ Joint
Baby Store
Bagel Shop
Bakery
Bank
Bar
Baseball Stadium
Basketball Stadium
Beach
Bed & Breakfast
Beer Bar
Beer Store
Belgian Restaurant
Bistro
Board Shop
Boat or Ferry
Bookstore
Boutique
Brazilian Restaurant
Breakfast Spot
Brewery
Bubble Tea Shop
Building
Burger Joint
Burrito Place
Bus Line
Butcher
Café
Cajun / Creole Restaurant
Candy Store
Caribbean Restaurant
Cheese Shop
Chinese Restaurant
Chocolate Shop
Church
Climbing Gym
Clothing Store
Cocktail Bar
Coffee Shop
College Arts Building
College Gym
College Rec Center
Colombian Restaurant
Comfort Food Restaurant
Comic Shop
Concert Hall
Convenience Store
Cosmetics Shop
Costume Shop
Coworking Space
Creperie
Cuban Restaurant
Cupcake Shop
Dance Studio
Deli / Bodega
Department Store
Dessert Shop
Dim Sum Restaurant
Diner
Discount Store
Dog Run
Doner Restaurant
Donut Shop
Dumpling Restaurant
Eastern European Restaurant
Electronics Store
Ethiopian Restaurant
Event Space
Falafel Restaurant
Farmers Market
Fast Food Restaurant
Filipino Restaurant
Fish & Chips Shop
Fish Market
Flea Market
Flower Shop
Food
Food & Drink Shop
Food Court
Food Truck
Fountain
French Restaurant
Fried Chicken Joint
Fruit & Vegetable Store
Furniture / Home Store
Gaming Cafe
Garden
Garden Center
Gastropub
Gay Bar
General Entertainment
General Travel
German Restaurant
Gift Shop
Gluten-free Restaurant
Gourmet Shop
Greek Restaurant
Grocery Store
Gym
Gym / Fitness Center
Harbor / Marina
Health & Beauty Service
Health Food Store
Historic Site
History Museum
Hobby Shop
Home Service
Hospital
Hostel
Hotel
Hotel Bar
Hotpot Restaurant
Ice Cream Shop
Indian Restaurant
Indie Movie Theater
Indoor Play Area
Intersection
Irish Pub
Italian Restaurant
Japanese Restaurant
Jazz Club
Jewelry Store
Juice Bar
Korean Restaurant
Lake
Latin American Restaurant
Light Rail Station
Lingerie Store
Liquor Store
Lounge
Mac & Cheese Joint
Malay Restaurant
Market
Mediterranean Restaurant
Men's Store
Metro Station
Mexican Restaurant
Middle Eastern Restaurant
Miscellaneous Shop
Modern European Restaurant
Molecular Gastronomy Restaurant
Monument / Landmark
Movie Theater
Museum
Music Venue
Neighborhood
New American Restaurant
Nightclub
Noodle House
Office
Opera House
Optical Shop
Organic Grocery
Other Great Outdoors
Park
Performing Arts Venue
Pet Store
Pharmacy
Pizza Place
Plane
Playground
Plaza
Poke Place
Portuguese Restaurant
Poutine Place
Pub
Ramen Restaurant
Record Shop
Recording Studio
Rental Car Location
Restaurant
Roof Deck
Sake Bar
Salad Place
Salon / Barbershop
Sandwich Place
Scenic Lookout
Sculpture Garden
Seafood Restaurant
Shoe Store
Shopping Mall
Skate Park
Skating Rink
Smoke Shop
Smoothie Shop
Snack Place
Soup Place
Southern / Soul Food Restaurant
Spa
Speakeasy
Sporting Goods Shop
Sports Bar
Stadium
Stationery Store
Steakhouse
Strip Club
Supermarket
Sushi Restaurant
Swim School
Taco Place
Tailor Shop
Taiwanese Restaurant
Tanning Salon
Tapas Restaurant
Tea Room
Tennis Court
Thai Restaurant
Theater
Theme Restaurant
Toy / Game Store
Trail
Train Station
Vegetarian / Vegan Restaurant
Video Game Store
Vietnamese Restaurant
Wine Bar
Wine Shop
Wings Joint
Yoga Studio
0
The Beaches
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
1
The Beaches
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
The Beaches
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
3
The Beaches
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
4
The Danforth West, Riverdale
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
let's group rows by neighborhood and by taking the mean of the frequency of occurrence of each category
#Grouping the
toronto_grouped = toronto_onehot .groupby ('Neighborhoods' ).mean ().reset_index ()
toronto_grouped .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhoods
Afghan Restaurant
Airport
Airport Food Court
Airport Gate
Airport Lounge
Airport Service
Airport Terminal
American Restaurant
Antique Shop
Aquarium
Art Gallery
Arts & Crafts Store
Asian Restaurant
Athletics & Sports
Auto Workshop
BBQ Joint
Baby Store
Bagel Shop
Bakery
Bank
Bar
Baseball Stadium
Basketball Stadium
Beach
Bed & Breakfast
Beer Bar
Beer Store
Belgian Restaurant
Bistro
Board Shop
Boat or Ferry
Bookstore
Boutique
Brazilian Restaurant
Breakfast Spot
Brewery
Bubble Tea Shop
Building
Burger Joint
Burrito Place
Bus Line
Butcher
Café
Cajun / Creole Restaurant
Candy Store
Caribbean Restaurant
Cheese Shop
Chinese Restaurant
Chocolate Shop
Church
Climbing Gym
Clothing Store
Cocktail Bar
Coffee Shop
College Arts Building
College Gym
College Rec Center
Colombian Restaurant
Comfort Food Restaurant
Comic Shop
Concert Hall
Convenience Store
Cosmetics Shop
Costume Shop
Coworking Space
Creperie
Cuban Restaurant
Cupcake Shop
Dance Studio
Deli / Bodega
Department Store
Dessert Shop
Dim Sum Restaurant
Diner
Discount Store
Dog Run
Doner Restaurant
Donut Shop
Dumpling Restaurant
Eastern European Restaurant
Electronics Store
Ethiopian Restaurant
Event Space
Falafel Restaurant
Farmers Market
Fast Food Restaurant
Filipino Restaurant
Fish & Chips Shop
Fish Market
Flea Market
Flower Shop
Food
Food & Drink Shop
Food Court
Food Truck
Fountain
French Restaurant
Fried Chicken Joint
Fruit & Vegetable Store
Furniture / Home Store
Gaming Cafe
Garden
Garden Center
Gastropub
Gay Bar
General Entertainment
General Travel
German Restaurant
Gift Shop
Gluten-free Restaurant
Gourmet Shop
Greek Restaurant
Grocery Store
Gym
Gym / Fitness Center
Harbor / Marina
Health & Beauty Service
Health Food Store
Historic Site
History Museum
Hobby Shop
Home Service
Hospital
Hostel
Hotel
Hotel Bar
Hotpot Restaurant
Ice Cream Shop
Indian Restaurant
Indie Movie Theater
Indoor Play Area
Intersection
Irish Pub
Italian Restaurant
Japanese Restaurant
Jazz Club
Jewelry Store
Juice Bar
Korean Restaurant
Lake
Latin American Restaurant
Light Rail Station
Lingerie Store
Liquor Store
Lounge
Mac & Cheese Joint
Malay Restaurant
Market
Mediterranean Restaurant
Men's Store
Metro Station
Mexican Restaurant
Middle Eastern Restaurant
Miscellaneous Shop
Modern European Restaurant
Molecular Gastronomy Restaurant
Monument / Landmark
Movie Theater
Museum
Music Venue
Neighborhood
New American Restaurant
Nightclub
Noodle House
Office
Opera House
Optical Shop
Organic Grocery
Other Great Outdoors
Park
Performing Arts Venue
Pet Store
Pharmacy
Pizza Place
Plane
Playground
Plaza
Poke Place
Portuguese Restaurant
Poutine Place
Pub
Ramen Restaurant
Record Shop
Recording Studio
Rental Car Location
Restaurant
Roof Deck
Sake Bar
Salad Place
Salon / Barbershop
Sandwich Place
Scenic Lookout
Sculpture Garden
Seafood Restaurant
Shoe Store
Shopping Mall
Skate Park
Skating Rink
Smoke Shop
Smoothie Shop
Snack Place
Soup Place
Southern / Soul Food Restaurant
Spa
Speakeasy
Sporting Goods Shop
Sports Bar
Stadium
Stationery Store
Steakhouse
Strip Club
Supermarket
Sushi Restaurant
Swim School
Taco Place
Tailor Shop
Taiwanese Restaurant
Tanning Salon
Tapas Restaurant
Tea Room
Tennis Court
Thai Restaurant
Theater
Theme Restaurant
Toy / Game Store
Trail
Train Station
Vegetarian / Vegan Restaurant
Video Game Store
Vietnamese Restaurant
Wine Bar
Wine Shop
Wings Joint
Yoga Studio
0
Adelaide, King, Richmond
0.0
0.0000
0.0000
0.0000
0.000
0.0000
0.0000
0.03
0.0
0.0
0.000000
0.0
0.03
0.0
0.000000
0.000000
0.0
0.000000
0.030000
0.0
0.040000
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.000000
0.0
0.0000
0.01
0.0000
0.01
0.030000
0.000000
0.0
0.01
0.02
0.010000
0.0
0.000000
0.050000
0.0
0.0
0.000000
0.000000
0.0
0.0
0.0
0.000000
0.010000
0.000000
0.070000
0.0
0.0
0.0
0.01
0.000000
0.000000
0.020000
0.000000
0.03
0.0
0.0
0.000000
0.0
0.0
0.0
0.01
0.01
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.0
0.000000
0.01
0.0
0.0
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.01
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.000000
0.000000
0.02
0.0
0.0
0.01
0.0
0.0
0.01
0.000000
0.010000
0.000000
0.020000
0.010000
0.0000
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.030000
0.0
0.0
0.01
0.01
0.0
0.0
0.000000
0.000000
0.010000
0.010000
0.010000
0.0
0.01
0.0
0.0
0.01
0.000000
0.0
0.000000
0.010000
0.0
0.0
0.0
0.01
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.01
0.0
0.000000
0.0
0.01
0.01
0.010000
0.01
0.01
0.01
0.0
0.0
0.0
0.000000
0.000000
0.000000
0.0
0.020000
0.0000
0.0
0.01
0.01
0.0
0.0
0.0
0.01
0.01
0.000000
0.0
0.030000
0.0
0.0
0.01
0.01
0.0
0.0
0.0000
0.010000
0.0
0.000000
0.000000
0.0
0.010000
0.0
0.0
0.0
0.0
0.000000
0.01
0.0
0.0
0.000000
0.0
0.040000
0.0
0.0
0.03
0.0
0.0
0.000000
0.0
0.0
0.0
0.000000
0.0
0.030000
0.01
0.0
0.0
0.0
0.0
0.020000
0.0
0.0
0.01
0.0
0.0
0.0
1
Berczy Park
0.0
0.0000
0.0000
0.0000
0.000
0.0000
0.0000
0.00
0.0
0.0
0.017544
0.0
0.00
0.0
0.000000
0.017544
0.0
0.017544
0.052632
0.0
0.000000
0.0
0.017544
0.017544
0.0
0.035088
0.0
0.0
0.017544
0.0
0.0000
0.00
0.0000
0.00
0.017544
0.000000
0.0
0.00
0.00
0.000000
0.0
0.017544
0.035088
0.0
0.0
0.000000
0.035088
0.0
0.0
0.0
0.000000
0.017544
0.035088
0.070175
0.0
0.0
0.0
0.00
0.017544
0.000000
0.017544
0.000000
0.00
0.0
0.0
0.017544
0.0
0.0
0.0
0.00
0.00
0.0
0.0
0.017544
0.0
0.0
0.0
0.0
0.0
0.017544
0.00
0.0
0.0
0.0
0.035088
0.000000
0.0
0.0
0.017544
0.0
0.0
0.0
0.0
0.00
0.0
0.017544
0.017544
0.0
0.0
0.000000
0.0
0.000000
0.000000
0.00
0.0
0.0
0.00
0.0
0.0
0.00
0.017544
0.017544
0.017544
0.000000
0.000000
0.0000
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.017544
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.017544
0.017544
0.017544
0.017544
0.0
0.00
0.0
0.0
0.00
0.000000
0.0
0.017544
0.017544
0.0
0.0
0.0
0.00
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.00
0.0
0.017544
0.0
0.00
0.00
0.017544
0.00
0.00
0.00
0.0
0.0
0.0
0.017544
0.000000
0.000000
0.0
0.000000
0.0000
0.0
0.00
0.00
0.0
0.0
0.0
0.00
0.00
0.000000
0.0
0.017544
0.0
0.0
0.00
0.00
0.0
0.0
0.0000
0.035088
0.0
0.017544
0.000000
0.0
0.000000
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.000000
0.0
0.035088
0.0
0.0
0.00
0.0
0.0
0.017544
0.0
0.0
0.0
0.017544
0.0
0.017544
0.00
0.0
0.0
0.0
0.0
0.017544
0.0
0.0
0.00
0.0
0.0
0.0
2
Brockton, Exhibition Place, Parkdale Village
0.0
0.0000
0.0000
0.0000
0.000
0.0000
0.0000
0.00
0.0
0.0
0.000000
0.0
0.00
0.0
0.000000
0.000000
0.0
0.000000
0.047619
0.0
0.047619
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.000000
0.0
0.0000
0.00
0.0000
0.00
0.095238
0.000000
0.0
0.00
0.00
0.047619
0.0
0.000000
0.095238
0.0
0.0
0.047619
0.000000
0.0
0.0
0.0
0.047619
0.000000
0.000000
0.095238
0.0
0.0
0.0
0.00
0.000000
0.000000
0.000000
0.047619
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.000000
0.0
0.0
0.047619
0.0
0.000000
0.000000
0.00
0.0
0.0
0.00
0.0
0.0
0.00
0.000000
0.000000
0.047619
0.047619
0.000000
0.0000
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.00
0.0
0.0
0.047619
0.000000
0.047619
0.000000
0.000000
0.0
0.00
0.0
0.0
0.00
0.000000
0.0
0.000000
0.000000
0.0
0.0
0.0
0.00
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.0
0.00
0.00
0.000000
0.00
0.00
0.00
0.0
0.0
0.0
0.000000
0.047619
0.047619
0.0
0.000000
0.0000
0.0
0.00
0.00
0.0
0.0
0.0
0.00
0.00
0.000000
0.0
0.047619
0.0
0.0
0.00
0.00
0.0
0.0
0.0000
0.000000
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.047619
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.000000
0.0
0.000000
0.00
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.0
3
Business Reply Mail Processing Centre 969 Eastern
0.0
0.0000
0.0000
0.0000
0.000
0.0000
0.0000
0.00
0.0
0.0
0.000000
0.0
0.00
0.0
0.055556
0.000000
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.000000
0.0
0.0000
0.00
0.0000
0.00
0.000000
0.055556
0.0
0.00
0.00
0.055556
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.000000
0.0
0.0
0.0
0.000000
0.000000
0.000000
0.000000
0.0
0.0
0.0
0.00
0.000000
0.055556
0.000000
0.000000
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.0
0.055556
0.055556
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.055556
0.055556
0.00
0.0
0.0
0.00
0.0
0.0
0.00
0.000000
0.000000
0.000000
0.000000
0.055556
0.0000
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.000000
0.000000
0.000000
0.000000
0.0
0.00
0.0
0.0
0.00
0.111111
0.0
0.000000
0.000000
0.0
0.0
0.0
0.00
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.0
0.00
0.00
0.000000
0.00
0.00
0.00
0.0
0.0
0.0
0.055556
0.000000
0.000000
0.0
0.055556
0.0000
0.0
0.00
0.00
0.0
0.0
0.0
0.00
0.00
0.055556
0.0
0.055556
0.0
0.0
0.00
0.00
0.0
0.0
0.0000
0.000000
0.0
0.000000
0.055556
0.0
0.055556
0.0
0.0
0.0
0.0
0.055556
0.00
0.0
0.0
0.000000
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.000000
0.0
0.000000
0.00
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.0
4
CN Tower, Bathurst Quay, Island airport, Harbo...
0.0
0.0625
0.0625
0.0625
0.125
0.1875
0.0625
0.00
0.0
0.0
0.000000
0.0
0.00
0.0
0.000000
0.000000
0.0
0.000000
0.000000
0.0
0.062500
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.000000
0.0
0.0625
0.00
0.0625
0.00
0.000000
0.000000
0.0
0.00
0.00
0.000000
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.000000
0.0
0.0
0.0
0.000000
0.000000
0.000000
0.062500
0.0
0.0
0.0
0.00
0.000000
0.000000
0.000000
0.000000
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.000000
0.0
0.0
0.000000
0.0
0.000000
0.000000
0.00
0.0
0.0
0.00
0.0
0.0
0.00
0.000000
0.000000
0.000000
0.000000
0.000000
0.0625
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.00
0.0
0.0
0.000000
0.000000
0.000000
0.000000
0.000000
0.0
0.00
0.0
0.0
0.00
0.000000
0.0
0.000000
0.000000
0.0
0.0
0.0
0.00
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.00
0.0
0.000000
0.0
0.00
0.00
0.000000
0.00
0.00
0.00
0.0
0.0
0.0
0.000000
0.000000
0.000000
0.0
0.000000
0.0625
0.0
0.00
0.00
0.0
0.0
0.0
0.00
0.00
0.000000
0.0
0.000000
0.0
0.0
0.00
0.00
0.0
0.0
0.0625
0.000000
0.0
0.000000
0.000000
0.0
0.000000
0.0
0.0
0.0
0.0
0.000000
0.00
0.0
0.0
0.000000
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.000000
0.0
0.0
0.0
0.000000
0.0
0.000000
0.00
0.0
0.0
0.0
0.0
0.000000
0.0
0.0
0.00
0.0
0.0
0.0
Let's get the neighborhoods with their top 5 most common venues
def return_most_common_venues (row , num_top_venues ):
row_categories = row .iloc [1 :]
row_categories_sorted = row_categories .sort_values (ascending = False )
return row_categories_sorted .index .values [0 :num_top_venues ]
num_top_venues = 5
indicators = ['st' , 'nd' , 'rd' ]
# create columns according to number of top venues
columns = ['Neighborhoods' ]
for ind in np .arange (num_top_venues ):
try :
columns .append ('{}{} Most Common Venue' .format (ind + 1 , indicators [ind ]))
except :
columns .append ('{}th Most Common Venue' .format (ind + 1 ))
# create a new dataframe
neighborhoods_venues_sorted = pd .DataFrame (columns = columns )
neighborhoods_venues_sorted ['Neighborhoods' ] = toronto_grouped ['Neighborhoods' ]
for ind in np .arange (toronto_grouped .shape [0 ]):
neighborhoods_venues_sorted .iloc [ind , 1 :] = return_most_common_venues (toronto_grouped .iloc [ind , :], num_top_venues )
neighborhoods_venues_sorted .rename (columns = {'Neighborhoods' :'Neighborhood' },inplace = True )
neighborhoods_venues_sorted .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
0
Adelaide, King, Richmond
Coffee Shop
Café
Bar
Steakhouse
American Restaurant
1
Berczy Park
Coffee Shop
Bakery
Café
Beer Bar
Cheese Shop
2
Brockton, Exhibition Place, Parkdale Village
Coffee Shop
Café
Breakfast Spot
Grocery Store
Intersection
3
Business Reply Mail Processing Centre 969 Eastern
Light Rail Station
Pizza Place
Auto Workshop
Comic Shop
Recording Studio
4
CN Tower, Bathurst Quay, Island airport, Harbo...
Airport Service
Airport Lounge
Plane
Boutique
Bar
Clustering the neighborhoods using Kmeans
# set number of clusters
kclusters = 5
toronto_grouped_clustering = toronto_grouped .drop ('Neighborhoods' , 1 )
# run k-means clustering
kmeans = KMeans (n_clusters = kclusters , random_state = 0 ).fit (toronto_grouped_clustering )
# check cluster labels generated for each row in the dataframe
kmeans .labels_
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
4, 0, 1, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32)
Creating a dataframe with cluster labels and the top 5 venues
# add clustering labels
neighborhoods_venues_sorted .insert (0 , 'Cluster Labels' , kmeans .labels_ )
toronto_merged = df_toronto
# merge toronto_grouped with toronto_data to add latitude/longitude for each neighborhood
toronto_merged = toronto_merged .join (neighborhoods_venues_sorted .set_index ('Neighborhood' ), on = 'Neighborhood' )
toronto_merged .head ()
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
PostalCode
Borough
Neighborhood
Latitude
Longitude
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
0
M4E
East Toronto
The Beaches
43.676357
-79.293031
0
Neighborhood
Health Food Store
Pub
Trail
Event Space
1
M4K
East Toronto
The Danforth West, Riverdale
43.679557
-79.352188
0
Greek Restaurant
Coffee Shop
Ice Cream Shop
Italian Restaurant
Furniture / Home Store
2
M4L
East Toronto
The Beaches West, India Bazaar
43.668999
-79.315572
0
Park
Sandwich Place
Brewery
Steakhouse
Sushi Restaurant
3
M4M
East Toronto
Studio District
43.659526
-79.340923
0
Café
Coffee Shop
Bakery
Italian Restaurant
American Restaurant
4
M4N
Central Toronto
Lawrence Park
43.728020
-79.388790
4
Park
Swim School
Bus Line
Yoga Studio
Diner
We will display the neighborhoods along with their cluster labels and colours on a map below
# create map
map_clusters = folium .Map (location = [latitude , longitude ], zoom_start = 12 )
# set color scheme for the clusters
x = np .arange (kclusters )
ys = [i + x + (i * x )** 2 for i in range (kclusters )]
colors_array = cm .rainbow (np .linspace (0 , 1 , len (ys )))
rainbow = [colors .rgb2hex (i ) for i in colors_array ]
# add markers to the map
markers_colors = []
for lat , lon , bor , poi , cluster in zip (toronto_merged ['Latitude' ], toronto_merged ['Longitude' ],toronto_merged ['Borough' ], toronto_merged ['Neighborhood' ], toronto_merged ['Cluster Labels' ]):
label = folium .Popup (str (bor )+ ': ' + str (poi ) + ' Cluster ' + str (cluster ), parse_html = True )
folium .CircleMarker (
[lat , lon ],
radius = 5 ,
popup = label ,
color = rainbow [cluster - 1 ],
fill = True ,
fill_color = rainbow [cluster - 1 ],
fill_opacity = 0.7 ).add_to (map_clusters )
map_clusters
<iframe src="data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdnaXQuY29tL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9tYXN0ZXIvZm9saXVtL3RlbXBsYXRlcy9sZWFmbGV0LmF3ZXNvbWUucm90YXRlLmNzcyIvPgogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIAogICAgICAgICAgICA8c3R5bGU+ICNtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQgewogICAgICAgICAgICAgICAgcG9zaXRpb24gOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgIHdpZHRoIDogMTAwLjAlOwogICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0IiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IG51bGw7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgdmFyIG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCA9IEwubWFwKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2VudGVyOiBbNDMuNjY3MjYyMTg0MjEwNTIsLTc5LjM4OTg4MzIzNDIxMDUzXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHpvb206IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Qm91bmRzOiBib3VuZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXllcnM6IFtdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ybGRDb3B5SnVtcDogZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnM6IEwuQ1JTLkVQU0czODU3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgdGlsZV9sYXllcl84ZTU5Njk1Y2JkYzQ0ZGNmYTdlZjNhMjM1OTg1MTExNSA9IEwudGlsZUxheWVyKAogICAgICAgICAgICAgICAgJ2h0dHBzOi8ve3N9LnRpbGUub3BlbnN0cmVldG1hcC5vcmcve3p9L3t4fS97eX0ucG5nJywKICAgICAgICAgICAgICAgIHsKICAiYXR0cmlidXRpb24iOiBudWxsLAogICJkZXRlY3RSZXRpbmEiOiBmYWxzZSwKICAibWF4Wm9vbSI6IDE4LAogICJtaW5ab29tIjogMSwKICAibm9XcmFwIjogZmFsc2UsCiAgInN1YmRvbWFpbnMiOiAiYWJjIgp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDM4Y2UwZDUxOTBkNDBhYTlhNGJhMmQ3MGEyMDcyNjggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NzYzNTczOTk5OTk5OSwtNzkuMjkzMDMxMl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zNjk2NGJiYjJiNzE0N2U3YTNlMWQyYzA4NDU5ZTc0NiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82ODI4NTkyYmNiZjk0ZGIyOGJmMjAxZWQwMjNlMmM0NiA9ICQoJzxkaXYgaWQ9Imh0bWxfNjgyODU5MmJjYmY5NGRiMjhiZjIwMWVkMDIzZTJjNDYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkVhc3QgVG9yb250bzogVGhlIEJlYWNoZXMgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zNjk2NGJiYjJiNzE0N2U3YTNlMWQyYzA4NDU5ZTc0Ni5zZXRDb250ZW50KGh0bWxfNjgyODU5MmJjYmY5NGRiMjhiZjIwMWVkMDIzZTJjNDYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZDM4Y2UwZDUxOTBkNDBhYTlhNGJhMmQ3MGEyMDcyNjguYmluZFBvcHVwKHBvcHVwXzM2OTY0YmJiMmI3MTQ3ZTdhM2UxZDJjMDg0NTllNzQ2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzc0ODhhNjhjMGY0ZTQwZGZhM2ZjYjY4Y2M3NDc4OTUzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjc5NTU3MSwtNzkuMzUyMTg4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzBmZWFhZDI5YmFkYzQxM2NhNjk3NWRjODE0MzVhNGQxID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJlNjQ3NzI0NDk2MDQzYjJiOGE2Y2RhYjMxZjY3MDRhID0gJCgnPGRpdiBpZD0iaHRtbF8yZTY0NzcyNDQ5NjA0M2IyYjhhNmNkYWIzMWY2NzA0YSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RWFzdCBUb3JvbnRvOiBUaGUgRGFuZm9ydGggV2VzdCwgUml2ZXJkYWxlIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMGZlYWFkMjliYWRjNDEzY2E2OTc1ZGM4MTQzNWE0ZDEuc2V0Q29udGVudChodG1sXzJlNjQ3NzI0NDk2MDQzYjJiOGE2Y2RhYjMxZjY3MDRhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzc0ODhhNjhjMGY0ZTQwZGZhM2ZjYjY4Y2M3NDc4OTUzLmJpbmRQb3B1cChwb3B1cF8wZmVhYWQyOWJhZGM0MTNjYTY5NzVkYzgxNDM1YTRkMSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl80NjZkYTFkODE5NzU0Yjc4OTFjZjBiNDhlNmJhNTVlMSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2ODk5ODUsLTc5LjMxNTU3MTU5OTk5OTk4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzQ1OGJhYjIyMGFiYzRmY2ViMzk0MDI5MjBmYTMyYTk3ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzQ5NzAzNWQ1Y2VmMDRiYTQ5YWI1OWEzZDMwMmNhNzNhID0gJCgnPGRpdiBpZD0iaHRtbF80OTcwMzVkNWNlZjA0YmE0OWFiNTlhM2QzMDJjYTczYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RWFzdCBUb3JvbnRvOiBUaGUgQmVhY2hlcyBXZXN0LCBJbmRpYSBCYXphYXIgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80NThiYWIyMjBhYmM0ZmNlYjM5NDAyOTIwZmEzMmE5Ny5zZXRDb250ZW50KGh0bWxfNDk3MDM1ZDVjZWYwNGJhNDlhYjU5YTNkMzAyY2E3M2EpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNDY2ZGExZDgxOTc1NGI3ODkxY2YwYjQ4ZTZiYTU1ZTEuYmluZFBvcHVwKHBvcHVwXzQ1OGJhYjIyMGFiYzRmY2ViMzk0MDI5MjBmYTMyYTk3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y3MDVjOGU0Y2EwODQwZWNiZmVhMjliNzY5NTZlY2Y5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjU5NTI1NSwtNzkuMzQwOTIzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzA0YjMxMDQxMDU3YzQ4NTRhYzA2NjRmYjUwZDM2MDA2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzgyNzllYWQ3Y2Q0MDQ3MjJiN2E0MDdkNTk0YjdjMDc4ID0gJCgnPGRpdiBpZD0iaHRtbF84Mjc5ZWFkN2NkNDA0NzIyYjdhNDA3ZDU5NGI3YzA3OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RWFzdCBUb3JvbnRvOiBTdHVkaW8gRGlzdHJpY3QgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8wNGIzMTA0MTA1N2M0ODU0YWMwNjY0ZmI1MGQzNjAwNi5zZXRDb250ZW50KGh0bWxfODI3OWVhZDdjZDQwNDcyMmI3YTQwN2Q1OTRiN2MwNzgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZjcwNWM4ZTRjYTA4NDBlY2JmZWEyOWI3Njk1NmVjZjkuYmluZFBvcHVwKHBvcHVwXzA0YjMxMDQxMDU3YzQ4NTRhYzA2NjRmYjUwZDM2MDA2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzViNzUxMTE4ODE5ZTQ5YjRhYTMwNDM5Y2ZjY2Y1ZGIxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzI4MDIwNSwtNzkuMzg4NzkwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmZiMzYwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmYjM2MCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83ODM3NzUxYTUxYTA0MjQ1OTI4MTVkMTBiMmIyNTI2OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80ZTYwNWFhYmQ0N2Q0NDU5OWQ2Y2VjMmI3ZmY4OTMxMyA9ICQoJzxkaXYgaWQ9Imh0bWxfNGU2MDVhYWJkNDdkNDQ1OTlkNmNlYzJiN2ZmODkzMTMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlbnRyYWwgVG9yb250bzogTGF3cmVuY2UgUGFyayBDbHVzdGVyIDQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzc4Mzc3NTFhNTFhMDQyNDU5MjgxNWQxMGIyYjI1MjY4LnNldENvbnRlbnQoaHRtbF80ZTYwNWFhYmQ0N2Q0NDU5OWQ2Y2VjMmI3ZmY4OTMxMyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl81Yjc1MTExODgxOWU0OWI0YWEzMDQzOWNmY2NmNWRiMS5iaW5kUG9wdXAocG9wdXBfNzgzNzc1MWE1MWEwNDI0NTkyODE1ZDEwYjJiMjUyNjgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDZhNjlkMjc3YjRjNDY1NmE1YzA0ZGZiZDk3MGU1YzEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTI3NTExLC03OS4zOTAxOTc1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2YyNWI2OTI0ZGEyOTQ2YWNiMWI3YTRhOTU1ZTM3ZDBjID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzA1MzNlOTkxY2M2ZTRjN2JiNDFmMjc2OWExOGIyZDhjID0gJCgnPGRpdiBpZD0iaHRtbF8wNTMzZTk5MWNjNmU0YzdiYjQxZjI3NjlhMThiMmQ4YyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBEYXZpc3ZpbGxlIE5vcnRoIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZjI1YjY5MjRkYTI5NDZhY2IxYjdhNGE5NTVlMzdkMGMuc2V0Q29udGVudChodG1sXzA1MzNlOTkxY2M2ZTRjN2JiNDFmMjc2OWExOGIyZDhjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzQ2YTY5ZDI3N2I0YzQ2NTZhNWMwNGRmYmQ5NzBlNWMxLmJpbmRQb3B1cChwb3B1cF9mMjViNjkyNGRhMjk0NmFjYjFiN2E0YTk1NWUzN2QwYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81OGQ0MDU3NGQxZDM0NjhiODI4YTcyMGY2Y2Q5NGFhZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjcxNTM4MzQsLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzE3YWY5NDk1MzgyYjQwNzlhMTIwYzIxYjM4ZGQ4MzMyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzhhZDVhNTMxMzEzNTQxZmZiMTAwMjM2NmYyZTY0M2E3ID0gJCgnPGRpdiBpZD0iaHRtbF84YWQ1YTUzMTMxMzU0MWZmYjEwMDIzNjZmMmU2NDNhNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBOb3J0aCBUb3JvbnRvIFdlc3QgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xN2FmOTQ5NTM4MmI0MDc5YTEyMGMyMWIzOGRkODMzMi5zZXRDb250ZW50KGh0bWxfOGFkNWE1MzEzMTM1NDFmZmIxMDAyMzY2ZjJlNjQzYTcpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNThkNDA1NzRkMWQzNDY4YjgyOGE3MjBmNmNkOTRhYWQuYmluZFBvcHVwKHBvcHVwXzE3YWY5NDk1MzgyYjQwNzlhMTIwYzIxYjM4ZGQ4MzMyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Q1Y2MyY2ZiZTc4ZDQyMWI5NTZjZmJiMzYxMTI4OGE1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNzA0MzI0NCwtNzkuMzg4NzkwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83MjcxYjIxMDRmMGM0YThmYmZiNjIyZWI1OWNmMmFjYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83NzQzMjBkMDhhM2Y0YjI2OTI5OWVhZjQ4YmI4NzhlZSA9ICQoJzxkaXYgaWQ9Imh0bWxfNzc0MzIwZDA4YTNmNGIyNjkyOTllYWY0OGJiODc4ZWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlbnRyYWwgVG9yb250bzogRGF2aXN2aWxsZSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzcyNzFiMjEwNGYwYzRhOGZiZmI2MjJlYjU5Y2YyYWNjLnNldENvbnRlbnQoaHRtbF83NzQzMjBkMDhhM2Y0YjI2OTI5OWVhZjQ4YmI4NzhlZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9kNWNjMmNmYmU3OGQ0MjFiOTU2Y2ZiYjM2MTEyODhhNS5iaW5kUG9wdXAocG9wdXBfNzI3MWIyMTA0ZjBjNGE4ZmJmYjYyMmViNTljZjJhY2MpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYmVhNDI4ODZhMGZkNDdmNDgxMWEyN2M5YmE2MWJmMTIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42ODk1NzQzLC03OS4zODMxNTk5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjODAwMGZmIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzgwMDBmZiIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yMjRmYWVlNDc1Yzk0MDBiODVkY2UzMGI3NjhmMjc2ZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iZjAzMmRiZWQzZjE0ZmRlYjI3Yjg2MTI3MjNiYzY0OCA9ICQoJzxkaXYgaWQ9Imh0bWxfYmYwMzJkYmVkM2YxNGZkZWIyN2I4NjEyNzIzYmM2NDgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlbnRyYWwgVG9yb250bzogTW9vcmUgUGFyaywgU3VtbWVyaGlsbCBFYXN0IENsdXN0ZXIgMTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjI0ZmFlZTQ3NWM5NDAwYjg1ZGNlMzBiNzY4ZjI3NmQuc2V0Q29udGVudChodG1sX2JmMDMyZGJlZDNmMTRmZGViMjdiODYxMjcyM2JjNjQ4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2JlYTQyODg2YTBmZDQ3ZjQ4MTFhMjdjOWJhNjFiZjEyLmJpbmRQb3B1cChwb3B1cF8yMjRmYWVlNDc1Yzk0MDBiODVkY2UzMGI3NjhmMjc2ZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iMTM2NDViZDEwNzg0MzY2YTQ1ZTZlZGE2NDU4ZjI2ZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY4NjQxMjI5OTk5OTk5LC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2U1ZWFhOWVhN2YxMjQ2MGJhMTMwNGJkNmM3MWVkYTE4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzhmYTMyZDcwZWUwZDQzYmE5NTc0OGJjNDI5NzI1NjdhID0gJCgnPGRpdiBpZD0iaHRtbF84ZmEzMmQ3MGVlMGQ0M2JhOTU3NDhiYzQyOTcyNTY3YSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBEZWVyIFBhcmssIEZvcmVzdCBIaWxsIFNFLCBSYXRobmVsbHksIFNvdXRoIEhpbGwsIFN1bW1lcmhpbGwgV2VzdCBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2U1ZWFhOWVhN2YxMjQ2MGJhMTMwNGJkNmM3MWVkYTE4LnNldENvbnRlbnQoaHRtbF84ZmEzMmQ3MGVlMGQ0M2JhOTU3NDhiYzQyOTcyNTY3YSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9iMTM2NDViZDEwNzg0MzY2YTQ1ZTZlZGE2NDU4ZjI2ZS5iaW5kUG9wdXAocG9wdXBfZTVlYWE5ZWE3ZjEyNDYwYmExMzA0YmQ2YzcxZWRhMTgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfY2M2ZTI3M2I3MjU5NGU4MmEyOGY5N2UwODdkY2I3NDEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Nzk1NjI2LC03OS4zNzc1Mjk0MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjODAwMGZmIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzgwMDBmZiIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82ODkxMWNlYTNiY2E0ZTIyOWZlOTc5NjY3ZjM0ZGUyNCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kZjUxNTBhZmZkMzE0YTcxOWE1NTBiYjlhOGI0NzU3YiA9ICQoJzxkaXYgaWQ9Imh0bWxfZGY1MTUwYWZmZDMxNGE3MTlhNTUwYmI5YThiNDc1N2IiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IFJvc2VkYWxlIENsdXN0ZXIgMTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjg5MTFjZWEzYmNhNGUyMjlmZTk3OTY2N2YzNGRlMjQuc2V0Q29udGVudChodG1sX2RmNTE1MGFmZmQzMTRhNzE5YTU1MGJiOWE4YjQ3NTdiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2NjNmUyNzNiNzI1OTRlODJhMjhmOTdlMDg3ZGNiNzQxLmJpbmRQb3B1cChwb3B1cF82ODkxMWNlYTNiY2E0ZTIyOWZlOTc5NjY3ZjM0ZGUyNCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lZTA2ZTllZmFkYWY0YTRjYmViMDkyMjY4ZTkxZTkwZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2Nzk2NywtNzkuMzY3Njc1M10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82MzZlYzY2MDZjMTU0N2JlOWRjMTk3ZmZiOGRiNmVmYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jMjk2YjhmOGYzMjI0MWI4OGE5NmNkZjgxNTVkOWUwNSA9ICQoJzxkaXYgaWQ9Imh0bWxfYzI5NmI4ZjhmMzIyNDFiODhhOTZjZGY4MTU1ZDllMDUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENhYmJhZ2V0b3duLCBTdC4gSmFtZXMgVG93biBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzYzNmVjNjYwNmMxNTQ3YmU5ZGMxOTdmZmI4ZGI2ZWZjLnNldENvbnRlbnQoaHRtbF9jMjk2YjhmOGYzMjI0MWI4OGE5NmNkZjgxNTVkOWUwNSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9lZTA2ZTllZmFkYWY0YTRjYmViMDkyMjY4ZTkxZTkwZC5iaW5kUG9wdXAocG9wdXBfNjM2ZWM2NjA2YzE1NDdiZTlkYzE5N2ZmYjhkYjZlZmMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMzlhMDRkYzc4YTE5NDM0YjkzMmRmZDFmZjQ4NDNkOWMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjU4NTk5LC03OS4zODMxNTk5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xNmU4NTQ3MDVmNWM0NTMwYmYwM2UzODMwYjBlMDk4NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82NDVmM2U1NmY5ZWU0OTMyYjM2ZjIzYjkzZjRiNjI5YSA9ICQoJzxkaXYgaWQ9Imh0bWxfNjQ1ZjNlNTZmOWVlNDkzMmIzNmYyM2I5M2Y0YjYyOWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENodXJjaCBhbmQgV2VsbGVzbGV5IENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMTZlODU0NzA1ZjVjNDUzMGJmMDNlMzgzMGIwZTA5ODQuc2V0Q29udGVudChodG1sXzY0NWYzZTU2ZjllZTQ5MzJiMzZmMjNiOTNmNGI2MjlhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzM5YTA0ZGM3OGExOTQzNGI5MzJkZmQxZmY0ODQzZDljLmJpbmRQb3B1cChwb3B1cF8xNmU4NTQ3MDVmNWM0NTMwYmYwM2UzODMwYjBlMDk4NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kYThmYjA5NjM5OWI0NWZiYjI0YjE5MWFhNzNlZGRhOCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1NDI1OTksLTc5LjM2MDYzNTldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMjNhZWVkODcxMjQ5NDU5ZGE0YzYyMzQxNTM1NTBjMDMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2E4NmIyOWJmNDdjNDMzMGI2NDU5M2Y1ODg1ODE5ODAgPSAkKCc8ZGl2IGlkPSJodG1sX2NhODZiMjliZjQ3YzQzMzBiNjQ1OTNmNTg4NTgxOTgwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBIYXJib3VyZnJvbnQgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yM2FlZWQ4NzEyNDk0NTlkYTRjNjIzNDE1MzU1MGMwMy5zZXRDb250ZW50KGh0bWxfY2E4NmIyOWJmNDdjNDMzMGI2NDU5M2Y1ODg1ODE5ODApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZGE4ZmIwOTYzOTliNDVmYmIyNGIxOTFhYTczZWRkYTguYmluZFBvcHVwKHBvcHVwXzIzYWVlZDg3MTI0OTQ1OWRhNGM2MjM0MTUzNTUwYzAzKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IzYjUwOWQ2MDc0MjRlMGNiNWI3Mzc5Y2MwNGMwMjEzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjU3MTYxOCwtNzkuMzc4OTM3MDk5OTk5OTldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjMyNTQ0ZTEwM2E5NGZlY2FjY2NmN2FjMzA3ZmI2OGUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2YwMTQxMzI2YTY3NDMwMDgyYTMxYjRiYjRjNzRkYTAgPSAkKCc8ZGl2IGlkPSJodG1sXzdmMDE0MTMyNmE2NzQzMDA4MmEzMWI0YmI0Yzc0ZGEwIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBSeWVyc29uLCBHYXJkZW4gRGlzdHJpY3QgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9iMzI1NDRlMTAzYTk0ZmVjYWNjY2Y3YWMzMDdmYjY4ZS5zZXRDb250ZW50KGh0bWxfN2YwMTQxMzI2YTY3NDMwMDgyYTMxYjRiYjRjNzRkYTApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYjNiNTA5ZDYwNzQyNGUwY2I1YjczNzljYzA0YzAyMTMuYmluZFBvcHVwKHBvcHVwX2IzMjU0NGUxMDNhOTRmZWNhY2NjZjdhYzMwN2ZiNjhlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzc5MDAzZTQwMGVjYjQ3MmE4Y2IwOGQ3YjA4YWM2NjFlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUxNDkzOSwtNzkuMzc1NDE3OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xMGJjMTk4YjlmNmQ0MTBmODIxNjIyN2JlMDkxYjhiNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81NDRmYTNkYzNjZjc0YjljYmNhMTljZDc3NGMwYTg3NCA9ICQoJzxkaXYgaWQ9Imh0bWxfNTQ0ZmEzZGMzY2Y3NGI5Y2JjYTE5Y2Q3NzRjMGE4NzQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IFN0LiBKYW1lcyBUb3duIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMTBiYzE5OGI5ZjZkNDEwZjgyMTYyMjdiZTA5MWI4YjUuc2V0Q29udGVudChodG1sXzU0NGZhM2RjM2NmNzRiOWNiY2ExOWNkNzc0YzBhODc0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzc5MDAzZTQwMGVjYjQ3MmE4Y2IwOGQ3YjA4YWM2NjFlLmJpbmRQb3B1cChwb3B1cF8xMGJjMTk4YjlmNmQ0MTBmODIxNjIyN2JlMDkxYjhiNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85NTBlMWY3MzA1Njg0NTI3OWYyYzRlOThlM2Q1MGUwMCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NDc3MDc5OTk5OTk5NiwtNzkuMzczMzA2NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82OTkzMGYyZTBhY2Y0ZTc2YWY2NGNhNTNjZWYyNzg2OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9hMmRlZDMyNGJjMWU0NjM4OTc2ZjZmN2Q0NzU3OGMyNiA9ICQoJzxkaXYgaWQ9Imh0bWxfYTJkZWQzMjRiYzFlNDYzODk3NmY2ZjdkNDc1NzhjMjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IEJlcmN6eSBQYXJrIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjk5MzBmMmUwYWNmNGU3NmFmNjRjYTUzY2VmMjc4Njguc2V0Q29udGVudChodG1sX2EyZGVkMzI0YmMxZTQ2Mzg5NzZmNmY3ZDQ3NTc4YzI2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzk1MGUxZjczMDU2ODQ1Mjc5ZjJjNGU5OGUzZDUwZTAwLmJpbmRQb3B1cChwb3B1cF82OTkzMGYyZTBhY2Y0ZTc2YWY2NGNhNTNjZWYyNzg2OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84YmZmMmVhYmYxNTc0YWFiYTBiNDY1N2QyMjBkZDViYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1Nzk1MjQsLTc5LjM4NzM4MjZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZjQyZTA2ZjIyMGJiNDI4NWIzMGMyZjUxNWU5YWI3MDcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYWNhMjMwNTRjZGFkNDBlYWE3ZWEyM2EyNzAyOWViZjIgPSAkKCc8ZGl2IGlkPSJodG1sX2FjYTIzMDU0Y2RhZDQwZWFhN2VhMjNhMjcwMjllYmYyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBDZW50cmFsIEJheSBTdHJlZXQgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mNDJlMDZmMjIwYmI0Mjg1YjMwYzJmNTE1ZTlhYjcwNy5zZXRDb250ZW50KGh0bWxfYWNhMjMwNTRjZGFkNDBlYWE3ZWEyM2EyNzAyOWViZjIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfOGJmZjJlYWJmMTU3NGFhYmEwYjQ2NTdkMjIwZGQ1YmIuYmluZFBvcHVwKHBvcHVwX2Y0MmUwNmYyMjBiYjQyODViMzBjMmY1MTVlOWFiNzA3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzgzOTc0NWUwYmJiMzRlMjRhODViZWU3ZmQ2YjkwODlmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjUwNTcxMjAwMDAwMDEsLTc5LjM4NDU2NzVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTdkNjVlNTdiMzYzNGFjMjkyNjNkN2YzYWQ3MTliNjEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOWRiM2M0NGE0MDhlNGY1NmI4YjA4YmIyMzNkM2Q1NzYgPSAkKCc8ZGl2IGlkPSJodG1sXzlkYjNjNDRhNDA4ZTRmNTZiOGIwOGJiMjMzZDNkNTc2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBBZGVsYWlkZSwgS2luZywgUmljaG1vbmQgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hN2Q2NWU1N2IzNjM0YWMyOTI2M2Q3ZjNhZDcxOWI2MS5zZXRDb250ZW50KGh0bWxfOWRiM2M0NGE0MDhlNGY1NmI4YjA4YmIyMzNkM2Q1NzYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfODM5NzQ1ZTBiYmIzNGUyNGE4NWJlZTdmZDZiOTA4OWYuYmluZFBvcHVwKHBvcHVwX2E3ZDY1ZTU3YjM2MzRhYzI5MjYzZDdmM2FkNzE5YjYxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzdlNmVmYzUwOWQ0MDQ3NDI5YWUxMDkxOWNhMzhhMTA1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQwODE1NywtNzkuMzgxNzUyMjk5OTk5OTldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTQ5MGM3MDQzOGRhNDVlM2I5MDAwNzZlZDczNjhjZDAgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYTk1MzliYTU3NjVlNDc2MDhjNDU0MzEzYTU4MTI4N2YgPSAkKCc8ZGl2IGlkPSJodG1sX2E5NTM5YmE1NzY1ZTQ3NjA4YzQ1NDMxM2E1ODEyODdmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBIYXJib3VyZnJvbnQgRWFzdCwgVG9yb250byBJc2xhbmRzLCBVbmlvbiBTdGF0aW9uIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTQ5MGM3MDQzOGRhNDVlM2I5MDAwNzZlZDczNjhjZDAuc2V0Q29udGVudChodG1sX2E5NTM5YmE1NzY1ZTQ3NjA4YzQ1NDMxM2E1ODEyODdmKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzdlNmVmYzUwOWQ0MDQ3NDI5YWUxMDkxOWNhMzhhMTA1LmJpbmRQb3B1cChwb3B1cF9hNDkwYzcwNDM4ZGE0NWUzYjkwMDA3NmVkNzM2OGNkMCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iNDQwMmIzYjRlNDQ0NDYxYWU1ZGU3MjhhMzIwNTlhZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NzE3NjgsLTc5LjM4MTU3NjQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2FjOTc3ZjFjZWI2MzRmYmNiMjRhYTk1NjEwZWM5MjZhID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzU5MjM0N2Y3MWI1MTQ1NGRhZmY3ZTZlMzNiY2EzNjc4ID0gJCgnPGRpdiBpZD0iaHRtbF81OTIzNDdmNzFiNTE0NTRkYWZmN2U2ZTMzYmNhMzY3OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogRGVzaWduIEV4Y2hhbmdlLCBUb3JvbnRvIERvbWluaW9uIENlbnRyZSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2FjOTc3ZjFjZWI2MzRmYmNiMjRhYTk1NjEwZWM5MjZhLnNldENvbnRlbnQoaHRtbF81OTIzNDdmNzFiNTE0NTRkYWZmN2U2ZTMzYmNhMzY3OCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9iNDQwMmIzYjRlNDQ0NDYxYWU1ZGU3MjhhMzIwNTlhZS5iaW5kUG9wdXAocG9wdXBfYWM5NzdmMWNlYjYzNGZiY2IyNGFhOTU2MTBlYzkyNmEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYTYyYjU3MzM3MGYxNDUzNzhmZjBkYWM4M2I2MGU2MzkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDgxOTg1LC03OS4zNzk4MTY5MDAwMDAwMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jMjVkMTE1NWNlZDE0MmUyYjU0MDZjODkzNWM1M2JmOSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82NjUyZmJiNjEwYmY0Y2M1YTdhMmRjYjdiMjA4OWQwZCA9ICQoJzxkaXYgaWQ9Imh0bWxfNjY1MmZiYjYxMGJmNGNjNWE3YTJkY2I3YjIwODlkMGQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENvbW1lcmNlIENvdXJ0LCBWaWN0b3JpYSBIb3RlbCBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2MyNWQxMTU1Y2VkMTQyZTJiNTQwNmM4OTM1YzUzYmY5LnNldENvbnRlbnQoaHRtbF82NjUyZmJiNjEwYmY0Y2M1YTdhMmRjYjdiMjA4OWQwZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9hNjJiNTczMzcwZjE0NTM3OGZmMGRhYzgzYjYwZTYzOS5iaW5kUG9wdXAocG9wdXBfYzI1ZDExNTVjZWQxNDJlMmI1NDA2Yzg5MzVjNTNiZjkpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZmZkODE3ZThjNDk4NGQ4ZDkwNWFmZmMyZDEyM2UyNDMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My43MTE2OTQ4LC03OS40MTY5MzU1OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjMDBiNWViIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiIzAwYjVlYiIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF84ODhlNDA4NGM2MGI0MzZiYjA5MzI0ODFhYmIyNTRlOCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82ZDg3MTEwMDNhNTU0M2Y4OGZiZTRiZWUzZjA3MGVlYyA9ICQoJzxkaXYgaWQ9Imh0bWxfNmQ4NzExMDAzYTU1NDNmODhmYmU0YmVlM2YwNzBlZWMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNlbnRyYWwgVG9yb250bzogUm9zZWxhd24gQ2x1c3RlciAyPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ODhlNDA4NGM2MGI0MzZiYjA5MzI0ODFhYmIyNTRlOC5zZXRDb250ZW50KGh0bWxfNmQ4NzExMDAzYTU1NDNmODhmYmU0YmVlM2YwNzBlZWMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZmZkODE3ZThjNDk4NGQ4ZDkwNWFmZmMyZDEyM2UyNDMuYmluZFBvcHVwKHBvcHVwXzg4OGU0MDg0YzYwYjQzNmJiMDkzMjQ4MWFiYjI1NGU4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzk3NTA0NDAzMWRhODRmMjU4YWUyODQyZDdjMjE2ZGIzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjk2OTQ3NiwtNzkuNDExMzA3MjAwMDAwMDFdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiIzgwZmZiNCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiM4MGZmYjQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOTUzYzhlNDdiOGFhNDM0NWJkMzU3N2YzMTI1N2VhYWQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2QxYWNmMGFlMzNkNDc4YjgwOWFjZDZkMmU0NzA3NmIgPSAkKCc8ZGl2IGlkPSJodG1sX2NkMWFjZjBhZTMzZDQ3OGI4MDlhY2Q2ZDJlNDcwNzZiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DZW50cmFsIFRvcm9udG86IEZvcmVzdCBIaWxsIE5vcnRoLCBGb3Jlc3QgSGlsbCBXZXN0IENsdXN0ZXIgMzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOTUzYzhlNDdiOGFhNDM0NWJkMzU3N2YzMTI1N2VhYWQuc2V0Q29udGVudChodG1sX2NkMWFjZjBhZTMzZDQ3OGI4MDlhY2Q2ZDJlNDcwNzZiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzk3NTA0NDAzMWRhODRmMjU4YWUyODQyZDdjMjE2ZGIzLmJpbmRQb3B1cChwb3B1cF85NTNjOGU0N2I4YWE0MzQ1YmQzNTc3ZjMxMjU3ZWFhZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82MDM3YjU1Mjk2NDI0YjQyOGZkYTYyM2ZlNzg0M2ZjYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3MjcwOTcsLTc5LjQwNTY3ODQwMDAwMDAxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzUxOTg2YzRiYzA0NTRlNjc5NzJjYjg0NTE3OTBiMjdkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzkxOGM0NGQ1ODk1ZTQ1MDNhYzJiNDUxZDYzNzEwY2Y0ID0gJCgnPGRpdiBpZD0iaHRtbF85MThjNDRkNTg5NWU0NTAzYWMyYjQ1MWQ2MzcxMGNmNCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2VudHJhbCBUb3JvbnRvOiBUaGUgQW5uZXgsIE5vcnRoIE1pZHRvd24sIFlvcmt2aWxsZSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzUxOTg2YzRiYzA0NTRlNjc5NzJjYjg0NTE3OTBiMjdkLnNldENvbnRlbnQoaHRtbF85MThjNDRkNTg5NWU0NTAzYWMyYjQ1MWQ2MzcxMGNmNCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl82MDM3YjU1Mjk2NDI0YjQyOGZkYTYyM2ZlNzg0M2ZjYy5iaW5kUG9wdXAocG9wdXBfNTE5ODZjNGJjMDQ1NGU2Nzk3MmNiODQ1MTc5MGIyN2QpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzAxYWE3YzdlMjdiNDQyMWE2Yjg0N2YwZDc4ODQxNTMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjI2OTU2LC03OS40MDAwNDkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2ViNWZiOTA4N2Q1ZjQ0OGI5MGQ1MjIzMDFlZDQ1NDE0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2U4Y2I2NmZmZGU5YTRjZmFhZmU1YzJmMmJjMzVkOTQ4ID0gJCgnPGRpdiBpZD0iaHRtbF9lOGNiNjZmZmRlOWE0Y2ZhYWZlNWMyZjJiYzM1ZDk0OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogSGFyYm9yZCwgVW5pdmVyc2l0eSBvZiBUb3JvbnRvIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZWI1ZmI5MDg3ZDVmNDQ4YjkwZDUyMjMwMWVkNDU0MTQuc2V0Q29udGVudChodG1sX2U4Y2I2NmZmZGU5YTRjZmFhZmU1YzJmMmJjMzVkOTQ4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzcwMWFhN2M3ZTI3YjQ0MjFhNmI4NDdmMGQ3ODg0MTUzLmJpbmRQb3B1cChwb3B1cF9lYjVmYjkwODdkNWY0NDhiOTBkNTIyMzAxZWQ0NTQxNCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85MWQzNzk3NjM2MjE0YmNhOTQ1NmMwMGQyYTc1Y2FhYyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MzIwNTcsLTc5LjQwMDA0OTNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTQ0OWJkZGQ5NDM4NDk0Zjg4MzlkNjc2MjA0Mjc2MzAgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWI5NmVkYzQzYzE5NGMwNTlhMDdjMjc1ZDRlMDkyYWMgPSAkKCc8ZGl2IGlkPSJodG1sXzFiOTZlZGM0M2MxOTRjMDU5YTA3YzI3NWQ0ZTA5MmFjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Eb3dudG93biBUb3JvbnRvOiBDaGluYXRvd24sIEdyYW5nZSBQYXJrLCBLZW5zaW5ndG9uIE1hcmtldCBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2E0NDliZGRkOTQzODQ5NGY4ODM5ZDY3NjIwNDI3NjMwLnNldENvbnRlbnQoaHRtbF8xYjk2ZWRjNDNjMTk0YzA1OWEwN2MyNzVkNGUwOTJhYyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl85MWQzNzk3NjM2MjE0YmNhOTQ1NmMwMGQyYTc1Y2FhYy5iaW5kUG9wdXAocG9wdXBfYTQ0OWJkZGQ5NDM4NDk0Zjg4MzlkNjc2MjA0Mjc2MzApOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjAyYzNmNmE2NzdiNGU3MGJiZmMzYTNlOGYzMzVlZWEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42Mjg5NDY3LC03OS4zOTQ0MTk5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzljNWM2ZWMzNzFjNTRhZTRhNjVjZTIwZWE1MDY2YTVhID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzRjM2ZhYjVkZTAzOTQ2MTViOWUyZDIyZjY1YTI5MzUwID0gJCgnPGRpdiBpZD0iaHRtbF80YzNmYWI1ZGUwMzk0NjE1YjllMmQyMmY2NWEyOTM1MCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RG93bnRvd24gVG9yb250bzogQ04gVG93ZXIsIEJhdGh1cnN0IFF1YXksIElzbGFuZCBhaXJwb3J0LCBIYXJib3VyZnJvbnQgV2VzdCwgS2luZyBhbmQgU3BhZGluYSwgUmFpbHdheSBMYW5kcywgU291dGggTmlhZ2FyYSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzljNWM2ZWMzNzFjNTRhZTRhNjVjZTIwZWE1MDY2YTVhLnNldENvbnRlbnQoaHRtbF80YzNmYWI1ZGUwMzk0NjE1YjllMmQyMmY2NWEyOTM1MCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8yMDJjM2Y2YTY3N2I0ZTcwYmJmYzNhM2U4ZjMzNWVlYS5iaW5kUG9wdXAocG9wdXBfOWM1YzZlYzM3MWM1NGFlNGE2NWNlMjBlYTUwNjZhNWEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZWNkZmQ2MDI5MTUxNDg5ZGExNTZjZmZlMDJjNDdjZmMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NDY0MzUyLC03OS4zNzQ4NDU5OTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF85NDA4N2ZkOWViM2Q0NmM0OGZkNDQ4YzE3NTBiOGU1NiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iYzYwM2I3ODcwMGM0NzZhOWZiNTBmNmU5NmFkYTM3MCA9ICQoJzxkaXYgaWQ9Imh0bWxfYmM2MDNiNzg3MDBjNDc2YTlmYjUwZjZlOTZhZGEzNzAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IFN0biBBIFBPIEJveGVzIDI1IFRoZSBFc3BsYW5hZGUgQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF85NDA4N2ZkOWViM2Q0NmM0OGZkNDQ4YzE3NTBiOGU1Ni5zZXRDb250ZW50KGh0bWxfYmM2MDNiNzg3MDBjNDc2YTlmYjUwZjZlOTZhZGEzNzApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZWNkZmQ2MDI5MTUxNDg5ZGExNTZjZmZlMDJjNDdjZmMuYmluZFBvcHVwKHBvcHVwXzk0MDg3ZmQ5ZWIzZDQ2YzQ4ZmQ0NDhjMTc1MGI4ZTU2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzJlZmRjZWI2ZmRiZDRlMTM4N2Y2ZmM0NDkwYzg5ZGQ4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ4NDI5MiwtNzkuMzgyMjgwMl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9iZDk1OTYyYWMxYTg0ODUyYTM4YjI5NWNmZDQ0NDc1ZSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81ZTJkMmJhNTZkYjU0ZWUzODZlZDJiZDQyY2UxMzExZCA9ICQoJzxkaXYgaWQ9Imh0bWxfNWUyZDJiYTU2ZGI1NGVlMzg2ZWQyYmQ0MmNlMTMxMWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IEZpcnN0IENhbmFkaWFuIFBsYWNlLCBVbmRlcmdyb3VuZCBjaXR5IENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmQ5NTk2MmFjMWE4NDg1MmEzOGIyOTVjZmQ0NDQ3NWUuc2V0Q29udGVudChodG1sXzVlMmQyYmE1NmRiNTRlZTM4NmVkMmJkNDJjZTEzMTFkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzJlZmRjZWI2ZmRiZDRlMTM4N2Y2ZmM0NDkwYzg5ZGQ4LmJpbmRQb3B1cChwb3B1cF9iZDk1OTYyYWMxYTg0ODUyYTM4YjI5NWNmZDQ0NDc1ZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl81MDY2NjNlMDg5Yjc0ZDM2OTAwNjU2MmM1OWZkNzQxNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2OTU0MiwtNzkuNDIyNTYzN10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xYTIzOWY3YzdkYWU0MGY4YjI5MjViNjIwZDU2YmFjYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zNjVjMmE4NmQ5YTA0ZmMwYmQ1M2U3ZjY1OGIwYTU4NCA9ICQoJzxkaXYgaWQ9Imh0bWxfMzY1YzJhODZkOWEwNGZjMGJkNTNlN2Y2NThiMGE1ODQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkRvd250b3duIFRvcm9udG86IENocmlzdGllIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMWEyMzlmN2M3ZGFlNDBmOGIyOTI1YjYyMGQ1NmJhY2Euc2V0Q29udGVudChodG1sXzM2NWMyYTg2ZDlhMDRmYzBiZDUzZTdmNjU4YjBhNTg0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzUwNjY2M2UwODliNzRkMzY5MDA2NTYyYzU5ZmQ3NDE2LmJpbmRQb3B1cChwb3B1cF8xYTIzOWY3YzdkYWU0MGY4YjI5MjViNjIwZDU2YmFjYSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kOGViOTk2NDUyYWM0MGEwYTg2ZjQ2NjVkNjlmYzBmNCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY2OTAwNTEwMDAwMDAxLC03OS40NDIyNTkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzBkODYyYmNmMTUyNzRjZGZhOTM3M2E4MjM4ODMwOWYzID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2IwNDAwNmU4NTAwMzQ4ZmY4Yzc4ZjY3MjBiNmViNWFiID0gJCgnPGRpdiBpZD0iaHRtbF9iMDQwMDZlODUwMDM0OGZmOGM3OGY2NzIwYjZlYjVhYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdCBUb3JvbnRvOiBEb3ZlcmNvdXJ0IFZpbGxhZ2UsIER1ZmZlcmluIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMGQ4NjJiY2YxNTI3NGNkZmE5MzczYTgyMzg4MzA5ZjMuc2V0Q29udGVudChodG1sX2IwNDAwNmU4NTAwMzQ4ZmY4Yzc4ZjY3MjBiNmViNWFiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2Q4ZWI5OTY0NTJhYzQwYTBhODZmNDY2NWQ2OWZjMGY0LmJpbmRQb3B1cChwb3B1cF8wZDg2MmJjZjE1Mjc0Y2RmYTkzNzNhODIzODgzMDlmMyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jNDA2ODQwYmQ0OGY0MTFhYjI3M2IyOTdlY2E0Y2FkZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY0NzkyNjcwMDAwMDAwNiwtNzkuNDE5NzQ5N10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mYjE0YzM5MzJjYmY0MDY2YjI1NmZjZTAwNmVmNjJhOCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81YTgzZmM5ZmM2OTc0NjI2YWQyMDY0NzkxNmMyYjRjMSA9ICQoJzxkaXYgaWQ9Imh0bWxfNWE4M2ZjOWZjNjk3NDYyNmFkMjA2NDc5MTZjMmI0YzEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldlc3QgVG9yb250bzogTGl0dGxlIFBvcnR1Z2FsLCBUcmluaXR5IENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZmIxNGMzOTMyY2JmNDA2NmIyNTZmY2UwMDZlZjYyYTguc2V0Q29udGVudChodG1sXzVhODNmYzlmYzY5NzQ2MjZhZDIwNjQ3OTE2YzJiNGMxKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2M0MDY4NDBiZDQ4ZjQxMWFiMjczYjI5N2VjYTRjYWRmLmJpbmRQb3B1cChwb3B1cF9mYjE0YzM5MzJjYmY0MDY2YjI1NmZjZTAwNmVmNjJhOCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82OWQ1MzlhNWIzOGI0YmRlYWIwMTc1ODAxZDFhNzI3MCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYzNjg0NzIsLTc5LjQyODE5MTQwMDAwMDAyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI1NjAwZTI1NWQzMzQ2ZmE5MjMyZjg0NzkxMGFiYjcwID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzQ3YjNhMDNiOTU5MjQ5YWJiOTQ2NGM5ZjhlZDUxMDAyID0gJCgnPGRpdiBpZD0iaHRtbF80N2IzYTAzYjk1OTI0OWFiYjk0NjRjOWY4ZWQ1MTAwMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdCBUb3JvbnRvOiBCcm9ja3RvbiwgRXhoaWJpdGlvbiBQbGFjZSwgUGFya2RhbGUgVmlsbGFnZSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzI1NjAwZTI1NWQzMzQ2ZmE5MjMyZjg0NzkxMGFiYjcwLnNldENvbnRlbnQoaHRtbF80N2IzYTAzYjk1OTI0OWFiYjk0NjRjOWY4ZWQ1MTAwMik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl82OWQ1MzlhNWIzOGI0YmRlYWIwMTc1ODAxZDFhNzI3MC5iaW5kUG9wdXAocG9wdXBfMjU2MDBlMjU1ZDMzNDZmYTkyMzJmODQ3OTEwYWJiNzApOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTI1OWUxZjAxMTgyNGNiNGExMmJmYjUzZGQ2M2NhY2IgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjE2MDgzLC03OS40NjQ3NjMyOTk5OTk5OV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICIjZmYwMDAwIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiI2ZmMDAwMCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9iOTU0NGE1MzFlMzQ0ZmMxYjczNjRlZmFlNTBlZjE0NCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mMmUzNzlhMDJhMzI0Njc3YjkwOThlODY4MDViMTE4MSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xNzViZDEzOWE1Mzc0OTUyOGU3ZmRmZTA2ZTVkZDhlNiA9ICQoJzxkaXYgaWQ9Imh0bWxfMTc1YmQxMzlhNTM3NDk1MjhlN2ZkZmUwNmU1ZGQ4ZTYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldlc3QgVG9yb250bzogSGlnaCBQYXJrLCBUaGUgSnVuY3Rpb24gU291dGggQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mMmUzNzlhMDJhMzI0Njc3YjkwOThlODY4MDViMTE4MS5zZXRDb250ZW50KGh0bWxfMTc1YmQxMzlhNTM3NDk1MjhlN2ZkZmUwNmU1ZGQ4ZTYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMTI1OWUxZjAxMTgyNGNiNGExMmJmYjUzZGQ2M2NhY2IuYmluZFBvcHVwKHBvcHVwX2YyZTM3OWEwMmEzMjQ2NzdiOTA5OGU4NjgwNWIxMTgxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y3Y2M3MDlkYTMxYzQyNTM4MzZhZjY3MzM0NWUzZGUzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjQ4OTU5NywtNzkuNDU2MzI1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogIiNmZjAwMDAiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICIjZmYwMDAwIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2I5NTQ0YTUzMWUzNDRmYzFiNzM2NGVmYWU1MGVmMTQ0KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2FkOGQ4YWM2YjhlMDRjZmJhOGUwMDFlMzk0MmM3N2QwID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJiZDI3OTVlZTczODQzYmE5NDBlYzZiMWQ2NGZiMTM3ID0gJCgnPGRpdiBpZD0iaHRtbF8yYmQyNzk1ZWU3Mzg0M2JhOTQwZWM2YjFkNjRmYjEzNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+V2VzdCBUb3JvbnRvOiBQYXJrZGFsZSwgUm9uY2VzdmFsbGVzIENsdXN0ZXIgMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYWQ4ZDhhYzZiOGUwNGNmYmE4ZTAwMWUzOTQyYzc3ZDAuc2V0Q29udGVudChodG1sXzJiZDI3OTVlZTczODQzYmE5NDBlYzZiMWQ2NGZiMTM3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2Y3Y2M3MDlkYTMxYzQyNTM4MzZhZjY3MzM0NWUzZGUzLmJpbmRQb3B1cChwb3B1cF9hZDhkOGFjNmI4ZTA0Y2ZiYThlMDAxZTM5NDJjNzdkMCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82MTQxNTQ2NmJjNTk0MGQyOGI2NDgyMWYxOGJkMzVjZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY1MTU3MDYsLTc5LjQ4NDQ0OTldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfY2VjMDUwY2IyNWI1NGYzYmFjMDI2ODRkMmQ3NjNiNTEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMTIxOTk0OWZiNDgyNGIwNjgyNmQwZjY5ZDk1NDVlNGYgPSAkKCc8ZGl2IGlkPSJodG1sXzEyMTk5NDlmYjQ4MjRiMDY4MjZkMGY2OWQ5NTQ1ZTRmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5XZXN0IFRvcm9udG86IFJ1bm55bWVkZSwgU3dhbnNlYSBDbHVzdGVyIDA8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2NlYzA1MGNiMjViNTRmM2JhYzAyNjg0ZDJkNzYzYjUxLnNldENvbnRlbnQoaHRtbF8xMjE5OTQ5ZmI0ODI0YjA2ODI2ZDBmNjlkOTU0NWU0Zik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl82MTQxNTQ2NmJjNTk0MGQyOGI2NDgyMWYxOGJkMzVjZC5iaW5kUG9wdXAocG9wdXBfY2VjMDUwY2IyNWI1NGYzYmFjMDI2ODRkMmQ3NjNiNTEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZjY5NzNlODgzYjEyNDMxMmE3Mjg5Y2E3NGFiY2MxMTggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42NjI3NDM5LC03OS4zMjE1NThdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiI2ZmMDAwMCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogIiNmZjAwMDAiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYjk1NDRhNTMxZTM0NGZjMWI3MzY0ZWZhZTUwZWYxNDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZWY5MjZiN2ZlODFlNGVmMGFhYzZjODA5Yzk2YzFjMDYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWNkYmM4MjlhOWIxNGRhNmIzOWJkZWIwZjYzNzhjMDIgPSAkKCc8ZGl2IGlkPSJodG1sXzFjZGJjODI5YTliMTRkYTZiMzliZGViMGY2Mzc4YzAyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5FYXN0IFRvcm9udG86IEJ1c2luZXNzIFJlcGx5IE1haWwgUHJvY2Vzc2luZyBDZW50cmUgOTY5IEVhc3Rlcm4gQ2x1c3RlciAwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lZjkyNmI3ZmU4MWU0ZWYwYWFjNmM4MDljOTZjMWMwNi5zZXRDb250ZW50KGh0bWxfMWNkYmM4MjlhOWIxNGRhNmIzOWJkZWIwZjYzNzhjMDIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZjY5NzNlODgzYjEyNDMxMmE3Mjg5Y2E3NGFiY2MxMTguYmluZFBvcHVwKHBvcHVwX2VmOTI2YjdmZTgxZTRlZjBhYWM2YzgwOWM5NmMxYzA2KTsKCiAgICAgICAgICAgIAogICAgICAgIAo8L3NjcmlwdD4=" style="position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe>
Lets examine the clusters closely and name them if possible
Neighborhoods with Cluster Label: 0
toronto_merged .loc [toronto_merged ['Cluster Labels' ] == 0 , toronto_merged .columns [[2 ] + list (range (5 , toronto_merged .shape [1 ]))]]
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
0
The Beaches
0
Neighborhood
Health Food Store
Pub
Trail
Event Space
1
The Danforth West, Riverdale
0
Greek Restaurant
Coffee Shop
Ice Cream Shop
Italian Restaurant
Furniture / Home Store
2
The Beaches West, India Bazaar
0
Park
Sandwich Place
Brewery
Steakhouse
Sushi Restaurant
3
Studio District
0
Café
Coffee Shop
Bakery
Italian Restaurant
American Restaurant
5
Davisville North
0
Gym
Breakfast Spot
Food & Drink Shop
Hotel
Clothing Store
6
North Toronto West
0
Clothing Store
Coffee Shop
Sporting Goods Shop
Gym / Fitness Center
Mexican Restaurant
7
Davisville
0
Sandwich Place
Gym
Dessert Shop
Pizza Place
Café
9
Deer Park, Forest Hill SE, Rathnelly, South Hi...
0
Pub
Coffee Shop
Pizza Place
Liquor Store
Sports Bar
11
Cabbagetown, St. James Town
0
Restaurant
Coffee Shop
Pub
Italian Restaurant
Park
12
Church and Wellesley
0
Coffee Shop
Japanese Restaurant
Sushi Restaurant
Restaurant
Gay Bar
13
Harbourfront
0
Coffee Shop
Pub
Park
Bakery
Café
14
Ryerson, Garden District
0
Clothing Store
Coffee Shop
Cosmetics Shop
Café
Fast Food Restaurant
15
St. James Town
0
Café
Coffee Shop
Hotel
Restaurant
Italian Restaurant
16
Berczy Park
0
Coffee Shop
Bakery
Café
Beer Bar
Cheese Shop
17
Central Bay Street
0
Coffee Shop
Italian Restaurant
Ice Cream Shop
Café
Burger Joint
18
Adelaide, King, Richmond
0
Coffee Shop
Café
Bar
Steakhouse
American Restaurant
19
Harbourfront East, Toronto Islands, Union Station
0
Coffee Shop
Aquarium
Hotel
Café
Italian Restaurant
20
Design Exchange, Toronto Dominion Centre
0
Coffee Shop
Café
Hotel
Restaurant
American Restaurant
21
Commerce Court, Victoria Hotel
0
Coffee Shop
Café
Hotel
Restaurant
American Restaurant
24
The Annex, North Midtown, Yorkville
0
Café
Sandwich Place
Coffee Shop
Pizza Place
BBQ Joint
25
Harbord, University of Toronto
0
Café
Restaurant
Bar
Italian Restaurant
Japanese Restaurant
26
Chinatown, Grange Park, Kensington Market
0
Café
Bar
Vietnamese Restaurant
Vegetarian / Vegan Restaurant
Chinese Restaurant
27
CN Tower, Bathurst Quay, Island airport, Harbo...
0
Airport Service
Airport Lounge
Plane
Boutique
Bar
28
Stn A PO Boxes 25 The Esplanade
0
Coffee Shop
Restaurant
Café
Seafood Restaurant
Hotel
29
First Canadian Place, Underground city
0
Coffee Shop
Café
Hotel
Restaurant
Steakhouse
30
Christie
0
Grocery Store
Café
Park
Nightclub
Convenience Store
31
Dovercourt Village, Dufferin
0
Pharmacy
Supermarket
Bakery
Pizza Place
Furniture / Home Store
32
Little Portugal, Trinity
0
Bar
Coffee Shop
Restaurant
Asian Restaurant
Vietnamese Restaurant
33
Brockton, Exhibition Place, Parkdale Village
0
Coffee Shop
Café
Breakfast Spot
Grocery Store
Intersection
34
High Park, The Junction South
0
Discount Store
Bar
Mexican Restaurant
Café
Thai Restaurant
35
Parkdale, Roncesvalles
0
Gift Shop
Coffee Shop
Bookstore
Bank
Italian Restaurant
36
Runnymede, Swansea
0
Coffee Shop
Café
Italian Restaurant
Sushi Restaurant
Bookstore
37
Business Reply Mail Processing Centre 969 Eastern
0
Light Rail Station
Pizza Place
Auto Workshop
Comic Shop
Recording Studio
Neighborhoods with Cluster Label: 1
toronto_merged .loc [toronto_merged ['Cluster Labels' ] == 1 , toronto_merged .columns [[2 ] + list (range (5 , toronto_merged .shape [1 ]))]]
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
8
Moore Park, Summerhill East
1
Trail
Playground
Park
Tennis Court
Donut Shop
10
Rosedale
1
Park
Playground
Trail
Yoga Studio
Dessert Shop
Neighborhoods with Cluster Label: 2
toronto_merged .loc [toronto_merged ['Cluster Labels' ] == 2 , toronto_merged .columns [[2 ] + list (range (5 , toronto_merged .shape [1 ]))]]
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
22
Roselawn
2
Garden
Home Service
Dim Sum Restaurant
Farmers Market
Falafel Restaurant
Neighborhoods with Cluster Label: 3
toronto_merged .loc [toronto_merged ['Cluster Labels' ] == 3 , toronto_merged .columns [[2 ] + list (range (5 , toronto_merged .shape [1 ]))]]
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
23
Forest Hill North, Forest Hill West
3
Park
Trail
Jewelry Store
Sushi Restaurant
Yoga Studio
Neighborhoods with Cluster Label: 4
toronto_merged .loc [toronto_merged ['Cluster Labels' ] == 4 , toronto_merged .columns [[2 ] + list (range (5 , toronto_merged .shape [1 ]))]]
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
Neighborhood
Cluster Labels
1st Most Common Venue
2nd Most Common Venue
3rd Most Common Venue
4th Most Common Venue
5th Most Common Venue
4
Lawrence Park
4
Park
Swim School
Bus Line
Yoga Studio
Diner
Observations about the clusters
Neighborhoods in Cluster-0 has the most common venues related to food. Hence the cluster can be named as the Eatery cluster.
Neighborhoods in other clusters are not sufficent enough to give a proper name to those clusters
------End of Assignment-----