Skip to content

Instantly share code, notes, and snippets.

@lccambiaghi
Created December 11, 2018 21:38
Show Gist options
  • Save lccambiaghi/58e83770a163eac66f9c53e3cf8a7bef to your computer and use it in GitHub Desktop.
Save lccambiaghi/58e83770a163eac66f9c53e3cf8a7bef to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
{
"cells": [
{
"cell_type": "code",
"execution_count": 115,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n",
"/data/home/lca153/udf_deep_learning\n"
]
}
],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
"%cd '/home/lca153/udf_deep_learning/'"
]
},
{
"cell_type": "code",
"execution_count": 116,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"from datetime import timedelta\n",
"\n",
"from scripts.arx_preprocessor import Preprocessor\n",
"from scripts.arx import ARX\n",
"\n",
"from folium import Map, CircleMarker, PolyLine, FeatureGroup, LayerControl\n",
"from folium.plugins import FeatureGroupSubGroup"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"paths = {'bookings_df_path': 'data/focus_full.feather',\n",
" 'holidays_df_path': 'data/holidays_matrix.h5',\n",
" 'seasonal_df_path': 'data/seasonal_matrix.h5'}\n",
"pp_pars = paths.copy()\n",
"\n",
"ar_order = 4\n",
"n_dfus = 20\n",
"horizon = pp_pars['forecast_horizon'] = 4\n",
"\n",
"pp = Preprocessor(**pp_pars)\n",
"varx = ARX(pp, lags_order=ar_order)\n",
"x, Y = varx.get_X_Y()\n",
"top = list(pp.Y.mean().sort_values(ascending=False).index)[:n_dfus]\n",
"\n",
"test_weeks = 52\n",
"start_test = x.index[-1] - timedelta(weeks=test_weeks + 1)\n",
"Y_test = Y[start_test:]"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# start with coeff_df: id=DFU, coef=coef\n",
"enet_h4 = np.load('results/enet_ev/r95_h4.npy').item()\n",
"enet_h4 = pd.DataFrame(enet_h4)\n",
"top = list(enet_h4.transpose().index)\n",
"enet_h4_coefs = enet_h4.transpose()['coef']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Coefficients data"
]
},
{
"cell_type": "code",
"execution_count": 178,
"metadata": {},
"outputs": [],
"source": [
"i = 6\n",
"dfu_id = top[i]"
]
},
{
"cell_type": "code",
"execution_count": 179,
"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>coef</th>\n",
" <th>abs_coef</th>\n",
" <th>lopfi</th>\n",
" <th>dipla</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>CNYAT_GBFXS_PP_DRY _40_-1</th>\n",
" <td>3.667393</td>\n",
" <td>3.667393</td>\n",
" <td>CNYAT</td>\n",
" <td>GBFXS</td>\n",
" </tr>\n",
" <tr>\n",
" <th>CNYAT_NLROT_PP_DRY _40_-1</th>\n",
" <td>0.610678</td>\n",
" <td>0.610678</td>\n",
" <td>CNYAT</td>\n",
" <td>NLROT</td>\n",
" </tr>\n",
" <tr>\n",
" <th>CNYAT_GBFXS_PP_DRY _40_-3</th>\n",
" <td>0.343879</td>\n",
" <td>0.343879</td>\n",
" <td>CNYAT</td>\n",
" <td>GBFXS</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" coef abs_coef lopfi dipla\n",
"CNYAT_GBFXS_PP_DRY _40_-1 3.667393 3.667393 CNYAT GBFXS\n",
"CNYAT_NLROT_PP_DRY _40_-1 0.610678 0.610678 CNYAT NLROT\n",
"CNYAT_GBFXS_PP_DRY _40_-3 0.343879 0.343879 CNYAT GBFXS"
]
},
"execution_count": 179,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"en_coefs = enet_h4_coefs[i]\n",
"en_selected = np.nonzero(en_coefs)[0]\n",
"en_coefs_df = pd.DataFrame(data=en_coefs[en_selected],index=x.columns[en_selected], columns=['coef'])\n",
"en_coefs_df['abs_coef'] = np.abs(en_coefs_df['coef'])\n",
"en_coefs_df = en_coefs_df.sort_values(by='abs_coef', ascending=False).head(3)\n",
"\n",
"# From the ID, extract port of origin and port of destination\n",
"en_coefs_df['lopfi'] = list(map(lambda s: s.split('_')[0], en_coefs_df.index))\n",
"en_coefs_df['dipla'] = list(map(lambda s: s.split('_')[1], en_coefs_df.index))\n",
"en_coefs_df"
]
},
{
"cell_type": "code",
"execution_count": 180,
"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>lon</th>\n",
" <th>lat</th>\n",
" </tr>\n",
" <tr>\n",
" <th>port</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>AEAMN</th>\n",
" <td>55.421800</td>\n",
" <td>25.390600</td>\n",
" </tr>\n",
" <tr>\n",
" <th>AEAUH</th>\n",
" <td>54.359300</td>\n",
" <td>24.453100</td>\n",
" </tr>\n",
" <tr>\n",
" <th>AEDXB</th>\n",
" <td>55.399333</td>\n",
" <td>25.166666</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" lon lat\n",
"port \n",
"AEAMN 55.421800 25.390600\n",
"AEAUH 54.359300 24.453100\n",
"AEDXB 55.399333 25.166666"
]
},
"execution_count": 180,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# join with ports and get lat and lon\n",
"ports = pd.read_csv('data/ports.csv', header=None)\n",
"ports.columns = ['port', 'lon', 'lat']\n",
"ports.set_index('port', inplace=True); ports.head(3)"
]
},
{
"cell_type": "code",
"execution_count": 181,
"metadata": {},
"outputs": [],
"source": [
"en_coefs_df = en_coefs_df.join(ports, on='lopfi')\n",
"en_coefs_df.rename(columns={\"lon\": \"lopfi_lon\", \"lat\": \"lopfi_lat\"}, inplace=True)\n",
"en_coefs_df = en_coefs_df.join(ports, on='dipla')\n",
"en_coefs_df.rename(columns={\"lon\": \"dipla_lon\", \"lat\": \"dipla_lat\"}, inplace=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Map"
]
},
{
"cell_type": "code",
"execution_count": 182,
"metadata": {},
"outputs": [],
"source": [
"dfu_lopfi = dfu_id.split('_')[0]\n",
"dfu_dipla = dfu_id.split('_')[1]\n",
"\n",
"dfu_lopfi_lat = ports.loc[dfu_lopfi]['lat']\n",
"dfu_lopfi_lon = ports.loc[dfu_lopfi]['lon']\n",
"\n",
"dfu_dipla_lat = ports.loc[dfu_dipla]['lat']\n",
"dfu_dipla_lon = ports.loc[dfu_dipla]['lon']"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = folium.Map(location=[30, 0],\n",
" zoom_start=2, tiles=\"CartoDB dark_matter\")\n",
"\n",
"lopfi = folium.CircleMarker(location=[dfu_lopfi_lat, dfu_lopfi_lon],\n",
" popup=f'LOPFI:{dfu_lopfi}', color='red', fill=True).add_to(m)\n",
"dipla = folium.CircleMarker(location=[dfu_dipla_lat, dfu_dipla_lon], \n",
" popup=f'DIPLA:{dfu_dipla}', color='red', fill=True).add_to(m)\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Add coefficients edges"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"colors = ['blue', 'lightblue', 'gray']\n",
"\n",
"for coef_id, row in en_coefs_df.iterrows():\n",
" i = en_coefs_df.index.get_loc(coef_id)\n",
" color = colors[i]\n",
" \n",
" lopfi_lat, lopfi_lon = row['lopfi_lat'], row['lopfi_lon']\n",
" dipla_lat, dipla_lon = row['dipla_lat'], row['dipla_lon']\n",
" \n",
" if row.lopfi != dfu_lopfi:\n",
" lopfi = folium.CircleMarker(location=[lopfi_lat, lopfi_lon],\n",
" popup=f'LOPFI:{row.lopfi}', color=color, fill=True).add_to(m)\n",
" if row.dipla != dfu_dipla:\n",
" dipla = folium.CircleMarker(location=[dipla_lat, dipla_lon],\n",
" popup=f'LOPFI:{row.dipla}', color=color, fill=True).add_to(m)\n",
" \n",
" coef_line = PolyLine([[lopfi_lat, lopfi_lon],[dipla_lat, dipla_lon]], \n",
" popup=f'id:{coef_id}, coef:{row.coef}',\n",
" weight=row['coef'], color = color).add_to(m)\n",
"\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Coefficients group"
]
},
{
"cell_type": "code",
"execution_count": 185,
"metadata": {},
"outputs": [],
"source": [
"m = Map(location=[30, 0],\n",
" zoom_start=2, tiles=\"CartoDB dark_matter\")\n",
"\n",
"lopfi = CircleMarker(location=[dfu_lopfi_lat, dfu_lopfi_lon],\n",
" popup=f'LOPFI:{dfu_lopfi}', color='red', fill=True).add_to(m)\n",
"dipla = CircleMarker(location=[dfu_dipla_lat, dfu_dipla_lon], \n",
" popup=f'DIPLA:{dfu_dipla}', color='red', fill=True).add_to(m)\n",
"\n",
"enet_group = FeatureGroup(name='ElasticNet coefficients')\n",
"m.add_child(enet_group)\n",
"for coef_id, row in en_coefs_df.iterrows():\n",
" subgroup = FeatureGroupSubGroup(enet_group, coef_id)\n",
" m.add_child(subgroup)\n",
" \n",
" i = en_coefs_df.index.get_loc(coef_id)\n",
" color = colors[i]\n",
" \n",
" lopfi_lat, lopfi_lon = row['lopfi_lat'], row['lopfi_lon']\n",
" dipla_lat, dipla_lon = row['dipla_lat'], row['dipla_lon']\n",
" \n",
" if row.lopfi != dfu_lopfi:\n",
" lopfi = folium.CircleMarker(location=[lopfi_lat, lopfi_lon],\n",
" popup=f'LOPFI:{row.lopfi}', color=color, fill=True).add_to(subgroup)\n",
" if row.dipla != dfu_dipla:\n",
" dipla = folium.CircleMarker(location=[dipla_lat, dipla_lon],\n",
" popup=f'LOPFI:{row.dipla}', color=color, fill=True).add_to(subgroup)\n",
" \n",
" coef_line = PolyLine([[lopfi_lat, lopfi_lon],[dipla_lat, dipla_lon]],\n",
" popup=f'id:{coef_id}, coef:{row.coef}',\n",
" weight=row['coef'], color = color).add_to(subgroup)"
]
},
{
"cell_type": "code",
"execution_count": 186,
"metadata": {},
"outputs": [],
"source": [
"# start with coeff_df: id=DFU, coef=coef\n",
"sgl_h4 = np.load('results/glasso_ev/r95_h4.npy').item()\n",
"sgl_h4 = pd.DataFrame(sgl_h4)\n",
"top = list(sgl_h4.transpose().index)\n",
"sgl_h4_coefs = sgl_h4.transpose()['coef']\n",
"\n",
"sgl_coefs = sgl_h4_coefs[i]\n",
"sgl_coefs = sgl_coefs[:-1]\n",
"sgl_selected = np.nonzero(sgl_coefs)[0]\n",
"sgl_coefs_df = pd.DataFrame(data=sgl_coefs[sgl_selected],index=x.columns[sgl_selected], columns=['coef'])\n",
"sgl_coefs_df['abs_coef'] = np.abs(sgl_coefs_df['coef'])\n",
"sgl_coefs_df = sgl_coefs_df.sort_values(by='abs_coef', ascending=False).head(3)\n",
"\n",
"# From the ID, extract port of origin and port of destination\n",
"sgl_coefs_df['lopfi'] = list(map(lambda s: s.split('_')[0], sgl_coefs_df.index))\n",
"sgl_coefs_df['dipla'] = list(map(lambda s: s.split('_')[1], sgl_coefs_df.index))\n",
"\n",
"sgl_coefs_df = sgl_coefs_df.join(ports, on='lopfi')\n",
"sgl_coefs_df.rename(columns={\"lon\": \"lopfi_lon\", \"lat\": \"lopfi_lat\"}, inplace=True)\n",
"sgl_coefs_df = sgl_coefs_df.join(ports, on='dipla')\n",
"sgl_coefs_df.rename(columns={\"lon\": \"dipla_lon\", \"lat\": \"dipla_lat\"}, inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": 187,
"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+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVM9ZmFsc2U7IExfTk9fVE9VQ0g9ZmFsc2U7IExfRElTQUJMRV8zRD1mYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4zLjQvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4zLjQvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdjZG4uZ2l0aGFjay5jb20vcHl0aG9uLXZpc3VhbGl6YXRpb24vZm9saXVtL21hc3Rlci9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUuY3NzIi8+CiAgICA8c3R5bGU+aHRtbCwgYm9keSB7d2lkdGg6IDEwMCU7aGVpZ2h0OiAxMDAlO21hcmdpbjogMDtwYWRkaW5nOiAwO308L3N0eWxlPgogICAgPHN0eWxlPiNtYXAge3Bvc2l0aW9uOmFic29sdXRlO3RvcDowO2JvdHRvbTowO3JpZ2h0OjA7bGVmdDowO308L3N0eWxlPgogICAgCiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLAogICAgICAgIGluaXRpYWwtc2NhbGU9MS4wLCBtYXhpbXVtLXNjYWxlPTEuMCwgdXNlci1zY2FsYWJsZT1ubyIgLz4KICAgIDxzdHlsZT4jbWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4IHsKICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgICAgICAgd2lkdGg6IDEwMC4wJTsKICAgICAgICBoZWlnaHQ6IDEwMC4wJTsKICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgIHRvcDogMC4wJTsKICAgICAgICB9CiAgICA8L3N0eWxlPgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vdW5wa2cuY29tL2xlYWZsZXQuZmVhdHVyZWdyb3VwLnN1Ymdyb3VwQDEuMC4yL2Rpc3QvbGVhZmxldC5mZWF0dXJlZ3JvdXAuc3ViZ3JvdXAuanMiPjwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgPGRpdiBjbGFzcz0iZm9saXVtLW1hcCIgaWQ9Im1hcF9hYjA0NmNhMmM0MDg0N2MyYTcxZTg3YmUxMDBhYTA1OCIgPjwvZGl2Pgo8L2JvZHk+CjxzY3JpcHQ+ICAgIAogICAgCiAgICAKICAgICAgICB2YXIgYm91bmRzID0gbnVsbDsKICAgIAoKICAgIHZhciBtYXBfYWIwNDZjYTJjNDA4NDdjMmE3MWU4N2JlMTAwYWEwNTggPSBMLm1hcCgKICAgICAgICAnbWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4JywgewogICAgICAgIGNlbnRlcjogWzMwLCAwXSwKICAgICAgICB6b29tOiAyLAogICAgICAgIG1heEJvdW5kczogYm91bmRzLAogICAgICAgIGxheWVyczogW10sCiAgICAgICAgd29ybGRDb3B5SnVtcDogZmFsc2UsCiAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NywKICAgICAgICB6b29tQ29udHJvbDogdHJ1ZSwKICAgICAgICB9KTsKCiAgICAKICAgIAogICAgdmFyIHRpbGVfbGF5ZXJfODBlNTdlY2FmM2Y0NGE1OWFiNzgzZGU2NDA2NDA0YTMgPSBMLnRpbGVMYXllcigKICAgICAgICAnaHR0cHM6Ly9jYXJ0b2RiLWJhc2VtYXBzLXtzfS5nbG9iYWwuc3NsLmZhc3RseS5uZXQvZGFya19hbGwve3p9L3t4fS97eX0ucG5nJywKICAgICAgICB7CiAgICAgICAgImF0dHJpYnV0aW9uIjogbnVsbCwKICAgICAgICAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsCiAgICAgICAgIm1heE5hdGl2ZVpvb20iOiAxOCwKICAgICAgICAibWF4Wm9vbSI6IDE4LAogICAgICAgICJtaW5ab29tIjogMCwKICAgICAgICAibm9XcmFwIjogZmFsc2UsCiAgICAgICAgIm9wYWNpdHkiOiAxLAogICAgICAgICJzdWJkb21haW5zIjogImFiYyIsCiAgICAgICAgInRtcyI6IGZhbHNlCn0pLmFkZFRvKG1hcF9hYjA0NmNhMmM0MDg0N2MyYTcxZTg3YmUxMDBhYTA1OCk7CiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZDNjMmQ0YWVhODVlNGQ2NjlkYTkwYmNhNDNmNmFiNGEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyMi41ODMzMywgMTE0LjI2NjY3MV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJyZWQiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJyZWQiLAogICJmaWxsT3BhY2l0eSI6IDAuMiwKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDEwLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYWIwNDZjYTJjNDA4NDdjMmE3MWU4N2JlMTAwYWEwNTgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMDJiNTMxMzRhMjc4NGMxYzg1NmU2OTcyNGY5ZmM0ZWQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82N2Y0MTQ0MzliMGI0OGVlOWY2MzU4MDIzYWEzMjMzOSA9ICQoYDxkaXYgaWQ9Imh0bWxfNjdmNDE0NDM5YjBiNDhlZTlmNjM1ODAyM2FhMzIzMzkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOkNOWUFUPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8wMmI1MzEzNGEyNzg0YzFjODU2ZTY5NzI0ZjlmYzRlZC5zZXRDb250ZW50KGh0bWxfNjdmNDE0NDM5YjBiNDhlZTlmNjM1ODAyM2FhMzIzMzkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZDNjMmQ0YWVhODVlNGQ2NjlkYTkwYmNhNDNmNmFiNGEuYmluZFBvcHVwKHBvcHVwXzAyYjUzMTM0YTI3ODRjMWM4NTZlNjk3MjRmOWZjNGVkKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9kMjJkMGJhNzFkNjE0MjhhYTA4MTIzZTRiNTFjOTM1OSA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzUxLjkxNjY3LCA0LjVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAicmVkIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiB0cnVlLAogICJmaWxsQ29sb3IiOiAicmVkIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzY3NDRlYjhiMjVmNTQ0NzNhOGYyZTFiZjIzZWI3M2YwID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnCiAgICAgICAgICAgIAogICAgICAgICAgICB9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfM2I3ZThjZWU2MGVjNDhiOGI4NmUzYWE3ZWNiZmQ4N2QgPSAkKGA8ZGl2IGlkPSJodG1sXzNiN2U4Y2VlNjBlYzQ4YjhiODZlM2FhN2VjYmZkODdkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5ESVBMQTpOTFJPVDwvZGl2PmApWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjc0NGViOGIyNWY1NDQ3M2E4ZjJlMWJmMjNlYjczZjAuc2V0Q29udGVudChodG1sXzNiN2U4Y2VlNjBlYzQ4YjhiODZlM2FhN2VjYmZkODdkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBjaXJjbGVfbWFya2VyX2QyMmQwYmE3MWQ2MTQyOGFhMDgxMjNlNGI1MWM5MzU5LmJpbmRQb3B1cChwb3B1cF82NzQ0ZWI4YjI1ZjU0NDczYThmMmUxYmYyM2ViNzNmMCkKICAgICAgICAgICAgOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGZlYXR1cmVfZ3JvdXBfZmRkMzY2ZmIxYjk3NDAyMDk1ZjI3YzI4MWVlMTI1NmIgPSBMLmZlYXR1cmVHcm91cCgKICAgICAgICAgICAgICAgICkuYWRkVG8obWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4KTsKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYmE0MDAwZDc1OWM3NGJlM2E4ZjNhNDAwODQ4N2IzODAgPSBMLmZlYXR1cmVHcm91cC5zdWJHcm91cChmZWF0dXJlX2dyb3VwX2ZkZDM2NmZiMWI5NzQwMjA5NWYyN2MyODFlZTEyNTZiKTsKICAgICAgICAgICAgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYmE0MDAwZDc1OWM3NGJlM2E4ZjNhNDAwODQ4N2IzODAuYWRkVG8obWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfOTVlM2IyNmFlMDM0NGZjMDhjYWI0Y2ZmNDMwOTdhMjUgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs1MS45NTMxLCAxLjM1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYmE0MDAwZDc1OWM3NGJlM2E4ZjNhNDAwODQ4N2IzODApOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfN2Y3YjgxMmUzY2NhNDAxMmJmNzFhMDVmOWQ3NzExODAgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iNjI5MWQzMWVhYmE0NWY1OWQ4ZmUwNGRhMmEwZjNiYyA9ICQoYDxkaXYgaWQ9Imh0bWxfYjYyOTFkMzFlYWJhNDVmNTlkOGZlMDRkYTJhMGYzYmMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOkdCRlhTPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83ZjdiODEyZTNjY2E0MDEyYmY3MWEwNWY5ZDc3MTE4MC5zZXRDb250ZW50KGh0bWxfYjYyOTFkMzFlYWJhNDVmNTlkOGZlMDRkYTJhMGYzYmMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfOTVlM2IyNmFlMDM0NGZjMDhjYWI0Y2ZmNDMwOTdhMjUuYmluZFBvcHVwKHBvcHVwXzdmN2I4MTJlM2NjYTQwMTJiZjcxYTA1ZjlkNzcxMTgwKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICAgICAgdmFyIHBvbHlfbGluZV9mYzI3MGFmYmQ3OWU0NGJmYWJhNzFlYTA5YjQyYjc3YiA9IEwucG9seWxpbmUoCiAgICAgICAgICAgICAgICAgICAgW1syMi41ODMzMywgMTE0LjI2NjY3MV0sIFs1MS45NTMxLCAxLjM1XV0sCiAgICAgICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiYmx1ZSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogZmFsc2UsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJub0NsaXAiOiBmYWxzZSwKICAib3BhY2l0eSI6IDEuMCwKICAic21vb3RoRmFjdG9yIjogMS4wLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzLjY2NzM5MzE5NjIyMDYwMjYKfQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYmE0MDAwZDc1OWM3NGJlM2E4ZjNhNDAwODQ4N2IzODApOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGYzNjJiYzZhMWFmNGNiMTk2ZmUyNTliYTA5Yzg0MmYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81N2MxYzc2NzEzOWU0NzdlOTgxZjI4MThkN2RhNjg2MCA9ICQoYDxkaXYgaWQ9Imh0bWxfNTdjMWM3NjcxMzllNDc3ZTk4MWYyODE4ZDdkYTY4NjAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPmlkOkNOWUFUX0dCRlhTX1BQX0RSWSBfNDBfLTEsIGNvZWY6My42NjczOTMxOTYyMjA2MDI2PC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ZjM2MmJjNmExYWY0Y2IxOTZmZTI1OWJhMDljODQyZi5zZXRDb250ZW50KGh0bWxfNTdjMWM3NjcxMzllNDc3ZTk4MWYyODE4ZDdkYTY4NjApOwogICAgICAgICAgICAKCiAgICAgICAgICAgIHBvbHlfbGluZV9mYzI3MGFmYmQ3OWU0NGJmYWJhNzFlYTA5YjQyYjc3Yi5iaW5kUG9wdXAocG9wdXBfOGYzNjJiYzZhMWFmNGNiMTk2ZmUyNTliYTA5Yzg0MmYpCiAgICAgICAgICAgIDsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xOTUxZWNjOTU2Yjk0YjY4OTQwYWQ1OTM4ZDExYmY4YiA9IEwuZmVhdHVyZUdyb3VwLnN1Ykdyb3VwKGZlYXR1cmVfZ3JvdXBfZmRkMzY2ZmIxYjk3NDAyMDk1ZjI3YzI4MWVlMTI1NmIpOwogICAgICAgICAgICBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xOTUxZWNjOTU2Yjk0YjY4OTQwYWQ1OTM4ZDExYmY4Yi5hZGRUbyhtYXBfYWIwNDZjYTJjNDA4NDdjMmE3MWU4N2JlMTAwYWEwNTgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICAgICAgdmFyIHBvbHlfbGluZV85MmNlZGYyMGUzYzE0OGEwYjIzZDhmMDJlZWJmODk3OCA9IEwucG9seWxpbmUoCiAgICAgICAgICAgICAgICAgICAgW1syMi41ODMzMywgMTE0LjI2NjY3MV0sIFs1MS45MTY2NywgNC41XV0sCiAgICAgICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAibGlnaHRibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiBmYWxzZSwKICAiZmlsbENvbG9yIjogImxpZ2h0Ymx1ZSIsCiAgImZpbGxPcGFjaXR5IjogMC4yLAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAibm9DbGlwIjogZmFsc2UsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInNtb290aEZhY3RvciI6IDEuMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMC42MTA2NzgzMjAzMjMxNjM3Cn0KICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgLmFkZFRvKGZlYXR1cmVfZ3JvdXBfc3ViX2dyb3VwXzE5NTFlY2M5NTZiOTRiNjg5NDBhZDU5MzhkMTFiZjhiKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzY5MTU5ZTJmYzVlYzQyZjU4OWQxYmJiNDA4ZGI2NmQxID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnCiAgICAgICAgICAgIAogICAgICAgICAgICB9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYjM0NzY5NjhlZTMxNDA5YWFhOTAxM2ZjOTQ1MmMwNzMgPSAkKGA8ZGl2IGlkPSJodG1sX2IzNDc2OTY4ZWUzMTQwOWFhYTkwMTNmYzk0NTJjMDczIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij5pZDpDTllBVF9OTFJPVF9QUF9EUlkgXzQwXy0xLCBjb2VmOjAuNjEwNjc4MzIwMzIzMTYzNzwvZGl2PmApWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNjkxNTllMmZjNWVjNDJmNTg5ZDFiYmI0MDhkYjY2ZDEuc2V0Q29udGVudChodG1sX2IzNDc2OTY4ZWUzMTQwOWFhYTkwMTNmYzk0NTJjMDczKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBwb2x5X2xpbmVfOTJjZWRmMjBlM2MxNDhhMGIyM2Q4ZjAyZWViZjg5NzguYmluZFBvcHVwKHBvcHVwXzY5MTU5ZTJmYzVlYzQyZjU4OWQxYmJiNDA4ZGI2NmQxKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfZjkzMWI1NDViYWMyNGQxMmEyZTRjMmViMTRiZWQ3MjQgPSBMLmZlYXR1cmVHcm91cC5zdWJHcm91cChmZWF0dXJlX2dyb3VwX2ZkZDM2NmZiMWI5NzQwMjA5NWYyN2MyODFlZTEyNTZiKTsKICAgICAgICAgICAgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfZjkzMWI1NDViYWMyNGQxMmEyZTRjMmViMTRiZWQ3MjQuYWRkVG8obWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfZGY0NGYxZWQ1MTFiNGE4NWJiOTgxNzkxMjhiMDc5MTEgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFs1MS45NTMxLCAxLjM1XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyYXkiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJncmF5IiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfZjkzMWI1NDViYWMyNGQxMmEyZTRjMmViMTRiZWQ3MjQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZTNhN2MzYzc4MWQ0NGU0MWJkMTNiNzNkMDUxYzBkYWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9lNWRhYTBkZjQ0ODE0YTRhYmRhMTA1ZGE1MDBlZWE0NyA9ICQoYDxkaXYgaWQ9Imh0bWxfZTVkYWEwZGY0NDgxNGE0YWJkYTEwNWRhNTAwZWVhNDciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOkdCRlhTPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lM2E3YzNjNzgxZDQ0ZTQxYmQxM2I3M2QwNTFjMGRhZS5zZXRDb250ZW50KGh0bWxfZTVkYWEwZGY0NDgxNGE0YWJkYTEwNWRhNTAwZWVhNDcpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfZGY0NGYxZWQ1MTFiNGE4NWJiOTgxNzkxMjhiMDc5MTEuYmluZFBvcHVwKHBvcHVwX2UzYTdjM2M3ODFkNDRlNDFiZDEzYjczZDA1MWMwZGFlKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICAgICAgdmFyIHBvbHlfbGluZV9iYTJmOTM5Mzk0M2M0NDJiYThjYjk5OTY4ZTk1N2ZjNSA9IEwucG9seWxpbmUoCiAgICAgICAgICAgICAgICAgICAgW1syMi41ODMzMywgMTE0LjI2NjY3MV0sIFs1MS45NTMxLCAxLjM1XV0sCiAgICAgICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiZ3JheSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogZmFsc2UsCiAgImZpbGxDb2xvciI6ICJncmF5IiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJub0NsaXAiOiBmYWxzZSwKICAib3BhY2l0eSI6IDEuMCwKICAic21vb3RoRmFjdG9yIjogMS4wLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAwLjM0Mzg3OTM4Mzk1NDk5NzMKfQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfZjkzMWI1NDViYWMyNGQxMmEyZTRjMmViMTRiZWQ3MjQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZGVhMDM5ZjQxOTAxNDIwYWExNDE2YzU2MTA0OWE2MDIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80NjRiYThlODcwNWI0YTIzODMzZjRiZWI0NzFlMTdkOSA9ICQoYDxkaXYgaWQ9Imh0bWxfNDY0YmE4ZTg3MDViNGEyMzgzM2Y0YmViNDcxZTE3ZDkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPmlkOkNOWUFUX0dCRlhTX1BQX0RSWSBfNDBfLTMsIGNvZWY6MC4zNDM4NzkzODM5NTQ5OTczPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kZWEwMzlmNDE5MDE0MjBhYTE0MTZjNTYxMDQ5YTYwMi5zZXRDb250ZW50KGh0bWxfNDY0YmE4ZTg3MDViNGEyMzgzM2Y0YmViNDcxZTE3ZDkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIHBvbHlfbGluZV9iYTJmOTM5Mzk0M2M0NDJiYThjYjk5OTY4ZTk1N2ZjNS5iaW5kUG9wdXAocG9wdXBfZGVhMDM5ZjQxOTAxNDIwYWExNDE2YzU2MTA0OWE2MDIpCiAgICAgICAgICAgIDsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBmZWF0dXJlX2dyb3VwXzI2ZDcxMGViMGQyMDQxNGNiY2UyMGJkNjY1N2VjNTUyID0gTC5mZWF0dXJlR3JvdXAoCiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9hYjA0NmNhMmM0MDg0N2MyYTcxZTg3YmUxMDBhYTA1OCk7CiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGZlYXR1cmVfZ3JvdXBfc3ViX2dyb3VwXzhmYmJmYjBjZTM5YTRjMjQ4ZTFmNjcxOTdlMTI0NTRiID0gTC5mZWF0dXJlR3JvdXAuc3ViR3JvdXAoZmVhdHVyZV9ncm91cF8yNmQ3MTBlYjBkMjA0MTRjYmNlMjBiZDY2NTdlYzU1Mik7CiAgICAgICAgICAgIGZlYXR1cmVfZ3JvdXBfc3ViX2dyb3VwXzhmYmJmYjBjZTM5YTRjMjQ4ZTFmNjcxOTdlMTI0NTRiLmFkZFRvKG1hcF9hYjA0NmNhMmM0MDg0N2MyYTcxZTg3YmUxMDBhYTA1OCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyXzMzYjFlODljMjI0MTQ4YTk4OTkzY2Q5YWVlZmY4OTU0ID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbMzQuMDUyMiwgLTExOC4yNDI4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfOGZiYmZiMGNlMzlhNGMyNDhlMWY2NzE5N2UxMjQ1NGIpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfODFiY2U2OWRkOGFmNDNiN2EyMjYxYTUxYzlkOTMxMjIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zODllMzhkMmFjMDQ0ZWZmYWNhMTE5NWZjOWQzZTM2ZiA9ICQoYDxkaXYgaWQ9Imh0bWxfMzg5ZTM4ZDJhYzA0NGVmZmFjYTExOTVmYzlkM2UzNmYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOlVTTFNBPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84MWJjZTY5ZGQ4YWY0M2I3YTIyNjFhNTFjOWQ5MzEyMi5zZXRDb250ZW50KGh0bWxfMzg5ZTM4ZDJhYzA0NGVmZmFjYTExOTVmYzlkM2UzNmYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMzNiMWU4OWMyMjQxNDhhOTg5OTNjZDlhZWVmZjg5NTQuYmluZFBvcHVwKHBvcHVwXzgxYmNlNjlkZDhhZjQzYjdhMjI2MWE1MWM5ZDkzMTIyKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl9jMjBjN2QxYzJjOWI0MmJkYjNkMWM1Yjk1YzAwMTY0YyA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzIyLjc2LCAxMTMuNTcyXSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfOGZiYmZiMGNlMzlhNGMyNDhlMWY2NzE5N2UxMjQ1NGIpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMmI1ZmE0ZjhmMjU4NGYyMmEwNDc4Njc4YzJjMTJlNmIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85NjdiMjcyZTVmYjA0YTU0YTk3M2Y2YTg4MTc1ZDYzYyA9ICQoYDxkaXYgaWQ9Imh0bWxfOTY3YjI3MmU1ZmIwNGE1NGE5NzNmNmE4ODE3NWQ2M2MiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOkNOTkFOPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yYjVmYTRmOGYyNTg0ZjIyYTA0Nzg2NzhjMmMxMmU2Yi5zZXRDb250ZW50KGh0bWxfOTY3YjI3MmU1ZmIwNGE1NGE5NzNmNmE4ODE3NWQ2M2MpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfYzIwYzdkMWMyYzliNDJiZGIzZDFjNWI5NWMwMDE2NGMuYmluZFBvcHVwKHBvcHVwXzJiNWZhNGY4ZjI1ODRmMjJhMDQ3ODY3OGMyYzEyZTZiKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICAgICAgdmFyIHBvbHlfbGluZV82MmUyZDg2ZDc1ZmY0ZDdlOTQyOGU4ZmRiZDE2MWE3MiA9IEwucG9seWxpbmUoCiAgICAgICAgICAgICAgICAgICAgW1szNC4wNTIyLCAtMTE4LjI0MjhdLCBbMjIuNzYsIDExMy41NzJdXSwKICAgICAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJibHVlIiwKICAiZGFzaEFycmF5IjogbnVsbCwKICAiZGFzaE9mZnNldCI6IG51bGwsCiAgImZpbGwiOiBmYWxzZSwKICAiZmlsbENvbG9yIjogImJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuMiwKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm5vQ2xpcCI6IGZhbHNlLAogICJvcGFjaXR5IjogMS4wLAogICJzbW9vdGhGYWN0b3IiOiAxLjAsCiAgInN0cm9rZSI6IHRydWUsCiAgIndlaWdodCI6IDMuMTUxNzMyNDM1MjYxNTU2Ngp9CiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIC5hZGRUbyhmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF84ZmJiZmIwY2UzOWE0YzI0OGUxZjY3MTk3ZTEyNDU0Yik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81NjM0M2E5ZWZjMDk0OTZmYTgzZWQ2Zjk2YjJhNWQyZiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJwogICAgICAgICAgICAKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzdjZWRjZDVjYTUwNzRmYjQ5MjQ0M2Y1OWNmN2NmYmUzID0gJChgPGRpdiBpZD0iaHRtbF83Y2VkY2Q1Y2E1MDc0ZmI0OTI0NDNmNTljZjdjZmJlMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+aWQ6VVNMU0FfQ05OQU5fSVBfRFJZIF80MF8tMiwgY29lZjozLjE1MTczMjQzNTI2MTU1NjY8L2Rpdj5gKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzU2MzQzYTllZmMwOTQ5NmZhODNlZDZmOTZiMmE1ZDJmLnNldENvbnRlbnQoaHRtbF83Y2VkY2Q1Y2E1MDc0ZmI0OTI0NDNmNTljZjdjZmJlMyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgcG9seV9saW5lXzYyZTJkODZkNzVmZjRkN2U5NDI4ZThmZGJkMTYxYTcyLmJpbmRQb3B1cChwb3B1cF81NjM0M2E5ZWZjMDk0OTZmYTgzZWQ2Zjk2YjJhNWQyZikKICAgICAgICAgICAgOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGZlYXR1cmVfZ3JvdXBfc3ViX2dyb3VwXzE3NzY3MTI5OWMwMTRjMTVhYThlMTY0Nzg0Y2JmZWViID0gTC5mZWF0dXJlR3JvdXAuc3ViR3JvdXAoZmVhdHVyZV9ncm91cF8yNmQ3MTBlYjBkMjA0MTRjYmNlMjBiZDY2NTdlYzU1Mik7CiAgICAgICAgICAgIGZlYXR1cmVfZ3JvdXBfc3ViX2dyb3VwXzE3NzY3MTI5OWMwMTRjMTVhYThlMTY0Nzg0Y2JmZWViLmFkZFRvKG1hcF9hYjA0NmNhMmM0MDg0N2MyYTcxZTg3YmUxMDBhYTA1OCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBjaXJjbGVfbWFya2VyX2Y3MDdkMDZjMGViOTQwM2E5MmZmZmIzNjNjZDk5N2MyID0gTC5jaXJjbGVNYXJrZXIoCiAgICAgICAgICAgICAgICBbNTEuOTUzMSwgMS4zNV0sCiAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJsaWdodGJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJsaWdodGJsdWUiLAogICJmaWxsT3BhY2l0eSI6IDAuMiwKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDEwLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xNzc2NzEyOTljMDE0YzE1YWE4ZTE2NDc4NGNiZmVlYik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zNjA2NWY5OTU4ZTA0MGY2YjVjZThjYmE4YjdkZWI0MCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJwogICAgICAgICAgICAKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzI2M2M4OGZmN2M0ODRjMDA4ZWEyYmNmYjUxZjkxNzA1ID0gJChgPGRpdiBpZD0iaHRtbF8yNjNjODhmZjdjNDg0YzAwOGVhMmJjZmI1MWY5MTcwNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TE9QRkk6R0JGWFM8L2Rpdj5gKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzM2MDY1Zjk5NThlMDQwZjZiNWNlOGNiYThiN2RlYjQwLnNldENvbnRlbnQoaHRtbF8yNjNjODhmZjdjNDg0YzAwOGVhMmJjZmI1MWY5MTcwNSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl9mNzA3ZDA2YzBlYjk0MDNhOTJmZmZiMzYzY2Q5OTdjMi5iaW5kUG9wdXAocG9wdXBfMzYwNjVmOTk1OGUwNDBmNmI1Y2U4Y2JhOGI3ZGViNDApCiAgICAgICAgICAgIDsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgICAgICB2YXIgcG9seV9saW5lX2ZhNGMxNTBmNGNiMDQ5OGViZTAwZTFmOTkyMWJlYjJlID0gTC5wb2x5bGluZSgKICAgICAgICAgICAgICAgICAgICBbWzIyLjU4MzMzLCAxMTQuMjY2NjcxXSwgWzUxLjk1MzEsIDEuMzVdXSwKICAgICAgICAgICAgICAgICAgICB7CiAgImJ1YmJsaW5nTW91c2VFdmVudHMiOiB0cnVlLAogICJjb2xvciI6ICJsaWdodGJsdWUiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IGZhbHNlLAogICJmaWxsQ29sb3IiOiAibGlnaHRibHVlIiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJub0NsaXAiOiBmYWxzZSwKICAib3BhY2l0eSI6IDEuMCwKICAic21vb3RoRmFjdG9yIjogMS4wLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAyLjg4Nzk5NjcyOTE0NTI4Nwp9CiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIC5hZGRUbyhmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xNzc2NzEyOTljMDE0YzE1YWE4ZTE2NDc4NGNiZmVlYik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9iM2U3Mjg0MzQ3Yzc0ZDYxYWJlNGMwODc1MjcyZjBlYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJwogICAgICAgICAgICAKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzllN2IyZDNlODQzYTQ5Yzk4YjQ3ZTU4NmNmMmQ3ZjIxID0gJChgPGRpdiBpZD0iaHRtbF85ZTdiMmQzZTg0M2E0OWM5OGI0N2U1ODZjZjJkN2YyMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+aWQ6Q05ZQVRfR0JGWFNfUFBfRFJZIF80MF8tMSwgY29lZjoyLjg4Nzk5NjcyOTE0NTI4NzwvZGl2PmApWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYjNlNzI4NDM0N2M3NGQ2MWFiZTRjMDg3NTI3MmYwZWMuc2V0Q29udGVudChodG1sXzllN2IyZDNlODQzYTQ5Yzk4YjQ3ZTU4NmNmMmQ3ZjIxKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBwb2x5X2xpbmVfZmE0YzE1MGY0Y2IwNDk4ZWJlMDBlMWY5OTIxYmViMmUuYmluZFBvcHVwKHBvcHVwX2IzZTcyODQzNDdjNzRkNjFhYmU0YzA4NzUyNzJmMGVjKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYjA3YzM0OTYxNTc1NGJiZGE5N2YyMmY0ZWU4NDk5NjMgPSBMLmZlYXR1cmVHcm91cC5zdWJHcm91cChmZWF0dXJlX2dyb3VwXzI2ZDcxMGViMGQyMDQxNGNiY2UyMGJkNjY1N2VjNTUyKTsKICAgICAgICAgICAgZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYjA3YzM0OTYxNTc1NGJiZGE5N2YyMmY0ZWU4NDk5NjMuYWRkVG8obWFwX2FiMDQ2Y2EyYzQwODQ3YzJhNzFlODdiZTEwMGFhMDU4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIGNpcmNsZV9tYXJrZXJfMTViNGMyZTUwNjliNDVkNmE3Mjg2ZWQ2ZWMxYThiN2YgPSBMLmNpcmNsZU1hcmtlcigKICAgICAgICAgICAgICAgIFsyOS44NzUsIDEyMS41NDY4XSwKICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyYXkiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IHRydWUsCiAgImZpbGxDb2xvciI6ICJncmF5IiwKICAiZmlsbE9wYWNpdHkiOiAwLjIsCiAgImZpbGxSdWxlIjogImV2ZW5vZGQiLAogICJsaW5lQ2FwIjogInJvdW5kIiwKICAibGluZUpvaW4iOiAicm91bmQiLAogICJvcGFjaXR5IjogMS4wLAogICJyYWRpdXMiOiAxMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogMwp9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8oZmVhdHVyZV9ncm91cF9zdWJfZ3JvdXBfYjA3YzM0OTYxNTc1NGJiZGE5N2YyMmY0ZWU4NDk5NjMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGU5OGIzNTRhZjA5NDE2ODkzOGM1YzYwZGJmOWEwMWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCcKICAgICAgICAgICAgCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85YjY3YjNiYzAyZjQ0MWNiYmIwNmE5ZGJlZTk0Y2I2MSA9ICQoYDxkaXYgaWQ9Imh0bWxfOWI2N2IzYmMwMmY0NDFjYmJiMDZhOWRiZWU5NGNiNjEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPkxPUEZJOkNOTlBPPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ZTk4YjM1NGFmMDk0MTY4OTM4YzVjNjBkYmY5YTAxZS5zZXRDb250ZW50KGh0bWxfOWI2N2IzYmMwMmY0NDFjYmJiMDZhOWRiZWU5NGNiNjEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIGNpcmNsZV9tYXJrZXJfMTViNGMyZTUwNjliNDVkNmE3Mjg2ZWQ2ZWMxYThiN2YuYmluZFBvcHVwKHBvcHVwXzhlOThiMzU0YWYwOTQxNjg5MzhjNWM2MGRiZjlhMDFlKQogICAgICAgICAgICA7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgY2lyY2xlX21hcmtlcl8zYzVhMDY1Yjg1NzI0OWY1OWY0YTA3NTg2ZDIxN2FjMiA9IEwuY2lyY2xlTWFya2VyKAogICAgICAgICAgICAgICAgWzUxLjk1MzEsIDEuMzVdLAogICAgICAgICAgICAgICAgewogICJidWJibGluZ01vdXNlRXZlbnRzIjogdHJ1ZSwKICAiY29sb3IiOiAiZ3JheSIsCiAgImRhc2hBcnJheSI6IG51bGwsCiAgImRhc2hPZmZzZXQiOiBudWxsLAogICJmaWxsIjogdHJ1ZSwKICAiZmlsbENvbG9yIjogImdyYXkiLAogICJmaWxsT3BhY2l0eSI6IDAuMiwKICAiZmlsbFJ1bGUiOiAiZXZlbm9kZCIsCiAgImxpbmVDYXAiOiAicm91bmQiLAogICJsaW5lSm9pbiI6ICJyb3VuZCIsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInJhZGl1cyI6IDEwLAogICJzdHJva2UiOiB0cnVlLAogICJ3ZWlnaHQiOiAzCn0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF9iMDdjMzQ5NjE1NzU0YmJkYTk3ZjIyZjRlZTg0OTk2Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mNDM5OGU2M2FkYTg0OWM3YTkxNTBiZTdjMWEwMzBlMiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJwogICAgICAgICAgICAKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2YxMmQxNmViMzljODRjYjFhODg1YmNlYjllYjNiNjRkID0gJChgPGRpdiBpZD0iaHRtbF9mMTJkMTZlYjM5Yzg0Y2IxYTg4NWJjZWI5ZWIzYjY0ZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+TE9QRkk6R0JGWFM8L2Rpdj5gKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2Y0Mzk4ZTYzYWRhODQ5YzdhOTE1MGJlN2MxYTAzMGUyLnNldENvbnRlbnQoaHRtbF9mMTJkMTZlYjM5Yzg0Y2IxYTg4NWJjZWI5ZWIzYjY0ZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgY2lyY2xlX21hcmtlcl8zYzVhMDY1Yjg1NzI0OWY1OWY0YTA3NTg2ZDIxN2FjMi5iaW5kUG9wdXAocG9wdXBfZjQzOThlNjNhZGE4NDljN2E5MTUwYmU3YzFhMDMwZTIpCiAgICAgICAgICAgIDsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgICAgICB2YXIgcG9seV9saW5lXzExOGZhNGJlYzA3ZjRlMzhiNGU2NDJkNzczYmU3M2M4ID0gTC5wb2x5bGluZSgKICAgICAgICAgICAgICAgICAgICBbWzI5Ljg3NSwgMTIxLjU0NjhdLCBbNTEuOTUzMSwgMS4zNV1dLAogICAgICAgICAgICAgICAgICAgIHsKICAiYnViYmxpbmdNb3VzZUV2ZW50cyI6IHRydWUsCiAgImNvbG9yIjogImdyYXkiLAogICJkYXNoQXJyYXkiOiBudWxsLAogICJkYXNoT2Zmc2V0IjogbnVsbCwKICAiZmlsbCI6IGZhbHNlLAogICJmaWxsQ29sb3IiOiAiZ3JheSIsCiAgImZpbGxPcGFjaXR5IjogMC4yLAogICJmaWxsUnVsZSI6ICJldmVub2RkIiwKICAibGluZUNhcCI6ICJyb3VuZCIsCiAgImxpbmVKb2luIjogInJvdW5kIiwKICAibm9DbGlwIjogZmFsc2UsCiAgIm9wYWNpdHkiOiAxLjAsCiAgInNtb290aEZhY3RvciI6IDEuMCwKICAic3Ryb2tlIjogdHJ1ZSwKICAid2VpZ2h0IjogLTIuNTc5Mjg3NTg3Mjc2MTI2Mwp9CiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIC5hZGRUbyhmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF9iMDdjMzQ5NjE1NzU0YmJkYTk3ZjIyZjRlZTg0OTk2Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xNjcwMzIyMmRkZjU0MzU5YjZiNjFiOTM3NGUzMWE2NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJwogICAgICAgICAgICAKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2UwODdlNmFkMDcyOTRiYWQ5ZGRmYmIxNjY5MzJhMmExID0gJChgPGRpdiBpZD0iaHRtbF9lMDg3ZTZhZDA3Mjk0YmFkOWRkZmJiMTY2OTMyYTJhMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+aWQ6Q05OUE9fR0JGWFNfUFBfRFJZIF80MF8tMywgY29lZjotMi41NzkyODc1ODcyNzYxMjYzPC9kaXY+YClbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xNjcwMzIyMmRkZjU0MzU5YjZiNjFiOTM3NGUzMWE2NC5zZXRDb250ZW50KGh0bWxfZTA4N2U2YWQwNzI5NGJhZDlkZGZiYjE2NjkzMmEyYTEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIHBvbHlfbGluZV8xMThmYTRiZWMwN2Y0ZTM4YjRlNjQyZDc3M2JlNzNjOC5iaW5kUG9wdXAocG9wdXBfMTY3MDMyMjJkZGY1NDM1OWI2YjYxYjkzNzRlMzFhNjQpCiAgICAgICAgICAgIDsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBsYXllcl9jb250cm9sXzRjMWExOGQ1ZDI0MjQ3ZmY5MmM2YzY3ZTc3OTY1MDg2ID0gewogICAgICAgICAgICAgICAgYmFzZV9sYXllcnMgOiB7ICJjYXJ0b2RiZGFya19tYXR0ZXIiIDogdGlsZV9sYXllcl84MGU1N2VjYWYzZjQ0YTU5YWI3ODNkZTY0MDY0MDRhMywgfSwKICAgICAgICAgICAgICAgIG92ZXJsYXlzIDogeyAiRWxhc3RpY05ldCBjb2VmZmljaWVudHMiIDogZmVhdHVyZV9ncm91cF9mZGQzNjZmYjFiOTc0MDIwOTVmMjdjMjgxZWUxMjU2YiwiQ05ZQVRfR0JGWFNfUFBfRFJZIF80MF8tMSIgOiBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xNzc2NzEyOTljMDE0YzE1YWE4ZTE2NDc4NGNiZmVlYiwiQ05ZQVRfTkxST1RfUFBfRFJZIF80MF8tMSIgOiBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF8xOTUxZWNjOTU2Yjk0YjY4OTQwYWQ1OTM4ZDExYmY4YiwiQ05ZQVRfR0JGWFNfUFBfRFJZIF80MF8tMyIgOiBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF9mOTMxYjU0NWJhYzI0ZDEyYTJlNGMyZWIxNGJlZDcyNCwiR3JvdXBMYXNzbyBjb2VmZmljaWVudHMiIDogZmVhdHVyZV9ncm91cF8yNmQ3MTBlYjBkMjA0MTRjYmNlMjBiZDY2NTdlYzU1MiwiVVNMU0FfQ05OQU5fSVBfRFJZIF80MF8tMiIgOiBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF84ZmJiZmIwY2UzOWE0YzI0OGUxZjY3MTk3ZTEyNDU0YiwiQ05OUE9fR0JGWFNfUFBfRFJZIF80MF8tMyIgOiBmZWF0dXJlX2dyb3VwX3N1Yl9ncm91cF9iMDdjMzQ5NjE1NzU0YmJkYTk3ZjIyZjRlZTg0OTk2MywgfQogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgTC5jb250cm9sLmxheWVycygKICAgICAgICAgICAgICAgIGxheWVyX2NvbnRyb2xfNGMxYTE4ZDVkMjQyNDdmZjkyYzZjNjdlNzc5NjUwODYuYmFzZV9sYXllcnMsCiAgICAgICAgICAgICAgICBsYXllcl9jb250cm9sXzRjMWExOGQ1ZDI0MjQ3ZmY5MmM2YzY3ZTc3OTY1MDg2Lm92ZXJsYXlzLAogICAgICAgICAgICAgICAge3Bvc2l0aW9uOiAndG9wcmlnaHQnLAogICAgICAgICAgICAgICAgIGNvbGxhcHNlZDogdHJ1ZSwKICAgICAgICAgICAgICAgICBhdXRvWkluZGV4OiB0cnVlCiAgICAgICAgICAgICAgICB9KS5hZGRUbyhtYXBfYWIwNDZjYTJjNDA4NDdjMmE3MWU4N2JlMTAwYWEwNTgpOwogICAgICAgICAgICAKICAgICAgICAKPC9zY3JpcHQ+\" 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 0x7f4041308278>"
]
},
"execution_count": 187,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sgl_group = FeatureGroup(name='GroupLasso coefficients')\n",
"m.add_child(sgl_group)\n",
"for coef_id, row in sgl_coefs_df.iterrows():\n",
" subgroup = FeatureGroupSubGroup(sgl_group, coef_id)\n",
" m.add_child(subgroup)\n",
" \n",
" i = sgl_coefs_df.index.get_loc(coef_id)\n",
" color = colors[i]\n",
" \n",
" lopfi_lat, lopfi_lon = row['lopfi_lat'], row['lopfi_lon']\n",
" dipla_lat, dipla_lon = row['dipla_lat'], row['dipla_lon']\n",
" \n",
" if row.lopfi != dfu_lopfi:\n",
" lopfi = folium.CircleMarker(location=[lopfi_lat, lopfi_lon],\n",
" popup=f'LOPFI:{row.lopfi}', color=color, fill=True).add_to(subgroup)\n",
" if row.dipla != dfu_dipla:\n",
" dipla = folium.CircleMarker(location=[dipla_lat, dipla_lon],\n",
" popup=f'LOPFI:{row.dipla}', color=color, fill=True).add_to(subgroup)\n",
" \n",
" coef_line = PolyLine([[lopfi_lat, lopfi_lon],[dipla_lat, dipla_lon]],\n",
" popup=f'id:{coef_id}, coef:{row.coef}',\n",
" weight=row['coef'], color = color).add_to(subgroup)\n",
" \n",
"LayerControl().add_to(m)\n",
"m"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [conda env:py36]",
"language": "python",
"name": "conda-env-py36-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment