Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save connectwithprakash/67eb77685ce9f8be3e3eef4b97bdf937 to your computer and use it in GitHub Desktop.

Select an option

Save connectwithprakash/67eb77685ce9f8be3e3eef4b97bdf937 to your computer and use it in GitHub Desktop.
Created on Cognitive Class Labs
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **A program For Photographers Event**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Introduction**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nepal is a beautiful country with a great prospect of tourism. Every year a lot of tourists come to visit Nepal. Hence in this analytical project I want find the best region of Kathmandu for tourist to stay such that they have maximum access to facilities."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Data Description**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The data used in this project is provided by Foursquare location data. The data are grouped by landscape area, and each area included the information about this area and all information about restaurants, cafes, and stores which in this area."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Table of contents**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1- Import Libraries\n",
"#### 2- Define Foursquare Credentials\n",
"#### 3- Search for Hotels\n",
"#### 4- Search for Temples\n",
"#### 5- Search for Resturants\n",
"#### 6- Search for Cafe\n",
"#### 7- Search for Shopping Mall\n",
"#### 8- Generating Map for Analysis"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Import Libraries**"
]
},
{
"cell_type": "code",
"execution_count": 198,
"metadata": {},
"outputs": [],
"source": [
"import requests # to handle requests\n",
"import pandas as pd # for data analsysis\n",
"import numpy as np # to handle data in a vectorized manner\n",
"\n",
"#!conda install -c conda-forge geopy --yes \n",
"from geopy.geocoders import Nominatim # module to convert an address into latitude and longitude values\n",
"\n",
"# libraries for displaying images\n",
"from IPython.display import Image \n",
"from IPython.core.display import HTML \n",
" \n",
"#tranforming json file into a pandas dataframe library\n",
"from pandas.io.json import json_normalize\n",
"\n",
"#!conda install -c conda-forge folium=0.5.0 --yes\n",
"import folium # plotting library"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Define Foursquare Credentials**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### code has been removed"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Define the city and get its latitude & longitude** "
]
},
{
"cell_type": "code",
"execution_count": 200,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"27.708796 85.320244\n"
]
}
],
"source": [
"# define the city and get its latitude & longitude \n",
"city = 'Kathmandu'\n",
"geolocator = Nominatim(user_agent=\"foursquare_agent\")\n",
"location = geolocator.geocode(city)\n",
"latitude = location.latitude\n",
"longitude = location.longitude\n",
"print(latitude, longitude)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Search for Hotels**"
]
},
{
"cell_type": "code",
"execution_count": 201,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'https://api.foursquare.com/v2/venues/search?client_id=UGHFMNO1HCOWOZTT0W5MXN0CKUIFZZU2OXV1KIM1CUL1KX31&client_secret=O0WTNIHI0W2Q1GUUJ34U0KCB3GBRD4OXCESMXMTVBB1SRCJV&ll=27.708796,85.320244&v=20190604&query=Hotel&radius=20000&limit=50'"
]
},
"execution_count": 201,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# search for hotels\n",
"search_query = 'Hotel'\n",
"radius = 20000\n",
"\n",
"# Define the corresponding URL\n",
"url = 'https://api.foursquare.com/v2/venues/search?client_id={}&client_secret={}&ll={},{}&v={}&query={}&radius={}&limit={}'\\\n",
".format(ClIENT_ID, ClIENT_SECRET, latitude, longitude, VERSION, search_query, radius, LIMIT)\n",
"url"
]
},
{
"cell_type": "code",
"execution_count": 202,
"metadata": {},
"outputs": [],
"source": [
"# Send the GET Request and examine the results\n",
"results = requests.get(url).json()\n",
"#results"
]
},
{
"cell_type": "code",
"execution_count": 203,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>categories</th>\n",
" <th>hasPerk</th>\n",
" <th>id</th>\n",
" <th>location.address</th>\n",
" <th>location.cc</th>\n",
" <th>location.city</th>\n",
" <th>location.country</th>\n",
" <th>location.crossStreet</th>\n",
" <th>location.distance</th>\n",
" <th>location.formattedAddress</th>\n",
" <th>location.labeledLatLngs</th>\n",
" <th>location.lat</th>\n",
" <th>location.lng</th>\n",
" <th>location.neighborhood</th>\n",
" <th>location.postalCode</th>\n",
" <th>location.state</th>\n",
" <th>name</th>\n",
" <th>referralId</th>\n",
" <th>venuePage.id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fa931735', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>4bc7886a93bdeee12e7d37ae</td>\n",
" <td>Lalupate Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Hattisar Sadak</td>\n",
" <td>310</td>\n",
" <td>[Lalupate Marg (Hattisar Sadak), काठमाडौं 4460...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71158105367929...</td>\n",
" <td>27.711581</td>\n",
" <td>85.320274</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>Hotel Yak &amp; Yeti</td>\n",
" <td>v-1562684375</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fa931735', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>4bded3bafe0e62b5e7fa0506</td>\n",
" <td>Lazimpat</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1131</td>\n",
" <td>[Lazimpat, काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71895583641048...</td>\n",
" <td>27.718956</td>\n",
" <td>85.320082</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>Hotel Shanker</td>\n",
" <td>v-1562684375</td>\n",
" <td>95447536</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fa931735', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>4cba0e303481199c9c036b3f</td>\n",
" <td>Lal Durbar</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Durbar Marg</td>\n",
" <td>250</td>\n",
" <td>[Lal Durbar (Durbar Marg), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71093952161910...</td>\n",
" <td>27.710940</td>\n",
" <td>85.319466</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Royal Singhi Hotel</td>\n",
" <td>v-1562684375</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fa931735', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>4bcf47520ffdce724657b2c0</td>\n",
" <td>Durbar Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>457</td>\n",
" <td>[Durbar Marg, काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71111728880132...</td>\n",
" <td>27.711117</td>\n",
" <td>85.316408</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>De L'Annapurna Hotel</td>\n",
" <td>v-1562684375</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fa931735', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>4f4399d3e4b05d3b161f7ef7</td>\n",
" <td>25728</td>\n",
" <td>NP</td>\n",
" <td>Kathmandu</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1332</td>\n",
" <td>[25728 (Thamel), Kathmandu, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71704390787054...</td>\n",
" <td>27.717044</td>\n",
" <td>85.310450</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Kathmando</td>\n",
" <td>Hotel Buddha</td>\n",
" <td>v-1562684375</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" categories hasPerk \\\n",
"0 [{'id': '4bf58dd8d48988d1fa931735', 'name': 'H... False \n",
"1 [{'id': '4bf58dd8d48988d1fa931735', 'name': 'H... False \n",
"2 [{'id': '4bf58dd8d48988d1fa931735', 'name': 'H... False \n",
"3 [{'id': '4bf58dd8d48988d1fa931735', 'name': 'H... False \n",
"4 [{'id': '4bf58dd8d48988d1fa931735', 'name': 'H... False \n",
"\n",
" id location.address location.cc location.city \\\n",
"0 4bc7886a93bdeee12e7d37ae Lalupate Marg NP काठमाडौं \n",
"1 4bded3bafe0e62b5e7fa0506 Lazimpat NP काठमाडौं \n",
"2 4cba0e303481199c9c036b3f Lal Durbar NP काठमाडौं \n",
"3 4bcf47520ffdce724657b2c0 Durbar Marg NP काठमाडौं \n",
"4 4f4399d3e4b05d3b161f7ef7 25728 NP Kathmandu \n",
"\n",
" location.country location.crossStreet location.distance \\\n",
"0 नेपाल Hattisar Sadak 310 \n",
"1 नेपाल NaN 1131 \n",
"2 नेपाल Durbar Marg 250 \n",
"3 नेपाल NaN 457 \n",
"4 नेपाल Thamel 1332 \n",
"\n",
" location.formattedAddress \\\n",
"0 [Lalupate Marg (Hattisar Sadak), काठमाडौं 4460... \n",
"1 [Lazimpat, काठमाडौं 44600, नेपाल] \n",
"2 [Lal Durbar (Durbar Marg), काठमाडौं, नेपाल] \n",
"3 [Durbar Marg, काठमाडौं 44600, नेपाल] \n",
"4 [25728 (Thamel), Kathmandu, नेपाल] \n",
"\n",
" location.labeledLatLngs location.lat \\\n",
"0 [{'label': 'display', 'lat': 27.71158105367929... 27.711581 \n",
"1 [{'label': 'display', 'lat': 27.71895583641048... 27.718956 \n",
"2 [{'label': 'display', 'lat': 27.71093952161910... 27.710940 \n",
"3 [{'label': 'display', 'lat': 27.71111728880132... 27.711117 \n",
"4 [{'label': 'display', 'lat': 27.71704390787054... 27.717044 \n",
"\n",
" location.lng location.neighborhood location.postalCode location.state \\\n",
"0 85.320274 NaN 44600 Central Region \n",
"1 85.320082 NaN 44600 Central Region \n",
"2 85.319466 NaN NaN Central Region \n",
"3 85.316408 NaN 44600 Central Region \n",
"4 85.310450 NaN NaN Kathmando \n",
"\n",
" name referralId venuePage.id \n",
"0 Hotel Yak & Yeti v-1562684375 NaN \n",
"1 Hotel Shanker v-1562684375 95447536 \n",
"2 Royal Singhi Hotel v-1562684375 NaN \n",
"3 De L'Annapurna Hotel v-1562684375 NaN \n",
"4 Hotel Buddha v-1562684375 NaN "
]
},
"execution_count": 203,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# assign relevant part of JSON to venues\n",
"venues = results['response']['venues']\n",
"\n",
"# tranform venues into a dataframe\n",
"dataframe = json_normalize(venues)\n",
"dataframe.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Clean Hotel Dataframe**"
]
},
{
"cell_type": "code",
"execution_count": 204,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>cc</th>\n",
" <th>city</th>\n",
" <th>country</th>\n",
" <th>crossStreet</th>\n",
" <th>distance</th>\n",
" <th>formattedAddress</th>\n",
" <th>labeledLatLngs</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>neighborhood</th>\n",
" <th>postalCode</th>\n",
" <th>state</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Hotel Yak &amp; Yeti</td>\n",
" <td>Hotel</td>\n",
" <td>Lalupate Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Hattisar Sadak</td>\n",
" <td>310</td>\n",
" <td>[Lalupate Marg (Hattisar Sadak), काठमाडौं 4460...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71158105367929...</td>\n",
" <td>27.711581</td>\n",
" <td>85.320274</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>4bc7886a93bdeee12e7d37ae</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hotel Shanker</td>\n",
" <td>Hotel</td>\n",
" <td>Lazimpat</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1131</td>\n",
" <td>[Lazimpat, काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71895583641048...</td>\n",
" <td>27.718956</td>\n",
" <td>85.320082</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>4bded3bafe0e62b5e7fa0506</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Royal Singhi Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Lal Durbar</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Durbar Marg</td>\n",
" <td>250</td>\n",
" <td>[Lal Durbar (Durbar Marg), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71093952161910...</td>\n",
" <td>27.710940</td>\n",
" <td>85.319466</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4cba0e303481199c9c036b3f</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>De L'Annapurna Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Durbar Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>457</td>\n",
" <td>[Durbar Marg, काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71111728880132...</td>\n",
" <td>27.711117</td>\n",
" <td>85.316408</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>4bcf47520ffdce724657b2c0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Hotel Buddha</td>\n",
" <td>Hotel</td>\n",
" <td>25728</td>\n",
" <td>NP</td>\n",
" <td>Kathmandu</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1332</td>\n",
" <td>[25728 (Thamel), Kathmandu, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71704390787054...</td>\n",
" <td>27.717044</td>\n",
" <td>85.310450</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Kathmando</td>\n",
" <td>4f4399d3e4b05d3b161f7ef7</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address cc city country \\\n",
"0 Hotel Yak & Yeti Hotel Lalupate Marg NP काठमाडौं नेपाल \n",
"1 Hotel Shanker Hotel Lazimpat NP काठमाडौं नेपाल \n",
"2 Royal Singhi Hotel Hotel Lal Durbar NP काठमाडौं नेपाल \n",
"3 De L'Annapurna Hotel Hotel Durbar Marg NP काठमाडौं नेपाल \n",
"4 Hotel Buddha Hotel 25728 NP Kathmandu नेपाल \n",
"\n",
" crossStreet distance \\\n",
"0 Hattisar Sadak 310 \n",
"1 NaN 1131 \n",
"2 Durbar Marg 250 \n",
"3 NaN 457 \n",
"4 Thamel 1332 \n",
"\n",
" formattedAddress \\\n",
"0 [Lalupate Marg (Hattisar Sadak), काठमाडौं 4460... \n",
"1 [Lazimpat, काठमाडौं 44600, नेपाल] \n",
"2 [Lal Durbar (Durbar Marg), काठमाडौं, नेपाल] \n",
"3 [Durbar Marg, काठमाडौं 44600, नेपाल] \n",
"4 [25728 (Thamel), Kathmandu, नेपाल] \n",
"\n",
" labeledLatLngs lat lng \\\n",
"0 [{'label': 'display', 'lat': 27.71158105367929... 27.711581 85.320274 \n",
"1 [{'label': 'display', 'lat': 27.71895583641048... 27.718956 85.320082 \n",
"2 [{'label': 'display', 'lat': 27.71093952161910... 27.710940 85.319466 \n",
"3 [{'label': 'display', 'lat': 27.71111728880132... 27.711117 85.316408 \n",
"4 [{'label': 'display', 'lat': 27.71704390787054... 27.717044 85.310450 \n",
"\n",
" neighborhood postalCode state id \n",
"0 NaN 44600 Central Region 4bc7886a93bdeee12e7d37ae \n",
"1 NaN 44600 Central Region 4bded3bafe0e62b5e7fa0506 \n",
"2 NaN NaN Central Region 4cba0e303481199c9c036b3f \n",
"3 NaN 44600 Central Region 4bcf47520ffdce724657b2c0 \n",
"4 NaN NaN Kathmando 4f4399d3e4b05d3b161f7ef7 "
]
},
"execution_count": 204,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# keep only columns that include venue name, and anything that is associated with location\n",
"clean_columns = ['name', 'categories'] + [col for col in dataframe.columns if col.startswith('location.')]+ ['id']\n",
"clean_dataframe = dataframe.loc[:,clean_columns]\n",
"\n",
"# function that extracts the category of the venue\n",
"def get_category_type(row):\n",
" try:\n",
" categories_list = row['categories']\n",
" except:\n",
" categories_list = row['venue.categories']\n",
" \n",
" if len(categories_list) == 0:\n",
" return None\n",
" else:\n",
" return categories_list[0]['name']\n",
"\n",
"# filter the category for each row\n",
"clean_dataframe['categories'] = clean_dataframe.apply(get_category_type, axis=1)\n",
"\n",
"# clean column names by keeping only last term\n",
"clean_dataframe.columns = [column.split('.')[-1] for column in clean_dataframe.columns]\n",
"\n",
"clean_dataframe.head()"
]
},
{
"cell_type": "code",
"execution_count": 205,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Hotel Yak &amp; Yeti</td>\n",
" <td>Hotel</td>\n",
" <td>Lalupate Marg</td>\n",
" <td>27.711581</td>\n",
" <td>85.320274</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hotel Shanker</td>\n",
" <td>Hotel</td>\n",
" <td>Lazimpat</td>\n",
" <td>27.718956</td>\n",
" <td>85.320082</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Royal Singhi Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Lal Durbar</td>\n",
" <td>27.710940</td>\n",
" <td>85.319466</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>De L'Annapurna Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Durbar Marg</td>\n",
" <td>27.711117</td>\n",
" <td>85.316408</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Hotel Buddha</td>\n",
" <td>Hotel</td>\n",
" <td>25728</td>\n",
" <td>27.717044</td>\n",
" <td>85.310450</td>\n",
" <td>Kathmando</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address lat lng \\\n",
"0 Hotel Yak & Yeti Hotel Lalupate Marg 27.711581 85.320274 \n",
"1 Hotel Shanker Hotel Lazimpat 27.718956 85.320082 \n",
"2 Royal Singhi Hotel Hotel Lal Durbar 27.710940 85.319466 \n",
"3 De L'Annapurna Hotel Hotel Durbar Marg 27.711117 85.316408 \n",
"4 Hotel Buddha Hotel 25728 27.717044 85.310450 \n",
"\n",
" state \n",
"0 Central Region \n",
"1 Central Region \n",
"2 Central Region \n",
"3 Central Region \n",
"4 Kathmando "
]
},
"execution_count": 205,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete unnecessary columns\n",
"clean_dataframe2= clean_dataframe.drop(['cc', 'city', 'country', 'crossStreet', 'distance', 'formattedAddress',\\\n",
" 'labeledLatLngs', 'neighborhood', 'postalCode', 'id'], axis=1)\n",
"clean_dataframe2.head()"
]
},
{
"cell_type": "code",
"execution_count": 206,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Hotel Yak &amp; Yeti</td>\n",
" <td>Hotel</td>\n",
" <td>Lalupate Marg</td>\n",
" <td>27.711581</td>\n",
" <td>85.320274</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hotel Shanker</td>\n",
" <td>Hotel</td>\n",
" <td>Lazimpat</td>\n",
" <td>27.718956</td>\n",
" <td>85.320082</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Royal Singhi Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Lal Durbar</td>\n",
" <td>27.710940</td>\n",
" <td>85.319466</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>De L'Annapurna Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Durbar Marg</td>\n",
" <td>27.711117</td>\n",
" <td>85.316408</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Hotel Buddha</td>\n",
" <td>Hotel</td>\n",
" <td>25728</td>\n",
" <td>27.717044</td>\n",
" <td>85.310450</td>\n",
" <td>Kathmando</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address lat lng \\\n",
"0 Hotel Yak & Yeti Hotel Lalupate Marg 27.711581 85.320274 \n",
"1 Hotel Shanker Hotel Lazimpat 27.718956 85.320082 \n",
"2 Royal Singhi Hotel Hotel Lal Durbar 27.710940 85.319466 \n",
"3 De L'Annapurna Hotel Hotel Durbar Marg 27.711117 85.316408 \n",
"4 Hotel Buddha Hotel 25728 27.717044 85.310450 \n",
"\n",
" state \n",
"0 Central Region \n",
"1 Central Region \n",
"2 Central Region \n",
"3 Central Region \n",
"4 Kathmando "
]
},
"execution_count": 206,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows with none values\n",
"clean_dataframe3 = clean_dataframe2.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)\n",
"clean_dataframe3.head()"
]
},
{
"cell_type": "code",
"execution_count": 207,
"metadata": {},
"outputs": [],
"source": [
"# delete rows which its category is not Hotel or Event Space\n",
"array= ['Hotel', 'Event Space', 'Resort']\n",
"hotel_dataframe= clean_dataframe3.loc[clean_dataframe3['categories'].isin(array)]\n",
"hotel_dataframe = clean_dataframe3"
]
},
{
"cell_type": "code",
"execution_count": 208,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Hotel Yak &amp; Yeti</td>\n",
" <td>Hotel</td>\n",
" <td>Lalupate Marg</td>\n",
" <td>27.711581</td>\n",
" <td>85.320274</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hotel Shanker</td>\n",
" <td>Hotel</td>\n",
" <td>Lazimpat</td>\n",
" <td>27.718956</td>\n",
" <td>85.320082</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Royal Singhi Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Lal Durbar</td>\n",
" <td>27.710940</td>\n",
" <td>85.319466</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>De L'Annapurna Hotel</td>\n",
" <td>Hotel</td>\n",
" <td>Durbar Marg</td>\n",
" <td>27.711117</td>\n",
" <td>85.316408</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Hotel Buddha</td>\n",
" <td>Hotel</td>\n",
" <td>25728</td>\n",
" <td>27.717044</td>\n",
" <td>85.310450</td>\n",
" <td>Kathmando</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address lat lng \\\n",
"0 Hotel Yak & Yeti Hotel Lalupate Marg 27.711581 85.320274 \n",
"1 Hotel Shanker Hotel Lazimpat 27.718956 85.320082 \n",
"2 Royal Singhi Hotel Hotel Lal Durbar 27.710940 85.319466 \n",
"3 De L'Annapurna Hotel Hotel Durbar Marg 27.711117 85.316408 \n",
"4 Hotel Buddha Hotel 25728 27.717044 85.310450 \n",
"\n",
" state \n",
"0 Central Region \n",
"1 Central Region \n",
"2 Central Region \n",
"3 Central Region \n",
"4 Kathmando "
]
},
"execution_count": 208,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows which has duplicate hotel's name\n",
"df_hotels = hotel_dataframe.drop_duplicates(subset='name', keep=\"first\")\n",
"df_hotels.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Search for temples**"
]
},
{
"cell_type": "code",
"execution_count": 209,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'https://api.foursquare.com/v2/venues/search?client_id=UGHFMNO1HCOWOZTT0W5MXN0CKUIFZZU2OXV1KIM1CUL1KX31&client_secret=O0WTNIHI0W2Q1GUUJ34U0KCB3GBRD4OXCESMXMTVBB1SRCJV&ll=27.708796,85.320244&v=20190604&query=Temple&radius=20000&limit=50'"
]
},
"execution_count": 209,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# search for temples\n",
"search_query = 'Temple'\n",
"radius = 20000\n",
"\n",
"# Define the corresponding URL\n",
"url = 'https://api.foursquare.com/v2/venues/search?client_id={}&client_secret={}&ll={},{}&v={}&query={}&radius={}&limit={}'\\\n",
".format(ClIENT_ID, ClIENT_SECRET, latitude, longitude, VERSION, search_query, radius, LIMIT)\n",
"url"
]
},
{
"cell_type": "code",
"execution_count": 210,
"metadata": {},
"outputs": [],
"source": [
"# Send the GET Request and examine the results\n",
"presults = requests.get(url).json()\n",
"#presults"
]
},
{
"cell_type": "code",
"execution_count": 211,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>categories</th>\n",
" <th>hasPerk</th>\n",
" <th>id</th>\n",
" <th>location.address</th>\n",
" <th>location.cc</th>\n",
" <th>location.city</th>\n",
" <th>location.country</th>\n",
" <th>location.crossStreet</th>\n",
" <th>location.distance</th>\n",
" <th>location.formattedAddress</th>\n",
" <th>location.labeledLatLngs</th>\n",
" <th>location.lat</th>\n",
" <th>location.lng</th>\n",
" <th>location.postalCode</th>\n",
" <th>location.state</th>\n",
" <th>name</th>\n",
" <th>referralId</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>[{'id': '4bf58dd8d48988d13a941735', 'name': 'T...</td>\n",
" <td>False</td>\n",
" <td>4bcf47520ffdce724457b2c0</td>\n",
" <td>Chusyabahal</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Jyatha</td>\n",
" <td>769</td>\n",
" <td>[Chusyabahal (Jyatha), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71123533061801...</td>\n",
" <td>27.711235</td>\n",
" <td>85.312934</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Kantipur Temple House</td>\n",
" <td>v-1562684380</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>[{'id': '52e81612bcbc57f1066b7a3e', 'name': 'B...</td>\n",
" <td>False</td>\n",
" <td>51790da9e4b0de302b37fed6</td>\n",
" <td>Kwabahal</td>\n",
" <td>NP</td>\n",
" <td>Pātan</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>3757</td>\n",
" <td>[Kwabahal, Patan, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.67524821814495...</td>\n",
" <td>27.675248</td>\n",
" <td>85.324419</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Hiranya Varna Mahavihar (Golden Temple)</td>\n",
" <td>v-1562684380</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>[{'id': '4bf58dd8d48988d13a941735', 'name': 'T...</td>\n",
" <td>False</td>\n",
" <td>527b6c6511d28e4aa2a056f9</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>555</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70881275112659...</td>\n",
" <td>27.708813</td>\n",
" <td>85.314609</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Bal Gopal Temple</td>\n",
" <td>v-1562684380</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>[{'id': '4bf58dd8d48988d13a941735', 'name': 'T...</td>\n",
" <td>False</td>\n",
" <td>5690fc4338fafe86458fef24</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1096</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.705959, 'lng':...</td>\n",
" <td>27.705959</td>\n",
" <td>85.309586</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Akash Bhairab Temple</td>\n",
" <td>v-1562684380</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[{'id': '4deefb944765f83613cdba6e', 'name': 'H...</td>\n",
" <td>False</td>\n",
" <td>507e919ee4b00e30b6288444</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>701</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71498960118585...</td>\n",
" <td>27.714990</td>\n",
" <td>85.321530</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Golden Temple</td>\n",
" <td>v-1562684380</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" categories hasPerk \\\n",
"0 [{'id': '4bf58dd8d48988d13a941735', 'name': 'T... False \n",
"1 [{'id': '52e81612bcbc57f1066b7a3e', 'name': 'B... False \n",
"2 [{'id': '4bf58dd8d48988d13a941735', 'name': 'T... False \n",
"3 [{'id': '4bf58dd8d48988d13a941735', 'name': 'T... False \n",
"4 [{'id': '4deefb944765f83613cdba6e', 'name': 'H... False \n",
"\n",
" id location.address location.cc location.city \\\n",
"0 4bcf47520ffdce724457b2c0 Chusyabahal NP काठमाडौं \n",
"1 51790da9e4b0de302b37fed6 Kwabahal NP Pātan \n",
"2 527b6c6511d28e4aa2a056f9 NaN NP NaN \n",
"3 5690fc4338fafe86458fef24 NaN NP NaN \n",
"4 507e919ee4b00e30b6288444 NaN NP NaN \n",
"\n",
" location.country location.crossStreet location.distance \\\n",
"0 नेपाल Jyatha 769 \n",
"1 नेपाल NaN 3757 \n",
"2 नेपाल NaN 555 \n",
"3 नेपाल NaN 1096 \n",
"4 नेपाल NaN 701 \n",
"\n",
" location.formattedAddress \\\n",
"0 [Chusyabahal (Jyatha), काठमाडौं, नेपाल] \n",
"1 [Kwabahal, Patan, नेपाल] \n",
"2 [नेपाल] \n",
"3 [नेपाल] \n",
"4 [नेपाल] \n",
"\n",
" location.labeledLatLngs location.lat \\\n",
"0 [{'label': 'display', 'lat': 27.71123533061801... 27.711235 \n",
"1 [{'label': 'display', 'lat': 27.67524821814495... 27.675248 \n",
"2 [{'label': 'display', 'lat': 27.70881275112659... 27.708813 \n",
"3 [{'label': 'display', 'lat': 27.705959, 'lng':... 27.705959 \n",
"4 [{'label': 'display', 'lat': 27.71498960118585... 27.714990 \n",
"\n",
" location.lng location.postalCode location.state \\\n",
"0 85.312934 NaN Central Region \n",
"1 85.324419 NaN Central Region \n",
"2 85.314609 NaN NaN \n",
"3 85.309586 NaN NaN \n",
"4 85.321530 NaN NaN \n",
"\n",
" name referralId \n",
"0 Kantipur Temple House v-1562684380 \n",
"1 Hiranya Varna Mahavihar (Golden Temple) v-1562684380 \n",
"2 Bal Gopal Temple v-1562684380 \n",
"3 Akash Bhairab Temple v-1562684380 \n",
"4 Golden Temple v-1562684380 "
]
},
"execution_count": 211,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# assign relevant part of JSON to venues\n",
"venues = presults['response']['venues']\n",
"\n",
"# tranform venues into a dataframe\n",
"temples_dataframe = json_normalize(venues)\n",
"temples_dataframe.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Clean temples Dataframe**"
]
},
{
"cell_type": "code",
"execution_count": 212,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>cc</th>\n",
" <th>city</th>\n",
" <th>country</th>\n",
" <th>crossStreet</th>\n",
" <th>distance</th>\n",
" <th>formattedAddress</th>\n",
" <th>labeledLatLngs</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>postalCode</th>\n",
" <th>state</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Kantipur Temple House</td>\n",
" <td>Temple</td>\n",
" <td>Chusyabahal</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Jyatha</td>\n",
" <td>769</td>\n",
" <td>[Chusyabahal (Jyatha), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71123533061801...</td>\n",
" <td>27.711235</td>\n",
" <td>85.312934</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4bcf47520ffdce724457b2c0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hiranya Varna Mahavihar (Golden Temple)</td>\n",
" <td>Buddhist Temple</td>\n",
" <td>Kwabahal</td>\n",
" <td>NP</td>\n",
" <td>Pātan</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>3757</td>\n",
" <td>[Kwabahal, Patan, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.67524821814495...</td>\n",
" <td>27.675248</td>\n",
" <td>85.324419</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>51790da9e4b0de302b37fed6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Bal Gopal Temple</td>\n",
" <td>Temple</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>555</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70881275112659...</td>\n",
" <td>27.708813</td>\n",
" <td>85.314609</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>527b6c6511d28e4aa2a056f9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Akash Bhairab Temple</td>\n",
" <td>Temple</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1096</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.705959, 'lng':...</td>\n",
" <td>27.705959</td>\n",
" <td>85.309586</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>5690fc4338fafe86458fef24</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Golden Temple</td>\n",
" <td>Historic Site</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>701</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71498960118585...</td>\n",
" <td>27.714990</td>\n",
" <td>85.321530</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>507e919ee4b00e30b6288444</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address cc \\\n",
"0 Kantipur Temple House Temple Chusyabahal NP \n",
"1 Hiranya Varna Mahavihar (Golden Temple) Buddhist Temple Kwabahal NP \n",
"2 Bal Gopal Temple Temple NaN NP \n",
"3 Akash Bhairab Temple Temple NaN NP \n",
"4 Golden Temple Historic Site NaN NP \n",
"\n",
" city country crossStreet distance \\\n",
"0 काठमाडौं नेपाल Jyatha 769 \n",
"1 Pātan नेपाल NaN 3757 \n",
"2 NaN नेपाल NaN 555 \n",
"3 NaN नेपाल NaN 1096 \n",
"4 NaN नेपाल NaN 701 \n",
"\n",
" formattedAddress \\\n",
"0 [Chusyabahal (Jyatha), काठमाडौं, नेपाल] \n",
"1 [Kwabahal, Patan, नेपाल] \n",
"2 [नेपाल] \n",
"3 [नेपाल] \n",
"4 [नेपाल] \n",
"\n",
" labeledLatLngs lat lng \\\n",
"0 [{'label': 'display', 'lat': 27.71123533061801... 27.711235 85.312934 \n",
"1 [{'label': 'display', 'lat': 27.67524821814495... 27.675248 85.324419 \n",
"2 [{'label': 'display', 'lat': 27.70881275112659... 27.708813 85.314609 \n",
"3 [{'label': 'display', 'lat': 27.705959, 'lng':... 27.705959 85.309586 \n",
"4 [{'label': 'display', 'lat': 27.71498960118585... 27.714990 85.321530 \n",
"\n",
" postalCode state id \n",
"0 NaN Central Region 4bcf47520ffdce724457b2c0 \n",
"1 NaN Central Region 51790da9e4b0de302b37fed6 \n",
"2 NaN NaN 527b6c6511d28e4aa2a056f9 \n",
"3 NaN NaN 5690fc4338fafe86458fef24 \n",
"4 NaN NaN 507e919ee4b00e30b6288444 "
]
},
"execution_count": 212,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# keep only columns that include venue name, and anything that is associated with location\n",
"temples_clean_columns = ['name', 'categories'] + [col for col in temples_dataframe.columns if col.startswith('location.')]+ ['id']\n",
"clean_temples_dataframe = temples_dataframe.loc[:,temples_clean_columns]\n",
"\n",
"# function that extracts the category of the venue\n",
"def get_category_type(row):\n",
" try:\n",
" categories_list1 = row['categories']\n",
" except:\n",
" categories_list1 = row['venue.categories']\n",
" \n",
" if len(categories_list1) == 0:\n",
" return None\n",
" else:\n",
" return categories_list1[0]['name']\n",
"\n",
"# filter the category for each row\n",
"clean_temples_dataframe['categories'] = clean_temples_dataframe.apply(get_category_type, axis=1)\n",
"\n",
"# clean column names by keeping only last term\n",
"clean_temples_dataframe.columns = [column.split('.')[-1] for column in clean_temples_dataframe.columns]\n",
"\n",
"clean_temples_dataframe.head()"
]
},
{
"cell_type": "code",
"execution_count": 213,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Kantipur Temple House</td>\n",
" <td>Temple</td>\n",
" <td>Chusyabahal</td>\n",
" <td>27.711235</td>\n",
" <td>85.312934</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hiranya Varna Mahavihar (Golden Temple)</td>\n",
" <td>Buddhist Temple</td>\n",
" <td>Kwabahal</td>\n",
" <td>27.675248</td>\n",
" <td>85.324419</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Bal Gopal Temple</td>\n",
" <td>Temple</td>\n",
" <td>NaN</td>\n",
" <td>27.708813</td>\n",
" <td>85.314609</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Akash Bhairab Temple</td>\n",
" <td>Temple</td>\n",
" <td>NaN</td>\n",
" <td>27.705959</td>\n",
" <td>85.309586</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Golden Temple</td>\n",
" <td>Historic Site</td>\n",
" <td>NaN</td>\n",
" <td>27.714990</td>\n",
" <td>85.321530</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address \\\n",
"0 Kantipur Temple House Temple Chusyabahal \n",
"1 Hiranya Varna Mahavihar (Golden Temple) Buddhist Temple Kwabahal \n",
"2 Bal Gopal Temple Temple NaN \n",
"3 Akash Bhairab Temple Temple NaN \n",
"4 Golden Temple Historic Site NaN \n",
"\n",
" lat lng state \n",
"0 27.711235 85.312934 Central Region \n",
"1 27.675248 85.324419 Central Region \n",
"2 27.708813 85.314609 NaN \n",
"3 27.705959 85.309586 NaN \n",
"4 27.714990 85.321530 NaN "
]
},
"execution_count": 213,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete unnecessary columns\n",
"clean_temples_dataframe2= clean_temples_dataframe.drop(['cc', 'city', 'country', 'distance', 'formattedAddress',\\\n",
" 'labeledLatLngs','crossStreet','postalCode', 'id'], axis=1)\n",
"clean_temples_dataframe2.head()"
]
},
{
"cell_type": "code",
"execution_count": 214,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Kantipur Temple House</td>\n",
" <td>Temple</td>\n",
" <td>Chusyabahal</td>\n",
" <td>27.711235</td>\n",
" <td>85.312934</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hiranya Varna Mahavihar (Golden Temple)</td>\n",
" <td>Buddhist Temple</td>\n",
" <td>Kwabahal</td>\n",
" <td>27.675248</td>\n",
" <td>85.324419</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>The Temple</td>\n",
" <td>Bar</td>\n",
" <td>Thamel</td>\n",
" <td>27.715492</td>\n",
" <td>85.310461</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>Pashupatinath Temple</td>\n",
" <td>Temple</td>\n",
" <td>Pashupatinath Rd.</td>\n",
" <td>27.709101</td>\n",
" <td>85.348620</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>Taleju Temple</td>\n",
" <td>Temple</td>\n",
" <td>Makhan Tole</td>\n",
" <td>27.712171</td>\n",
" <td>85.311342</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories \\\n",
"0 Kantipur Temple House Temple \n",
"1 Hiranya Varna Mahavihar (Golden Temple) Buddhist Temple \n",
"5 The Temple Bar \n",
"6 Pashupatinath Temple Temple \n",
"8 Taleju Temple Temple \n",
"\n",
" address lat lng state \n",
"0 Chusyabahal 27.711235 85.312934 Central Region \n",
"1 Kwabahal 27.675248 85.324419 Central Region \n",
"5 Thamel 27.715492 85.310461 Central Region \n",
"6 Pashupatinath Rd. 27.709101 85.348620 Central Region \n",
"8 Makhan Tole 27.712171 85.311342 Central Region "
]
},
"execution_count": 214,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows with none values\n",
"clean_temples_dataframe3 = clean_temples_dataframe2.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)\n",
"clean_temples_dataframe3.head()"
]
},
{
"cell_type": "code",
"execution_count": 215,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Kantipur Temple House</td>\n",
" <td>Temple</td>\n",
" <td>Chusyabahal</td>\n",
" <td>27.711235</td>\n",
" <td>85.312934</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Hiranya Varna Mahavihar (Golden Temple)</td>\n",
" <td>Buddhist Temple</td>\n",
" <td>Kwabahal</td>\n",
" <td>27.675248</td>\n",
" <td>85.324419</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>Pashupatinath Temple</td>\n",
" <td>Temple</td>\n",
" <td>Pashupatinath Rd.</td>\n",
" <td>27.709101</td>\n",
" <td>85.348620</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>Taleju Temple</td>\n",
" <td>Temple</td>\n",
" <td>Makhan Tole</td>\n",
" <td>27.712171</td>\n",
" <td>85.311342</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>Pachali Bhairav Temple</td>\n",
" <td>Temple</td>\n",
" <td>Sanepa</td>\n",
" <td>27.703415</td>\n",
" <td>85.304869</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories \\\n",
"0 Kantipur Temple House Temple \n",
"1 Hiranya Varna Mahavihar (Golden Temple) Buddhist Temple \n",
"6 Pashupatinath Temple Temple \n",
"8 Taleju Temple Temple \n",
"16 Pachali Bhairav Temple Temple \n",
"\n",
" address lat lng state \n",
"0 Chusyabahal 27.711235 85.312934 Central Region \n",
"1 Kwabahal 27.675248 85.324419 Central Region \n",
"6 Pashupatinath Rd. 27.709101 85.348620 Central Region \n",
"8 Makhan Tole 27.712171 85.311342 Central Region \n",
"16 Sanepa 27.703415 85.304869 Central Region "
]
},
"execution_count": 215,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows which its category is not temples\n",
"df_temples = clean_temples_dataframe3[clean_temples_dataframe3.categories != 'Bar']\n",
"df_temples.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Search for Restaurants**"
]
},
{
"cell_type": "code",
"execution_count": 217,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'https://api.foursquare.com/v2/venues/search?client_id=UGHFMNO1HCOWOZTT0W5MXN0CKUIFZZU2OXV1KIM1CUL1KX31&client_secret=O0WTNIHI0W2Q1GUUJ34U0KCB3GBRD4OXCESMXMTVBB1SRCJV&ll=27.708796,85.320244&v=20190604&query=Restaurant&radius=20000&limit=50'"
]
},
"execution_count": 217,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# search for Restaurants\n",
"search_query = 'Restaurant'\n",
"radius = 20000\n",
"\n",
"# Define the corresponding URL\n",
"url = 'https://api.foursquare.com/v2/venues/search?client_id={}&client_secret={}&ll={},{}&v={}&query={}&radius={}&limit={}'.format(ClIENT_ID, ClIENT_SECRET, latitude, longitude, VERSION, search_query, radius, LIMIT)\n",
"url"
]
},
{
"cell_type": "code",
"execution_count": 218,
"metadata": {},
"outputs": [],
"source": [
"# Send the GET Request and examine the results\n",
"Rresults = requests.get(url).json()\n",
"#Rresults"
]
},
{
"cell_type": "code",
"execution_count": 219,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>categories</th>\n",
" <th>hasPerk</th>\n",
" <th>id</th>\n",
" <th>location.address</th>\n",
" <th>location.cc</th>\n",
" <th>location.city</th>\n",
" <th>location.country</th>\n",
" <th>location.crossStreet</th>\n",
" <th>location.distance</th>\n",
" <th>location.formattedAddress</th>\n",
" <th>location.labeledLatLngs</th>\n",
" <th>location.lat</th>\n",
" <th>location.lng</th>\n",
" <th>location.neighborhood</th>\n",
" <th>location.postalCode</th>\n",
" <th>location.state</th>\n",
" <th>name</th>\n",
" <th>referralId</th>\n",
" <th>venuePage.id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>[{'id': '4bf58dd8d48988d142941735', 'name': 'A...</td>\n",
" <td>False</td>\n",
" <td>4c829894d6ebbfb7b3234ca4</td>\n",
" <td>Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>971</td>\n",
" <td>[Thamel, काठमाडौं 44614, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71210903970303...</td>\n",
" <td>27.712109</td>\n",
" <td>85.311125</td>\n",
" <td>NaN</td>\n",
" <td>44614</td>\n",
" <td>Central Region</td>\n",
" <td>Yak Restaurant Bar &amp; Lodge</td>\n",
" <td>v-1562684417</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>[{'id': '4bf58dd8d48988d149941735', 'name': 'T...</td>\n",
" <td>False</td>\n",
" <td>4c73be8cf4d476b0cc2568cf</td>\n",
" <td>Chakshibari Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1188</td>\n",
" <td>[Chakshibari Marg (Thamel), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71463352584197...</td>\n",
" <td>27.714634</td>\n",
" <td>85.310147</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Yin Yang Restaurant</td>\n",
" <td>v-1562684417</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>[{'id': '4bf58dd8d48988d1ca941735', 'name': 'P...</td>\n",
" <td>False</td>\n",
" <td>4ed4d667cc216e1a537fcaaa</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>858</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71409424486691...</td>\n",
" <td>27.714094</td>\n",
" <td>85.313907</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Tranzit, Woodfire Pizza, Restaurant &amp; Bar</td>\n",
" <td>v-1562684417</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>[{'id': '4bf58dd8d48988d1c4941735', 'name': 'R...</td>\n",
" <td>False</td>\n",
" <td>5226cc3a93cd4ef097a79f2b</td>\n",
" <td>132, Kwobahal,Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Next to Hotel Nepalaya</td>\n",
" <td>935</td>\n",
" <td>[132, Kwobahal,Thamel (Next to Hotel Nepalaya)...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71167154001644...</td>\n",
" <td>27.711672</td>\n",
" <td>85.311328</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>Pilgrims 24 Restaurant &amp; Bar ( Formerly feed ...</td>\n",
" <td>v-1562684417</td>\n",
" <td>79287569</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[{'id': '4bf58dd8d48988d142941735', 'name': 'A...</td>\n",
" <td>False</td>\n",
" <td>5b41d00016fa04002c5397b5</td>\n",
" <td>Thamel-29, Narsing chowck</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1050</td>\n",
" <td>[Thamel-29, Narsing chowck, काठमाडौं 44600, ने...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71344161494465...</td>\n",
" <td>27.713442</td>\n",
" <td>85.310970</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>Nomad's Restaurant and Bar</td>\n",
" <td>v-1562684417</td>\n",
" <td>501845895</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" categories hasPerk \\\n",
"0 [{'id': '4bf58dd8d48988d142941735', 'name': 'A... False \n",
"1 [{'id': '4bf58dd8d48988d149941735', 'name': 'T... False \n",
"2 [{'id': '4bf58dd8d48988d1ca941735', 'name': 'P... False \n",
"3 [{'id': '4bf58dd8d48988d1c4941735', 'name': 'R... False \n",
"4 [{'id': '4bf58dd8d48988d142941735', 'name': 'A... False \n",
"\n",
" id location.address location.cc \\\n",
"0 4c829894d6ebbfb7b3234ca4 Thamel NP \n",
"1 4c73be8cf4d476b0cc2568cf Chakshibari Marg NP \n",
"2 4ed4d667cc216e1a537fcaaa NaN NP \n",
"3 5226cc3a93cd4ef097a79f2b 132, Kwobahal,Thamel NP \n",
"4 5b41d00016fa04002c5397b5 Thamel-29, Narsing chowck NP \n",
"\n",
" location.city location.country location.crossStreet location.distance \\\n",
"0 काठमाडौं नेपाल NaN 971 \n",
"1 काठमाडौं नेपाल Thamel 1188 \n",
"2 NaN नेपाल NaN 858 \n",
"3 काठमाडौं नेपाल Next to Hotel Nepalaya 935 \n",
"4 काठमाडौं नेपाल NaN 1050 \n",
"\n",
" location.formattedAddress \\\n",
"0 [Thamel, काठमाडौं 44614, नेपाल] \n",
"1 [Chakshibari Marg (Thamel), काठमाडौं, नेपाल] \n",
"2 [नेपाल] \n",
"3 [132, Kwobahal,Thamel (Next to Hotel Nepalaya)... \n",
"4 [Thamel-29, Narsing chowck, काठमाडौं 44600, ने... \n",
"\n",
" location.labeledLatLngs location.lat \\\n",
"0 [{'label': 'display', 'lat': 27.71210903970303... 27.712109 \n",
"1 [{'label': 'display', 'lat': 27.71463352584197... 27.714634 \n",
"2 [{'label': 'display', 'lat': 27.71409424486691... 27.714094 \n",
"3 [{'label': 'display', 'lat': 27.71167154001644... 27.711672 \n",
"4 [{'label': 'display', 'lat': 27.71344161494465... 27.713442 \n",
"\n",
" location.lng location.neighborhood location.postalCode location.state \\\n",
"0 85.311125 NaN 44614 Central Region \n",
"1 85.310147 NaN NaN Central Region \n",
"2 85.313907 NaN NaN NaN \n",
"3 85.311328 NaN 44600 Central Region \n",
"4 85.310970 NaN 44600 Central Region \n",
"\n",
" name referralId \\\n",
"0 Yak Restaurant Bar & Lodge v-1562684417 \n",
"1 Yin Yang Restaurant v-1562684417 \n",
"2 Tranzit, Woodfire Pizza, Restaurant & Bar v-1562684417 \n",
"3 Pilgrims 24 Restaurant & Bar ( Formerly feed ... v-1562684417 \n",
"4 Nomad's Restaurant and Bar v-1562684417 \n",
"\n",
" venuePage.id \n",
"0 NaN \n",
"1 NaN \n",
"2 NaN \n",
"3 79287569 \n",
"4 501845895 "
]
},
"execution_count": 219,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# assign relevant part of JSON to venues\n",
"venues = Rresults['response']['venues']\n",
"\n",
"# tranform venues into a dataframe\n",
"Restaurant_dataframe = json_normalize(venues)\n",
"Restaurant_dataframe.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Clean Restaurant Dataframe**"
]
},
{
"cell_type": "code",
"execution_count": 220,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>cc</th>\n",
" <th>city</th>\n",
" <th>country</th>\n",
" <th>crossStreet</th>\n",
" <th>distance</th>\n",
" <th>formattedAddress</th>\n",
" <th>labeledLatLngs</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>neighborhood</th>\n",
" <th>postalCode</th>\n",
" <th>state</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Yak Restaurant Bar &amp; Lodge</td>\n",
" <td>Asian Restaurant</td>\n",
" <td>Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>971</td>\n",
" <td>[Thamel, काठमाडौं 44614, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71210903970303...</td>\n",
" <td>27.712109</td>\n",
" <td>85.311125</td>\n",
" <td>NaN</td>\n",
" <td>44614</td>\n",
" <td>Central Region</td>\n",
" <td>4c829894d6ebbfb7b3234ca4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Yin Yang Restaurant</td>\n",
" <td>Thai Restaurant</td>\n",
" <td>Chakshibari Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1188</td>\n",
" <td>[Chakshibari Marg (Thamel), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71463352584197...</td>\n",
" <td>27.714634</td>\n",
" <td>85.310147</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4c73be8cf4d476b0cc2568cf</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Tranzit, Woodfire Pizza, Restaurant &amp; Bar</td>\n",
" <td>Pizza Place</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>858</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71409424486691...</td>\n",
" <td>27.714094</td>\n",
" <td>85.313907</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>4ed4d667cc216e1a537fcaaa</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Pilgrims 24 Restaurant &amp; Bar ( Formerly feed ...</td>\n",
" <td>Restaurant</td>\n",
" <td>132, Kwobahal,Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Next to Hotel Nepalaya</td>\n",
" <td>935</td>\n",
" <td>[132, Kwobahal,Thamel (Next to Hotel Nepalaya)...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71167154001644...</td>\n",
" <td>27.711672</td>\n",
" <td>85.311328</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>5226cc3a93cd4ef097a79f2b</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Nomad's Restaurant and Bar</td>\n",
" <td>Asian Restaurant</td>\n",
" <td>Thamel-29, Narsing chowck</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1050</td>\n",
" <td>[Thamel-29, Narsing chowck, काठमाडौं 44600, ने...</td>\n",
" <td>[{'label': 'display', 'lat': 27.71344161494465...</td>\n",
" <td>27.713442</td>\n",
" <td>85.310970</td>\n",
" <td>NaN</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>5b41d00016fa04002c5397b5</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories \\\n",
"0 Yak Restaurant Bar & Lodge Asian Restaurant \n",
"1 Yin Yang Restaurant Thai Restaurant \n",
"2 Tranzit, Woodfire Pizza, Restaurant & Bar Pizza Place \n",
"3 Pilgrims 24 Restaurant & Bar ( Formerly feed ... Restaurant \n",
"4 Nomad's Restaurant and Bar Asian Restaurant \n",
"\n",
" address cc city country crossStreet \\\n",
"0 Thamel NP काठमाडौं नेपाल NaN \n",
"1 Chakshibari Marg NP काठमाडौं नेपाल Thamel \n",
"2 NaN NP NaN नेपाल NaN \n",
"3 132, Kwobahal,Thamel NP काठमाडौं नेपाल Next to Hotel Nepalaya \n",
"4 Thamel-29, Narsing chowck NP काठमाडौं नेपाल NaN \n",
"\n",
" distance formattedAddress \\\n",
"0 971 [Thamel, काठमाडौं 44614, नेपाल] \n",
"1 1188 [Chakshibari Marg (Thamel), काठमाडौं, नेपाल] \n",
"2 858 [नेपाल] \n",
"3 935 [132, Kwobahal,Thamel (Next to Hotel Nepalaya)... \n",
"4 1050 [Thamel-29, Narsing chowck, काठमाडौं 44600, ने... \n",
"\n",
" labeledLatLngs lat lng \\\n",
"0 [{'label': 'display', 'lat': 27.71210903970303... 27.712109 85.311125 \n",
"1 [{'label': 'display', 'lat': 27.71463352584197... 27.714634 85.310147 \n",
"2 [{'label': 'display', 'lat': 27.71409424486691... 27.714094 85.313907 \n",
"3 [{'label': 'display', 'lat': 27.71167154001644... 27.711672 85.311328 \n",
"4 [{'label': 'display', 'lat': 27.71344161494465... 27.713442 85.310970 \n",
"\n",
" neighborhood postalCode state id \n",
"0 NaN 44614 Central Region 4c829894d6ebbfb7b3234ca4 \n",
"1 NaN NaN Central Region 4c73be8cf4d476b0cc2568cf \n",
"2 NaN NaN NaN 4ed4d667cc216e1a537fcaaa \n",
"3 NaN 44600 Central Region 5226cc3a93cd4ef097a79f2b \n",
"4 NaN 44600 Central Region 5b41d00016fa04002c5397b5 "
]
},
"execution_count": 220,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# keep only columns that include venue name, and anything that is associated with location\n",
"Restaurant_clean_columns = ['name', 'categories'] + [col for col in Restaurant_dataframe.columns if col.startswith('location.')]+ ['id']\n",
"clean_Restaurant_dataframe = Restaurant_dataframe.loc[:,Restaurant_clean_columns]\n",
"\n",
"# function that extracts the category of the venue\n",
"def get_category_type(row):\n",
" try:\n",
" categories_list3 = row['categories']\n",
" except:\n",
" categories_list3 = row['venue.categories']\n",
" \n",
" if len(categories_list3) == 0:\n",
" return None\n",
" else:\n",
" return categories_list3[0]['name']\n",
"\n",
"# filter the category for each row\n",
"clean_Restaurant_dataframe['categories'] = clean_Restaurant_dataframe.apply(get_category_type, axis=1)\n",
"\n",
"# clean column names by keeping only last term\n",
"clean_Restaurant_dataframe.columns = [column.split('.')[-1] for column in clean_Restaurant_dataframe.columns]\n",
"\n",
"clean_Restaurant_dataframe.head()"
]
},
{
"cell_type": "code",
"execution_count": 221,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>neighborhood</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Yak Restaurant Bar &amp; Lodge</td>\n",
" <td>Asian Restaurant</td>\n",
" <td>Thamel</td>\n",
" <td>27.712109</td>\n",
" <td>85.311125</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Yin Yang Restaurant</td>\n",
" <td>Thai Restaurant</td>\n",
" <td>Chakshibari Marg</td>\n",
" <td>27.714634</td>\n",
" <td>85.310147</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Tranzit, Woodfire Pizza, Restaurant &amp; Bar</td>\n",
" <td>Pizza Place</td>\n",
" <td>NaN</td>\n",
" <td>27.714094</td>\n",
" <td>85.313907</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Pilgrims 24 Restaurant &amp; Bar ( Formerly feed ...</td>\n",
" <td>Restaurant</td>\n",
" <td>132, Kwobahal,Thamel</td>\n",
" <td>27.711672</td>\n",
" <td>85.311328</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Nomad's Restaurant and Bar</td>\n",
" <td>Asian Restaurant</td>\n",
" <td>Thamel-29, Narsing chowck</td>\n",
" <td>27.713442</td>\n",
" <td>85.310970</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories \\\n",
"0 Yak Restaurant Bar & Lodge Asian Restaurant \n",
"1 Yin Yang Restaurant Thai Restaurant \n",
"2 Tranzit, Woodfire Pizza, Restaurant & Bar Pizza Place \n",
"3 Pilgrims 24 Restaurant & Bar ( Formerly feed ... Restaurant \n",
"4 Nomad's Restaurant and Bar Asian Restaurant \n",
"\n",
" address lat lng neighborhood \\\n",
"0 Thamel 27.712109 85.311125 NaN \n",
"1 Chakshibari Marg 27.714634 85.310147 NaN \n",
"2 NaN 27.714094 85.313907 NaN \n",
"3 132, Kwobahal,Thamel 27.711672 85.311328 NaN \n",
"4 Thamel-29, Narsing chowck 27.713442 85.310970 NaN \n",
"\n",
" state \n",
"0 Central Region \n",
"1 Central Region \n",
"2 NaN \n",
"3 Central Region \n",
"4 Central Region "
]
},
"execution_count": 221,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete unnecessary columns\n",
"clean_Restaurant_dataframe2= clean_Restaurant_dataframe.drop(['cc', 'city', 'country', 'crossStreet', 'distance', 'formattedAddress',\\\n",
" 'labeledLatLngs','postalCode', 'id'], axis=1)\n",
"clean_Restaurant_dataframe2.head()"
]
},
{
"cell_type": "code",
"execution_count": 222,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>neighborhood</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"Empty DataFrame\n",
"Columns: [name, categories, address, lat, lng, neighborhood, state]\n",
"Index: []"
]
},
"execution_count": 222,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows with none values\n",
"df_Restaurant = clean_Restaurant_dataframe2.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)\n",
"df_Restaurant.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Search for Cafeteria**"
]
},
{
"cell_type": "code",
"execution_count": 223,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'https://api.foursquare.com/v2/venues/search?client_id=UGHFMNO1HCOWOZTT0W5MXN0CKUIFZZU2OXV1KIM1CUL1KX31&client_secret=O0WTNIHI0W2Q1GUUJ34U0KCB3GBRD4OXCESMXMTVBB1SRCJV&ll=27.708796,85.320244&v=20190604&query=Cafe&radius=20000&limit=50'"
]
},
"execution_count": 223,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# search for Cafeteria\n",
"search_query = 'Cafe'\n",
"radius = 20000\n",
"\n",
"# Define the corresponding URL\n",
"url = 'https://api.foursquare.com/v2/venues/search?client_id={}&client_secret={}&ll={},{}&v={}&query={}&radius={}&limit={}'.format(ClIENT_ID, ClIENT_SECRET, latitude, longitude, VERSION, search_query, radius, LIMIT)\n",
"url"
]
},
{
"cell_type": "code",
"execution_count": 224,
"metadata": {},
"outputs": [],
"source": [
"# Send the GET Request and examine the results\n",
"cresults = requests.get(url).json()\n",
"#cresults"
]
},
{
"cell_type": "code",
"execution_count": 225,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>categories</th>\n",
" <th>hasPerk</th>\n",
" <th>id</th>\n",
" <th>location.address</th>\n",
" <th>location.cc</th>\n",
" <th>location.city</th>\n",
" <th>location.country</th>\n",
" <th>location.crossStreet</th>\n",
" <th>location.distance</th>\n",
" <th>location.formattedAddress</th>\n",
" <th>location.labeledLatLngs</th>\n",
" <th>location.lat</th>\n",
" <th>location.lng</th>\n",
" <th>location.neighborhood</th>\n",
" <th>location.postalCode</th>\n",
" <th>location.state</th>\n",
" <th>name</th>\n",
" <th>referralId</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>[{'id': '4bf58dd8d48988d16d941735', 'name': 'C...</td>\n",
" <td>False</td>\n",
" <td>4d859cde7e8ef04d051625be</td>\n",
" <td>Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1244</td>\n",
" <td>[Thamel, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71555500419936...</td>\n",
" <td>27.715555</td>\n",
" <td>85.310185</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>The Northfield Cafe and Jesse James Bar</td>\n",
" <td>v-1562684420</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>[{'id': '4bf58dd8d48988d1e0931735', 'name': 'C...</td>\n",
" <td>False</td>\n",
" <td>4ea4309a30f8b9d5ad12dd10</td>\n",
" <td>Amrit Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1033</td>\n",
" <td>[Amrit Marg (Thamel), काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.715046, 'lng':...</td>\n",
" <td>27.715046</td>\n",
" <td>85.312490</td>\n",
" <td>Oposite of TIM Office at Manang Plaza</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>Revolution Cafe</td>\n",
" <td>v-1562684420</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>[{'id': '4bf58dd8d48988d1e0931735', 'name': 'C...</td>\n",
" <td>False</td>\n",
" <td>5c00c65178782c002cf88376</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1116</td>\n",
" <td>[काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.716141, 'lng':...</td>\n",
" <td>27.716141</td>\n",
" <td>85.312529</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>The Musketeerz Cafe</td>\n",
" <td>v-1562684420</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>[{'id': '4bf58dd8d48988d16d941735', 'name': 'C...</td>\n",
" <td>False</td>\n",
" <td>515a8aeae4b04ee4fe4123a1</td>\n",
" <td>Naxal</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Narayanchour</td>\n",
" <td>910</td>\n",
" <td>[Naxal (Narayanchour), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71517974841629...</td>\n",
" <td>27.715180</td>\n",
" <td>85.326025</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Espression: The Cafe</td>\n",
" <td>v-1562684420</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[{'id': '4bf58dd8d48988d16d941735', 'name': 'C...</td>\n",
" <td>False</td>\n",
" <td>4db18ee3fa8ca4b3e9f9f631</td>\n",
" <td>Bhat Bhateni</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1674</td>\n",
" <td>[Bhat Bhateni, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.72010609039776...</td>\n",
" <td>27.720106</td>\n",
" <td>85.331453</td>\n",
" <td>Baluwatar</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Road House Cafe</td>\n",
" <td>v-1562684420</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" categories hasPerk \\\n",
"0 [{'id': '4bf58dd8d48988d16d941735', 'name': 'C... False \n",
"1 [{'id': '4bf58dd8d48988d1e0931735', 'name': 'C... False \n",
"2 [{'id': '4bf58dd8d48988d1e0931735', 'name': 'C... False \n",
"3 [{'id': '4bf58dd8d48988d16d941735', 'name': 'C... False \n",
"4 [{'id': '4bf58dd8d48988d16d941735', 'name': 'C... False \n",
"\n",
" id location.address location.cc location.city \\\n",
"0 4d859cde7e8ef04d051625be Thamel NP काठमाडौं \n",
"1 4ea4309a30f8b9d5ad12dd10 Amrit Marg NP काठमाडौं \n",
"2 5c00c65178782c002cf88376 NaN NP काठमाडौं \n",
"3 515a8aeae4b04ee4fe4123a1 Naxal NP काठमाडौं \n",
"4 4db18ee3fa8ca4b3e9f9f631 Bhat Bhateni NP काठमाडौं \n",
"\n",
" location.country location.crossStreet location.distance \\\n",
"0 नेपाल NaN 1244 \n",
"1 नेपाल Thamel 1033 \n",
"2 नेपाल NaN 1116 \n",
"3 नेपाल Narayanchour 910 \n",
"4 नेपाल NaN 1674 \n",
"\n",
" location.formattedAddress \\\n",
"0 [Thamel, काठमाडौं, नेपाल] \n",
"1 [Amrit Marg (Thamel), काठमाडौं 44600, नेपाल] \n",
"2 [काठमाडौं, नेपाल] \n",
"3 [Naxal (Narayanchour), काठमाडौं, नेपाल] \n",
"4 [Bhat Bhateni, काठमाडौं, नेपाल] \n",
"\n",
" location.labeledLatLngs location.lat \\\n",
"0 [{'label': 'display', 'lat': 27.71555500419936... 27.715555 \n",
"1 [{'label': 'display', 'lat': 27.715046, 'lng':... 27.715046 \n",
"2 [{'label': 'display', 'lat': 27.716141, 'lng':... 27.716141 \n",
"3 [{'label': 'display', 'lat': 27.71517974841629... 27.715180 \n",
"4 [{'label': 'display', 'lat': 27.72010609039776... 27.720106 \n",
"\n",
" location.lng location.neighborhood location.postalCode \\\n",
"0 85.310185 NaN NaN \n",
"1 85.312490 Oposite of TIM Office at Manang Plaza 44600 \n",
"2 85.312529 NaN NaN \n",
"3 85.326025 NaN NaN \n",
"4 85.331453 Baluwatar NaN \n",
"\n",
" location.state name referralId \n",
"0 Central Region The Northfield Cafe and Jesse James Bar v-1562684420 \n",
"1 Central Region Revolution Cafe v-1562684420 \n",
"2 Central Region The Musketeerz Cafe v-1562684420 \n",
"3 Central Region Espression: The Cafe v-1562684420 \n",
"4 Central Region Road House Cafe v-1562684420 "
]
},
"execution_count": 225,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# assign relevant part of JSON to venues\n",
"venues = cresults['response']['venues']\n",
"\n",
"# tranform venues into a dataframe\n",
"Cafeteria_dataframe = json_normalize(venues)\n",
"Cafeteria_dataframe.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Clean Cafeteria Dataframe**"
]
},
{
"cell_type": "code",
"execution_count": 226,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>cc</th>\n",
" <th>city</th>\n",
" <th>country</th>\n",
" <th>crossStreet</th>\n",
" <th>distance</th>\n",
" <th>formattedAddress</th>\n",
" <th>labeledLatLngs</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>neighborhood</th>\n",
" <th>postalCode</th>\n",
" <th>state</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>The Northfield Cafe and Jesse James Bar</td>\n",
" <td>Café</td>\n",
" <td>Thamel</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1244</td>\n",
" <td>[Thamel, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71555500419936...</td>\n",
" <td>27.715555</td>\n",
" <td>85.310185</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4d859cde7e8ef04d051625be</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Revolution Cafe</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Amrit Marg</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Thamel</td>\n",
" <td>1033</td>\n",
" <td>[Amrit Marg (Thamel), काठमाडौं 44600, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.715046, 'lng':...</td>\n",
" <td>27.715046</td>\n",
" <td>85.312490</td>\n",
" <td>Oposite of TIM Office at Manang Plaza</td>\n",
" <td>44600</td>\n",
" <td>Central Region</td>\n",
" <td>4ea4309a30f8b9d5ad12dd10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>The Musketeerz Cafe</td>\n",
" <td>Coffee Shop</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1116</td>\n",
" <td>[काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.716141, 'lng':...</td>\n",
" <td>27.716141</td>\n",
" <td>85.312529</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>5c00c65178782c002cf88376</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Espression: The Cafe</td>\n",
" <td>Café</td>\n",
" <td>Naxal</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>Narayanchour</td>\n",
" <td>910</td>\n",
" <td>[Naxal (Narayanchour), काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.71517974841629...</td>\n",
" <td>27.715180</td>\n",
" <td>85.326025</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>515a8aeae4b04ee4fe4123a1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Road House Cafe</td>\n",
" <td>Café</td>\n",
" <td>Bhat Bhateni</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1674</td>\n",
" <td>[Bhat Bhateni, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.72010609039776...</td>\n",
" <td>27.720106</td>\n",
" <td>85.331453</td>\n",
" <td>Baluwatar</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4db18ee3fa8ca4b3e9f9f631</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address cc \\\n",
"0 The Northfield Cafe and Jesse James Bar Café Thamel NP \n",
"1 Revolution Cafe Coffee Shop Amrit Marg NP \n",
"2 The Musketeerz Cafe Coffee Shop NaN NP \n",
"3 Espression: The Cafe Café Naxal NP \n",
"4 Road House Cafe Café Bhat Bhateni NP \n",
"\n",
" city country crossStreet distance \\\n",
"0 काठमाडौं नेपाल NaN 1244 \n",
"1 काठमाडौं नेपाल Thamel 1033 \n",
"2 काठमाडौं नेपाल NaN 1116 \n",
"3 काठमाडौं नेपाल Narayanchour 910 \n",
"4 काठमाडौं नेपाल NaN 1674 \n",
"\n",
" formattedAddress \\\n",
"0 [Thamel, काठमाडौं, नेपाल] \n",
"1 [Amrit Marg (Thamel), काठमाडौं 44600, नेपाल] \n",
"2 [काठमाडौं, नेपाल] \n",
"3 [Naxal (Narayanchour), काठमाडौं, नेपाल] \n",
"4 [Bhat Bhateni, काठमाडौं, नेपाल] \n",
"\n",
" labeledLatLngs lat lng \\\n",
"0 [{'label': 'display', 'lat': 27.71555500419936... 27.715555 85.310185 \n",
"1 [{'label': 'display', 'lat': 27.715046, 'lng':... 27.715046 85.312490 \n",
"2 [{'label': 'display', 'lat': 27.716141, 'lng':... 27.716141 85.312529 \n",
"3 [{'label': 'display', 'lat': 27.71517974841629... 27.715180 85.326025 \n",
"4 [{'label': 'display', 'lat': 27.72010609039776... 27.720106 85.331453 \n",
"\n",
" neighborhood postalCode state \\\n",
"0 NaN NaN Central Region \n",
"1 Oposite of TIM Office at Manang Plaza 44600 Central Region \n",
"2 NaN NaN Central Region \n",
"3 NaN NaN Central Region \n",
"4 Baluwatar NaN Central Region \n",
"\n",
" id \n",
"0 4d859cde7e8ef04d051625be \n",
"1 4ea4309a30f8b9d5ad12dd10 \n",
"2 5c00c65178782c002cf88376 \n",
"3 515a8aeae4b04ee4fe4123a1 \n",
"4 4db18ee3fa8ca4b3e9f9f631 "
]
},
"execution_count": 226,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# keep only columns that include venue name, and anything that is associated with location\n",
"Cafeteria_clean_columns = ['name', 'categories'] + [col for col in Cafeteria_dataframe.columns if col.startswith('location.')]+ ['id']\n",
"clean_Cafeteria_dataframe = Cafeteria_dataframe.loc[:,Cafeteria_clean_columns]\n",
"\n",
"# function that extracts the category of the venue\n",
"def get_category_type(row):\n",
" try:\n",
" categories_list4 = row['categories']\n",
" except:\n",
" categories_list4 = row['venue.categories']\n",
" \n",
" if len(categories_list4) == 0:\n",
" return None\n",
" else:\n",
" return categories_list4[0]['name']\n",
"\n",
"# filter the category for each row\n",
"clean_Cafeteria_dataframe['categories'] = clean_Cafeteria_dataframe.apply(get_category_type, axis=1)\n",
"\n",
"# clean column names by keeping only last term\n",
"clean_Cafeteria_dataframe.columns = [column.split('.')[-1] for column in clean_Cafeteria_dataframe.columns]\n",
"\n",
"clean_Cafeteria_dataframe.head()"
]
},
{
"cell_type": "code",
"execution_count": 227,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>The Northfield Cafe and Jesse James Bar</td>\n",
" <td>Café</td>\n",
" <td>Thamel</td>\n",
" <td>27.715555</td>\n",
" <td>85.310185</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Revolution Cafe</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Amrit Marg</td>\n",
" <td>27.715046</td>\n",
" <td>85.312490</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>The Musketeerz Cafe</td>\n",
" <td>Coffee Shop</td>\n",
" <td>NaN</td>\n",
" <td>27.716141</td>\n",
" <td>85.312529</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Espression: The Cafe</td>\n",
" <td>Café</td>\n",
" <td>Naxal</td>\n",
" <td>27.715180</td>\n",
" <td>85.326025</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Road House Cafe</td>\n",
" <td>Café</td>\n",
" <td>Bhat Bhateni</td>\n",
" <td>27.720106</td>\n",
" <td>85.331453</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address \\\n",
"0 The Northfield Cafe and Jesse James Bar Café Thamel \n",
"1 Revolution Cafe Coffee Shop Amrit Marg \n",
"2 The Musketeerz Cafe Coffee Shop NaN \n",
"3 Espression: The Cafe Café Naxal \n",
"4 Road House Cafe Café Bhat Bhateni \n",
"\n",
" lat lng state \n",
"0 27.715555 85.310185 Central Region \n",
"1 27.715046 85.312490 Central Region \n",
"2 27.716141 85.312529 Central Region \n",
"3 27.715180 85.326025 Central Region \n",
"4 27.720106 85.331453 Central Region "
]
},
"execution_count": 227,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete unnecessary columns\n",
"clean_Cafeteria_dataframe2= clean_Cafeteria_dataframe.drop(['cc', 'city', 'country', 'crossStreet', 'distance', 'formattedAddress',\\\n",
" 'labeledLatLngs', 'postalCode', 'neighborhood', 'id'], axis=1)\n",
"clean_Cafeteria_dataframe2.head()"
]
},
{
"cell_type": "code",
"execution_count": 228,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>The Northfield Cafe and Jesse James Bar</td>\n",
" <td>Café</td>\n",
" <td>Thamel</td>\n",
" <td>27.715555</td>\n",
" <td>85.310185</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Revolution Cafe</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Amrit Marg</td>\n",
" <td>27.715046</td>\n",
" <td>85.312490</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Espression: The Cafe</td>\n",
" <td>Café</td>\n",
" <td>Naxal</td>\n",
" <td>27.715180</td>\n",
" <td>85.326025</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Road House Cafe</td>\n",
" <td>Café</td>\n",
" <td>Bhat Bhateni</td>\n",
" <td>27.720106</td>\n",
" <td>85.331453</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Cafe Mondo Bizarro</td>\n",
" <td>Restaurant</td>\n",
" <td>Freak Street</td>\n",
" <td>27.703222</td>\n",
" <td>85.307922</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address \\\n",
"0 The Northfield Cafe and Jesse James Bar Café Thamel \n",
"1 Revolution Cafe Coffee Shop Amrit Marg \n",
"3 Espression: The Cafe Café Naxal \n",
"4 Road House Cafe Café Bhat Bhateni \n",
"5 Cafe Mondo Bizarro Restaurant Freak Street \n",
"\n",
" lat lng state \n",
"0 27.715555 85.310185 Central Region \n",
"1 27.715046 85.312490 Central Region \n",
"3 27.715180 85.326025 Central Region \n",
"4 27.720106 85.331453 Central Region \n",
"5 27.703222 85.307922 Central Region "
]
},
"execution_count": 228,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows with none values\n",
"df_Cafeteria = clean_Cafeteria_dataframe2.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)\n",
"df_Cafeteria.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Search for Shopping Stores**"
]
},
{
"cell_type": "code",
"execution_count": 229,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'https://api.foursquare.com/v2/venues/search?client_id=UGHFMNO1HCOWOZTT0W5MXN0CKUIFZZU2OXV1KIM1CUL1KX31&client_secret=O0WTNIHI0W2Q1GUUJ34U0KCB3GBRD4OXCESMXMTVBB1SRCJV&ll=27.708796,85.320244&v=20190604&query=Mall&radius=20000&limit=50'"
]
},
"execution_count": 229,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# search for Shopping\n",
"search_query = 'Mall'\n",
"radius = 20000\n",
"\n",
"# Define the corresponding URL\n",
"url = 'https://api.foursquare.com/v2/venues/search?client_id={}&client_secret={}&ll={},{}&v={}&query={}&radius={}&limit={}'.format(ClIENT_ID, ClIENT_SECRET, latitude, longitude, VERSION, search_query, radius, LIMIT)\n",
"url"
]
},
{
"cell_type": "code",
"execution_count": 230,
"metadata": {},
"outputs": [],
"source": [
"# Send the GET Request and examine the results\n",
"sresults = requests.get(url).json()\n",
"#sresults"
]
},
{
"cell_type": "code",
"execution_count": 231,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>categories</th>\n",
" <th>hasPerk</th>\n",
" <th>id</th>\n",
" <th>location.address</th>\n",
" <th>location.cc</th>\n",
" <th>location.city</th>\n",
" <th>location.country</th>\n",
" <th>location.crossStreet</th>\n",
" <th>location.distance</th>\n",
" <th>location.formattedAddress</th>\n",
" <th>location.labeledLatLngs</th>\n",
" <th>location.lat</th>\n",
" <th>location.lng</th>\n",
" <th>location.postalCode</th>\n",
" <th>location.state</th>\n",
" <th>name</th>\n",
" <th>referralId</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>[{'id': '4bf58dd8d48988d1f6941735', 'name': 'D...</td>\n",
" <td>False</td>\n",
" <td>4c99d148d4b1b1f7348fca35</td>\n",
" <td>Tripureshwor</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1931</td>\n",
" <td>[Tripureshwor, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.69167187818288...</td>\n",
" <td>27.691672</td>\n",
" <td>85.317112</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Bluebird Mall</td>\n",
" <td>v-1562684424</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>[{'id': '4bf58dd8d48988d108951735', 'name': 'W...</td>\n",
" <td>False</td>\n",
" <td>556ac8d7498e64da5cd5548f</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>160</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.709596, 'lng':...</td>\n",
" <td>27.709596</td>\n",
" <td>85.318886</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>The Collective, Rising Mall</td>\n",
" <td>v-1562684424</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fd941735', 'name': 'S...</td>\n",
" <td>False</td>\n",
" <td>4c6bb91d0c3ac9b6a78dd238</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>170</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70887801979128...</td>\n",
" <td>27.708878</td>\n",
" <td>85.321969</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>China Town Mall</td>\n",
" <td>v-1562684424</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>[{'id': '4bf58dd8d48988d1fd941735', 'name': 'S...</td>\n",
" <td>False</td>\n",
" <td>5291e861498e3ee2d83f0dcb</td>\n",
" <td>Kamaladi</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>171</td>\n",
" <td>[Kamaladi, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70994931134238...</td>\n",
" <td>27.709949</td>\n",
" <td>85.319086</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>Rising Mall</td>\n",
" <td>v-1562684424</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>[{'id': '4bf58dd8d48988d108951735', 'name': 'W...</td>\n",
" <td>False</td>\n",
" <td>5956305df4b5252a672602f7</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>247</td>\n",
" <td>[काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.710111, 'lng':...</td>\n",
" <td>27.710111</td>\n",
" <td>85.318224</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>Madame Rising Mall</td>\n",
" <td>v-1562684424</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" categories hasPerk \\\n",
"0 [{'id': '4bf58dd8d48988d1f6941735', 'name': 'D... False \n",
"1 [{'id': '4bf58dd8d48988d108951735', 'name': 'W... False \n",
"2 [{'id': '4bf58dd8d48988d1fd941735', 'name': 'S... False \n",
"3 [{'id': '4bf58dd8d48988d1fd941735', 'name': 'S... False \n",
"4 [{'id': '4bf58dd8d48988d108951735', 'name': 'W... False \n",
"\n",
" id location.address location.cc location.city \\\n",
"0 4c99d148d4b1b1f7348fca35 Tripureshwor NP काठमाडौं \n",
"1 556ac8d7498e64da5cd5548f NaN NP NaN \n",
"2 4c6bb91d0c3ac9b6a78dd238 NaN NP NaN \n",
"3 5291e861498e3ee2d83f0dcb Kamaladi NP NaN \n",
"4 5956305df4b5252a672602f7 NaN NP काठमाडौं \n",
"\n",
" location.country location.crossStreet location.distance \\\n",
"0 नेपाल NaN 1931 \n",
"1 नेपाल NaN 160 \n",
"2 नेपाल NaN 170 \n",
"3 नेपाल NaN 171 \n",
"4 नेपाल NaN 247 \n",
"\n",
" location.formattedAddress \\\n",
"0 [Tripureshwor, काठमाडौं, नेपाल] \n",
"1 [नेपाल] \n",
"2 [नेपाल] \n",
"3 [Kamaladi, नेपाल] \n",
"4 [काठमाडौं, नेपाल] \n",
"\n",
" location.labeledLatLngs location.lat \\\n",
"0 [{'label': 'display', 'lat': 27.69167187818288... 27.691672 \n",
"1 [{'label': 'display', 'lat': 27.709596, 'lng':... 27.709596 \n",
"2 [{'label': 'display', 'lat': 27.70887801979128... 27.708878 \n",
"3 [{'label': 'display', 'lat': 27.70994931134238... 27.709949 \n",
"4 [{'label': 'display', 'lat': 27.710111, 'lng':... 27.710111 \n",
"\n",
" location.lng location.postalCode location.state \\\n",
"0 85.317112 NaN Central Region \n",
"1 85.318886 NaN NaN \n",
"2 85.321969 NaN NaN \n",
"3 85.319086 NaN NaN \n",
"4 85.318224 NaN Central Region \n",
"\n",
" name referralId \n",
"0 Bluebird Mall v-1562684424 \n",
"1 The Collective, Rising Mall v-1562684424 \n",
"2 China Town Mall v-1562684424 \n",
"3 Rising Mall v-1562684424 \n",
"4 Madame Rising Mall v-1562684424 "
]
},
"execution_count": 231,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# assign relevant part of JSON to venues\n",
"venues = sresults['response']['venues']\n",
"\n",
"# tranform venues into a dataframe\n",
"Shopping_dataframe = json_normalize(venues)\n",
"Shopping_dataframe.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Clean Shopping Dataframe**"
]
},
{
"cell_type": "code",
"execution_count": 232,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>cc</th>\n",
" <th>city</th>\n",
" <th>country</th>\n",
" <th>crossStreet</th>\n",
" <th>distance</th>\n",
" <th>formattedAddress</th>\n",
" <th>labeledLatLngs</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>postalCode</th>\n",
" <th>state</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Bluebird Mall</td>\n",
" <td>Department Store</td>\n",
" <td>Tripureshwor</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>1931</td>\n",
" <td>[Tripureshwor, काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.69167187818288...</td>\n",
" <td>27.691672</td>\n",
" <td>85.317112</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>4c99d148d4b1b1f7348fca35</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>The Collective, Rising Mall</td>\n",
" <td>Women's Store</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>160</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.709596, 'lng':...</td>\n",
" <td>27.709596</td>\n",
" <td>85.318886</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>556ac8d7498e64da5cd5548f</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>China Town Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>170</td>\n",
" <td>[नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70887801979128...</td>\n",
" <td>27.708878</td>\n",
" <td>85.321969</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>4c6bb91d0c3ac9b6a78dd238</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Rising Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Kamaladi</td>\n",
" <td>NP</td>\n",
" <td>NaN</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>171</td>\n",
" <td>[Kamaladi, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.70994931134238...</td>\n",
" <td>27.709949</td>\n",
" <td>85.319086</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>5291e861498e3ee2d83f0dcb</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Madame Rising Mall</td>\n",
" <td>Women's Store</td>\n",
" <td>NaN</td>\n",
" <td>NP</td>\n",
" <td>काठमाडौं</td>\n",
" <td>नेपाल</td>\n",
" <td>NaN</td>\n",
" <td>247</td>\n",
" <td>[काठमाडौं, नेपाल]</td>\n",
" <td>[{'label': 'display', 'lat': 27.710111, 'lng':...</td>\n",
" <td>27.710111</td>\n",
" <td>85.318224</td>\n",
" <td>NaN</td>\n",
" <td>Central Region</td>\n",
" <td>5956305df4b5252a672602f7</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address cc city \\\n",
"0 Bluebird Mall Department Store Tripureshwor NP काठमाडौं \n",
"1 The Collective, Rising Mall Women's Store NaN NP NaN \n",
"2 China Town Mall Shopping Mall NaN NP NaN \n",
"3 Rising Mall Shopping Mall Kamaladi NP NaN \n",
"4 Madame Rising Mall Women's Store NaN NP काठमाडौं \n",
"\n",
" country crossStreet distance formattedAddress \\\n",
"0 नेपाल NaN 1931 [Tripureshwor, काठमाडौं, नेपाल] \n",
"1 नेपाल NaN 160 [नेपाल] \n",
"2 नेपाल NaN 170 [नेपाल] \n",
"3 नेपाल NaN 171 [Kamaladi, नेपाल] \n",
"4 नेपाल NaN 247 [काठमाडौं, नेपाल] \n",
"\n",
" labeledLatLngs lat lng \\\n",
"0 [{'label': 'display', 'lat': 27.69167187818288... 27.691672 85.317112 \n",
"1 [{'label': 'display', 'lat': 27.709596, 'lng':... 27.709596 85.318886 \n",
"2 [{'label': 'display', 'lat': 27.70887801979128... 27.708878 85.321969 \n",
"3 [{'label': 'display', 'lat': 27.70994931134238... 27.709949 85.319086 \n",
"4 [{'label': 'display', 'lat': 27.710111, 'lng':... 27.710111 85.318224 \n",
"\n",
" postalCode state id \n",
"0 NaN Central Region 4c99d148d4b1b1f7348fca35 \n",
"1 NaN NaN 556ac8d7498e64da5cd5548f \n",
"2 NaN NaN 4c6bb91d0c3ac9b6a78dd238 \n",
"3 NaN NaN 5291e861498e3ee2d83f0dcb \n",
"4 NaN Central Region 5956305df4b5252a672602f7 "
]
},
"execution_count": 232,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# keep only columns that include venue name, and anything that is associated with location\n",
"Shopping_clean_columns = ['name', 'categories'] + [col for col in Shopping_dataframe.columns if col.startswith('location.')]+ ['id']\n",
"clean_Shopping_dataframe = Shopping_dataframe.loc[:,Shopping_clean_columns]\n",
"\n",
"# function that extracts the category of the venue\n",
"def get_category_type(row):\n",
" try:\n",
" categories_list5 = row['categories']\n",
" except:\n",
" categories_list5 = row['venue.categories']\n",
" \n",
" if len(categories_list5) == 0:\n",
" return None\n",
" else:\n",
" return categories_list5[0]['name']\n",
"\n",
"# filter the category for each row\n",
"clean_Shopping_dataframe['categories'] = clean_Shopping_dataframe.apply(get_category_type, axis=1)\n",
"\n",
"# clean column names by keeping only last term\n",
"clean_Shopping_dataframe.columns = [column.split('.')[-1] for column in clean_Shopping_dataframe.columns]\n",
"\n",
"clean_Shopping_dataframe.head()"
]
},
{
"cell_type": "code",
"execution_count": 233,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Bluebird Mall</td>\n",
" <td>Department Store</td>\n",
" <td>Tripureshwor</td>\n",
" <td>27.691672</td>\n",
" <td>85.317112</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>The Collective, Rising Mall</td>\n",
" <td>Women's Store</td>\n",
" <td>NaN</td>\n",
" <td>27.709596</td>\n",
" <td>85.318886</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>China Town Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>NaN</td>\n",
" <td>27.708878</td>\n",
" <td>85.321969</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Rising Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Kamaladi</td>\n",
" <td>27.709949</td>\n",
" <td>85.319086</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Madame Rising Mall</td>\n",
" <td>Women's Store</td>\n",
" <td>NaN</td>\n",
" <td>27.710111</td>\n",
" <td>85.318224</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address lat \\\n",
"0 Bluebird Mall Department Store Tripureshwor 27.691672 \n",
"1 The Collective, Rising Mall Women's Store NaN 27.709596 \n",
"2 China Town Mall Shopping Mall NaN 27.708878 \n",
"3 Rising Mall Shopping Mall Kamaladi 27.709949 \n",
"4 Madame Rising Mall Women's Store NaN 27.710111 \n",
"\n",
" lng state \n",
"0 85.317112 Central Region \n",
"1 85.318886 NaN \n",
"2 85.321969 NaN \n",
"3 85.319086 NaN \n",
"4 85.318224 Central Region "
]
},
"execution_count": 233,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete unnecessary columns\n",
"clean_Shopping_dataframe2= clean_Shopping_dataframe.drop(['cc', 'city', 'country', 'distance', 'formattedAddress',\\\n",
" 'crossStreet', 'postalCode' ,'labeledLatLngs', 'id'], axis=1)\n",
"clean_Shopping_dataframe2.head()"
]
},
{
"cell_type": "code",
"execution_count": 234,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>China Town Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>NaN</td>\n",
" <td>27.708878</td>\n",
" <td>85.321969</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Rising Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Kamaladi</td>\n",
" <td>27.709949</td>\n",
" <td>85.319086</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Kathmandu Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Kathmandu</td>\n",
" <td>27.701529</td>\n",
" <td>85.313348</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>Sherpa Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>DURBAR MARG, KATHMANDU, NEPAL Kathmandu,</td>\n",
" <td>27.710692</td>\n",
" <td>85.317591</td>\n",
" <td>nepal</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>Times Square Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>NaN</td>\n",
" <td>27.710723</td>\n",
" <td>85.317481</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories address \\\n",
"2 China Town Mall Shopping Mall NaN \n",
"3 Rising Mall Shopping Mall Kamaladi \n",
"5 Kathmandu Mall Shopping Mall Kathmandu \n",
"7 Sherpa Mall Shopping Mall DURBAR MARG, KATHMANDU, NEPAL Kathmandu, \n",
"8 Times Square Mall Shopping Mall NaN \n",
"\n",
" lat lng state \n",
"2 27.708878 85.321969 NaN \n",
"3 27.709949 85.319086 NaN \n",
"5 27.701529 85.313348 Central Region \n",
"7 27.710692 85.317591 nepal \n",
"8 27.710723 85.317481 NaN "
]
},
"execution_count": 234,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows which its category is not Shopping Mall\n",
"df_Shopping = clean_Shopping_dataframe2[clean_Shopping_dataframe2.categories == 'Shopping Mall']\n",
"df_Shopping.head()"
]
},
{
"cell_type": "code",
"execution_count": 235,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>name</th>\n",
" <th>categories</th>\n",
" <th>address</th>\n",
" <th>lat</th>\n",
" <th>lng</th>\n",
" <th>state</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Bluebird Mall</td>\n",
" <td>Department Store</td>\n",
" <td>Tripureshwor</td>\n",
" <td>27.691672</td>\n",
" <td>85.317112</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Kathmandu Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Kathmandu</td>\n",
" <td>27.701529</td>\n",
" <td>85.313348</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>Sherpa Mall Coffee Express</td>\n",
" <td>Coffee Shop</td>\n",
" <td>Durbar Marg</td>\n",
" <td>27.710735</td>\n",
" <td>85.317734</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>Sherpa Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>DURBAR MARG, KATHMANDU, NEPAL Kathmandu,</td>\n",
" <td>27.710692</td>\n",
" <td>85.317591</td>\n",
" <td>nepal</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>Civil Mall</td>\n",
" <td>Shopping Mall</td>\n",
" <td>Sundhara</td>\n",
" <td>27.699399</td>\n",
" <td>85.312736</td>\n",
" <td>Central Region</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" name categories \\\n",
"0 Bluebird Mall Department Store \n",
"5 Kathmandu Mall Shopping Mall \n",
"6 Sherpa Mall Coffee Express Coffee Shop \n",
"7 Sherpa Mall Shopping Mall \n",
"11 Civil Mall Shopping Mall \n",
"\n",
" address lat lng \\\n",
"0 Tripureshwor 27.691672 85.317112 \n",
"5 Kathmandu 27.701529 85.313348 \n",
"6 Durbar Marg 27.710735 85.317734 \n",
"7 DURBAR MARG, KATHMANDU, NEPAL Kathmandu, 27.710692 85.317591 \n",
"11 Sundhara 27.699399 85.312736 \n",
"\n",
" state \n",
"0 Central Region \n",
"5 Central Region \n",
"6 Central Region \n",
"7 nepal \n",
"11 Central Region "
]
},
"execution_count": 235,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# delete rows with none values\n",
"clean_Shopping_dataframe2 = clean_Shopping_dataframe2.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)\n",
"clean_Shopping_dataframe2.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Generate maps to visualize venues and how they cluster together**"
]
},
{
"cell_type": "code",
"execution_count": 236,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdnaXQuY29tL3B5dGhvbi12aXN1YWxpemF0aW9uL2ZvbGl1bS9tYXN0ZXIvZm9saXVtL3RlbXBsYXRlcy9sZWFmbGV0LmF3ZXNvbWUucm90YXRlLmNzcyIvPgogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIAogICAgICAgICAgICA8c3R5bGU+ICNtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMgewogICAgICAgICAgICAgICAgcG9zaXRpb24gOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgIHdpZHRoIDogMTAwLjAlOwogICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzIiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IG51bGw7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgdmFyIG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5MyA9IEwubWFwKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5MycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2VudGVyOiBbMjcuNzA4Nzk2LDg1LjMyMDI0NF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6b29tOiAxNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEJvdW5kczogYm91bmRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJzOiBbXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkQ29weUp1bXA6IGZhbHNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHRpbGVfbGF5ZXJfNzg0YzEwNzI2MzdlNDVkMjg5OTg0NWFhMzYwZTNjYmYgPSBMLnRpbGVMYXllcigKICAgICAgICAgICAgICAgICdodHRwczovL3tzfS50aWxlLm9wZW5zdHJlZXRtYXAub3JnL3t6fS97eH0ve3l9LnBuZycsCiAgICAgICAgICAgICAgICB7CiAgImF0dHJpYnV0aW9uIjogbnVsbCwKICAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsCiAgIm1heFpvb20iOiAxOCwKICAibWluWm9vbSI6IDEsCiAgIm5vV3JhcCI6IGZhbHNlLAogICJzdWJkb21haW5zIjogImFiYyIKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzZiMjg2NWYyZWFmMjQ4MWRhMTBlNjVkODMyODFiNzllID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzExNTgxMDUzNjc5Mjk2LDg1LjMyMDI3NDM0NjQ1MzA2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yOTM4OTZjZWYzZTE0NTI1OGFiZTE1MmFiODc4NmYxYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80ODM0N2FkYmFiN2M0YTEwYThlYzY2MmQ3YTczOWIwNCA9ICQoJzxkaXYgaWQ9Imh0bWxfNDgzNDdhZGJhYjdjNGExMGE4ZWM2NjJkN2E3MzliMDQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhvdGVsIFlhayAmYW1wOyBZZXRpLCBMYWx1cGF0ZSBNYXJnPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yOTM4OTZjZWYzZTE0NTI1OGFiZTE1MmFiODc4NmYxYS5zZXRDb250ZW50KGh0bWxfNDgzNDdhZGJhYjdjNGExMGE4ZWM2NjJkN2E3MzliMDQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNmIyODY1ZjJlYWYyNDgxZGExMGU2NWQ4MzI4MWI3OWUuYmluZFBvcHVwKHBvcHVwXzI5Mzg5NmNlZjNlMTQ1MjU4YWJlMTUyYWI4Nzg2ZjFhKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzgzODAyMDU1NWZmZDQ4ZTNiYWRiNTk5NmY0NDdlNmQwID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE4OTU1ODM2NDEwNDgzLDg1LjMyMDA4MjI0MTMxNTU5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82MjQ5MGQ0MzMyOTQ0Mzc1YWE0YzRiNTA3N2VjOTNmMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iZTkyMDEwNTVlYjM0MWE1OTlkNTVmOGNlNTZmMWEzOCA9ICQoJzxkaXYgaWQ9Imh0bWxfYmU5MjAxMDU1ZWIzNDFhNTk5ZDU1ZjhjZTU2ZjFhMzgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhvdGVsIFNoYW5rZXIsIExhemltcGF0PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF82MjQ5MGQ0MzMyOTQ0Mzc1YWE0YzRiNTA3N2VjOTNmMC5zZXRDb250ZW50KGh0bWxfYmU5MjAxMDU1ZWIzNDFhNTk5ZDU1ZjhjZTU2ZjFhMzgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfODM4MDIwNTU1ZmZkNDhlM2JhZGI1OTk2ZjQ0N2U2ZDAuYmluZFBvcHVwKHBvcHVwXzYyNDkwZDQzMzI5NDQzNzVhYTRjNGI1MDc3ZWM5M2YwKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzFiOTUwZmRiNjU5ZjRiNGQ5ZGFjNGIwNzI2NGZjNzY5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEwOTM5NTIxNjE5MTA3LDg1LjMxOTQ2NTc3MzkwMTc1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hMGI1OGFkMDM5Nzk0YzY3YjViNjU5MDA0YWE2MGI1MiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zNzJjMjlmYTk5OWQ0NmUyODM4MTAzMzIzYmM5NDhkMyA9ICQoJzxkaXYgaWQ9Imh0bWxfMzcyYzI5ZmE5OTlkNDZlMjgzODEwMzMyM2JjOTQ4ZDMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJveWFsIFNpbmdoaSBIb3RlbCwgTGFsIER1cmJhcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTBiNThhZDAzOTc5NGM2N2I1YjY1OTAwNGFhNjBiNTIuc2V0Q29udGVudChodG1sXzM3MmMyOWZhOTk5ZDQ2ZTI4MzgxMDMzMjNiYzk0OGQzKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzFiOTUwZmRiNjU5ZjRiNGQ5ZGFjNGIwNzI2NGZjNzY5LmJpbmRQb3B1cChwb3B1cF9hMGI1OGFkMDM5Nzk0YzY3YjViNjU5MDA0YWE2MGI1Mik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl80MjljZmFhODBiNjU0Mjg5YjQ2MGM5NWFmNTlkY2Q4ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMTExNzI4ODgwMTMyNiw4NS4zMTY0MDg0NzIxNjQ2NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNDU3ZTU4N2VkODQwNDE0ODk2NzllMDRiMmI1YjJhODIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2NjMzRiN2FiYzRiNGJmNWI3NTVjZWVlOGZhZGEyMjUgPSAkKCc8ZGl2IGlkPSJodG1sX2NjYzM0YjdhYmM0YjRiZjViNzU1Y2VlZThmYWRhMjI1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EZSBMJiMzOTtBbm5hcHVybmEgSG90ZWwsIER1cmJhciBNYXJnPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80NTdlNTg3ZWQ4NDA0MTQ4OTY3OWUwNGIyYjViMmE4Mi5zZXRDb250ZW50KGh0bWxfY2NjMzRiN2FiYzRiNGJmNWI3NTVjZWVlOGZhZGEyMjUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNDI5Y2ZhYTgwYjY1NDI4OWI0NjBjOTVhZjU5ZGNkOGQuYmluZFBvcHVwKHBvcHVwXzQ1N2U1ODdlZDg0MDQxNDg5Njc5ZTA0YjJiNWIyYTgyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y1Njc5ODI3ZjhlNTQ5N2JhMzUwNzZiYmY4MjBkYmUwID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE3MDQzOTA3ODcwNTQ3LDg1LjMxMDQ0OTUxODEzNDg3XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81OTQ2ODIyYzZjYmU0YzkzODZkODgxMmFhMjEwODFkZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wZDg2MGI2ZGRkODQ0NTFiODU4ZjYyZmU0YTlhODllZiA9ICQoJzxkaXYgaWQ9Imh0bWxfMGQ4NjBiNmRkZDg0NDUxYjg1OGY2MmZlNGE5YTg5ZWYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhvdGVsIEJ1ZGRoYSwgMjU3Mjg8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzU5NDY4MjJjNmNiZTRjOTM4NmQ4ODEyYWEyMTA4MWRkLnNldENvbnRlbnQoaHRtbF8wZDg2MGI2ZGRkODQ0NTFiODU4ZjYyZmU0YTlhODllZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9mNTY3OTgyN2Y4ZTU0OTdiYTM1MDc2YmJmODIwZGJlMC5iaW5kUG9wdXAocG9wdXBfNTk0NjgyMmM2Y2JlNGM5Mzg2ZDg4MTJhYTIxMDgxZGQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjc2NDFiYmYxZTUzNDJlMjk2ZWMzODQ2YzQ2MjBkNTEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTA4MDksODUuMzEyOTIyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yMzc2NzlmMzgwNmQ0NWRmOWU2MTZlZGRiNzc4MGQ5NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9lMDc3YTFiZmI1N2U0YmVkODA0NmUwYTllNTAxNDcwNCA9ICQoJzxkaXYgaWQ9Imh0bWxfZTA3N2ExYmZiNTdlNGJlZDgwNDZlMGE5ZTUwMTQ3MDQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhvdGVsIEJsaXNzIEludGVybmF0aW9uYWwsIENoaHVzeWEgR2FsbGksIEp5YXRoYTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjM3Njc5ZjM4MDZkNDVkZjllNjE2ZWRkYjc3ODBkOTQuc2V0Q29udGVudChodG1sX2UwNzdhMWJmYjU3ZTRiZWQ4MDQ2ZTBhOWU1MDE0NzA0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzI3NjQxYmJmMWU1MzQyZTI5NmVjMzg0NmM0NjIwZDUxLmJpbmRQb3B1cChwb3B1cF8yMzc2NzlmMzgwNmQ0NWRmOWU2MTZlZGRiNzc4MGQ5NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xMWE0ZWU2YzBlM2U0YjdiYTY0NDA4NGU0Y2UzNzc0ZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxNDE1OTUyMzYyMDU5NCw4NS4zMTMwNDg3MjM2NDY1N10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfM2RhOWYyMTc1MGFhNDY0ZWJkOGMzOTA3NDcyMTQzY2EgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYzg0ZDQ3ZDRkYjE2NDZmMTk5N2UxYzg5YWMzNDBiNTMgPSAkKCc8ZGl2IGlkPSJodG1sX2M4NGQ0N2Q0ZGIxNjQ2ZjE5OTdlMWM4OWFjMzQwYjUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBPbSYjMzk7cyBIb21lIEpvbXNvbSAoQ2l0eSBPZmZpY2UpLCBUaGFtZWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzNkYTlmMjE3NTBhYTQ2NGViZDhjMzkwNzQ3MjE0M2NhLnNldENvbnRlbnQoaHRtbF9jODRkNDdkNGRiMTY0NmYxOTk3ZTFjODlhYzM0MGI1Myk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8xMWE0ZWU2YzBlM2U0YjdiYTY0NDA4NGU0Y2UzNzc0Zi5iaW5kUG9wdXAocG9wdXBfM2RhOWYyMTc1MGFhNDY0ZWJkOGMzOTA3NDcyMTQzY2EpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNTM1YmI1ZTY3N2Y3NDNmNGFhZDJlNWVjNDViNDAzZGQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTc3NzczODQ1OTI1Miw4NS4zMTAxMDQxMDQ2NDQxM10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfODRhNWVhNjUzMzI5NDAyYzk2ZGRkYTFjNDU1NDIwZTMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMTJlNTMxODJkYTFkNDc0NWE4NDQ1OTkzODljYzA5ZWEgPSAkKCc8ZGl2IGlkPSJodG1sXzEyZTUzMTgyZGExZDQ3NDVhODQ0NTk5Mzg5Y2MwOWVhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBNYW5hbmcsIFAuTy4gYm94IDU2MDggVGhhbWVsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84NGE1ZWE2NTMzMjk0MDJjOTZkZGRhMWM0NTU0MjBlMy5zZXRDb250ZW50KGh0bWxfMTJlNTMxODJkYTFkNDc0NWE4NDQ1OTkzODljYzA5ZWEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNTM1YmI1ZTY3N2Y3NDNmNGFhZDJlNWVjNDViNDAzZGQuYmluZFBvcHVwKHBvcHVwXzg0YTVlYTY1MzMyOTQwMmM5NmRkZGExYzQ1NTQyMGUzKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2FiZmI3MTY3MzViZjQyNDY4OGYyZTk4ZDQzMDM4MzE5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyNzY0LDg1LjMwOTc3Nl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYmM2MjdjZmZlYzI4NDVjZTlkZjBiYmEzZDEzZTEzNTUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZDc4ZjI2OTkwZjgwNDA1Mzk2ZDk1ZjRhZmZjNGM5NzkgPSAkKCc8ZGl2IGlkPSJodG1sX2Q3OGYyNjk5MGY4MDQwNTM5NmQ5NWY0YWZmYzRjOTc5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBIb3Jpem9uIEthdGhtYW5kdSAoUCkgTHRkLiwgUHlyYW1pZCBHYWxsaTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmM2MjdjZmZlYzI4NDVjZTlkZjBiYmEzZDEzZTEzNTUuc2V0Q29udGVudChodG1sX2Q3OGYyNjk5MGY4MDQwNTM5NmQ5NWY0YWZmYzRjOTc5KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2FiZmI3MTY3MzViZjQyNDY4OGYyZTk4ZDQzMDM4MzE5LmJpbmRQb3B1cChwb3B1cF9iYzYyN2NmZmVjMjg0NWNlOWRmMGJiYTNkMTNlMTM1NSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9lMWMwM2M1ZTYxYjM0ZWY3YmVmYTNmNDE3ZTEzY2E5ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxNTEwMzc2NTAxODQxNiw4NS4zMDk0MTcyNDc3NzIyMl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfODQwMGZkZjc5MmJlNDgxOWJkNWZjOGZmOWZhMDc1MGUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMDYyNmE4Njg3Y2QxNGRhNzk0NzVhZWY1NjE4ZTRlMzEgPSAkKCc8ZGl2IGlkPSJodG1sXzA2MjZhODY4N2NkMTRkYTc5NDc1YWVmNTYxOGU0ZTMxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBNZXRyb3BvbGl0YW4gS2FudGlwdXIsIFBha25ham9sLCBUaGFtZWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzg0MDBmZGY3OTJiZTQ4MTliZDVmYzhmZjlmYTA3NTBlLnNldENvbnRlbnQoaHRtbF8wNjI2YTg2ODdjZDE0ZGE3OTQ3NWFlZjU2MThlNGUzMSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9lMWMwM2M1ZTYxYjM0ZWY3YmVmYTNmNDE3ZTEzY2E5ZC5iaW5kUG9wdXAocG9wdXBfODQwMGZkZjc5MmJlNDgxOWJkNWZjOGZmOWZhMDc1MGUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDM2OTk1ZDU1YzZiNDdkNGFjODM3YjI3YTA4NzExODYgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTY2ODYzOTU0MDkwMTcsODUuMzEwOTYxNjU4MDAzNzZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzNjOTA4NzJhZGI0ZjQxNzliZmFkYTU5OWExYTljYmNkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2JjZGRkODZiZTAyYjQ3MWQ4NjQ2NWRiN2Y3N2NlZWQ3ID0gJCgnPGRpdiBpZD0iaHRtbF9iY2RkZDg2YmUwMmI0NzFkODY0NjVkYjdmNzdjZWVkNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SG90ZWwgVmFpc2hhbGksIFRoYW1lbDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfM2M5MDg3MmFkYjRmNDE3OWJmYWRhNTk5YTFhOWNiY2Quc2V0Q29udGVudChodG1sX2JjZGRkODZiZTAyYjQ3MWQ4NjQ2NWRiN2Y3N2NlZWQ3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2QzNjk5NWQ1NWM2YjQ3ZDRhYzgzN2IyN2EwODcxMTg2LmJpbmRQb3B1cChwb3B1cF8zYzkwODcyYWRiNGY0MTc5YmZhZGE1OTlhMWE5Y2JjZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wNjg2MjZiNGNiMDE0NzJhYWI1MjZiMzI2ZTcyMGNkZiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxNjI0Mzc1MTQ4OTUxNSw4NS4zMTAwNDQ2MzY3MDAzNV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZTExYTc5ZTdmNDMxNDYzM2FkMjFiOTczMDlhMzIzNDEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNDI1ZmZjZjM2NTFkNDM2M2I1YWRlMzk4ZTExODk0ODMgPSAkKCc8ZGl2IGlkPSJodG1sXzQyNWZmY2YzNjUxZDQzNjNiNWFkZTM5OGUxMTg5NDgzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBNYW5kYXAsIENoYWtzaWJhcmkgTWFyZywgVGhhbWVsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lMTFhNzllN2Y0MzE0NjMzYWQyMWI5NzMwOWEzMjM0MS5zZXRDb250ZW50KGh0bWxfNDI1ZmZjZjM2NTFkNDM2M2I1YWRlMzk4ZTExODk0ODMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDY4NjI2YjRjYjAxNDcyYWFiNTI2YjMyNmU3MjBjZGYuYmluZFBvcHVwKHBvcHVwX2UxMWE3OWU3ZjQzMTQ2MzNhZDIxYjk3MzA5YTMyMzQxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzkyNDA5ZWQ4ZGI1MDRkYzE4MzgyMDVlZDk2YjhjMjE5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE3NDA5ODc1MTA4ODksODUuMzEwMjE2MzAzMjU3NzVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2I3ZjMwZWM2MjY1MzRiZmFiZGU2YWRmOGYyZTNkNjBmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2QxNDBkOGIyNDg1NDQ3YWQ4NDkzM2Q4MmU0OWM2MDI3ID0gJCgnPGRpdiBpZD0iaHRtbF9kMTQwZDhiMjQ4NTQ0N2FkODQ5MzNkODJlNDljNjAyNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SG90ZWwgVGVua2ksIENoYWtzaWJhcmkgTWFyZzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYjdmMzBlYzYyNjUzNGJmYWJkZTZhZGY4ZjJlM2Q2MGYuc2V0Q29udGVudChodG1sX2QxNDBkOGIyNDg1NDQ3YWQ4NDkzM2Q4MmU0OWM2MDI3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzkyNDA5ZWQ4ZGI1MDRkYzE4MzgyMDVlZDk2YjhjMjE5LmJpbmRQb3B1cChwb3B1cF9iN2YzMGVjNjI2NTM0YmZhYmRlNmFkZjhmMmUzZDYwZik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kMTEyZTI1Y2Y3NzA0MGRmOGQ4NTE0OTIzYTJmZTlmYiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMjcxMSw4NS4zMjQ5XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9lODIyMmY3MTJmN2I0OTM0YTc5MDNjOWRiODViZTg3ZiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zMGY0MmE1OTFmOGQ0MTEwODMxMDAyZTZmYWQzZGM0ZiA9ICQoJzxkaXYgaWQ9Imh0bWxfMzBmNDJhNTkxZjhkNDExMDgzMTAwMmU2ZmFkM2RjNGYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkthdGhtYW5kdSBNYXJyaW90dCBIb3RlbCwgTWFuYWthbWFuYSBNYXJnPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lODIyMmY3MTJmN2I0OTM0YTc5MDNjOWRiODViZTg3Zi5zZXRDb250ZW50KGh0bWxfMzBmNDJhNTkxZjhkNDExMDgzMTAwMmU2ZmFkM2RjNGYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZDExMmUyNWNmNzcwNDBkZjhkODUxNDkyM2EyZmU5ZmIuYmluZFBvcHVwKHBvcHVwX2U4MjIyZjcxMmY3YjQ5MzRhNzkwM2M5ZGI4NWJlODdmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2VmOGY5YmYwZmE1YTQ1YTZiZTQ5MGMxYzZhZTEyNDZkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE0OTgyNDM1OTE3MzI4LDg1LjMwNzY0MTI0ODMxMzI2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82OGU5ODk5NDY1ZWU0ZThlYjI2YWU3MzkxODhjMjZkYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85OTNhNGFhMWIzYTg0ZDQ4YmE1YmM5ZmQwZTdjMDUyNyA9ICQoJzxkaXYgaWQ9Imh0bWxfOTkzYTRhYTFiM2E4NGQ0OGJhNWJjOWZkMGU3YzA1MjciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhhcmF0aSBIb3RlbCwgQW1yaXQgTWFyZzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjhlOTg5OTQ2NWVlNGU4ZWIyNmFlNzM5MTg4YzI2ZGMuc2V0Q29udGVudChodG1sXzk5M2E0YWExYjNhODRkNDhiYTViYzlmZDBlN2MwNTI3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2VmOGY5YmYwZmE1YTQ1YTZiZTQ5MGMxYzZhZTEyNDZkLmJpbmRQb3B1cChwb3B1cF82OGU5ODk5NDY1ZWU0ZThlYjI2YWU3MzkxODhjMjZkYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hNDA3Y2YxNWQzMGU0YjA3OTllYWUwMTFkMDQ1YmMxNyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY4NDI1NjM2OTEzNzEwNiw4NS4zMTk1NDMwNTgwNzUwNl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGZiYThkZjc2YTcyNGMzNzk1YjE2NmI0YzQzN2U2YTUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2U3OTJhNjhiYjZlNDZhMGI3MTdmZDJkNjk3ODgyM2UgPSAkKCc8ZGl2IGlkPSJodG1sX2NlNzkyYTY4YmI2ZTQ2YTBiNzE3ZmQyZDY5Nzg4MjNlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5IaW1hbGF5YSBIb3RlbCBLYXRobWFuZHUsIFAuTy4gQk9YIDIxNDEgS1VQT05ET0xFLCBTYWhpZCBTdWtyYSBNYXJnLCBMYWxpdHB1cjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOGZiYThkZjc2YTcyNGMzNzk1YjE2NmI0YzQzN2U2YTUuc2V0Q29udGVudChodG1sX2NlNzkyYTY4YmI2ZTQ2YTBiNzE3ZmQyZDY5Nzg4MjNlKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2E0MDdjZjE1ZDMwZTRiMDc5OWVhZTAxMWQwNDViYzE3LmJpbmRQb3B1cChwb3B1cF84ZmJhOGRmNzZhNzI0YzM3OTViMTY2YjRjNDM3ZTZhNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83MWE2ODFmNzA1Yzk0ZDdkYWVjYWY0ZmY4YjQ0ZWJkZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcyMTEwNjI5MDM0NTI4Myw4NS4zMDg1MjY3NTQzNzkyN10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYzU2YjQyYmM1YzA2NDRkZjk0ZDkwZGM1Yjk1ZjczNmUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMDVhZDI3NzVjZGJmNGU4MmE1Yzc5NjBjNDEzM2QxMDEgPSAkKCc8ZGl2IGlkPSJodG1sXzA1YWQyNzc1Y2RiZjRlODJhNWM3OTYwYzQxMzNkMTAxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBEYXJ3aW4g6L6+5bCU5paH6YWS5bqXLCBOYXlhYmF6YXIsIFNvcmhha2h1dHRlPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9jNTZiNDJiYzVjMDY0NGRmOTRkOTBkYzViOTVmNzM2ZS5zZXRDb250ZW50KGh0bWxfMDVhZDI3NzVjZGJmNGU4MmE1Yzc5NjBjNDEzM2QxMDEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNzFhNjgxZjcwNWM5NGQ3ZGFlY2FmNGZmOGI0NGViZGUuYmluZFBvcHVwKHBvcHVwX2M1NmI0MmJjNWMwNjQ0ZGY5NGQ5MGRjNWI5NWY3MzZlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IwYTliNDFlYWI4ZDRhODZiY2FmNTY0M2Y3YWU4ZmY1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzA0OTE4MzM4NTk0Nzk0LDg1LjMwNjY3NjgzMzc4NDU2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8wZjVlNTQzODMzZDQ0MjNjYjIxNjJiMTFhZDYzNWY3OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xNTY1NTRmODA3NWI0MDIxODg4M2RlNmY2MmY0MDY2OSA9ICQoJzxkaXYgaWQ9Imh0bWxfMTU2NTU0ZjgwNzViNDAyMTg4ODNkZTZmNjJmNDA2NjkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldvcmxkIEhlcml0YWdlIEhvdGVsICZhbXA7IEFwYXJ0bWVudCAoRHdhcmlrYSYjMzk7cyBDaGhlbiksIEhhbnVtYW4gRGhva2EsIER1cmJhciBTcXVhcmU8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzBmNWU1NDM4MzNkNDQyM2NiMjE2MmIxMWFkNjM1Zjc4LnNldENvbnRlbnQoaHRtbF8xNTY1NTRmODA3NWI0MDIxODg4M2RlNmY2MmY0MDY2OSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9iMGE5YjQxZWFiOGQ0YTg2YmNhZjU2NDNmN2FlOGZmNS5iaW5kUG9wdXAocG9wdXBfMGY1ZTU0MzgzM2Q0NDIzY2IyMTYyYjExYWQ2MzVmNzgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGU5NTk3ZTYyNjUwNDI4NDgzMzI2MmFiZWNlNjYzZTggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTA1NTcsODUuMzE5OTAyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xMTMzMzgyODYzYWQ0Y2M0OGEyYTczMjBhZWE4MDViNyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jOTc5YjA0OWU1OWY0NTk4YTYwZTZhNDk2N2NmY2Q0OCA9ICQoJzxkaXYgaWQ9Imh0bWxfYzk3OWIwNDllNTlmNDU5OGE2MGU2YTQ5NjdjZmNkNDgiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxhbmRtYXJrIEhvdGVsICZhbXA7IEFwYXJ0bWVudCwgS2FtYWxhZGk8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzExMzMzODI4NjNhZDRjYzQ4YTJhNzMyMGFlYTgwNWI3LnNldENvbnRlbnQoaHRtbF9jOTc5YjA0OWU1OWY0NTk4YTYwZTZhNDk2N2NmY2Q0OCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl80ZTk1OTdlNjI2NTA0Mjg0ODMzMjYyYWJlY2U2NjNlOC5iaW5kUG9wdXAocG9wdXBfMTEzMzM4Mjg2M2FkNGNjNDhhMmE3MzIwYWVhODA1YjcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjYwNTljMTg1ZTY0NGZiOGE4NzU0Y2ZkMjU3Mzc5ZjcgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDUxNTQ0MTk1Mjc2NTYsODUuMzQyNjE5NzM3OTg0MzFdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2EzZWY5OWRlYzIzOTRjZjI4MTZjNWI4OWNmM2UzYzk5ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzk3MWI1MWM1ZTQ4YzQ4OTc4MWYzMGYwZjRiYjk3OGU3ID0gJCgnPGRpdiBpZD0iaHRtbF85NzFiNTFjNWU0OGM0ODk3ODFmMzBmMGY0YmI5NzhlNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+RHdhcmlrYSBIb3RlbCwgQmF0dGlzcHV0YWxpIFJkLjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTNlZjk5ZGVjMjM5NGNmMjgxNmM1Yjg5Y2YzZTNjOTkuc2V0Q29udGVudChodG1sXzk3MWI1MWM1ZTQ4YzQ4OTc4MWYzMGYwZjRiYjk3OGU3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2I2MDU5YzE4NWU2NDRmYjhhODc1NGNmZDI1NzM3OWY3LmJpbmRQb3B1cChwb3B1cF9hM2VmOTlkZWMyMzk0Y2YyODE2YzViODljZjNlM2M5OSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl82MGM2MjJlZGU5N2Q0MTdlYTQ0NWQzNmYwYjJjZjk4ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMjMxNSw4NS4zMTMyNTRdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzkzZjY1M2JkZTY3MjRmZWJiOGQ2NDc1MjA2OWZhMGI4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2MwOGRmZDBjODViYTQyMjc5ODgyNjc0NDBlMzk3ZWJkID0gJCgnPGRpdiBpZD0iaHRtbF9jMDhkZmQwYzg1YmE0MjI3OTg4MjY3NDQwZTM5N2ViZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+S3VtYXJpIEJvdXRpcXVlIEhvdGVsLCBKeWF0aGEsIFRoYW1lbDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOTNmNjUzYmRlNjcyNGZlYmI4ZDY0NzUyMDY5ZmEwYjguc2V0Q29udGVudChodG1sX2MwOGRmZDBjODViYTQyMjc5ODgyNjc0NDBlMzk3ZWJkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzYwYzYyMmVkZTk3ZDQxN2VhNDQ1ZDM2ZjBiMmNmOThkLmJpbmRQb3B1cChwb3B1cF85M2Y2NTNiZGU2NzI0ZmViYjhkNjQ3NTIwNjlmYTBiOCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wNmViNTM3Nzg4ZDE0MjlmODRmYTQ5ZDk4ZDJjOWUxMSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY4NTYzMjc0NjQzMDY0NSw4NS4zMTE4NDEzNzIxODk4Ml0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZmZlMGQ0YzBhM2MyNDMxNjkzZjFhOWYyN2I2NWM4YzAgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWU4MzUwYzY2NDc3NDVhMzg4ZDgxNDNiNGIwYzQwMzkgPSAkKCc8ZGl2IGlkPSJodG1sXzFlODM1MGM2NjQ3NzQ1YTM4OGQ4MTQzYjRiMGM0MDM5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TdW1taXQgSG90ZWwsIEt1cG9uZG9sZSBIZWlnaHRzIFJkPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mZmUwZDRjMGEzYzI0MzE2OTNmMWE5ZjI3YjY1YzhjMC5zZXRDb250ZW50KGh0bWxfMWU4MzUwYzY2NDc3NDVhMzg4ZDgxNDNiNGIwYzQwMzkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDZlYjUzNzc4OGQxNDI5Zjg0ZmE0OWQ5OGQyYzllMTEuYmluZFBvcHVwKHBvcHVwX2ZmZTBkNGMwYTNjMjQzMTY5M2YxYTlmMjdiNjVjOGMwKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzcxMDQ5YjlhZTcwYTQ2N2NiMGFkNGNkZmM2MjU1MWRkID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEwNDI1NDQyMjY4OSw4NS4zMTkxOTcxNjg5ODQ1M10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTU5MjY2NzBjNDIyNDExZDhkZjZhNmY2YjA3NjFkNGIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZjU0ZmUzMTI2MjFmNGUwNzllNzA4YWZkZGQ4M2Q0NjMgPSAkKCc8ZGl2IGlkPSJodG1sX2Y1NGZlMzEyNjIxZjRlMDc5ZTcwOGFmZGRkODNkNDYzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Sb3lhbCBTaW5naSBIb3RlbCBLYXRobWFuZHUsIGR1cmJhciBtYXJnLiBrYXRobWFuZHUgbmVwYWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2E1OTI2NjcwYzQyMjQxMWQ4ZGY2YTZmNmIwNzYxZDRiLnNldENvbnRlbnQoaHRtbF9mNTRmZTMxMjYyMWY0ZTA3OWU3MDhhZmRkZDgzZDQ2Myk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl83MTA0OWI5YWU3MGE0NjdjYjBhZDRjZGZjNjI1NTFkZC5iaW5kUG9wdXAocG9wdXBfYTU5MjY2NzBjNDIyNDExZDhkZjZhNmY2YjA3NjFkNGIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNmRjZDk2OGI0ZjI0NDdhNTkzNTdmMzQ5MDc4ZWEyOTUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTAxMjY3MzcxNjg5Niw4NS4zMjE5Njk5ODU5NjE5MV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMzA3YWRkMDBjMGMyNDUzYzlmNGZiZDU4MzQ2N2ZjNzEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOWUxMjUwMTU3ZTkyNGZmY2FmMTU1MGFkZTVkYjljYzYgPSAkKCc8ZGl2IGlkPSJodG1sXzllMTI1MDE1N2U5MjRmZmNhZjE1NTBhZGU1ZGI5Y2M2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5NYXJjbyBQb2xvIEJ1c2luZXNzIEhvdGVsLCBLYW1hbCBQb2toYXJpLCBIYXR0aXNhcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMzA3YWRkMDBjMGMyNDUzYzlmNGZiZDU4MzQ2N2ZjNzEuc2V0Q29udGVudChodG1sXzllMTI1MDE1N2U5MjRmZmNhZjE1NTBhZGU1ZGI5Y2M2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzZkY2Q5NjhiNGYyNDQ3YTU5MzU3ZjM0OTA3OGVhMjk1LmJpbmRQb3B1cChwb3B1cF8zMDdhZGQwMGMwYzI0NTNjOWY0ZmJkNTgzNDY3ZmM3MSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jMGNhOWIwYTc2M2M0ODdlYjc3N2NmZTNkYzVlNjc1MiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMDQzMDY4NDMxMTc4NSw4NS4zMTUwNTUyNTExMjE1Ml0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTI5YjJlNTg5YWY1NDc5N2FhY2VlYTVjZjE2N2VmOGYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNmQ5MmQzOGQ1ZDJlNDU5NmJkM2ZiNDczNWQ0M2ZhMzQgPSAkKCc8ZGl2IGlkPSJodG1sXzZkOTJkMzhkNWQyZTQ1OTZiZDNmYjQ3MzVkNDNmYTM0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Ib3RlbCBNb3VudGFpbiwgRHVyYmFyIE1hcmc8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzEyOWIyZTU4OWFmNTQ3OTdhYWNlZWE1Y2YxNjdlZjhmLnNldENvbnRlbnQoaHRtbF82ZDkyZDM4ZDVkMmU0NTk2YmQzZmI0NzM1ZDQzZmEzNCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9jMGNhOWIwYTc2M2M0ODdlYjc3N2NmZTNkYzVlNjc1Mi5iaW5kUG9wdXAocG9wdXBfMTI5YjJlNTg5YWY1NDc5N2FhY2VlYTVjZjE2N2VmOGYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMDg3NDg4MmY3ZmZhNDNlNGEwYmZiY2MzYTQ2NzBkYTUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTI2MDkxNTEzMjE3OTYsODUuMzEyNzYwNzcwOTU0MDNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzk4ZmYzY2NhZjc4MTQwMWQ5NmI1ZjEyYWQ0MzllYTlkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2IwY2Q1NDA1MDk3NzQ0NjBiMjc0YzQ5N2MzM2M2YTc0ID0gJCgnPGRpdiBpZD0iaHRtbF9iMGNkNTQwNTA5Nzc0NDYwYjI3NGM0OTdjMzNjNmE3NCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SG9seSBIaW1hbGF5YSBIb3RlbCwgVGhhbWVsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF85OGZmM2NjYWY3ODE0MDFkOTZiNWYxMmFkNDM5ZWE5ZC5zZXRDb250ZW50KGh0bWxfYjBjZDU0MDUwOTc3NDQ2MGIyNzRjNDk3YzMzYzZhNzQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDg3NDg4MmY3ZmZhNDNlNGEwYmZiY2MzYTQ2NzBkYTUuYmluZFBvcHVwKHBvcHVwXzk4ZmYzY2NhZjc4MTQwMWQ5NmI1ZjEyYWQ0MzllYTlkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzg2NjBkNGJkYjg5NjQ1YTVhOTRlMDdiYWQ3N2UzMWVmID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjk4ODMwMzYwOTIwMjY1LDg1LjI5MDkwODM1OTI2NTQyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF85YWJkMDJmNDMyMDA0Yzg5ODIyZTY2NGY2YjI1NDIwYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xYmIxYTU1OWFjZWM0N2Y0YThjODc0YzZkNGQ1NjA0NiA9ICQoJzxkaXYgaWQ9Imh0bWxfMWJiMWE1NTlhY2VjNDdmNGE4Yzg3NGM2ZDRkNTYwNDYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkdyYW5kIEhvdGVsLCBSZWQgQ3Jvc3MgUmQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzlhYmQwMmY0MzIwMDRjODk4MjJlNjY0ZjZiMjU0MjBjLnNldENvbnRlbnQoaHRtbF8xYmIxYTU1OWFjZWM0N2Y0YThjODc0YzZkNGQ1NjA0Nik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl84NjYwZDRiZGI4OTY0NWE1YTk0ZTA3YmFkNzdlMzFlZi5iaW5kUG9wdXAocG9wdXBfOWFiZDAyZjQzMjAwNGM4OTgyMmU2NjRmNmIyNTQyMGMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYTUyOTdiMDQ2YmVkNDIxN2JlZGY3NzRiMzg4N2Q4YjggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTAwMTgxNTc5NTksODUuMzE3MjY4MzcxNTgyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hZjJhOTM2NTZiYjA0OWY0OGJkNmUxNDIzYzg0ZDBlOCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85YjU0MmQ4YWJhODQ0ZWM0YmM5ZDdhMmRkMDg2YzJjNiA9ICQoJzxkaXYgaWQ9Imh0bWxfOWI1NDJkOGFiYTg0NGVjNGJjOWQ3YTJkZDA4NmMyYzYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlNoZXJwYSBIb3RlbCBLYXRobWFuZHUsIERVUkJBUiBNQVJHIFAuTy5CT1ggOTAxIEtBVEhNQU5EVU5FUEFMPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hZjJhOTM2NTZiYjA0OWY0OGJkNmUxNDIzYzg0ZDBlOC5zZXRDb250ZW50KGh0bWxfOWI1NDJkOGFiYTg0NGVjNGJjOWQ3YTJkZDA4NmMyYzYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYTUyOTdiMDQ2YmVkNDIxN2JlZGY3NzRiMzg4N2Q4YjguYmluZFBvcHVwKHBvcHVwX2FmMmE5MzY1NmJiMDQ5ZjQ4YmQ2ZTE0MjNjODRkMGU4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2YwNTlkMmYwMTllNTQzMTBhNzM3ZmQ5ZjA1YWIzZTMyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyNTA0Mjk0MjAzOTUsODUuMzE0NDIxOTY1NTYxOTZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzU1NjFkODM2MGE3NjQ2ZGRhN2VhNmRkN2M5N2Q1NDFiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2JmOWMzNDJjMjRmODQxZTlhYmQ3Y2M1Y2YzYWIzZGEzID0gJCgnPGRpdiBpZD0iaHRtbF9iZjljMzQyYzI0Zjg0MWU5YWJkN2NjNWNmM2FiM2RhMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+SG90ZWwgWWFrIEluIFRoYW1lbCwgVGhhaGl0eSBrd2FiaGFsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF81NTYxZDgzNjBhNzY0NmRkYTdlYTZkZDdjOTdkNTQxYi5zZXRDb250ZW50KGh0bWxfYmY5YzM0MmMyNGY4NDFlOWFiZDdjYzVjZjNhYjNkYTMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZjA1OWQyZjAxOWU1NDMxMGE3MzdmZDlmMDVhYjNlMzIuYmluZFBvcHVwKHBvcHVwXzU1NjFkODM2MGE3NjQ2ZGRhN2VhNmRkN2M5N2Q1NDFiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzAwMTIwMzhlMjhiMDRmOTY4Zjg0YWE4ODUxODJiNjgyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyNzE1LDg1LjMxMzI2Ml0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMWRlYzNhNDM5YjcxNDgxMzkzMzM0ZDM1OGJkMjk2OWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZGI0YjM5NTVlMjBmNDdiZGIxODBlMDhkMDk2NGU5NWIgPSAkKCc8ZGl2IGlkPSJodG1sX2RiNGIzOTU1ZTIwZjQ3YmRiMTgwZTA4ZDA5NjRlOTViIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Lb3lhIExvdW5nZSBhbmQgUm9vZnRvcCBCYXIgQCBIb3RlbCBNdWxiZXJyeSwgSnlhdGhhPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xZGVjM2E0MzliNzE0ODEzOTMzMzRkMzU4YmQyOTY5ZS5zZXRDb250ZW50KGh0bWxfZGI0YjM5NTVlMjBmNDdiZGIxODBlMDhkMDk2NGU5NWIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDAxMjAzOGUyOGIwNGY5NjhmODRhYTg4NTE4MmI2ODIuYmluZFBvcHVwKHBvcHVwXzFkZWMzYTQzOWI3MTQ4MTM5MzMzNGQzNThiZDI5NjllKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzJjNGFiNjNlMjAxMjQzN2E4NzA1NDJiNTQ0MGUyOWE5ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyODc0ODAwMDg0MjcyLDg1LjMxMDE3NTkxMTE3NTA4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInJlZCIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInJlZCIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hZmE1M2E4NGMyZmI0NTUzYjgxY2RjOWQ4YjZjNWEzNiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kNTE3ZGExMTUzNGE0MWQ5YWMwYTIyMzFkNTUzYzMxMiA9ICQoJzxkaXYgaWQ9Imh0bWxfZDUxN2RhMTE1MzRhNDFkOWFjMGEyMjMxZDU1M2MzMTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhvdGVsIFBob2VuaXgsIEpQIFJvYWQgVGhhbWVsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hZmE1M2E4NGMyZmI0NTUzYjgxY2RjOWQ4YjZjNWEzNi5zZXRDb250ZW50KGh0bWxfZDUxN2RhMTE1MzRhNDFkOWFjMGEyMjMxZDU1M2MzMTIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMmM0YWI2M2UyMDEyNDM3YTg3MDU0MmI1NDQwZTI5YTkuYmluZFBvcHVwKHBvcHVwX2FmYTUzYTg0YzJmYjQ1NTNiODFjZGM5ZDhiNmM1YTM2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2U5NjlkNTdjYmZhMTQ4ZjdhN2IzY2JhMTA3NTA1MWU3ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE1NTU1MDA0MTk5MzY2LDg1LjMxMDE4NDkxMjg3MjIyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzhhODNlZTZmZTYxMzQ1MTA4OTE0NDViOTVhZTk5NjRhID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzVhZjNjZjUzYTc0MzRiNDA5NGM2ZDQwN2YxYWFkYmJhID0gJCgnPGRpdiBpZD0iaHRtbF81YWYzY2Y1M2E3NDM0YjQwOTRjNmQ0MDdmMWFhZGJiYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIE5vcnRoZmllbGQgQ2FmZSBhbmQgSmVzc2UgSmFtZXMgQmFyLCBUaGFtZWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzhhODNlZTZmZTYxMzQ1MTA4OTE0NDViOTVhZTk5NjRhLnNldENvbnRlbnQoaHRtbF81YWYzY2Y1M2E3NDM0YjQwOTRjNmQ0MDdmMWFhZGJiYSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9lOTY5ZDU3Y2JmYTE0OGY3YTdiM2NiYTEwNzUwNTFlNy5iaW5kUG9wdXAocG9wdXBfOGE4M2VlNmZlNjEzNDUxMDg5MTQ0NWI5NWFlOTk2NGEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNGEyNDA4ZTI4ZWVmNDVjNmJmZDk1ZmQ2NGYzN2NkMWMgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTUwNDYsODUuMzEyNDldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMDgxMGQzYWU2ODM4NDVlMGI2ODYyNjNlNjEwMTI2ZDUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNTk1NjM5OWMzYjdjNDE0MGE0YzVhMmNlYzdiOTVjODIgPSAkKCc8ZGl2IGlkPSJodG1sXzU5NTYzOTljM2I3YzQxNDBhNGM1YTJjZWM3Yjk1YzgyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5SZXZvbHV0aW9uIENhZmUsIEFtcml0IE1hcmc8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzA4MTBkM2FlNjgzODQ1ZTBiNjg2MjYzZTYxMDEyNmQ1LnNldENvbnRlbnQoaHRtbF81OTU2Mzk5YzNiN2M0MTQwYTRjNWEyY2VjN2I5NWM4Mik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl80YTI0MDhlMjhlZWY0NWM2YmZkOTVmZDY0ZjM3Y2QxYy5iaW5kUG9wdXAocG9wdXBfMDgxMGQzYWU2ODM4NDVlMGI2ODYyNjNlNjEwMTI2ZDUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYzdiNGQwMWM2YTQzNDlhMjk4OWZhM2NlMzJkOThmYzQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTUxNzk3NDg0MTYyOTcsODUuMzI2MDI1NDg1OTkyNDJdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOWU1OWExYmU2M2M1NDQ1N2I0MmE3YzZlOTBmYWQ3YjQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZWJjNjFhNGU2NjVkNGQ1MDkxMWVhODhkZjRjZDdiNWUgPSAkKCc8ZGl2IGlkPSJodG1sX2ViYzYxYTRlNjY1ZDRkNTA5MTFlYTg4ZGY0Y2Q3YjVlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Fc3ByZXNzaW9uOiBUaGUgQ2FmZSwgTmF4YWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzllNTlhMWJlNjNjNTQ0NTdiNDJhN2M2ZTkwZmFkN2I0LnNldENvbnRlbnQoaHRtbF9lYmM2MWE0ZTY2NWQ0ZDUwOTExZWE4OGRmNGNkN2I1ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9jN2I0ZDAxYzZhNDM0OWEyOTg5ZmEzY2UzMmQ5OGZjNC5iaW5kUG9wdXAocG9wdXBfOWU1OWExYmU2M2M1NDQ1N2I0MmE3YzZlOTBmYWQ3YjQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNDlmOWY3YjBlYjM5NGI2MWE1ZGM3MDM1ZmJjNzhkYTAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MjAxMDYwOTAzOTc3NjcsODUuMzMxNDUzMzU1MTIxNV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF80ODdkMzkzY2UzNmQ0NWFmYjA4MDY3NDE0MDg5NDhmMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wMTE5ZTk3MThlOWY0YWQ1OTNkNmQxMDQzOGQ0ZGE5ZiA9ICQoJzxkaXYgaWQ9Imh0bWxfMDExOWU5NzE4ZTlmNGFkNTkzZDZkMTA0MzhkNGRhOWYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJvYWQgSG91c2UgQ2FmZSwgQmhhdCBCaGF0ZW5pPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80ODdkMzkzY2UzNmQ0NWFmYjA4MDY3NDE0MDg5NDhmMC5zZXRDb250ZW50KGh0bWxfMDExOWU5NzE4ZTlmNGFkNTkzZDZkMTA0MzhkNGRhOWYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNDlmOWY3YjBlYjM5NGI2MWE1ZGM3MDM1ZmJjNzhkYTAuYmluZFBvcHVwKHBvcHVwXzQ4N2QzOTNjZTM2ZDQ1YWZiMDgwNjc0MTQwODk0OGYwKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzYzYzdlYmQzOTAyNTQ0YzhiMTE4MmVlZTI2NDM2ZDg2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzAzMjIyMjc0NzgwMjczLDg1LjMwNzkyMjM2MzI4MTI1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Y1MGNmZjNiNGIzMzQ5ZTBiMGM4OTk3OTBjYmVkNzUwID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2ExZmYyNDEzZmY0NjQ4MDM4YzFlM2I2ZDQ0MTU5MmU2ID0gJCgnPGRpdiBpZD0iaHRtbF9hMWZmMjQxM2ZmNDY0ODAzOGMxZTNiNmQ0NDE1OTJlNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2FmZSBNb25kbyBCaXphcnJvLCBGcmVhayBTdHJlZXQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2Y1MGNmZjNiNGIzMzQ5ZTBiMGM4OTk3OTBjYmVkNzUwLnNldENvbnRlbnQoaHRtbF9hMWZmMjQxM2ZmNDY0ODAzOGMxZTNiNmQ0NDE1OTJlNik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl82M2M3ZWJkMzkwMjU0NGM4YjExODJlZWUyNjQzNmQ4Ni5iaW5kUG9wdXAocG9wdXBfZjUwY2ZmM2I0YjMzNDllMGIwYzg5OTc5MGNiZWQ3NTApOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGFiOGI1NDgxMmJjNDk1MDkzYjg3NjI0YmFlNzFkOTEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDUxMDM5Mzc4OTg2OTUsODUuMzA4NjIwNzkzMzA2MzVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZTZjMzJjY2E3NWJlNDNiZjljODdmNTNmMjI0ZDFiOTkgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2EwZDRjMWEwMmVkNGJmMzg0OGI4MmVhOGJjZWZiNmQgPSAkKCc8ZGl2IGlkPSJodG1sXzdhMGQ0YzFhMDJlZDRiZjM4NDhiODJlYThiY2VmYjZkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5KeW9uYSBCZWxlZSBDYWZlLCBNYWtoYW4gVG9sZTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZTZjMzJjY2E3NWJlNDNiZjljODdmNTNmMjI0ZDFiOTkuc2V0Q29udGVudChodG1sXzdhMGQ0YzFhMDJlZDRiZjM4NDhiODJlYThiY2VmYjZkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2RhYjhiNTQ4MTJiYzQ5NTA5M2I4NzYyNGJhZTcxZDkxLmJpbmRQb3B1cChwb3B1cF9lNmMzMmNjYTc1YmU0M2JmOWM4N2Y1M2YyMjRkMWI5OSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl84MDZkMzg0OTI3YzA0OTg0YjgwNTdmMjVlYTkzZTZlNSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcwNzkyNTQzMjc2NjM1Niw4NS4zMTg3NzY1MTQyMTIxM10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83YzU3ODQ0YTMxN2Y0Y2I1YjJjNzQ5OGNjYzJiZTA0OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82Y2M0MjU1Yzg4MjA0MTA2ODFkZjFmYmVjNGRkNzZhNyA9ICQoJzxkaXYgaWQ9Imh0bWxfNmNjNDI1NWM4ODIwNDEwNjgxZGYxZmJlYzRkZDc2YTciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPm5hbmdsbyBDYWZlICZhbXA7IFB1YiwgS2FtYWxhZGk8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzdjNTc4NDRhMzE3ZjRjYjViMmM3NDk4Y2NjMmJlMDQ4LnNldENvbnRlbnQoaHRtbF82Y2M0MjU1Yzg4MjA0MTA2ODFkZjFmYmVjNGRkNzZhNyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl84MDZkMzg0OTI3YzA0OTg0YjgwNTdmMjVlYTkzZTZlNS5iaW5kUG9wdXAocG9wdXBfN2M1Nzg0NGEzMTdmNGNiNWIyYzc0OThjY2MyYmUwNDgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjUxNTE3YWM2YzJlNDYxZmFjNDZjNTY0YWE4ZWE0ZTQgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDc2Niw4NS4zMTkxNzZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMzkzYTU0MGViZThlNGNjYzhhY2IwNTQwZGVmMTg0NDcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMGJkNTkyZTE4OWY1NDU5OWI5ZjU0YzcyZGEyOWI3ZGIgPSAkKCc8ZGl2IGlkPSJodG1sXzBiZDU5MmUxODlmNTQ1OTliOWY1NGM3MmRhMjliN2RiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5ZYW5hIENhZmUsIEthbWFsYWRpIEdhbmVzaHRoYW48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzM5M2E1NDBlYmU4ZTRjY2M4YWNiMDU0MGRlZjE4NDQ3LnNldENvbnRlbnQoaHRtbF8wYmQ1OTJlMTg5ZjU0NTk5YjlmNTRjNzJkYTI5YjdkYik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8yNTE1MTdhYzZjMmU0NjFmYWM0NmM1NjRhYThlYTRlNC5iaW5kUG9wdXAocG9wdXBfMzkzYTU0MGViZThlNGNjYzhhY2IwNTQwZGVmMTg0NDcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfYjRlZmExNTNmYzUwNGNkMmIyMjQyNjc3MmU5MjAxY2UgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDk4MTYsODUuMzIxMTJdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfY2YzODg2YzEzMjViNDcyZTgxOWVhMGI0M2JlMDk1MTUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMDRkZjNlZmQ3ODZlNDAzNGIzOWRjZjQ1YjcyNDdmNDYgPSAkKCc8ZGl2IGlkPSJodG1sXzA0ZGYzZWZkNzg2ZTQwMzRiMzlkY2Y0NWI3MjQ3ZjQ2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CYXJpc3RhIENhZsOpLCBHYW5hZ2F1ciBSZWdlbmN5PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9jZjM4ODZjMTMyNWI0NzJlODE5ZWEwYjQzYmUwOTUxNS5zZXRDb250ZW50KGh0bWxfMDRkZjNlZmQ3ODZlNDAzNGIzOWRjZjQ1YjcyNDdmNDYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYjRlZmExNTNmYzUwNGNkMmIyMjQyNjc3MmU5MjAxY2UuYmluZFBvcHVwKHBvcHVwX2NmMzg4NmMxMzI1YjQ3MmU4MTllYTBiNDNiZTA5NTE1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzNlODc4OGJjMTg2YjQ4NmNiMDMyYmZmYTMyNGMxMmQxID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzExMDkxOTY2ODIzMDM3LDg1LjMxNjEwODE3ODY2NzQ4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2QyYzRhNjcyYTQzMDQ2NDY4N2I1NGQxNDY4YWU3OGY5ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzE0NzBiMWMxYjY0NDRkODliOGEwOWEwZDgxNzIwMDMzID0gJCgnPGRpdiBpZD0iaHRtbF8xNDcwYjFjMWI2NDQ0ZDg5YjhhMDlhMGQ4MTcyMDAzMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2Fmw6kgRGUmIzM5O2xpdGUsIEthbnRpIFBhdGgsIEthdGhtYW5kdSA0NDYwMDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZDJjNGE2NzJhNDMwNDY0Njg3YjU0ZDE0NjhhZTc4Zjkuc2V0Q29udGVudChodG1sXzE0NzBiMWMxYjY0NDRkODliOGEwOWEwZDgxNzIwMDMzKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzNlODc4OGJjMTg2YjQ4NmNiMDMyYmZmYTMyNGMxMmQxLmJpbmRQb3B1cChwb3B1cF9kMmM0YTY3MmE0MzA0NjQ2ODdiNTRkMTQ2OGFlNzhmOSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jMWZkOGVkMTI0YTQ0ZDVkOTgxMGUwNmQ3NzQ1MmU0MCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY5ODg5OTA5NjI0ODMyMiw4NS4zMzg0OTIzOTM0OTM2NV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF85MjM3MmRiM2QxYWI0YzFlOWUwYzc2N2RhZDIxYjNjYiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8yMmVkMDRlMzFjMTE0ZmFkODhmMGMwMDEyMmQ3OGMzZCA9ICQoJzxkaXYgaWQ9Imh0bWxfMjJlZDA0ZTMxYzExNGZhZDg4ZjBjMDAxMjJkNzhjM2QiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlByZXNjYXMgQ2FmZSwgT2xkIEJhbmVzd29yPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF85MjM3MmRiM2QxYWI0YzFlOWUwYzc2N2RhZDIxYjNjYi5zZXRDb250ZW50KGh0bWxfMjJlZDA0ZTMxYzExNGZhZDg4ZjBjMDAxMjJkNzhjM2QpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYzFmZDhlZDEyNGE0NGQ1ZDk4MTBlMDZkNzc0NTJlNDAuYmluZFBvcHVwKHBvcHVwXzkyMzcyZGIzZDFhYjRjMWU5ZTBjNzY3ZGFkMjFiM2NiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzcwNmU0ZGFiYmJkNjQ2Yzg5ZjNiYzZmZGNjZDQ4Y2RhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyNzAxNTU5MDI4MDQsODUuMzExMzg3NDU3NDAxNThdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYzJkZjczOGY3OTNlNGRhNzgzZmQxNmEwY2M0OWMwNTEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZjhjNGM1ZmVhMWJlNDRkOTgzNWU1MTgyZGI2NzFmODkgPSAkKCc8ZGl2IGlkPSJodG1sX2Y4YzRjNWZlYTFiZTQ0ZDk4MzVlNTE4MmRiNjcxZjg5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DYWZlIE1pdHJhLCBUaGFtZWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2MyZGY3MzhmNzkzZTRkYTc4M2ZkMTZhMGNjNDljMDUxLnNldENvbnRlbnQoaHRtbF9mOGM0YzVmZWExYmU0NGQ5ODM1ZTUxODJkYjY3MWY4OSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl83MDZlNGRhYmJiZDY0NmM4OWYzYmM2ZmRjY2Q0OGNkYS5iaW5kUG9wdXAocG9wdXBfYzJkZjczOGY3OTNlNGRhNzgzZmQxNmEwY2M0OWMwNTEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDZhMGVjMzZhMWNkNDZkZTk5NmI4YjA2Mjk5ZjVmYzkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTA0NjE3NjE3NTg2MTIsODUuMzE3MjcxNDYyMzgwMDhdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTlkOGMzZWZjNGJhNGExYjk3ZDU5YmI3MmM4MzNlMTUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOGZmMWM3ODk5ODFmNDY2NWE0ZTg3ZWJmOTBkYTQ4NGQgPSAkKCc8ZGl2IGlkPSJodG1sXzhmZjFjNzg5OTgxZjQ2NjVhNGU4N2ViZjkwZGE0ODRkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5OYW5nbG8sIENhZmUgJmFtcDsgUHViLCBEdXJiYXIgTWFyZywgRHVyYmFyIE1hcmc8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzE5ZDhjM2VmYzRiYTRhMWI5N2Q1OWJiNzJjODMzZTE1LnNldENvbnRlbnQoaHRtbF84ZmYxYzc4OTk4MWY0NjY1YTRlODdlYmY5MGRhNDg0ZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9kNmEwZWMzNmExY2Q0NmRlOTk2YjhiMDYyOTlmNWZjOS5iaW5kUG9wdXAocG9wdXBfMTlkOGMzZWZjNGJhNGExYjk3ZDU5YmI3MmM4MzNlMTUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTc3ZTk1OTM0ZTkyNDk0MmJmM2U5MzY4MGNlNjYzNzggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTA3MDksODUuMzE3OTUyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2U3NzhiNzE5ZGVlMjRkZThiNjhmYjBjMDEzOWQyMzA2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzk1ZmM3ZTZjOGU1OTRjMTFiOGNiM2Y5NGQ5ZTEyNmQwID0gJCgnPGRpdiBpZD0iaHRtbF85NWZjN2U2YzhlNTk0YzExYjhjYjNmOTRkOWUxMjZkMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+QXJpeWEgQ2FmZSwgSW5zaWRlIFNoZXJwYSBNYWxsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lNzc4YjcxOWRlZTI0ZGU4YjY4ZmIwYzAxMzlkMjMwNi5zZXRDb250ZW50KGh0bWxfOTVmYzdlNmM4ZTU5NGMxMWI4Y2IzZjk0ZDllMTI2ZDApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMTc3ZTk1OTM0ZTkyNDk0MmJmM2U5MzY4MGNlNjYzNzguYmluZFBvcHVwKHBvcHVwX2U3NzhiNzE5ZGVlMjRkZThiNjhmYjBjMDEzOWQyMzA2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzZhN2E5ZmE4YTk5YzQ1MTRiNmViNmNmMTc3ZjI2ODJhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEwNDE2MTA4MDkyMjMsODUuMzE3MjYwMjE2NTY5NzldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMzllZjFiODQ3YWIzNDA1ZGJhOWM4MjdiOThmZmE5OWQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMmVmOGUxYWYwMWQ1NGJjMzk0YmRjZjBjMzRkZWFiMzcgPSAkKCc8ZGl2IGlkPSJodG1sXzJlZjhlMWFmMDFkNTRiYzM5NGJkY2YwYzM0ZGVhYjM3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TYW0mIzM5O3MgT25lIFRyZWUgQ2FmZSwgRHVyYmFyIE1hcmc8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzM5ZWYxYjg0N2FiMzQwNWRiYTljODI3Yjk4ZmZhOTlkLnNldENvbnRlbnQoaHRtbF8yZWY4ZTFhZjAxZDU0YmMzOTRiZGNmMGMzNGRlYWIzNyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl82YTdhOWZhOGE5OWM0NTE0YjZlYjZjZjE3N2YyNjgyYS5iaW5kUG9wdXAocG9wdXBfMzllZjFiODQ3YWIzNDA1ZGJhOWM4MjdiOThmZmE5OWQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfNzdiYWY4YjM0ZGUxNGJhNjliMTAzMGNjYTZkOTRhZmIgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDk4NzY3MTg2MzQzMTYsODUuMzE2OTI2MDIzNzc1MV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83Y2E3YmJjOTg2ZjE0MzQwOTIzZmFhNmEzYTA3NTYwNyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81MjdjZTU5OWMzOWU0ODc0YWQzZWJlNjUwYmIzMTE3MiA9ICQoJzxkaXYgaWQ9Imh0bWxfNTI3Y2U1OTljMzllNDg3NGFkM2ViZTY1MGJiMzExNzIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlZpbnRhZ2UgQ2FmZSBBbmQgUHViLCBXb29kbGFuZCBDb21wbGV4PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83Y2E3YmJjOTg2ZjE0MzQwOTIzZmFhNmEzYTA3NTYwNy5zZXRDb250ZW50KGh0bWxfNTI3Y2U1OTljMzllNDg3NGFkM2ViZTY1MGJiMzExNzIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNzdiYWY4YjM0ZGUxNGJhNjliMTAzMGNjYTZkOTRhZmIuYmluZFBvcHVwKHBvcHVwXzdjYTdiYmM5ODZmMTQzNDA5MjNmYWE2YTNhMDc1NjA3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzMxNWZhNzc2OWUwODQyZTJiZTg4NTY1MDk3NzZmZWY2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjc4NjI5NDk2NTYxOTY0LDg1LjMxMDUyMTU0Njc4MzQyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2IzNDk3NTM1NWRiYjQ3NDFiMjgwNGNlMjQ2NDBmYjE5ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2UwNjVkNTY3MjkyYjQ5YWFhNDNkYzdjYWI0ZWYzMzk4ID0gJCgnPGRpdiBpZD0iaHRtbF9lMDY1ZDU2NzI5MmI0OWFhYTQzZGM3Y2FiNGVmMzM5OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2Fmw6kgU29tYSwgTGFsaXRwdXI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2IzNDk3NTM1NWRiYjQ3NDFiMjgwNGNlMjQ2NDBmYjE5LnNldENvbnRlbnQoaHRtbF9lMDY1ZDU2NzI5MmI0OWFhYTQzZGM3Y2FiNGVmMzM5OCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8zMTVmYTc3NjllMDg0MmUyYmU4ODU2NTA5Nzc2ZmVmNi5iaW5kUG9wdXAocG9wdXBfYjM0OTc1MzU1ZGJiNDc0MWIyODA0Y2UyNDY0MGZiMTkpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOGI5NzU5OGI1YzAwNDFkNjlhOWIyNmNiMGY0MGM5ODkgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTE4Niw4NS4zMjIzMV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9lMzc2NDI0MDI4MTc0YWY3YTg4N2FjNzVmODEyYTQ4OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kNmVkMGRlNmY2ODg0Y2I5YWI4ZGViY2Q4N2UzMTJkYyA9ICQoJzxkaXYgaWQ9Imh0bWxfZDZlZDBkZTZmNjg4NGNiOWFiOGRlYmNkODdlMzEyZGMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPldhcmVob3VzZSBDYWZlLCBIYXR0aXNhcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZTM3NjQyNDAyODE3NGFmN2E4ODdhYzc1ZjgxMmE0ODguc2V0Q29udGVudChodG1sX2Q2ZWQwZGU2ZjY4ODRjYjlhYjhkZWJjZDg3ZTMxMmRjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzhiOTc1OThiNWMwMDQxZDY5YTliMjZjYjBmNDBjOTg5LmJpbmRQb3B1cChwb3B1cF9lMzc2NDI0MDI4MTc0YWY3YTg4N2FjNzVmODEyYTQ4OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83NWYyNTEyZmZlMDc0ZDY4OWViYjZiMTJkY2RiNTMxZSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMjA0OTI1MDU1NDExMyw4NS4zMTc1NTIwMjA0MDM1NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82NWEzOWMxZjI1Y2U0OTExOWVlZjE4OWU0NTYwZWUzYiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jYWJlNTA5NDFhZTg0ZWI4OGM0OTMzMTg1YjRmNzBlZiA9ICQoJzxkaXYgaWQ9Imh0bWxfY2FiZTUwOTQxYWU4NGViODhjNDkzMzE4NWI0ZjcwZWYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkdvdXJtZXQgQ2FmZSwgRHVyYmFybWFyZzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjVhMzljMWYyNWNlNDkxMTllZWYxODllNDU2MGVlM2Iuc2V0Q29udGVudChodG1sX2NhYmU1MDk0MWFlODRlYjg4YzQ5MzMxODViNGY3MGVmKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzc1ZjI1MTJmZmUwNzRkNjg5ZWJiNmIxMmRjZGI1MzFlLmJpbmRQb3B1cChwb3B1cF82NWEzOWMxZjI1Y2U0OTExOWVlZjE4OWU0NTYwZWUzYik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8yYTY0YmNlOGU0ZTU0MWYxOThlNDc2NTQ3OTg0Mjg1YSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMzE5ODM0NjM1MTY2NCw4NS4zMjA3ODc5MDQ3NjMxMl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xNGM1OTRjZmVjZDk0YzliODFlNjc1Mzc5NmFhZmJjZSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF84OGUxMGYyNzc3ZDI0NWM3ODIzNmNlZjRhMGYxZWRjYyA9ICQoJzxkaXYgaWQ9Imh0bWxfODhlMTBmMjc3N2QyNDVjNzgyMzZjZWY0YTBmMWVkY2MiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRoZSBWaWxsYWdlIENhZmUsIFB1bGNob3drPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xNGM1OTRjZmVjZDk0YzliODFlNjc1Mzc5NmFhZmJjZS5zZXRDb250ZW50KGh0bWxfODhlMTBmMjc3N2QyNDVjNzgyMzZjZWY0YTBmMWVkY2MpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMmE2NGJjZThlNGU1NDFmMTk4ZTQ3NjU0Nzk4NDI4NWEuYmluZFBvcHVwKHBvcHVwXzE0YzU5NGNmZWNkOTRjOWI4MWU2NzUzNzk2YWFmYmNlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Q1OWI3MGQ5ZGIxMzRkNWViNzVhMzQwZWNlYTZlNTBlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE2MTY2LDg1LjMyNTU0NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiYmx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yNGUyOTFiNzNjMTM0MzA5OGRlNTE0YmI5YWFhNmEwMyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wMzY5YjlhYWQ4MzA0ZjI1OGMwZTYyNDlkMWQzZWU3ZSA9ICQoJzxkaXYgaWQ9Imh0bWxfMDM2OWI5YWFkODMwNGYyNThjMGU2MjQ5ZDFkM2VlN2UiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNhZmUgRGVqYXZ1LCBOYXJheWFuY2hhdXI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzI0ZTI5MWI3M2MxMzQzMDk4ZGU1MTRiYjlhYWE2YTAzLnNldENvbnRlbnQoaHRtbF8wMzY5YjlhYWQ4MzA0ZjI1OGMwZTYyNDlkMWQzZWU3ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9kNTliNzBkOWRiMTM0ZDVlYjc1YTM0MGVjZWE2ZTUwZS5iaW5kUG9wdXAocG9wdXBfMjRlMjkxYjczYzEzNDMwOThkZTUxNGJiOWFhYTZhMDMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTdhMzFiYTMyOWRmNDhkNmFkYjFlNWNhMThhODAzMzAgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDg2MzY0NzQxNzQ0NTgsODUuMzI1MTg5NjExMzg0MDZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTBiMWU5MGUxZTg4NDQ2OWEyZjA2YzM4Y2E3MWE3NzggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2EyMjVhOGIzMjQ2NGFiYWEyMTgzODZjODg5MGIyYmYgPSAkKCc8ZGl2IGlkPSJodG1sXzdhMjI1YThiMzI0NjRhYmFhMjE4Mzg2Yzg4OTBiMmJmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5EZWxlY2lvdXMgQ2FmZSAoR3VmYSksIE1hY2hoYSBQb2toYXJpLCBSaW5nIFJkLCBLYXRobWFuZHUgMDA5Nzc8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzEwYjFlOTBlMWU4ODQ0NjlhMmYwNmMzOGNhNzFhNzc4LnNldENvbnRlbnQoaHRtbF83YTIyNWE4YjMyNDY0YWJhYTIxODM4NmM4ODkwYjJiZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8xN2EzMWJhMzI5ZGY0OGQ2YWRiMWU1Y2ExOGE4MDMzMC5iaW5kUG9wdXAocG9wdXBfMTBiMWU5MGUxZTg4NDQ2OWEyZjA2YzM4Y2E3MWE3NzgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDkzYjdkN2JmNWY2NGZjZmE1M2UwZjQ0ZjdiMGRlMjUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTUxNjgsODUuMzEwNTY1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzBlNmEyOTY0NmNmZjQ4YTk5MWUwZTk4ZDliNDIzZTYyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzA3Yzk3Zjk4MGU2MzQ5MmViZTgxZmQ2ODFkNWZjZDJhID0gJCgnPGRpdiBpZD0iaHRtbF8wN2M5N2Y5ODBlNjM0OTJlYmU4MWZkNjgxZDVmY2QyYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TmV3IE9ybGVhbnMgQ2FmZSwgVGhhbWVsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8wZTZhMjk2NDZjZmY0OGE5OTFlMGU5OGQ5YjQyM2U2Mi5zZXRDb250ZW50KGh0bWxfMDdjOTdmOTgwZTYzNDkyZWJlODFmZDY4MWQ1ZmNkMmEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZDkzYjdkN2JmNWY2NGZjZmE1M2UwZjQ0ZjdiMGRlMjUuYmluZFBvcHVwKHBvcHVwXzBlNmEyOTY0NmNmZjQ4YTk5MWUwZTk4ZDliNDIzZTYyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2IyZGE3MjZjMzAwNzRmZmE5YzYyMTNiZDM3NGU2MGY4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE0ODc0LDg1LjMxMDYxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzQzODhkODYyYWNhMjQ5NGE5NTkzOTViMzk5N2NiNjk1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2Q1OTkwNDE2MzhiZTRlNTc5ZDJiNzk4MmQ4NTJiZWM0ID0gJCgnPGRpdiBpZD0iaHRtbF9kNTk5MDQxNjM4YmU0ZTU3OWQyYjc5ODJkODUyYmVjNCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGhlIENhZmUgV2l0aCBObyBOYW1lLCBQYXJ5YXRhbiBNYXJnPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80Mzg4ZDg2MmFjYTI0OTRhOTU5Mzk1YjM5OTdjYjY5NS5zZXRDb250ZW50KGh0bWxfZDU5OTA0MTYzOGJlNGU1NzlkMmI3OTgyZDg1MmJlYzQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYjJkYTcyNmMzMDA3NGZmYTljNjIxM2JkMzc0ZTYwZjguYmluZFBvcHVwKHBvcHVwXzQzODhkODYyYWNhMjQ5NGE5NTkzOTViMzk5N2NiNjk1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzVjMjM5Y2Y4ODIyMjRkNWFiOWQwMTYxMzI1YWVmMTIwID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzE0Mzg5MjYzMTAwNTgsODUuMzEwNDI1NDg3MzA3MjddLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjg5Mjg3YmZmOWQzNDAzZjk4NjZjYWNhYzQwODMwZmMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2QxYmI4NGI3MzU2NDgzYjlmOTgzNTkwNWY1YzUyM2MgPSAkKCc8ZGl2IGlkPSJodG1sXzdkMWJiODRiNzM1NjQ4M2I5Zjk4MzU5MDVmNWM1MjNjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5Sb2FkSG91c2UgQ2Fmw6ksIFRoYW1lbDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYjg5Mjg3YmZmOWQzNDAzZjk4NjZjYWNhYzQwODMwZmMuc2V0Q29udGVudChodG1sXzdkMWJiODRiNzM1NjQ4M2I5Zjk4MzU5MDVmNWM1MjNjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzVjMjM5Y2Y4ODIyMjRkNWFiOWQwMTYxMzI1YWVmMTIwLmJpbmRQb3B1cChwb3B1cF9iODkyODdiZmY5ZDM0MDNmOTg2NmNhY2FjNDA4MzBmYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83MTQ0Nzc5ZTI2NmY0MjczOWMyM2I0MjA5ZDFkMTUwOSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcwODg3ODAxOTc5MTI4Miw4NS4zMjE5NjkxMzE0OTQ4MV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJncmVlbiIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyZWVuIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2IxZTMwY2UxNzdjZTRiMDViNzBkNDkwOTViN2NkZWRiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzhjNzlhMjdjZWM4NTRkOGViMDljNGVjYmMxMTA2ZjBmID0gJCgnPGRpdiBpZD0iaHRtbF84Yzc5YTI3Y2VjODU0ZDhlYjA5YzRlY2JjMTEwNmYwZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q2hpbmEgVG93biBNYWxsLCBuYW48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2IxZTMwY2UxNzdjZTRiMDViNzBkNDkwOTViN2NkZWRiLnNldENvbnRlbnQoaHRtbF84Yzc5YTI3Y2VjODU0ZDhlYjA5YzRlY2JjMTEwNmYwZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl83MTQ0Nzc5ZTI2NmY0MjczOWMyM2I0MjA5ZDFkMTUwOS5iaW5kUG9wdXAocG9wdXBfYjFlMzBjZTE3N2NlNGIwNWI3MGQ0OTA5NWI3Y2RlZGIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMmJkZWY5Njg0OWQzNDhlYjlkMmRiOTYxOGEyMWQwN2EgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDk5NDkzMTEzNDIzODUsODUuMzE5MDg1ODk5NTYyMjhdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiZ3JlZW4iLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJncmVlbiIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF85NjNlNjJkNDQzN2U0YjMzOWJkZGI0ZGI5MTk3MDFiMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80ZTk4ZWE5YTc1YjQ0YjQ1OGRkZDgzM2MyYzAwMmJkMCA9ICQoJzxkaXYgaWQ9Imh0bWxfNGU5OGVhOWE3NWI0NGI0NThkZGQ4MzNjMmMwMDJiZDAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJpc2luZyBNYWxsLCBLYW1hbGFkaTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOTYzZTYyZDQ0MzdlNGIzMzliZGRiNGRiOTE5NzAxYjAuc2V0Q29udGVudChodG1sXzRlOThlYTlhNzViNDRiNDU4ZGRkODMzYzJjMDAyYmQwKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzJiZGVmOTY4NDlkMzQ4ZWI5ZDJkYjk2MThhMjFkMDdhLmJpbmRQb3B1cChwb3B1cF85NjNlNjJkNDQzN2U0YjMzOWJkZGI0ZGI5MTk3MDFiMCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iYzBiOWY1NjU1ZGY0ZjAwODUyZDZmYmQ4ZGRkM2NmOCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcwMTUyOTQzODg0MDQ0Miw4NS4zMTMzNDc4NjEwMzU1NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJncmVlbiIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyZWVuIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Q1M2M4YzFhNTRiZjRhY2ZhYzhjN2EzMGJjYjc0YWI1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzUzODgxN2ZhYjk3ZDQyN2U4NmE3Yjg2YzgxZDQzMjM3ID0gJCgnPGRpdiBpZD0iaHRtbF81Mzg4MTdmYWI5N2Q0MjdlODZhN2I4NmM4MWQ0MzIzNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+S2F0aG1hbmR1IE1hbGwsIEthdGhtYW5kdTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZDUzYzhjMWE1NGJmNGFjZmFjOGM3YTMwYmNiNzRhYjUuc2V0Q29udGVudChodG1sXzUzODgxN2ZhYjk3ZDQyN2U4NmE3Yjg2YzgxZDQzMjM3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2JjMGI5ZjU2NTVkZjRmMDA4NTJkNmZiZDhkZGQzY2Y4LmJpbmRQb3B1cChwb3B1cF9kNTNjOGMxYTU0YmY0YWNmYWM4YzdhMzBiY2I3NGFiNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl85MGMyYWEzYjE1MTU0NGQwYmI3Nzc5ZWZmYjU4NjZmNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMDY5MTY1ODA2MTQyOCw4NS4zMTc1OTEwMjYyNDk2NF0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJncmVlbiIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyZWVuIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzcwZGY4NGNjNDNmNjRiM2E5MWI1NzBkZTBlMjg5ZGM4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzg4ZjhlYTk4MDg3ODQ0ZTFhMTkxOGJmYWI1ZmI2MTYzID0gJCgnPGRpdiBpZD0iaHRtbF84OGY4ZWE5ODA4Nzg0NGUxYTE5MThiZmFiNWZiNjE2MyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U2hlcnBhIE1hbGwsIERVUkJBUiBNQVJHLCBLQVRITUFORFUsIE5FUEFMIEthdGhtYW5kdSw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzcwZGY4NGNjNDNmNjRiM2E5MWI1NzBkZTBlMjg5ZGM4LnNldENvbnRlbnQoaHRtbF84OGY4ZWE5ODA4Nzg0NGUxYTE5MThiZmFiNWZiNjE2Myk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl85MGMyYWEzYjE1MTU0NGQwYmI3Nzc5ZWZmYjU4NjZmNi5iaW5kUG9wdXAocG9wdXBfNzBkZjg0Y2M0M2Y2NGIzYTkxYjU3MGRlMGUyODlkYzgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMmJjMjE5YzkzMzIwNGYyMzgyMTFmMGFkMjVjMDU1Y2IgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MTA3MjI4OTgzMjQ0MjMsODUuMzE3NDgxMzQzNzIzOV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJncmVlbiIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyZWVuIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2ZmMzFjYjg2NTRmNTRmMzE4ZWUyMzU2MjFiNjI4ZGM0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2E1MWZmNDQ3OTZmYzQ1YmM4N2ViMzE4YmM0NDc2NWY2ID0gJCgnPGRpdiBpZD0iaHRtbF9hNTFmZjQ0Nzk2ZmM0NWJjODdlYjMxOGJjNDQ3NjVmNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VGltZXMgU3F1YXJlIE1hbGwsIG5hbjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZmYzMWNiODY1NGY1NGYzMThlZTIzNTYyMWI2MjhkYzQuc2V0Q29udGVudChodG1sX2E1MWZmNDQ3OTZmYzQ1YmM4N2ViMzE4YmM0NDc2NWY2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzJiYzIxOWM5MzMyMDRmMjM4MjExZjBhZDI1YzA1NWNiLmJpbmRQb3B1cChwb3B1cF9mZjMxY2I4NjU0ZjU0ZjMxOGVlMjM1NjIxYjYyOGRjNCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mMGE2NDg3ZTFlNjU0ZTBiYWNmMmU5YTY1YzMyYjk1OSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcwNjc5Mjc2MTM1NjMxLDg1LjMyMjk4OTIyNTM4NzU3XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyZWVuIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiZ3JlZW4iLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYmViMGE1MmQyMThiNGI0NmFjOTI1NmU0MDQ3ZjJkOTkgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYTFmMzBiYjJhNzI2NDM4MWIyNDBiMDA3MGRlOGJmYTQgPSAkKCc8ZGl2IGlkPSJodG1sX2ExZjMwYmIyYTcyNjQzODFiMjQwYjAwNzBkZThiZmE0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5TdGFyIE1hbGwsIG5hbjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmViMGE1MmQyMThiNGI0NmFjOTI1NmU0MDQ3ZjJkOTkuc2V0Q29udGVudChodG1sX2ExZjMwYmIyYTcyNjQzODFiMjQwYjAwNzBkZThiZmE0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2YwYTY0ODdlMWU2NTRlMGJhY2YyZTlhNjVjMzJiOTU5LmJpbmRQb3B1cChwb3B1cF9iZWIwYTUyZDIxOGI0YjQ2YWM5MjU2ZTQwNDdmMmQ5OSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9mOTNlYzUxZjQyMjk0NzRiOWZhZGMzMDVjYTI1ODkwNiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY5OTM5OTM4NTU2Niw4NS4zMTI3MzYwMjIwODMxXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyZWVuIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiZ3JlZW4iLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTQ1MTRmZWQ0MWVjNGQxY2JmODQ5YjJiYjAyNmE3YWMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYzYzYmU5N2M0MzY5NDRiYmI5ZDE5OThiMWJhZWRhNzcgPSAkKCc8ZGl2IGlkPSJodG1sX2M2M2JlOTdjNDM2OTQ0YmJiOWQxOTk4YjFiYWVkYTc3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5DaXZpbCBNYWxsLCBTdW5kaGFyYTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMTQ1MTRmZWQ0MWVjNGQxY2JmODQ5YjJiYjAyNmE3YWMuc2V0Q29udGVudChodG1sX2M2M2JlOTdjNDM2OTQ0YmJiOWQxOTk4YjFiYWVkYTc3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2Y5M2VjNTFmNDIyOTQ3NGI5ZmFkYzMwNWNhMjU4OTA2LmJpbmRQb3B1cChwb3B1cF8xNDUxNGZlZDQxZWM0ZDFjYmY4NDliMmJiMDI2YTdhYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wNmFmN2M3NGI4YTk0ZWM0YTdlMWNkOTExMDFlMjZlZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY5NTc3ODgyNzU3MzAzNyw4NS4zMTI4MzE2MjcwOTc4Nl0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJncmVlbiIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyZWVuIiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Q3ZmI3ZDE5NjczMTRmMTNhM2U1MzMwYjk1ODI4NWIxID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJjNjA3ODAwMTFiNjQ1N2M5NmI2MjU5ZDI3OGRhYzIzID0gJCgnPGRpdiBpZD0iaHRtbF8yYzYwNzgwMDExYjY0NTdjOTZiNjI1OWQyNzhkYWMyMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+Q1RDIE1hbGwsIFN1bmRoYXJhPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kN2ZiN2QxOTY3MzE0ZjEzYTNlNTMzMGI5NTgyODViMS5zZXRDb250ZW50KGh0bWxfMmM2MDc4MDAxMWI2NDU3Yzk2YjYyNTlkMjc4ZGFjMjMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMDZhZjdjNzRiOGE5NGVjNGE3ZTFjZDkxMTAxZTI2ZWQuYmluZFBvcHVwKHBvcHVwX2Q3ZmI3ZDE5NjczMTRmMTNhM2U1MzMwYjk1ODI4NWIxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzBiNTk4MWE0YzczNDRmN2VhZTVmOTM1NjZmYzY1MmQ4ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzM0NTI4LDg1LjMxMDQ0XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyZWVuIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAiZ3JlZW4iLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNTBmMzk1OWM3YWM0NDU5ZWFhMmQ0YmI0YjEzMTI1NTYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYWIyYzIxYzVlOWM4NGUzNWI1NzU1MTAzZmRkYjZlNjMgPSAkKCc8ZGl2IGlkPSJodG1sX2FiMmMyMWM1ZTljODRlMzViNTc1NTEwM2ZkZGI2ZTYzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CRyBNYWxsLCBHb25nYWJ1PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF81MGYzOTU5YzdhYzQ0NTllYWEyZDRiYjRiMTMxMjU1Ni5zZXRDb250ZW50KGh0bWxfYWIyYzIxYzVlOWM4NGUzNWI1NzU1MTAzZmRkYjZlNjMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMGI1OTgxYTRjNzM0NGY3ZWFlNWY5MzU2NmZjNjUyZDguYmluZFBvcHVwKHBvcHVwXzUwZjM5NTljN2FjNDQ1OWVhYTJkNGJiNGIxMzEyNTU2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2I4NTU4Nzk4Yzg0NjQ1ZjJiYTkwOGZiYTlmZjhmZTk2ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjY3OTc1ODg0OTg2MTksODUuMzIxODMyODM3NDA2MDhdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiZ3JlZW4iLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJncmVlbiIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81ZDhjNWY1NGUyMDg0ZWUwYjJmODg4YTU4ZWYzNmUzMyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iNjY2YzhmZjljNzQ0YjE1Yjg4YzZkZDY0MzdlMmQzMCA9ICQoJzxkaXYgaWQ9Imh0bWxfYjY2NmM4ZmY5Yzc0NGIxNWI4OGM2ZGQ2NDM3ZTJkMzAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxhbGl0cHVyIE1hbGwsIG5hbjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNWQ4YzVmNTRlMjA4NGVlMGIyZjg4OGE1OGVmMzZlMzMuc2V0Q29udGVudChodG1sX2I2NjZjOGZmOWM3NDRiMTViODhjNmRkNjQzN2UyZDMwKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2I4NTU4Nzk4Yzg0NjQ1ZjJiYTkwOGZiYTlmZjhmZTk2LmJpbmRQb3B1cChwb3B1cF81ZDhjNWY1NGUyMDg0ZWUwYjJmODg4YTU4ZWYzNmUzMyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8xYWNjNzA1MDBiZTc0ZGNkYjVhYmE0OWNjOTIxYzk4MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcxMTIzNTMzMDYxODAxNyw4NS4zMTI5MzM5MjI3NDQ0M10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJ5ZWxsb3ciLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJ5ZWxsb3ciLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTc2ZDE2N2RhODc5NGVlZGIyZDgyZWUwNmE1ZDBjZjQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOWRhNDhkZGE3NWFjNGQwZDgwYjI5Zjc3N2Y1ZDc0YzMgPSAkKCc8ZGl2IGlkPSJodG1sXzlkYTQ4ZGRhNzVhYzRkMGQ4MGIyOWY3NzdmNWQ3NGMzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5LYW50aXB1ciBUZW1wbGUgSG91c2UsIENodXN5YWJhaGFsPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xNzZkMTY3ZGE4Nzk0ZWVkYjJkODJlZTA2YTVkMGNmNC5zZXRDb250ZW50KGh0bWxfOWRhNDhkZGE3NWFjNGQwZDgwYjI5Zjc3N2Y1ZDc0YzMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMWFjYzcwNTAwYmU3NGRjZGI1YWJhNDljYzkyMWM5ODEuYmluZFBvcHVwKHBvcHVwXzE3NmQxNjdkYTg3OTRlZWRiMmQ4MmVlMDZhNWQwY2Y0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzFkMjAwZDUxZjBkMzQxNDhhODA1MmU5MmQyMWVlMTlhID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjc1MjQ4MjE4MTQ0OTU4LDg1LjMyNDQxODYzNTk0NjkzXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInllbGxvdyIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInllbGxvdyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zM2MzMjAzMzk3ODk0YjZhODU3ODZhMjYzMDJlMjgyNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85MzEwMWQzYmFiYjk0NGI1YWYyOWJkM2ZhNTgwMDFlYiA9ICQoJzxkaXYgaWQ9Imh0bWxfOTMxMDFkM2JhYmI5NDRiNWFmMjliZDNmYTU4MDAxZWIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkhpcmFueWEgVmFybmEgTWFoYXZpaGFyIChHb2xkZW4gVGVtcGxlKSwgS3dhYmFoYWw8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzMzYzMyMDMzOTc4OTRiNmE4NTc4NmEyNjMwMmUyODI1LnNldENvbnRlbnQoaHRtbF85MzEwMWQzYmFiYjk0NGI1YWYyOWJkM2ZhNTgwMDFlYik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8xZDIwMGQ1MWYwZDM0MTQ4YTgwNTJlOTJkMjFlZTE5YS5iaW5kUG9wdXAocG9wdXBfMzNjMzIwMzM5Nzg5NGI2YTg1Nzg2YTI2MzAyZTI4MjUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMjhlNWRlZDA0NDU0NDkxMmJmNDQwZjBlY2RjNTYzMjggPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyNy43MDkxMDA5MDkzMDk0OTgsODUuMzQ4NjIwNDE0NzMzODldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAieWVsbG93IiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAieWVsbG93IiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2FiZGE1MTYyN2U0YzRiMTU5ZDNiYWVkYzk4N2IyZmViID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzU3Y2E2MGFmMGFkYTRhODg4NTE3MzI0YjBmZWQzYzJhID0gJCgnPGRpdiBpZD0iaHRtbF81N2NhNjBhZjBhZGE0YTg4ODUxNzMyNGIwZmVkM2MyYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UGFzaHVwYXRpbmF0aCBUZW1wbGUsIFBhc2h1cGF0aW5hdGggUmQuPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hYmRhNTE2MjdlNGM0YjE1OWQzYmFlZGM5ODdiMmZlYi5zZXRDb250ZW50KGh0bWxfNTdjYTYwYWYwYWRhNGE4ODg1MTczMjRiMGZlZDNjMmEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMjhlNWRlZDA0NDU0NDkxMmJmNDQwZjBlY2RjNTYzMjguYmluZFBvcHVwKHBvcHVwX2FiZGE1MTYyN2U0YzRiMTU5ZDNiYWVkYzk4N2IyZmViKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzNhODM0MTA3ZWJhMDQ1ZjA5YjZhOGI4ZjAxMjRiMjllID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzEyMTcwODk4MjQyNjE1LDg1LjMxMTM0MjIyMDU1NDY2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInllbGxvdyIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInllbGxvdyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hMjBhMzFhNzI2Yjc0NGZiYTVjNzU3OWYzZmRmOWE0NSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zNGExODZhYTYzMmU0YWQ4YWEwYjUxMmVjYzdhODdiZiA9ICQoJzxkaXYgaWQ9Imh0bWxfMzRhMTg2YWE2MzJlNGFkOGFhMGI1MTJlY2M3YTg3YmYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlRhbGVqdSBUZW1wbGUsIE1ha2hhbiBUb2xlPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hMjBhMzFhNzI2Yjc0NGZiYTVjNzU3OWYzZmRmOWE0NS5zZXRDb250ZW50KGh0bWxfMzRhMTg2YWE2MzJlNGFkOGFhMGI1MTJlY2M3YTg3YmYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfM2E4MzQxMDdlYmEwNDVmMDliNmE4YjhmMDEyNGIyOWUuYmluZFBvcHVwKHBvcHVwX2EyMGEzMWE3MjZiNzQ0ZmJhNWM3NTc5ZjNmZGY5YTQ1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2YyMDZkZDYzOWUzOTRkZGZiZTAyZGY0ZjNkNzI0NTUzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzAzNDE1MDM4MjA2NzI1LDg1LjMwNDg2OTE0MTg5OTRdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAieWVsbG93IiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAieWVsbG93IiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzZjNmE1Yzc5ZDA3NDQyNDRhNDgxNzllNmU0NTM4NTc0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2QwZWIyNzcyODlmNzQ4ODg4ZWQyYWQ2ZTVkMjk1MjhhID0gJCgnPGRpdiBpZD0iaHRtbF9kMGViMjc3Mjg5Zjc0ODg4OGVkMmFkNmU1ZDI5NTI4YSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UGFjaGFsaSBCaGFpcmF2IFRlbXBsZSwgU2FuZXBhPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF82YzZhNWM3OWQwNzQ0MjQ0YTQ4MTc5ZTZlNDUzODU3NC5zZXRDb250ZW50KGh0bWxfZDBlYjI3NzI4OWY3NDg4ODhlZDJhZDZlNWQyOTUyOGEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZjIwNmRkNjM5ZTM5NGRkZmJlMDJkZjRmM2Q3MjQ1NTMuYmluZFBvcHVwKHBvcHVwXzZjNmE1Yzc5ZDA3NDQyNDRhNDgxNzllNmU0NTM4NTc0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzE2YjU3ZmM2MzQ4MzQzNmRiYzIwNWRlODRkMzI3OTVlID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzAxNTQ2LDg1LjMwOTQ0XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInllbGxvdyIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInllbGxvdyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83MTNiMDNmNTRkYjc0NjdmYWYwZDBjNThjZjAxMDg4MSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xNzExMGNhMWM1YjM0MTVlYTM2MzdiODJkMWQ5MDczNiA9ICQoJzxkaXYgaWQ9Imh0bWxfMTcxMTBjYTFjNWIzNDE1ZWEzNjM3YjgyZDFkOTA3MzYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlJhbmFtdWt0ZXNod29yIFRlbXBsZSwg4KSw4KSj4KSu4KWB4KSV4KWN4KSk4KWH4KS24KWN4KS14KSwIOCkruCkvuCksOCljeCklzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNzEzYjAzZjU0ZGI3NDY3ZmFmMGQwYzU4Y2YwMTA4ODEuc2V0Q29udGVudChodG1sXzE3MTEwY2ExYzViMzQxNWVhMzYzN2I4MmQxZDkwNzM2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzE2YjU3ZmM2MzQ4MzQzNmRiYzIwNWRlODRkMzI3OTVlLmJpbmRQb3B1cChwb3B1cF83MTNiMDNmNTRkYjc0NjdmYWYwZDBjNThjZjAxMDg4MSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9iZWQyNDA1MTAzOTg0Yzk1YjA1N2M4NGUyZTBjZGI4MCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjcwNTg1MjM5MDc4MjY4NSw4NS4zMzM5ODYyODIzNDg2M10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJ5ZWxsb3ciLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJ5ZWxsb3ciLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGVmNWE4ZTQ4MDVkNDU1Yzk0ODU3NTJjMWIxZGRkMmIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMDA5MGU3NjIwNjkwNGI1ZGJjMTk0NWQxNTIyMTc4OTcgPSAkKCc8ZGl2IGlkPSJodG1sXzAwOTBlNzYyMDY5MDRiNWRiYzE5NDVkMTUyMjE3ODk3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5NYWl0aWRldmkgVGVtcGxlLCAxIE1haXRpZGV2aSBNYXJnPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ZWY1YThlNDgwNWQ0NTVjOTQ4NTc1MmMxYjFkZGQyYi5zZXRDb250ZW50KGh0bWxfMDA5MGU3NjIwNjkwNGI1ZGJjMTk0NWQxNTIyMTc4OTcpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYmVkMjQwNTEwMzk4NGM5NWIwNTdjODRlMmUwY2RiODAuYmluZFBvcHVwKHBvcHVwXzhlZjVhOGU0ODA1ZDQ1NWM5NDg1NzUyYzFiMWRkZDJiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzQ4MmRiYTVhOTZkOTRiYzBiZmYwMWYzM2I0N2UzYzhiID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNzA4ODcxODE1MTAzMDgsODUuMzM2NTM1NDk0MjI1NDNdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAieWVsbG93IiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAieWVsbG93IiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2QwNmNkYjE2MzUzNzQ4YTFhYTdiZGNhMThmOTAzNzI2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2ZmYzEwNDhhZjE4NTQxMGJiY2FhZjM0MzdhMDBlMmQ1ID0gJCgnPGRpdiBpZD0iaHRtbF9mZmMxMDQ4YWYxODU0MTBiYmNhYWYzNDM3YTAwZTJkNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+U2hyZWUgUGFzaHVwYXRpbmF0aCBUZW1wbGUsIEdhdXNoYWxhPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kMDZjZGIxNjM1Mzc0OGExYWE3YmRjYTE4ZjkwMzcyNi5zZXRDb250ZW50KGh0bWxfZmZjMTA0OGFmMTg1NDEwYmJjYWFmMzQzN2EwMGUyZDUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfNDgyZGJhNWE5NmQ5NGJjMGJmZjAxZjMzYjQ3ZTNjOGIuYmluZFBvcHVwKHBvcHVwX2QwNmNkYjE2MzUzNzQ4YTFhYTdiZGNhMThmOTAzNzI2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzhhNDY5ZGE2MDNjMjRjNmM5ZDY4MTBjOTNhZGViZTE1ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjczODU0OTYyNzI0MjUzLDg1LjMyNTMxNzIxOTAxMTE4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInllbGxvdyIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInllbGxvdyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81NTVlYTk4MDZkZGY0MTI5OTQ1OGZkZWQ1YmI4NzdkOSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9hNWM2NWJkYTAyMTc0YjJmYTY1OTI3ZWEzN2E4ZWMzYiA9ICQoJzxkaXYgaWQ9Imh0bWxfYTVjNjViZGEwMjE3NGIyZmE2NTkyN2VhMzdhOGVjM2IiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkNhZsOpIGR1IFRlbXBsZSwgTWFuZ2FsIEJhemFhcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTU1ZWE5ODA2ZGRmNDEyOTk0NThmZGVkNWJiODc3ZDkuc2V0Q29udGVudChodG1sX2E1YzY1YmRhMDIxNzRiMmZhNjU5MjdlYTM3YThlYzNiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzhhNDY5ZGE2MDNjMjRjNmM5ZDY4MTBjOTNhZGViZTE1LmJpbmRQb3B1cChwb3B1cF81NTVlYTk4MDZkZGY0MTI5OTQ1OGZkZWQ1YmI4NzdkOSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl80ZDI0YWUyNjIyMjY0NTdmYjY5NDQyNDE5NmJmYjc1NCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY3NjU0MDQxNDY2NTk1OCw4NS4zMjU4NzYzODk5Mjk4N10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJ5ZWxsb3ciLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJ5ZWxsb3ciLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNDNhOGE5NTNjZGY5NDUzOWJhYzIwMWYyMzY5NGI2MGYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMjJiMjRlY2M2Mjk5NDljMGEyZTBiYzIwYzI3NDRiZDcgPSAkKCc8ZGl2IGlkPSJodG1sXzIyYjI0ZWNjNjI5OTQ5YzBhMmUwYmMyMGMyNzQ0YmQ3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CYW5nbGFtdWtoaSBUZW1wbGUgJmFtcDsgS3VtYmhlc2h3b3IgVGVtcGxlLCBLdW1iaGVzaHdvcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNDNhOGE5NTNjZGY5NDUzOWJhYzIwMWYyMzY5NGI2MGYuc2V0Q29udGVudChodG1sXzIyYjI0ZWNjNjI5OTQ5YzBhMmUwYmMyMGMyNzQ0YmQ3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzRkMjRhZTI2MjIyNjQ1N2ZiNjk0NDI0MTk2YmZiNzU0LmJpbmRQb3B1cChwb3B1cF80M2E4YTk1M2NkZjk0NTM5YmFjMjAxZjIzNjk0YjYwZik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8wY2EwNWVkMTY0Mjk0Y2FhOGQ3OTUyNWJkZjQyMjI4MSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY4MDU0NTg5MzQxOTQ2Myw4NS4zMDY5NTk1OTU4MjcxN10sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJ5ZWxsb3ciLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJ5ZWxsb3ciLAogICJmaWxsT3BhY2l0eSI6IDAuNywKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDUsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYWI5NzE5YWM2MzE3NDMzNjg1NDM0YWJhMTc0MjM2OTMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMDk5MGEyZThmNDI5NDI0MTlkOTk2MTk2NzgxMDE2MGYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYjA1MzZmYjBlOTFkNDllZjhmYzk2NmI5YWExMDliN2MgPSAkKCc8ZGl2IGlkPSJodG1sX2IwNTM2ZmIwZTkxZDQ5ZWY4ZmM5NjZiOWFhMTA5YjdjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5CYWdsYW11a2hpIFRlbXBsZSwgS3VtYmhlc2hvcjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMDk5MGEyZThmNDI5NDI0MTlkOTk2MTk2NzgxMDE2MGYuc2V0Q29udGVudChodG1sX2IwNTM2ZmIwZTkxZDQ5ZWY4ZmM5NjZiOWFhMTA5YjdjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyXzBjYTA1ZWQxNjQyOTRjYWE4ZDc5NTI1YmRmNDIyMjgxLmJpbmRQb3B1cChwb3B1cF8wOTkwYTJlOGY0Mjk0MjQxOWQ5OTYxOTY3ODEwMTYwZik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9hOWM2OThiOGJhNDE0MTk0YTZiOWNkMmU3MGJhZmM5ZCA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3Ljc0NDc3LDg1LjI5NzldLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAieWVsbG93IiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAieWVsbG93IiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzQyYmFkY2RkODkxZTQ3NDhiZDc5YTI4MjRiZTE4OTA1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzQ4NTI1MDJkMGZlZjRjMzc5MjVhNGFiN2U0YzE0NTY5ID0gJCgnPGRpdiBpZD0iaHRtbF80ODUyNTAyZDBmZWY0YzM3OTI1YTRhYjdlNGMxNDU2OSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+UHVhcmFubyBHdWh5ZXNod29yaSBUZW1wbGUsIFB1cmFubyBHdWh5ZXNod29yaTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNDJiYWRjZGQ4OTFlNDc0OGJkNzlhMjgyNGJlMTg5MDUuc2V0Q29udGVudChodG1sXzQ4NTI1MDJkMGZlZjRjMzc5MjVhNGFiN2U0YzE0NTY5KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2E5YzY5OGI4YmE0MTQxOTRhNmI5Y2QyZTcwYmFmYzlkLmJpbmRQb3B1cChwb3B1cF80MmJhZGNkZDg5MWU0NzQ4YmQ3OWEyODI0YmUxODkwNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl83YzkxN2EyMzVlMmU0NGU4YTA4N2E1YzI3NjljODYxMyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzI3LjY3NTMzODE5NzM3ODUyLDg1LjMyNjQ1NjU1MDY0NDZdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAieWVsbG93IiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAieWVsbG93IiwKICAiZmlsbE9wYWNpdHkiOiAwLjcsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiA1LAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiOTcxOWFjNjMxNzQzMzY4NTQzNGFiYTE3NDIzNjkzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzJmYzIyMjA4ODZmOTRjN2M4YTI0M2M5NGMyZDQ3N2Y1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJiOGZiZjQ3NWZmYTQxOGNiNzI2NWVjYjM2NmExOTAxID0gJCgnPGRpdiBpZD0iaHRtbF8yYjhmYmY0NzVmZmE0MThjYjcyNjVlY2IzNjZhMTkwMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+VW1hIE1haGVzaHdvciBUZW1wbGUsIEtpcnRpcHVyPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yZmMyMjIwODg2Zjk0YzdjOGEyNDNjOTRjMmQ0NzdmNS5zZXRDb250ZW50KGh0bWxfMmI4ZmJmNDc1ZmZhNDE4Y2I3MjY1ZWNiMzY2YTE5MDEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfN2M5MTdhMjM1ZTJlNDRlOGEwODdhNWMyNzY5Yzg2MTMuYmluZFBvcHVwKHBvcHVwXzJmYzIyMjA4ODZmOTRjN2M4YTI0M2M5NGMyZDQ3N2Y1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y0ZjYwN2QxNGUyYzRlZThhZTA0N2ZmYzllM2M0OTgzID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMjcuNjc1MzkwNDUxMjc2NDM1LDg1LjMyNDcxNjU2Nzk5MzE2XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogInllbGxvdyIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogInllbGxvdyIsCiAgImZpbGxPcGFjaXR5IjogMC43LAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAib3BhY2l0eSI6IDEuMCwKICAicmFkaXVzIjogNSwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjk3MTlhYzYzMTc0MzM2ODU0MzRhYmExNzQyMzY5Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9lNzc4NjU1NGUxOWQ0NTdkOWM0MTJlYzU1ZTg5NWNkYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82NDljODZkYjVmODc0MTRmOThiN2ZhOTIyNzdkNzMyNSA9ICQoJzxkaXYgaWQ9Imh0bWxfNjQ5Yzg2ZGI1Zjg3NDE0Zjk4YjdmYTkyMjc3ZDczMjUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPlNocmVlIFNhcmFzd2F0aSBUZW1wbGUsIEt3YWxha2h1PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lNzc4NjU1NGUxOWQ0NTdkOWM0MTJlYzU1ZTg5NWNkYS5zZXRDb250ZW50KGh0bWxfNjQ5Yzg2ZGI1Zjg3NDE0Zjk4YjdmYTkyMjc3ZDczMjUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZjRmNjA3ZDE0ZTJjNGVlOGFlMDQ3ZmZjOWUzYzQ5ODMuYmluZFBvcHVwKHBvcHVwX2U3Nzg2NTU0ZTE5ZDQ1N2Q5YzQxMmVjNTVlODk1Y2RhKTsKCiAgICAgICAgICAgIAogICAgICAgIAo8L3NjcmlwdD4=\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
],
"text/plain": [
"<folium.folium.Map at 0x7f3c1858e358>"
]
},
"execution_count": 236,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Generate map to visualize hotel neighbourhood including shopping stores and Cafeteria \n",
"tourist_map = folium.Map(location=[latitude, longitude], zoom_start=14)\n",
"\n",
"for lat, lng, name, categories, address in zip(df_hotels['lat'], df_hotels['lng'], \n",
" df_hotels['name'], df_hotels['categories'],\n",
" df_hotels['address']):\n",
" label = '{}, {}'.format(name, address)\n",
" label = folium.Popup(label, parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lng],\n",
" radius=5,\n",
" popup=label,\n",
" color='red',\n",
" fill=True,\n",
" fill_color='red',\n",
" fill_opacity=0.7,\n",
" parse_html=False).add_to(tourist_map) \n",
" \n",
"for lat, lng, name, categories, address in zip(df_Cafeteria['lat'], df_Cafeteria['lng'], \n",
" df_Cafeteria['name'], df_Cafeteria['categories'],\n",
" df_Cafeteria['address']):\n",
" label = '{}, {}'.format(name, address)\n",
" label = folium.Popup(label, parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lng],\n",
" radius=5,\n",
" popup=label,\n",
" color='blue',\n",
" fill=True,\n",
" fill_color='blue',\n",
" fill_opacity=0.7,\n",
" parse_html=False).add_to(tourist_map)\n",
"\n",
"for lat, lng, name, categories, address in zip(df_Shopping['lat'], df_Shopping['lng'], \n",
" df_Shopping['name'], df_Shopping['categories'],\n",
" df_Shopping['address']):\n",
" label = '{}, {}'.format(name, address)\n",
" label = folium.Popup(label, parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lng],\n",
" radius=5,\n",
" popup=label,\n",
" color='green',\n",
" fill=True,\n",
" fill_color='green',\n",
" fill_opacity=0.7,\n",
" parse_html=False).add_to(tourist_map) \n",
"\n",
"for lat, lng, name, categories, address in zip(df_temples['lat'], df_temples['lng'], \n",
" df_temples['name'], df_temples['categories'],\n",
" df_temples['address']):\n",
" label = '{}, {}'.format(name, address)\n",
" label = folium.Popup(label, parse_html=True)\n",
" folium.CircleMarker(\n",
" [lat, lng],\n",
" radius=5,\n",
" popup=label,\n",
" color='yellow',\n",
" fill=True,\n",
" fill_color='yellow',\n",
" fill_opacity=0.7,\n",
" parse_html=False).add_to(tourist_map) \n",
" \n",
"tourist_map"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analytical Output\n",
"#### The above map ashows that the best place for tourist to live is the place which has the fastest way to get Thamel area and Durbarmarg area because the cluster of places is highly dense in this area.\n",
"\n",
"##### (Look at the screenshot of map on github)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment