Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
" ## Intro\n",
"Fetch locations of interesting job offers (e.g. https://www.amazon.jobs/ ).\n",
"\n",
"Use http://www.mapdevelopers.com/batch_geocode_tool.php to get coordinates\n",
"\n",
"Save the locations as locations.csv\n",
" \n",
"## Unifying locations\n",
"\n",
"Unifying locations: removing locations which are small, next to big cities."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>.container { width:100% !important; }</style>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pixiedust database opened successfully\n"
]
},
{
"data": {
"text/html": [
"\n",
" <div style=\"margin:10px\">\n",
" <a href=\"https://github.com/ibm-watson-data-lab/pixiedust\" target=\"_new\">\n",
" <img src=\"https://github.com/ibm-watson-data-lab/pixiedust/raw/master/docs/_static/pd_icon32.png\" style=\"float:left;margin-right:10px\"/>\n",
" </a>\n",
" <span>Pixiedust version 1.1.14</span>\n",
" </div>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#First, let's make some room:\n",
"from IPython.core.display import display, HTML\n",
"display(HTML(\"<style>.container { width:100% !important; }</style>\"))\n",
"del HTML\n",
"del display\n",
"\n",
"import pixiedust\n",
"import pandas as pd\n",
"AmazonCitiesWithCoordinates = pd.read_csv(\"AmazonCitiesWithCoordinates.csv\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#first item is the unified location\n",
"locationUnification = []\n",
"locationUnification.append([\"Germany, BY, Munich\", \"Germany, Muenchen\"])\n",
"locationUnification.append([\"Germany, BE, Berlin\", \"Germany, Berlin\"])\n",
"locationUnification.append([\"Japan, Tokyo\", \"Japan, 13, Meguro\"])\n",
"locationUnification.append([\"United States, WA, Seattle\", \"United States, WA, Bellevue\"])\n",
"locationUnification.append([\"United States, San Jose, CA Area\", \"United States, CA, Palo Alto\", \"United States, CA, East Palo Alto\", \"United States, CA, Sunnyvale\", \"United States, CA, Santa Clara\", \"United States, CA, Cupertino\"])\n",
"locationUnification.append([\"United States, VA, Arlington\", \"United States, VA, Ballston\", \"United States, VA, Herndon\"])\n",
"locationUnification.append([\"United States, NY, New York\", \"United States, NJ, Newark\"])\n",
"locationUnification.append([\"United States, CA, Los Angeles, CA Area\", \"United States, CA, Manhattan Beach\", \"United States, CA, Santa Monica\", \"United States, CA, Irvine\"])\n",
"locationUnification.append([\"United States, Boston, MA Area\", \"United States, MA, Andover\", \"United States, MA, North Reading\", \"United States, MA, Cambridge\", \"United States, MA, Boston\"])\n",
"locationUnification.append([\"India, KA, Bangalore\", \"India, KA, Bangalore East\"])"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"REPLACE Germany, Berlin to Germany, BE, Berlin\n",
"REPLACE Germany, Muenchen to Germany, BY, Munich\n",
"REPLACE India, KA, Bangalore East to India, KA, Bangalore\n",
"REPLACE Japan, 13, Meguro to Japan, Tokyo\n",
"REPLACE United States, CA, Cupertino to United States, San Jose, CA Area\n",
"REPLACE United States, CA, East Palo Alto to United States, San Jose, CA Area\n",
"REPLACE United States, CA, Irvine to United States, CA, Los Angeles, CA Area\n",
"REPLACE United States, CA, Manhattan Beach to United States, CA, Los Angeles, CA Area\n",
"REPLACE United States, CA, Palo Alto to United States, San Jose, CA Area\n",
"REPLACE United States, CA, Santa Clara to United States, San Jose, CA Area\n",
"REPLACE United States, CA, Santa Monica to United States, CA, Los Angeles, CA Area\n",
"REPLACE United States, CA, Sunnyvale to United States, San Jose, CA Area\n",
"REPLACE United States, MA, Andover to United States, Boston, MA Area\n",
"REPLACE United States, MA, Boston to United States, Boston, MA Area\n",
"REPLACE United States, MA, Cambridge to United States, Boston, MA Area\n",
"REPLACE United States, MA, North Reading to United States, Boston, MA Area\n",
"REPLACE United States, NJ, Newark to United States, NY, New York\n",
"REPLACE United States, VA, Ballston to United States, VA, Arlington\n",
"REPLACE United States, VA, Herndon to United States, VA, Arlington\n",
"REPLACE United States, WA, Bellevue to United States, WA, Seattle\n"
]
}
],
"source": [
"def unifyCity(location):\n",
" for replacementList in locationUnification:\n",
" for (i, replacementItem) in enumerate(replacementList):\n",
" if i == 0:\n",
" replaceTo = replacementItem\n",
" if location == replacementItem and location != replaceTo:\n",
" print('REPLACE {} to {}'.format(location, replaceTo))\n",
" return replaceTo\n",
" return location\n",
" \n",
"for i in AmazonCitiesWithCoordinates.index:\n",
" AmazonCitiesWithCoordinates.at[i, 'location'] = unifyCity(AmazonCitiesWithCoordinates.at[i, 'location'])\n",
"AmazonCitiesWithCoordinates = AmazonCitiesWithCoordinates.drop_duplicates(subset = 'location', keep='first')\n",
"\n",
"header = [\"location\"]\n",
"AmazonCitiesWithCoordinates.to_csv('locations_unified.csv', columns = header)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"pixiedust": {
"displayParams": {
"basemap": "dark-v9",
"chartsize": "100",
"coloropacity": "100",
"colorrampname": "Orange to Purple",
"handlerId": "mapView",
"keyFields": "latitude,longitude",
"mapboxtoken": "pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA",
"numbins": "6",
"rendererId": "mapbox",
"valueFields": "location"
}
},
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">.pd_warning{display:none;}</style><div class=\"pd_warning\"><em>Hey, there's something awesome here! To see it, open this notebook outside GitHub, in a viewer like Jupyter</em></div>\n",
" <div class=\"pd_save is-viewer-good\" style=\"padding-right:10px;text-align: center;line-height:initial !important;font-size: xx-large;font-weight: 500;color: coral;\">\n",
" \n",
" </div>\n",
" <div id=\"chartFigure57fd4037\" class=\"pd_save is-viewer-good\" style=\"overflow-x:auto\">\n",
" <script>\n",
" window.iframeLoaded = window.iframeLoaded || function(iframe) {\n",
" try {\n",
" iframe.contentWindow.pdMessageListeners = [];\n",
" iframe.contentWindow[\"addPDMessageListener\"] = function(listener){\n",
" iframe.contentWindow.pdMessageListeners.push(listener);\n",
" }\n",
" iframe.contentWindow.addEventListener(\"message\", function(event){\n",
" iframe.contentWindow.pdMessageListeners.forEach(function(listener){\n",
" listener(event);\n",
" });\n",
" }, false);\n",
" iframe.contentWindow.ready = true;\n",
" iframe.contentWindow[\"triggerPDEvent\"] = function(eventInfo) {\n",
" $(document).trigger('pd_event', eventInfo);\n",
" }\n",
" } catch (e) {\n",
" console.log(e)\n",
" }\n",
" }\n",
"\n",
" \n",
"</script>\n",
"<iframe id=\"mapframe57fd4037\" style=\"width:1495.2px;height:500px\" srcdoc=\"<!DOCTYPE html>\n",
"<html lang=&quot;en&quot;>\n",
"<head>\n",
" <meta charset=&quot;UTF-8&quot;>\n",
" <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;>\n",
" <title>Pixiedust Mapbox map</title>\n",
" <script src=&quot;https://api.tiles.mapbox.com/mapbox-gl-js/v0.32.1/mapbox-gl.js&quot;></script>\n",
" <link href=&quot;https://api.tiles.mapbox.com/mapbox-gl-js/v0.32.1/mapbox-gl.css&quot; rel=&quot;stylesheet&quot; />\n",
" <style>\n",
" .mapboxgl-popup-content h3 { \n",
" margin: 2px 0 2px 0;\n",
" font-style: italic;\n",
" }\n",
" .mapboxgl-popup {\n",
" max-width: 200px;\n",
" }\n",
" #map canvas {\n",
" cursor: crosshair;\n",
" }\n",
" .legend {\n",
" background-color: rgba(255,255,255, 0.75);\n",
" border-radius: 3px;\n",
" position: absolute;\n",
" left: 14px;\n",
" top: 14px;\n",
" box-shadow: 0 1px 2px rgba(0,0,0,0.10);\n",
" font-size: 12px;\n",
" line-height: 18px;\n",
" padding: 10px;\n",
" z-index: 1;\n",
" }\n",
" .legend h4 {\n",
" margin: 0 0 10px;\n",
" }\n",
" .legend div span {\n",
" border-radius: 50%;\n",
" display: inline-block;\n",
" height: 10px;\n",
" margin-right: 5px;\n",
" width: 10px;\n",
" }\n",
" body { \n",
" background-color:#333; \n",
" margin:0px !important; \n",
" overflow: hidden;\n",
" font-family: &quot;Helvetica Neue&quot;, Arial, Helvetica, sans-serif;\n",
" }\n",
" </style>\n",
"</head>\n",
"<body>\n",
"<div id=&quot;map-57fd4037-195ea93c&quot; style=&quot;width:calc(1495.2px - 4px);height:calc(500px - 4px)&quot; />\n",
"\n",
"\n",
"<script>\n",
" !function(e){if(&quot;object&quot;==typeof exports&amp;&amp;&quot;undefined&quot;!=typeof module)module.exports=e();else if(&quot;function&quot;==typeof define&amp;&amp;define.amd)define([],e);else{var n;&quot;undefined&quot;!=typeof window?n=window:&quot;undefined&quot;!=typeof global?n=global:&quot;undefined&quot;!=typeof self&amp;&amp;(n=self),n.geojsonExtent=e()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=&quot;function&quot;==typeof require&amp;&amp;require;if(!u&amp;&amp;a)return a(o,!0);if(i)return i(o,!0);var f=new Error(&quot;Cannot find module &quot;+o+&quot;&quot;);throw f.code=&quot;MODULE_NOT_FOUND&quot;,f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i=&quot;function&quot;==typeof require&amp;&amp;require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module){function getExtent(_){for(var ext=extent(),coords=geojsonCoords(_),i=0;i<coords.length;i++)ext.include(coords[i]);return ext}var geojsonCoords=require(&quot;geojson-coords&quot;),traverse=require(&quot;traverse&quot;),extent=require(&quot;extent&quot;),geojsonTypes=[&quot;Point&quot;,&quot;MultiPoint&quot;,&quot;LineString&quot;,&quot;MultiLineString&quot;,&quot;Polygon&quot;,&quot;MultiPolygon&quot;,&quot;Feature&quot;,&quot;FeatureCollection&quot;,&quot;GeometryCollection&quot;];module.exports=function(_){return getExtent(_).bbox()},module.exports.polygon=function(_){return getExtent(_).polygon()},module.exports.bboxify=function(_){return traverse(_).map(function(value){value&amp;&amp;-1!==typeof geojsonTypes.indexOf(value.type)&amp;&amp;(console.log(value.type,value),value.bbox=getExtent(value).bbox(),this.update(value))})}},{extent:2,&quot;geojson-coords&quot;:4,traverse:7}],2:[function(require,module){function Extent(){return this instanceof Extent?(this._bbox=[1/0,1/0,-(1/0),-(1/0)],void(this._valid=!1)):new Extent}module.exports=Extent,Extent.prototype.include=function(ll){return this._valid=!0,this._bbox[0]=Math.min(this._bbox[0],ll[0]),this._bbox[1]=Math.min(this._bbox[1],ll[1]),this._bbox[2]=Math.max(this._bbox[2],ll[0]),this._bbox[3]=Math.max(this._bbox[3],ll[1]),this},Extent.prototype.union=function(other){return this._valid=!0,this._bbox[0]=Math.min(this._bbox[0],other[0]),this._bbox[1]=Math.min(this._bbox[1],other[1]),this._bbox[2]=Math.max(this._bbox[2],other[2]),this._bbox[3]=Math.max(this._bbox[3],other[3]),this},Extent.prototype.bbox=function(){return this._valid?this._bbox:null},Extent.prototype.contains=function(ll){return this._valid?this._bbox[0]<=ll[0]&amp;&amp;this._bbox[1]<=ll[1]&amp;&amp;this._bbox[2]>=ll[0]&amp;&amp;this._bbox[3]>=ll[1]:null},Extent.prototype.polygon=function(){return this._valid?{type:&quot;Polygon&quot;,coordinates:[[[this._bbox[0],this._bbox[1]],[this._bbox[2],this._bbox[1]],[this._bbox[2],this._bbox[3]],[this._bbox[0],this._bbox[3]],[this._bbox[0],this._bbox[1]]]]}:null}},{}],3:[function(require,module){module.exports=function(list){function _flatten(list){return Array.isArray(list)&amp;&amp;list.length&amp;&amp;&quot;number&quot;==typeof list[0]?[list]:list.reduce(function(acc,item){return Array.isArray(item)&amp;&amp;Array.isArray(item[0])?acc.concat(_flatten(item)):(acc.push(item),acc)},[])}return _flatten(list)}},{}],4:[function(require,module){var geojsonNormalize=require(&quot;geojson-normalize&quot;),geojsonFlatten=require(&quot;geojson-flatten&quot;),flatten=require(&quot;./flatten&quot;);module.exports=function(_){if(!_)return[];var normalized=geojsonFlatten(geojsonNormalize(_)),coordinates=[];return normalized.features.forEach(function(feature){feature.geometry&amp;&amp;(coordinates=coordinates.concat(flatten(feature.geometry.coordinates)))}),coordinates}},{&quot;./flatten&quot;:3,&quot;geojson-flatten&quot;:5,&quot;geojson-normalize&quot;:6}],5:[function(require,module){function flatten(gj){switch(gj&amp;&amp;gj.type||null){case&quot;FeatureCollection&quot;:return gj.features=gj.features.reduce(function(mem,feature){return mem.concat(flatten(feature))},[]),gj;case&quot;Feature&quot;:return flatten(gj.geometry).map(function(geom){return{type:&quot;Feature&quot;,properties:JSON.parse(JSON.stringify(gj.properties)),geometry:geom}});case&quot;MultiPoint&quot;:return gj.coordinates.map(function(_){return{type:&quot;Point&quot;,coordinates:_}});case&quot;MultiPolygon&quot;:return gj.coordinates.map(function(_){return{type:&quot;Polygon&quot;,coordinates:_}});case&quot;MultiLineString&quot;:return gj.coordinates.map(function(_){return{type:&quot;LineString&quot;,coordinates:_}});case&quot;GeometryCollection&quot;:return gj.geometries;case&quot;Point&quot;:case&quot;Polygon&quot;:case&quot;LineString&quot;:return[gj];default:return gj}}module.exports=flatten},{}],6:[function(require,module){function normalize(gj){if(!gj||!gj.type)return null;var type=types[gj.type];return type?&quot;geometry&quot;===type?{type:&quot;FeatureCollection&quot;,features:[{type:&quot;Feature&quot;,properties:{},geometry:gj}]}:&quot;feature&quot;===type?{type:&quot;FeatureCollection&quot;,features:[gj]}:&quot;featurecollection&quot;===type?gj:void 0:null}module.exports=normalize;var types={Point:&quot;geometry&quot;,MultiPoint:&quot;geometry&quot;,LineString:&quot;geometry&quot;,MultiLineString:&quot;geometry&quot;,Polygon:&quot;geometry&quot;,MultiPolygon:&quot;geometry&quot;,GeometryCollection:&quot;geometry&quot;,Feature:&quot;feature&quot;,FeatureCollection:&quot;featurecollection&quot;}},{}],7:[function(require,module){function Traverse(obj){this.value=obj}function walk(root,cb,immutable){var path=[],parents=[],alive=!0;return function walker(node_){function updateState(){if(&quot;object&quot;==typeof state.node&amp;&amp;null!==state.node){state.keys&amp;&amp;state.node_===state.node||(state.keys=objectKeys(state.node)),state.isLeaf=0==state.keys.length;for(var i=0;i<parents.length;i++)if(parents[i].node_===node_){state.circular=parents[i];break}}else state.isLeaf=!0,state.keys=null;state.notLeaf=!state.isLeaf,state.notRoot=!state.isRoot}var node=immutable?copy(node_):node_,modifiers={},keepGoing=!0,state={node:node,node_:node_,path:[].concat(path),parent:parents[parents.length-1],parents:parents,key:path.slice(-1)[0],isRoot:0===path.length,level:path.length,circular:null,update:function(x,stopHere){state.isRoot||(state.parent.node[state.key]=x),state.node=x,stopHere&amp;&amp;(keepGoing=!1)},&quot;delete&quot;:function(stopHere){delete state.parent.node[state.key],stopHere&amp;&amp;(keepGoing=!1)},remove:function(stopHere){isArray(state.parent.node)?state.parent.node.splice(state.key,1):delete state.parent.node[state.key],stopHere&amp;&amp;(keepGoing=!1)},keys:null,before:function(f){modifiers.before=f},after:function(f){modifiers.after=f},pre:function(f){modifiers.pre=f},post:function(f){modifiers.post=f},stop:function(){alive=!1},block:function(){keepGoing=!1}};if(!alive)return state;updateState();var ret=cb.call(state,state.node);return void 0!==ret&amp;&amp;state.update&amp;&amp;state.update(ret),modifiers.before&amp;&amp;modifiers.before.call(state,state.node),keepGoing?(&quot;object&quot;!=typeof state.node||null===state.node||state.circular||(parents.push(state),updateState(),forEach(state.keys,function(key,i){path.push(key),modifiers.pre&amp;&amp;modifiers.pre.call(state,state.node[key],key);var child=walker(state.node[key]);immutable&amp;&amp;hasOwnProperty.call(state.node,key)&amp;&amp;(state.node[key]=child.node),child.isLast=i==state.keys.length-1,child.isFirst=0==i,modifiers.post&amp;&amp;modifiers.post.call(state,child),path.pop()}),parents.pop()),modifiers.after&amp;&amp;modifiers.after.call(state,state.node),state):state}(root).node}function copy(src){if(&quot;object&quot;==typeof src&amp;&amp;null!==src){var dst;if(isArray(src))dst=[];else if(isDate(src))dst=new Date(src.getTime?src.getTime():src);else if(isRegExp(src))dst=new RegExp(src);else if(isError(src))dst={message:src.message};else if(isBoolean(src))dst=new Boolean(src);else if(isNumber(src))dst=new Number(src);else if(isString(src))dst=new String(src);else if(Object.create&amp;&amp;Object.getPrototypeOf)dst=Object.create(Object.getPrototypeOf(src));else if(src.constructor===Object)dst={};else{var proto=src.constructor&amp;&amp;src.constructor.prototype||src.__proto__||{},T=function(){};T.prototype=proto,dst=new T}return forEach(objectKeys(src),function(key){dst[key]=src[key]}),dst}return src}function toS(obj){return Object.prototype.toString.call(obj)}function isDate(obj){return&quot;[object Date]&quot;===toS(obj)}function isRegExp(obj){return&quot;[object RegExp]&quot;===toS(obj)}function isError(obj){return&quot;[object Error]&quot;===toS(obj)}function isBoolean(obj){return&quot;[object Boolean]&quot;===toS(obj)}function isNumber(obj){return&quot;[object Number]&quot;===toS(obj)}function isString(obj){return&quot;[object String]&quot;===toS(obj)}var traverse=module.exports=function(obj){return new Traverse(obj)};Traverse.prototype.get=function(ps){for(var node=this.value,i=0;i<ps.length;i++){var key=ps[i];if(!node||!hasOwnProperty.call(node,key)){node=void 0;break}node=node[key]}return node},Traverse.prototype.has=function(ps){for(var node=this.value,i=0;i<ps.length;i++){var key=ps[i];if(!node||!hasOwnProperty.call(node,key))return!1;node=node[key]}return!0},Traverse.prototype.set=function(ps,value){for(var node=this.value,i=0;i<ps.length-1;i++){var key=ps[i];hasOwnProperty.call(node,key)||(node[key]={}),node=node[key]}return node[ps[i]]=value,value},Traverse.prototype.map=function(cb){return walk(this.value,cb,!0)},Traverse.prototype.forEach=function(cb){return this.value=walk(this.value,cb,!1),this.value},Traverse.prototype.reduce=function(cb,init){var skip=1===arguments.length,acc=skip?this.value:init;return this.forEach(function(x){this.isRoot&amp;&amp;skip||(acc=cb.call(this,acc,x))}),acc},Traverse.prototype.paths=function(){var acc=[];return this.forEach(function(){acc.push(this.path)}),acc},Traverse.prototype.nodes=function(){var acc=[];return this.forEach(function(){acc.push(this.node)}),acc},Traverse.prototype.clone=function(){var parents=[],nodes=[];return function clone(src){for(var i=0;i<parents.length;i++)if(parents[i]===src)return nodes[i];if(&quot;object&quot;==typeof src&amp;&amp;null!==src){var dst=copy(src);return parents.push(src),nodes.push(dst),forEach(objectKeys(src),function(key){dst[key]=clone(src[key])}),parents.pop(),nodes.pop(),dst}return src}(this.value)};var objectKeys=Object.keys||function(obj){var res=[];for(var key in obj)res.push(key);return res},isArray=Array.isArray||function(xs){return&quot;[object Array]&quot;===Object.prototype.toString.call(xs)},forEach=function(xs,fn){if(xs.forEach)return xs.forEach(fn);for(var i=0;i<xs.length;i++)fn(xs[i],i,xs)};forEach(objectKeys(Traverse.prototype),function(key){traverse[key]=function(obj){var args=[].slice.call(arguments,1),t=new Traverse(obj);return t[key].apply(t,args)}});var hasOwnProperty=Object.hasOwnProperty||function(obj,key){return key in obj}},{}]},{},[1])(1)}); \n",
" var comment = &quot;&quot;;\n",
" mapboxgl.accessToken=&quot;pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA&quot;;\n",
" var mapdata = null;\n",
" var map = new mapboxgl.Map({\n",
" container: &quot;map-57fd4037-195ea93c&quot;,\n",
" style: &quot;mapbox://styles/mapbox/dark-v9&quot;\n",
" });\n",
"\n",
" setTimeout(function(){\n",
" if (window.addPDMessageListener){\n",
" window.addPDMessageListener(function(event){\n",
" streamingLayer = map.getSource(&quot;streamingLayer&quot;);\n",
" if (streamingLayer){\n",
" streamingLayer.setData(event.data.data);\n",
" }else{\n",
" map.addLayer({\n",
" &quot;id&quot;: &quot;streamingLayer&quot;,\n",
" &quot;maptype&quot;: &quot;mapbox&quot;,\n",
" &quot;type&quot;: event.data.type,\n",
" &quot;source&quot;: { type: &quot;geojson&quot;, data: event.data.data },\n",
" &quot;layout&quot;: event.data.layout || {},\n",
" &quot;paint&quot;: event.data.paint || {}\n",
" });\n",
" if (event.data.fitbounds &amp;&amp; event.data.data.features){\n",
" function updateBounds(res, ar){\n",
" if (ar[0].length >=2 &amp;&amp; ar[1].length >= 2 ){\n",
" if (!res){\n",
" return ar;\n",
" }\n",
" return [ \n",
" [Math.min( ar[0][0]-0.1, res[0][0]), Math.min( ar[0][1]-0.1, res[0][1])],\n",
" [Math.max( ar[1][0]+0.1, res[1][0]), Math.max( ar[1][1]+0.1, res[1][1])]\n",
" ]\n",
" }\n",
" return null;\n",
" }\n",
" var bbox = event.data.data.features.reduce(function(res, value){\n",
" var coord = value.geometry.coordinates;\n",
" if (coord.length >= 2 ){\n",
" res = updateBounds( res, [coord[0], coord[1]]);\n",
" }\n",
" return res;\n",
" }, null);\n",
" if (bbox){\n",
" map.fitBounds(bbox);\n",
" }\n",
" }\n",
" }\n",
" });\n",
" };\n",
" },100);\n",
"\n",
" var popup = new mapboxgl.Popup({closeButton: false,closeOnClick: true});\n",
"\n",
" function divineGeometryType(mapdata) {\n",
" comment = &quot;check type of first geometry. Later expand to check all geometries and make a good decision&quot;;\n",
" return mapdata.features[0].geometry.type;\n",
" }\n",
" \n",
" map.on(&quot;mousemove&quot;, function (e) {\n",
" var fs = map.queryRenderedFeatures(e.point,{layers:[&quot;pxlayer&quot;]});\n",
" if (!fs || !fs.length) {popup.remove();return;};\n",
" popuphtml = &quot;&quot;;\n",
" var hr = false;\n",
" fs.forEach(function(f){\n",
" if (hr){ \n",
" popuphtml += &quot;<hr>\\n&quot;;\n",
" }\n",
" hr=true;\n",
" popuphtml += &quot;<h3>&quot;+f.layer.id.toUpperCase()+&quot;</h3>\\n&quot;;\n",
" var keylength = Object.keys(f.properties).length;\n",
" for (var key in f.properties) {\n",
" popuphtml += &quot;<b>&quot;+key+&quot;: </b> &quot;+f.properties[key]+&quot;<br/>\\n&quot;;\n",
" }\n",
" });\n",
" popup.setLngLat(e.lngLat).setHTML(popuphtml).addTo(map);\n",
" });\n",
" \n",
" map.on(&quot;click&quot;, function (e) {\n",
" var fs = map.queryRenderedFeatures(e.point, { layers: [&quot;pxlayer&quot;] });\n",
" if (fs &amp;&amp; fs.length) {\n",
" var f = fs[0];\n",
" console.log(&quot;clicked&quot;, f);\n",
" var keylength = Object.keys(f.properties).length;\n",
" var payload = {type:&quot;select&quot;, targetDivId: &quot;&quot; };\n",
"\n",
" for (var key in f.properties) {\n",
" payload[key] = f.properties[key];\n",
" }\n",
"\n",
" if (window.triggerPDEvent) {\n",
" window.triggerPDEvent(payload);\n",
" }\n",
" }\n",
" });\n",
" \n",
" map.on(&quot;load&quot;, function() {\n",
" \n",
" mapdata={&quot;type&quot;: &quot;FeatureCollection&quot;, &quot;features&quot;: [{&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Australia, NSW, Sydney&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [151.209296, -33.86882]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Brazil, SP, Sao Paulo&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-46.633309000000004, -23.550520000000002]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Canada, BC, Vancouver&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-123.12073799999999, 49.282728999999996]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Canada, ON, Toronto&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-79.383184, 43.653226000000004]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;China, 11, Beijing&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [116.23046200000002, 40.237352]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;China, 31, Shanghai&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-86.087644, 42.768197]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;France, Courbevoie&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [2.25929, 48.900552000000005]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Germany, Aachen&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [6.083887, 50.775346]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Germany, BE, Berlin&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [13.404954, 52.52000699999999]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Germany, BY, Munich&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [11.58198, 48.135125]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Hong Kong, Causeway Bay&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [114.191492, 22.285979]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;India, HR, Gurgaon&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [77.026638, 28.459497]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;India, KA, Bangalore&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [77.594563, 12.971599000000001]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;India, TN, Chennai&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [80.270718, 13.08268]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;India, TS, Hyderabad&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [78.486671, 17.385044]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Ireland, DUBLIN, Dublin&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-6.26031, 53.349805]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Israel, Haifa&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [34.989571000000005, 32.794046]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Israel, Tel Aviv&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [34.781768, 32.0853]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Japan, Tokyo&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [139.691706, 35.689488]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Jordan, Amman&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [35.928371999999996, 31.945366999999997]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Luxembourg, Luxembourg&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [6.1319349999999995, 49.611621]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Poland, Gdansk&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [18.646638, 54.352025]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Romania, Iasi&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [27.601442, 47.158455]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Singapore, Singapore&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [103.819836, 1.352083]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;South Africa, Cape Town&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [18.424055, -33.924868]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Spain, 28, Madrid&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-3.6857580000000003, 40.427566999999996]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;Sweden, Stockholm&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [18.068581, 59.329322999999995]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;UK, Cambridge&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [0.12181700000000001, 52.205337]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;UK, Edinburgh&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-3.1882669999999997, 55.953252]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;UK, London&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-0.12775799999999998, 51.507351]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, AZ, Tempe&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-111.940005, 33.425509999999996]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, Boston, MA Area&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-71.13679499999999, 42.658336]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CA, Los Angeles, CA Area&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-117.82650500000001, 33.684567]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CA, San Diego&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-117.161084, 32.715738]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CA, San Francisco&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-122.419416, 37.77493]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CA, San Luis Obispo&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-120.65961599999999, 35.282752]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CA, Santa Cruz&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-122.030796, 36.974117]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, CO, Denver&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-104.990251, 39.739236]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, GA, Atlanta&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-84.387982, 33.748995]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, IL, Chicago&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-87.629798, 41.878114000000004]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, MI, Detroit&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-83.045754, 42.331427000000005]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, MN, Minneapolis&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-93.265011, 44.977753]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, NY, New York&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-74.17236700000001, 40.735657]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, OR, Portland&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-122.65871899999999, 45.512231]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, PA, Malvern&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-75.513812, 40.036218]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, San Jose, CA Area&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-122.032182, 37.322998]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, TX, Austin&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-97.743061, 30.267153000000004]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, TX, Dallas&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-96.796988, 32.776664000000004]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, TX, Houston&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-95.369803, 29.760427000000004]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, VA, Arlington&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-77.105367, 38.885801]}}, {&quot;type&quot;: &quot;Feature&quot;, &quot;properties&quot;: {&quot;pd_count&quot;: 1, &quot;location&quot;: &quot;United States, WA, Seattle&quot;}, &quot;geometry&quot;: {&quot;type&quot;: &quot;Point&quot;, &quot;coordinates&quot;: [-122.201516, 47.61015]}}]};\n",
" geomtype = divineGeometryType(mapdata);\n",
" \n",
" var ds = {\n",
" &quot;type&quot;:&quot;geojson&quot;,\n",
" &quot;data&quot;:mapdata\n",
" };\n",
" var clusterme = false;\n",
" if (geomtype.substr(-5,5) == &quot;Point&quot;) {\n",
" \n",
" clusterme = true;\n",
" ds[&quot;cluster&quot;] = true;\n",
" ds[&quot;clusterMaxZoom&quot;] = 14;\n",
" ds[&quot;clusterRadius&quot;] = 20;\n",
" console.log(&quot;IM CLUSTERED&quot;);\n",
" \n",
" }\n",
" map.addSource(&quot;pxdatasource&quot;, ds);\n",
"\n",
" var maplayertype = &quot;circle&quot;;\n",
" if (geomtype.substr(-7,7) == &quot;Polygon&quot;) \n",
" maplayertype = &quot;fill&quot;;\n",
" else if (geomtype.substr(-10,10) == &quot;LineString&quot;)\n",
" maplayertype = &quot;line&quot;;\n",
" map.addLayer({\n",
" &quot;id&quot;:&quot;pxlayer&quot;,\n",
" &quot;type&quot;:maplayertype, \n",
" &quot;source&quot;: &quot;pxdatasource&quot;, \n",
" &quot;paint&quot;: {&quot;circle-radius&quot;: 12, &quot;circle-color&quot;: {&quot;property&quot;: &quot;pd_count&quot;, &quot;stops&quot;: [[1.0, &quot;#e66101&quot;], [1.0, &quot;#acd60e&quot;], [1.0, &quot;#1ac61a&quot;], [1.0, &quot;#26b798&quot;], [1.0, &quot;#3163a8&quot;], [1.0, &quot;#5e3c99&quot;]]}, &quot;circle-opacity&quot;: 1.0}\n",
" });\n",
" \n",
" if (clusterme &amp;&amp; geomtype.substr(-5,5) == &quot;Point&quot;) {\n",
" map.addLayer({\n",
" &quot;id&quot;: &quot;cluster-count-labels&quot;, \n",
" &quot;type&quot;: &quot;symbol&quot;, \n",
" &quot;source&quot;: &quot;pxdatasource&quot;, \n",
" &quot;paint&quot;: {\n",
" &quot;text-color&quot;: &quot;#FFF&quot;\n",
" },\n",
" &quot;layout&quot;: {\n",
" &quot;text-field&quot;: &quot;{point_count}&quot;, \n",
" &quot;text-font&quot;: [\n",
" &quot;DIN Offc Pro Medium&quot;, \n",
" &quot;Arial Unicode MS Bold&quot;\n",
" ],\n",
" &quot;text-size&quot;: 12\n",
" }\n",
" });\n",
" }\n",
" \n",
" \n",
"\n",
" comment = &quot;Add user layers&quot;;\n",
" var layers = [];\n",
" \n",
" layers.sort(function(a,b) {\n",
" return a[1] - b[1];\n",
" });\n",
" for (layersi=layers.length-1; layersi>=0; layersi--) {\n",
" map.addLayer(layers[layersi][0]);\n",
" comment = &quot;User layer legend&quot;;\n",
" \n",
" }\n",
" \n",
" map.fitBounds([[-123.12073799999999, -33.924868], [151.209296, 59.329322999999995]]);\n",
" \n",
" \n",
" });\n",
"</script>\n",
"</body>\n",
"</html>\" onload=\"iframeLoaded(this)\"></iframe>\n",
"<script>\n",
" var iframe = document.getElementById('mapframe57fd4037');\n",
" iframe.setAttribute('srcdoc', atob('PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiPgogICAgPHRpdGxlPlBpeGllZHVzdCBNYXBib3ggbWFwPC90aXRsZT4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FwaS50aWxlcy5tYXBib3guY29tL21hcGJveC1nbC1qcy92MC4zMi4xL21hcGJveC1nbC5qcyI+PC9zY3JpcHQ+CiAgICA8bGluayBocmVmPSJodHRwczovL2FwaS50aWxlcy5tYXBib3guY29tL21hcGJveC1nbC1qcy92MC4zMi4xL21hcGJveC1nbC5jc3MiIHJlbD0ic3R5bGVzaGVldCIgLz4KICAgIDxzdHlsZT4KICAgIC5tYXBib3hnbC1wb3B1cC1jb250ZW50IGgzIHsgCiAgICAgICAgbWFyZ2luOiAycHggMCAycHggMDsKICAgICAgICBmb250LXN0eWxlOiBpdGFsaWM7CiAgICB9CiAgICAubWFwYm94Z2wtcG9wdXAgewogICAgICAgIG1heC13aWR0aDogMjAwcHg7CiAgICB9CiAgICAjbWFwIGNhbnZhcyB7CiAgICAgICAgY3Vyc29yOiBjcm9zc2hhaXI7CiAgICB9CiAgICAubGVnZW5kIHsKICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwyNTUsMjU1LCAwLjc1KTsKICAgICAgICBib3JkZXItcmFkaXVzOiAzcHg7CiAgICAgICAgcG9zaXRpb246IGFic29sdXRlOwogICAgICAgIGxlZnQ6IDE0cHg7CiAgICAgICAgdG9wOiAxNHB4OwogICAgICAgIGJveC1zaGFkb3c6IDAgMXB4IDJweCByZ2JhKDAsMCwwLDAuMTApOwogICAgICAgIGZvbnQtc2l6ZTogMTJweDsKICAgICAgICBsaW5lLWhlaWdodDogMThweDsKICAgICAgICBwYWRkaW5nOiAxMHB4OwogICAgICAgIHotaW5kZXg6IDE7CiAgICB9CiAgICAubGVnZW5kIGg0IHsKICAgICAgICBtYXJnaW46IDAgMCAxMHB4OwogICAgfQogICAgLmxlZ2VuZCBkaXYgc3BhbiB7CiAgICAgICAgYm9yZGVyLXJhZGl1czogNTAlOwogICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICAgICAgICBoZWlnaHQ6IDEwcHg7CiAgICAgICAgbWFyZ2luLXJpZ2h0OiA1cHg7CiAgICAgICAgd2lkdGg6IDEwcHg7CiAgICB9CiAgICBib2R5IHsgCiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjojMzMzOyAKICAgICAgICBtYXJnaW46MHB4ICFpbXBvcnRhbnQ7IAogICAgICAgIG92ZXJmbG93OiBoaWRkZW47CiAgICAgICAgZm9udC1mYW1pbHk6ICJIZWx2ZXRpY2EgTmV1ZSIsIEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7CiAgICB9CiAgICA8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5Pgo8ZGl2IGlkPSJtYXAtNTdmZDQwMzctMTk1ZWE5M2MiIHN0eWxlPSJ3aWR0aDpjYWxjKDE0OTUuMnB4IC0gNHB4KTtoZWlnaHQ6Y2FsYyg1MDBweCAtIDRweCkiIC8+CgoKPHNjcmlwdD4KICAgICFmdW5jdGlvbihlKXtpZigib2JqZWN0Ij09dHlwZW9mIGV4cG9ydHMmJiJ1bmRlZmluZWQiIT10eXBlb2YgbW9kdWxlKW1vZHVsZS5leHBvcnRzPWUoKTtlbHNlIGlmKCJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQpZGVmaW5lKFtdLGUpO2Vsc2V7dmFyIG47InVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3c/bj13aW5kb3c6InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWw/bj1nbG9iYWw6InVuZGVmaW5lZCIhPXR5cGVvZiBzZWxmJiYobj1zZWxmKSxuLmdlb2pzb25FeHRlbnQ9ZSgpfX0oZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9ImZ1bmN0aW9uIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoIkNhbm5vdCBmaW5kIG1vZHVsZSAiK28rIiIpO3Rocm93IGYuY29kZT0iTU9EVUxFX05PVF9GT1VORCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfWZvcih2YXIgaT0iZnVuY3Rpb24iPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZSxvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30oezE6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlKXtmdW5jdGlvbiBnZXRFeHRlbnQoXyl7Zm9yKHZhciBleHQ9ZXh0ZW50KCksY29vcmRzPWdlb2pzb25Db29yZHMoXyksaT0wO2k8Y29vcmRzLmxlbmd0aDtpKyspZXh0LmluY2x1ZGUoY29vcmRzW2ldKTtyZXR1cm4gZXh0fXZhciBnZW9qc29uQ29vcmRzPXJlcXVpcmUoImdlb2pzb24tY29vcmRzIiksdHJhdmVyc2U9cmVxdWlyZSgidHJhdmVyc2UiKSxleHRlbnQ9cmVxdWlyZSgiZXh0ZW50IiksZ2VvanNvblR5cGVzPVsiUG9pbnQiLCJNdWx0aVBvaW50IiwiTGluZVN0cmluZyIsIk11bHRpTGluZVN0cmluZyIsIlBvbHlnb24iLCJNdWx0aVBvbHlnb24iLCJGZWF0dXJlIiwiRmVhdHVyZUNvbGxlY3Rpb24iLCJHZW9tZXRyeUNvbGxlY3Rpb24iXTttb2R1bGUuZXhwb3J0cz1mdW5jdGlvbihfKXtyZXR1cm4gZ2V0RXh0ZW50KF8pLmJib3goKX0sbW9kdWxlLmV4cG9ydHMucG9seWdvbj1mdW5jdGlvbihfKXtyZXR1cm4gZ2V0RXh0ZW50KF8pLnBvbHlnb24oKX0sbW9kdWxlLmV4cG9ydHMuYmJveGlmeT1mdW5jdGlvbihfKXtyZXR1cm4gdHJhdmVyc2UoXykubWFwKGZ1bmN0aW9uKHZhbHVlKXt2YWx1ZSYmLTEhPT10eXBlb2YgZ2VvanNvblR5cGVzLmluZGV4T2YodmFsdWUudHlwZSkmJihjb25zb2xlLmxvZyh2YWx1ZS50eXBlLHZhbHVlKSx2YWx1ZS5iYm94PWdldEV4dGVudCh2YWx1ZSkuYmJveCgpLHRoaXMudXBkYXRlKHZhbHVlKSl9KX19LHtleHRlbnQ6MiwiZ2VvanNvbi1jb29yZHMiOjQsdHJhdmVyc2U6N31dLDI6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlKXtmdW5jdGlvbiBFeHRlbnQoKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIEV4dGVudD8odGhpcy5fYmJveD1bMS8wLDEvMCwtKDEvMCksLSgxLzApXSx2b2lkKHRoaXMuX3ZhbGlkPSExKSk6bmV3IEV4dGVudH1tb2R1bGUuZXhwb3J0cz1FeHRlbnQsRXh0ZW50LnByb3RvdHlwZS5pbmNsdWRlPWZ1bmN0aW9uKGxsKXtyZXR1cm4gdGhpcy5fdmFsaWQ9ITAsdGhpcy5fYmJveFswXT1NYXRoLm1pbih0aGlzLl9iYm94WzBdLGxsWzBdKSx0aGlzLl9iYm94WzFdPU1hdGgubWluKHRoaXMuX2Jib3hbMV0sbGxbMV0pLHRoaXMuX2Jib3hbMl09TWF0aC5tYXgodGhpcy5fYmJveFsyXSxsbFswXSksdGhpcy5fYmJveFszXT1NYXRoLm1heCh0aGlzLl9iYm94WzNdLGxsWzFdKSx0aGlzfSxFeHRlbnQucHJvdG90eXBlLnVuaW9uPWZ1bmN0aW9uKG90aGVyKXtyZXR1cm4gdGhpcy5fdmFsaWQ9ITAsdGhpcy5fYmJveFswXT1NYXRoLm1pbih0aGlzLl9iYm94WzBdLG90aGVyWzBdKSx0aGlzLl9iYm94WzFdPU1hdGgubWluKHRoaXMuX2Jib3hbMV0sb3RoZXJbMV0pLHRoaXMuX2Jib3hbMl09TWF0aC5tYXgodGhpcy5fYmJveFsyXSxvdGhlclsyXSksdGhpcy5fYmJveFszXT1NYXRoLm1heCh0aGlzLl9iYm94WzNdLG90aGVyWzNdKSx0aGlzfSxFeHRlbnQucHJvdG90eXBlLmJib3g9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fdmFsaWQ/dGhpcy5fYmJveDpudWxsfSxFeHRlbnQucHJvdG90eXBlLmNvbnRhaW5zPWZ1bmN0aW9uKGxsKXtyZXR1cm4gdGhpcy5fdmFsaWQ/dGhpcy5fYmJveFswXTw9bGxbMF0mJnRoaXMuX2Jib3hbMV08PWxsWzFdJiZ0aGlzLl9iYm94WzJdPj1sbFswXSYmdGhpcy5fYmJveFszXT49bGxbMV06bnVsbH0sRXh0ZW50LnByb3RvdHlwZS5wb2x5Z29uPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3ZhbGlkP3t0eXBlOiJQb2x5Z29uIixjb29yZGluYXRlczpbW1t0aGlzLl9iYm94WzBdLHRoaXMuX2Jib3hbMV1dLFt0aGlzLl9iYm94WzJdLHRoaXMuX2Jib3hbMV1dLFt0aGlzLl9iYm94WzJdLHRoaXMuX2Jib3hbM11dLFt0aGlzLl9iYm94WzBdLHRoaXMuX2Jib3hbM11dLFt0aGlzLl9iYm94WzBdLHRoaXMuX2Jib3hbMV1dXV19Om51bGx9fSx7fV0sMzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUpe21vZHVsZS5leHBvcnRzPWZ1bmN0aW9uKGxpc3Qpe2Z1bmN0aW9uIF9mbGF0dGVuKGxpc3Qpe3JldHVybiBBcnJheS5pc0FycmF5KGxpc3QpJiZsaXN0Lmxlbmd0aCYmIm51bWJlciI9PXR5cGVvZiBsaXN0WzBdP1tsaXN0XTpsaXN0LnJlZHVjZShmdW5jdGlvbihhY2MsaXRlbSl7cmV0dXJuIEFycmF5LmlzQXJyYXkoaXRlbSkmJkFycmF5LmlzQXJyYXkoaXRlbVswXSk/YWNjLmNvbmNhdChfZmxhdHRlbihpdGVtKSk6KGFjYy5wdXNoKGl0ZW0pLGFjYyl9LFtdKX1yZXR1cm4gX2ZsYXR0ZW4obGlzdCl9fSx7fV0sNDpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUpe3ZhciBnZW9qc29uTm9ybWFsaXplPXJlcXVpcmUoImdlb2pzb24tbm9ybWFsaXplIiksZ2VvanNvbkZsYXR0ZW49cmVxdWlyZSgiZ2VvanNvbi1mbGF0dGVuIiksZmxhdHRlbj1yZXF1aXJlKCIuL2ZsYXR0ZW4iKTttb2R1bGUuZXhwb3J0cz1mdW5jdGlvbihfKXtpZighXylyZXR1cm5bXTt2YXIgbm9ybWFsaXplZD1nZW9qc29uRmxhdHRlbihnZW9qc29uTm9ybWFsaXplKF8pKSxjb29yZGluYXRlcz1bXTtyZXR1cm4gbm9ybWFsaXplZC5mZWF0dXJlcy5mb3JFYWNoKGZ1bmN0aW9uKGZlYXR1cmUpe2ZlYXR1cmUuZ2VvbWV0cnkmJihjb29yZGluYXRlcz1jb29yZGluYXRlcy5jb25jYXQoZmxhdHRlbihmZWF0dXJlLmdlb21ldHJ5LmNvb3JkaW5hdGVzKSkpfSksY29vcmRpbmF0ZXN9fSx7Ii4vZmxhdHRlbiI6MywiZ2VvanNvbi1mbGF0dGVuIjo1LCJnZW9qc29uLW5vcm1hbGl6ZSI6Nn1dLDU6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlKXtmdW5jdGlvbiBmbGF0dGVuKGdqKXtzd2l0Y2goZ2omJmdqLnR5cGV8fG51bGwpe2Nhc2UiRmVhdHVyZUNvbGxlY3Rpb24iOnJldHVybiBnai5mZWF0dXJlcz1nai5mZWF0dXJlcy5yZWR1Y2UoZnVuY3Rpb24obWVtLGZlYXR1cmUpe3JldHVybiBtZW0uY29uY2F0KGZsYXR0ZW4oZmVhdHVyZSkpfSxbXSksZ2o7Y2FzZSJGZWF0dXJlIjpyZXR1cm4gZmxhdHRlbihnai5nZW9tZXRyeSkubWFwKGZ1bmN0aW9uKGdlb20pe3JldHVybnt0eXBlOiJGZWF0dXJlIixwcm9wZXJ0aWVzOkpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZ2oucHJvcGVydGllcykpLGdlb21ldHJ5Omdlb219fSk7Y2FzZSJNdWx0aVBvaW50IjpyZXR1cm4gZ2ouY29vcmRpbmF0ZXMubWFwKGZ1bmN0aW9uKF8pe3JldHVybnt0eXBlOiJQb2ludCIsY29vcmRpbmF0ZXM6X319KTtjYXNlIk11bHRpUG9seWdvbiI6cmV0dXJuIGdqLmNvb3JkaW5hdGVzLm1hcChmdW5jdGlvbihfKXtyZXR1cm57dHlwZToiUG9seWdvbiIsY29vcmRpbmF0ZXM6X319KTtjYXNlIk11bHRpTGluZVN0cmluZyI6cmV0dXJuIGdqLmNvb3JkaW5hdGVzLm1hcChmdW5jdGlvbihfKXtyZXR1cm57dHlwZToiTGluZVN0cmluZyIsY29vcmRpbmF0ZXM6X319KTtjYXNlIkdlb21ldHJ5Q29sbGVjdGlvbiI6cmV0dXJuIGdqLmdlb21ldHJpZXM7Y2FzZSJQb2ludCI6Y2FzZSJQb2x5Z29uIjpjYXNlIkxpbmVTdHJpbmciOnJldHVybltnal07ZGVmYXVsdDpyZXR1cm4gZ2p9fW1vZHVsZS5leHBvcnRzPWZsYXR0ZW59LHt9XSw2OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSl7ZnVuY3Rpb24gbm9ybWFsaXplKGdqKXtpZighZ2p8fCFnai50eXBlKXJldHVybiBudWxsO3ZhciB0eXBlPXR5cGVzW2dqLnR5cGVdO3JldHVybiB0eXBlPyJnZW9tZXRyeSI9PT10eXBlP3t0eXBlOiJGZWF0dXJlQ29sbGVjdGlvbiIsZmVhdHVyZXM6W3t0eXBlOiJGZWF0dXJlIixwcm9wZXJ0aWVzOnt9LGdlb21ldHJ5OmdqfV19OiJmZWF0dXJlIj09PXR5cGU/e3R5cGU6IkZlYXR1cmVDb2xsZWN0aW9uIixmZWF0dXJlczpbZ2pdfToiZmVhdHVyZWNvbGxlY3Rpb24iPT09dHlwZT9najp2b2lkIDA6bnVsbH1tb2R1bGUuZXhwb3J0cz1ub3JtYWxpemU7dmFyIHR5cGVzPXtQb2ludDoiZ2VvbWV0cnkiLE11bHRpUG9pbnQ6Imdlb21ldHJ5IixMaW5lU3RyaW5nOiJnZW9tZXRyeSIsTXVsdGlMaW5lU3RyaW5nOiJnZW9tZXRyeSIsUG9seWdvbjoiZ2VvbWV0cnkiLE11bHRpUG9seWdvbjoiZ2VvbWV0cnkiLEdlb21ldHJ5Q29sbGVjdGlvbjoiZ2VvbWV0cnkiLEZlYXR1cmU6ImZlYXR1cmUiLEZlYXR1cmVDb2xsZWN0aW9uOiJmZWF0dXJlY29sbGVjdGlvbiJ9fSx7fV0sNzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUpe2Z1bmN0aW9uIFRyYXZlcnNlKG9iail7dGhpcy52YWx1ZT1vYmp9ZnVuY3Rpb24gd2Fsayhyb290LGNiLGltbXV0YWJsZSl7dmFyIHBhdGg9W10scGFyZW50cz1bXSxhbGl2ZT0hMDtyZXR1cm4gZnVuY3Rpb24gd2Fsa2VyKG5vZGVfKXtmdW5jdGlvbiB1cGRhdGVTdGF0ZSgpe2lmKCJvYmplY3QiPT10eXBlb2Ygc3RhdGUubm9kZSYmbnVsbCE9PXN0YXRlLm5vZGUpe3N0YXRlLmtleXMmJnN0YXRlLm5vZGVfPT09c3RhdGUubm9kZXx8KHN0YXRlLmtleXM9b2JqZWN0S2V5cyhzdGF0ZS5ub2RlKSksc3RhdGUuaXNMZWFmPTA9PXN0YXRlLmtleXMubGVuZ3RoO2Zvcih2YXIgaT0wO2k8cGFyZW50cy5sZW5ndGg7aSsrKWlmKHBhcmVudHNbaV0ubm9kZV89PT1ub2RlXyl7c3RhdGUuY2lyY3VsYXI9cGFyZW50c1tpXTticmVha319ZWxzZSBzdGF0ZS5pc0xlYWY9ITAsc3RhdGUua2V5cz1udWxsO3N0YXRlLm5vdExlYWY9IXN0YXRlLmlzTGVhZixzdGF0ZS5ub3RSb290PSFzdGF0ZS5pc1Jvb3R9dmFyIG5vZGU9aW1tdXRhYmxlP2NvcHkobm9kZV8pOm5vZGVfLG1vZGlmaWVycz17fSxrZWVwR29pbmc9ITAsc3RhdGU9e25vZGU6bm9kZSxub2RlXzpub2RlXyxwYXRoOltdLmNvbmNhdChwYXRoKSxwYXJlbnQ6cGFyZW50c1twYXJlbnRzLmxlbmd0aC0xXSxwYXJlbnRzOnBhcmVudHMsa2V5OnBhdGguc2xpY2UoLTEpWzBdLGlzUm9vdDowPT09cGF0aC5sZW5ndGgsbGV2ZWw6cGF0aC5sZW5ndGgsY2lyY3VsYXI6bnVsbCx1cGRhdGU6ZnVuY3Rpb24oeCxzdG9wSGVyZSl7c3RhdGUuaXNSb290fHwoc3RhdGUucGFyZW50Lm5vZGVbc3RhdGUua2V5XT14KSxzdGF0ZS5ub2RlPXgsc3RvcEhlcmUmJihrZWVwR29pbmc9ITEpfSwiZGVsZXRlIjpmdW5jdGlvbihzdG9wSGVyZSl7ZGVsZXRlIHN0YXRlLnBhcmVudC5ub2RlW3N0YXRlLmtleV0sc3RvcEhlcmUmJihrZWVwR29pbmc9ITEpfSxyZW1vdmU6ZnVuY3Rpb24oc3RvcEhlcmUpe2lzQXJyYXkoc3RhdGUucGFyZW50Lm5vZGUpP3N0YXRlLnBhcmVudC5ub2RlLnNwbGljZShzdGF0ZS5rZXksMSk6ZGVsZXRlIHN0YXRlLnBhcmVudC5ub2RlW3N0YXRlLmtleV0sc3RvcEhlcmUmJihrZWVwR29pbmc9ITEpfSxrZXlzOm51bGwsYmVmb3JlOmZ1bmN0aW9uKGYpe21vZGlmaWVycy5iZWZvcmU9Zn0sYWZ0ZXI6ZnVuY3Rpb24oZil7bW9kaWZpZXJzLmFmdGVyPWZ9LHByZTpmdW5jdGlvbihmKXttb2RpZmllcnMucHJlPWZ9LHBvc3Q6ZnVuY3Rpb24oZil7bW9kaWZpZXJzLnBvc3Q9Zn0sc3RvcDpmdW5jdGlvbigpe2FsaXZlPSExfSxibG9jazpmdW5jdGlvbigpe2tlZXBHb2luZz0hMX19O2lmKCFhbGl2ZSlyZXR1cm4gc3RhdGU7dXBkYXRlU3RhdGUoKTt2YXIgcmV0PWNiLmNhbGwoc3RhdGUsc3RhdGUubm9kZSk7cmV0dXJuIHZvaWQgMCE9PXJldCYmc3RhdGUudXBkYXRlJiZzdGF0ZS51cGRhdGUocmV0KSxtb2RpZmllcnMuYmVmb3JlJiZtb2RpZmllcnMuYmVmb3JlLmNhbGwoc3RhdGUsc3RhdGUubm9kZSksa2VlcEdvaW5nPygib2JqZWN0IiE9dHlwZW9mIHN0YXRlLm5vZGV8fG51bGw9PT1zdGF0ZS5ub2RlfHxzdGF0ZS5jaXJjdWxhcnx8KHBhcmVudHMucHVzaChzdGF0ZSksdXBkYXRlU3RhdGUoKSxmb3JFYWNoKHN0YXRlLmtleXMsZnVuY3Rpb24oa2V5LGkpe3BhdGgucHVzaChrZXkpLG1vZGlmaWVycy5wcmUmJm1vZGlmaWVycy5wcmUuY2FsbChzdGF0ZSxzdGF0ZS5ub2RlW2tleV0sa2V5KTt2YXIgY2hpbGQ9d2Fsa2VyKHN0YXRlLm5vZGVba2V5XSk7aW1tdXRhYmxlJiZoYXNPd25Qcm9wZXJ0eS5jYWxsKHN0YXRlLm5vZGUsa2V5KSYmKHN0YXRlLm5vZGVba2V5XT1jaGlsZC5ub2RlKSxjaGlsZC5pc0xhc3Q9aT09c3RhdGUua2V5cy5sZW5ndGgtMSxjaGlsZC5pc0ZpcnN0PTA9PWksbW9kaWZpZXJzLnBvc3QmJm1vZGlmaWVycy5wb3N0LmNhbGwoc3RhdGUsY2hpbGQpLHBhdGgucG9wKCl9KSxwYXJlbnRzLnBvcCgpKSxtb2RpZmllcnMuYWZ0ZXImJm1vZGlmaWVycy5hZnRlci5jYWxsKHN0YXRlLHN0YXRlLm5vZGUpLHN0YXRlKTpzdGF0ZX0ocm9vdCkubm9kZX1mdW5jdGlvbiBjb3B5KHNyYyl7aWYoIm9iamVjdCI9PXR5cGVvZiBzcmMmJm51bGwhPT1zcmMpe3ZhciBkc3Q7aWYoaXNBcnJheShzcmMpKWRzdD1bXTtlbHNlIGlmKGlzRGF0ZShzcmMpKWRzdD1uZXcgRGF0ZShzcmMuZ2V0VGltZT9zcmMuZ2V0VGltZSgpOnNyYyk7ZWxzZSBpZihpc1JlZ0V4cChzcmMpKWRzdD1uZXcgUmVnRXhwKHNyYyk7ZWxzZSBpZihpc0Vycm9yKHNyYykpZHN0PXttZXNzYWdlOnNyYy5tZXNzYWdlfTtlbHNlIGlmKGlzQm9vbGVhbihzcmMpKWRzdD1uZXcgQm9vbGVhbihzcmMpO2Vsc2UgaWYoaXNOdW1iZXIoc3JjKSlkc3Q9bmV3IE51bWJlcihzcmMpO2Vsc2UgaWYoaXNTdHJpbmcoc3JjKSlkc3Q9bmV3IFN0cmluZyhzcmMpO2Vsc2UgaWYoT2JqZWN0LmNyZWF0ZSYmT2JqZWN0LmdldFByb3RvdHlwZU9mKWRzdD1PYmplY3QuY3JlYXRlKE9iamVjdC5nZXRQcm90b3R5cGVPZihzcmMpKTtlbHNlIGlmKHNyYy5jb25zdHJ1Y3Rvcj09PU9iamVjdClkc3Q9e307ZWxzZXt2YXIgcHJvdG89c3JjLmNvbnN0cnVjdG9yJiZzcmMuY29uc3RydWN0b3IucHJvdG90eXBlfHxzcmMuX19wcm90b19ffHx7fSxUPWZ1bmN0aW9uKCl7fTtULnByb3RvdHlwZT1wcm90byxkc3Q9bmV3IFR9cmV0dXJuIGZvckVhY2gob2JqZWN0S2V5cyhzcmMpLGZ1bmN0aW9uKGtleSl7ZHN0W2tleV09c3JjW2tleV19KSxkc3R9cmV0dXJuIHNyY31mdW5jdGlvbiB0b1Mob2JqKXtyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iail9ZnVuY3Rpb24gaXNEYXRlKG9iail7cmV0dXJuIltvYmplY3QgRGF0ZV0iPT09dG9TKG9iail9ZnVuY3Rpb24gaXNSZWdFeHAob2JqKXtyZXR1cm4iW29iamVjdCBSZWdFeHBdIj09PXRvUyhvYmopfWZ1bmN0aW9uIGlzRXJyb3Iob2JqKXtyZXR1cm4iW29iamVjdCBFcnJvcl0iPT09dG9TKG9iail9ZnVuY3Rpb24gaXNCb29sZWFuKG9iail7cmV0dXJuIltvYmplY3QgQm9vbGVhbl0iPT09dG9TKG9iail9ZnVuY3Rpb24gaXNOdW1iZXIob2JqKXtyZXR1cm4iW29iamVjdCBOdW1iZXJdIj09PXRvUyhvYmopfWZ1bmN0aW9uIGlzU3RyaW5nKG9iail7cmV0dXJuIltvYmplY3QgU3RyaW5nXSI9PT10b1Mob2JqKX12YXIgdHJhdmVyc2U9bW9kdWxlLmV4cG9ydHM9ZnVuY3Rpb24ob2JqKXtyZXR1cm4gbmV3IFRyYXZlcnNlKG9iail9O1RyYXZlcnNlLnByb3RvdHlwZS5nZXQ9ZnVuY3Rpb24ocHMpe2Zvcih2YXIgbm9kZT10aGlzLnZhbHVlLGk9MDtpPHBzLmxlbmd0aDtpKyspe3ZhciBrZXk9cHNbaV07aWYoIW5vZGV8fCFoYXNPd25Qcm9wZXJ0eS5jYWxsKG5vZGUsa2V5KSl7bm9kZT12b2lkIDA7YnJlYWt9bm9kZT1ub2RlW2tleV19cmV0dXJuIG5vZGV9LFRyYXZlcnNlLnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24ocHMpe2Zvcih2YXIgbm9kZT10aGlzLnZhbHVlLGk9MDtpPHBzLmxlbmd0aDtpKyspe3ZhciBrZXk9cHNbaV07aWYoIW5vZGV8fCFoYXNPd25Qcm9wZXJ0eS5jYWxsKG5vZGUsa2V5KSlyZXR1cm4hMTtub2RlPW5vZGVba2V5XX1yZXR1cm4hMH0sVHJhdmVyc2UucHJvdG90eXBlLnNldD1mdW5jdGlvbihwcyx2YWx1ZSl7Zm9yKHZhciBub2RlPXRoaXMudmFsdWUsaT0wO2k8cHMubGVuZ3RoLTE7aSsrKXt2YXIga2V5PXBzW2ldO2hhc093blByb3BlcnR5LmNhbGwobm9kZSxrZXkpfHwobm9kZVtrZXldPXt9KSxub2RlPW5vZGVba2V5XX1yZXR1cm4gbm9kZVtwc1tpXV09dmFsdWUsdmFsdWV9LFRyYXZlcnNlLnByb3RvdHlwZS5tYXA9ZnVuY3Rpb24oY2Ipe3JldHVybiB3YWxrKHRoaXMudmFsdWUsY2IsITApfSxUcmF2ZXJzZS5wcm90b3R5cGUuZm9yRWFjaD1mdW5jdGlvbihjYil7cmV0dXJuIHRoaXMudmFsdWU9d2Fsayh0aGlzLnZhbHVlLGNiLCExKSx0aGlzLnZhbHVlfSxUcmF2ZXJzZS5wcm90b3R5cGUucmVkdWNlPWZ1bmN0aW9uKGNiLGluaXQpe3ZhciBza2lwPTE9PT1hcmd1bWVudHMubGVuZ3RoLGFjYz1za2lwP3RoaXMudmFsdWU6aW5pdDtyZXR1cm4gdGhpcy5mb3JFYWNoKGZ1bmN0aW9uKHgpe3RoaXMuaXNSb290JiZza2lwfHwoYWNjPWNiLmNhbGwodGhpcyxhY2MseCkpfSksYWNjfSxUcmF2ZXJzZS5wcm90b3R5cGUucGF0aHM9ZnVuY3Rpb24oKXt2YXIgYWNjPVtdO3JldHVybiB0aGlzLmZvckVhY2goZnVuY3Rpb24oKXthY2MucHVzaCh0aGlzLnBhdGgpfSksYWNjfSxUcmF2ZXJzZS5wcm90b3R5cGUubm9kZXM9ZnVuY3Rpb24oKXt2YXIgYWNjPVtdO3JldHVybiB0aGlzLmZvckVhY2goZnVuY3Rpb24oKXthY2MucHVzaCh0aGlzLm5vZGUpfSksYWNjfSxUcmF2ZXJzZS5wcm90b3R5cGUuY2xvbmU9ZnVuY3Rpb24oKXt2YXIgcGFyZW50cz1bXSxub2Rlcz1bXTtyZXR1cm4gZnVuY3Rpb24gY2xvbmUoc3JjKXtmb3IodmFyIGk9MDtpPHBhcmVudHMubGVuZ3RoO2krKylpZihwYXJlbnRzW2ldPT09c3JjKXJldHVybiBub2Rlc1tpXTtpZigib2JqZWN0Ij09dHlwZW9mIHNyYyYmbnVsbCE9PXNyYyl7dmFyIGRzdD1jb3B5KHNyYyk7cmV0dXJuIHBhcmVudHMucHVzaChzcmMpLG5vZGVzLnB1c2goZHN0KSxmb3JFYWNoKG9iamVjdEtleXMoc3JjKSxmdW5jdGlvbihrZXkpe2RzdFtrZXldPWNsb25lKHNyY1trZXldKX0pLHBhcmVudHMucG9wKCksbm9kZXMucG9wKCksZHN0fXJldHVybiBzcmN9KHRoaXMudmFsdWUpfTt2YXIgb2JqZWN0S2V5cz1PYmplY3Qua2V5c3x8ZnVuY3Rpb24ob2JqKXt2YXIgcmVzPVtdO2Zvcih2YXIga2V5IGluIG9iailyZXMucHVzaChrZXkpO3JldHVybiByZXN9LGlzQXJyYXk9QXJyYXkuaXNBcnJheXx8ZnVuY3Rpb24oeHMpe3JldHVybiJbb2JqZWN0IEFycmF5XSI9PT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoeHMpfSxmb3JFYWNoPWZ1bmN0aW9uKHhzLGZuKXtpZih4cy5mb3JFYWNoKXJldHVybiB4cy5mb3JFYWNoKGZuKTtmb3IodmFyIGk9MDtpPHhzLmxlbmd0aDtpKyspZm4oeHNbaV0saSx4cyl9O2ZvckVhY2gob2JqZWN0S2V5cyhUcmF2ZXJzZS5wcm90b3R5cGUpLGZ1bmN0aW9uKGtleSl7dHJhdmVyc2Vba2V5XT1mdW5jdGlvbihvYmope3ZhciBhcmdzPVtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpLHQ9bmV3IFRyYXZlcnNlKG9iaik7cmV0dXJuIHRba2V5XS5hcHBseSh0LGFyZ3MpfX0pO3ZhciBoYXNPd25Qcm9wZXJ0eT1PYmplY3QuaGFzT3duUHJvcGVydHl8fGZ1bmN0aW9uKG9iaixrZXkpe3JldHVybiBrZXkgaW4gb2JqfX0se31dfSx7fSxbMV0pKDEpfSk7ICAgIAogICAgdmFyIGNvbW1lbnQgPSAiIjsKICAgIG1hcGJveGdsLmFjY2Vzc1Rva2VuPSJway5leUoxSWpvaWJXRndZbTk0SWl3aVlTSTZJbU5wZWpZNE0yOWlhekEyWjJneWNYQTROMnBtYkRabWFuZ2lmUS4tZ192RTUzU0QyV3JKNnRGWDdRSG1BIjsKICAgIHZhciBtYXBkYXRhID0gbnVsbDsKICAgIHZhciBtYXAgPSBuZXcgbWFwYm94Z2wuTWFwKHsKICAgICAgICBjb250YWluZXI6ICJtYXAtNTdmZDQwMzctMTk1ZWE5M2MiLAogICAgICAgIHN0eWxlOiAibWFwYm94Oi8vc3R5bGVzL21hcGJveC9kYXJrLXY5IgogICAgfSk7CgogICAgc2V0VGltZW91dChmdW5jdGlvbigpewogICAgICAgIGlmICh3aW5kb3cuYWRkUERNZXNzYWdlTGlzdGVuZXIpewogICAgICAgICAgICB3aW5kb3cuYWRkUERNZXNzYWdlTGlzdGVuZXIoZnVuY3Rpb24oZXZlbnQpewogICAgICAgICAgICAgICAgc3RyZWFtaW5nTGF5ZXIgPSBtYXAuZ2V0U291cmNlKCJzdHJlYW1pbmdMYXllciIpOwogICAgICAgICAgICAgICAgaWYgKHN0cmVhbWluZ0xheWVyKXsKICAgICAgICAgICAgICAgICAgICBzdHJlYW1pbmdMYXllci5zZXREYXRhKGV2ZW50LmRhdGEuZGF0YSk7CiAgICAgICAgICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgICAgICAgICBtYXAuYWRkTGF5ZXIoewogICAgICAgICAgICAgICAgICAgICAgICAiaWQiOiAic3RyZWFtaW5nTGF5ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAibWFwdHlwZSI6ICJtYXBib3giLAogICAgICAgICAgICAgICAgICAgICAgICAidHlwZSI6IGV2ZW50LmRhdGEudHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgInNvdXJjZSI6IHsgdHlwZTogImdlb2pzb24iLCBkYXRhOiBldmVudC5kYXRhLmRhdGEgfSwKICAgICAgICAgICAgICAgICAgICAgICAgImxheW91dCI6IGV2ZW50LmRhdGEubGF5b3V0IHx8IHt9LAogICAgICAgICAgICAgICAgICAgICAgICAicGFpbnQiOiBldmVudC5kYXRhLnBhaW50IHx8IHt9CiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGV2ZW50LmRhdGEuZml0Ym91bmRzICYmIGV2ZW50LmRhdGEuZGF0YS5mZWF0dXJlcyl7CiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIHVwZGF0ZUJvdW5kcyhyZXMsIGFyKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhclswXS5sZW5ndGggPj0yICYmIGFyWzFdLmxlbmd0aCA+PSAyICl7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXMpewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYXI7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBbIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbTWF0aC5taW4oIGFyWzBdWzBdLTAuMSwgcmVzWzBdWzBdKSwgTWF0aC5taW4oIGFyWzBdWzFdLTAuMSwgcmVzWzBdWzFdKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtNYXRoLm1heCggYXJbMV1bMF0rMC4xLCByZXNbMV1bMF0pLCBNYXRoLm1heCggYXJbMV1bMV0rMC4xLCByZXNbMV1bMV0pXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBiYm94ID0gZXZlbnQuZGF0YS5kYXRhLmZlYXR1cmVzLnJlZHVjZShmdW5jdGlvbihyZXMsIHZhbHVlKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjb29yZCA9IHZhbHVlLmdlb21ldHJ5LmNvb3JkaW5hdGVzOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvb3JkLmxlbmd0aCA+PSAyICl7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzID0gdXBkYXRlQm91bmRzKCByZXMsIFtjb29yZFswXSwgY29vcmRbMV1dKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXM7CiAgICAgICAgICAgICAgICAgICAgICAgIH0sIG51bGwpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoYmJveCl7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXAuZml0Qm91bmRzKGJib3gpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9OwogICAgfSwxMDApOwoKICAgIHZhciBwb3B1cCA9IG5ldyBtYXBib3hnbC5Qb3B1cCh7Y2xvc2VCdXR0b246IGZhbHNlLGNsb3NlT25DbGljazogdHJ1ZX0pOwoKICAgIGZ1bmN0aW9uIGRpdmluZUdlb21ldHJ5VHlwZShtYXBkYXRhKSB7CiAgICAgICAgY29tbWVudCA9ICJjaGVjayB0eXBlIG9mIGZpcnN0IGdlb21ldHJ5LiBMYXRlciBleHBhbmQgdG8gY2hlY2sgYWxsIGdlb21ldHJpZXMgYW5kIG1ha2UgYSBnb29kIGRlY2lzaW9uIjsKICAgICAgICByZXR1cm4gbWFwZGF0YS5mZWF0dXJlc1swXS5nZW9tZXRyeS50eXBlOwogICAgfQogICAgCiAgICBtYXAub24oIm1vdXNlbW92ZSIsIGZ1bmN0aW9uIChlKSB7CiAgICAgICAgdmFyIGZzID0gbWFwLnF1ZXJ5UmVuZGVyZWRGZWF0dXJlcyhlLnBvaW50LHtsYXllcnM6WyJweGxheWVyIl19KTsKICAgICAgICBpZiAoIWZzIHx8ICFmcy5sZW5ndGgpIHtwb3B1cC5yZW1vdmUoKTtyZXR1cm47fTsKICAgICAgICBwb3B1cGh0bWwgPSAiIjsKICAgICAgICB2YXIgaHIgPSBmYWxzZTsKICAgICAgICBmcy5mb3JFYWNoKGZ1bmN0aW9uKGYpewogICAgICAgICAgICBpZiAoaHIpeyAKICAgICAgICAgICAgICAgIHBvcHVwaHRtbCArPSAiPGhyPlxuIjsKICAgICAgICAgICAgfQogICAgICAgICAgICBocj10cnVlOwogICAgICAgICAgICBwb3B1cGh0bWwgKz0gIjxoMz4iK2YubGF5ZXIuaWQudG9VcHBlckNhc2UoKSsiPC9oMz5cbiI7CiAgICAgICAgICAgIHZhciBrZXlsZW5ndGggPSBPYmplY3Qua2V5cyhmLnByb3BlcnRpZXMpLmxlbmd0aDsKICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIGYucHJvcGVydGllcykgewogICAgICAgICAgICAgICAgcG9wdXBodG1sICs9ICI8Yj4iK2tleSsiOiA8L2I+ICIrZi5wcm9wZXJ0aWVzW2tleV0rIjxici8+XG4iOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgcG9wdXAuc2V0TG5nTGF0KGUubG5nTGF0KS5zZXRIVE1MKHBvcHVwaHRtbCkuYWRkVG8obWFwKTsKICAgIH0pOwogICAgCiAgICBtYXAub24oImNsaWNrIiwgZnVuY3Rpb24gKGUpIHsKICAgICAgICB2YXIgZnMgPSBtYXAucXVlcnlSZW5kZXJlZEZlYXR1cmVzKGUucG9pbnQsIHsgbGF5ZXJzOiBbInB4bGF5ZXIiXSB9KTsKICAgICAgICBpZiAoZnMgJiYgZnMubGVuZ3RoKSB7CiAgICAgICAgICAgIHZhciBmID0gZnNbMF07CiAgICAgICAgICAgIGNvbnNvbGUubG9nKCJjbGlja2VkIiwgZik7CiAgICAgICAgICAgIHZhciBrZXlsZW5ndGggPSBPYmplY3Qua2V5cyhmLnByb3BlcnRpZXMpLmxlbmd0aDsKICAgICAgICAgICAgdmFyIHBheWxvYWQgPSB7dHlwZToic2VsZWN0IiwgdGFyZ2V0RGl2SWQ6ICIiIH07CgogICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gZi5wcm9wZXJ0aWVzKSB7CiAgICAgICAgICAgICAgICBwYXlsb2FkW2tleV0gPSBmLnByb3BlcnRpZXNba2V5XTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKHdpbmRvdy50cmlnZ2VyUERFdmVudCkgewogICAgICAgICAgICAgICAgd2luZG93LnRyaWdnZXJQREV2ZW50KHBheWxvYWQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfSk7CiAgICAgICAgCiAgICBtYXAub24oImxvYWQiLCBmdW5jdGlvbigpIHsKICAgICAgICAKICAgICAgICBtYXBkYXRhPXsidHlwZSI6ICJGZWF0dXJlQ29sbGVjdGlvbiIsICJmZWF0dXJlcyI6IFt7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJBdXN0cmFsaWEsIE5TVywgU3lkbmV5In0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsxNTEuMjA5Mjk2LCAtMzMuODY4ODJdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIkJyYXppbCwgU1AsIFNhbyBQYXVsbyJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTQ2LjYzMzMwOTAwMDAwMDAwNCwgLTIzLjU1MDUyMDAwMDAwMDAwMl19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiQ2FuYWRhLCBCQywgVmFuY291dmVyIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTIzLjEyMDczNzk5OTk5OTk5LCA0OS4yODI3Mjg5OTk5OTk5OTZdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIkNhbmFkYSwgT04sIFRvcm9udG8ifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWy03OS4zODMxODQsIDQzLjY1MzIyNjAwMDAwMDAwNF19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiQ2hpbmEsIDExLCBCZWlqaW5nIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsxMTYuMjMwNDYyMDAwMDAwMDIsIDQwLjIzNzM1Ml19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiQ2hpbmEsIDMxLCBTaGFuZ2hhaSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTg2LjA4NzY0NCwgNDIuNzY4MTk3XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJGcmFuY2UsIENvdXJiZXZvaWUifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzIuMjU5MjksIDQ4LjkwMDU1MjAwMDAwMDAwNV19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiR2VybWFueSwgQWFjaGVuIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFs2LjA4Mzg4NywgNTAuNzc1MzQ2XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJHZXJtYW55LCBCRSwgQmVybGluIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsxMy40MDQ5NTQsIDUyLjUyMDAwNjk5OTk5OTk5XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJHZXJtYW55LCBCWSwgTXVuaWNoIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsxMS41ODE5OCwgNDguMTM1MTI1XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJIb25nIEtvbmcsIENhdXNld2F5IEJheSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbMTE0LjE5MTQ5MiwgMjIuMjg1OTc5XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJJbmRpYSwgSFIsIEd1cmdhb24ifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzc3LjAyNjYzOCwgMjguNDU5NDk3XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJJbmRpYSwgS0EsIEJhbmdhbG9yZSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbNzcuNTk0NTYzLCAxMi45NzE1OTkwMDAwMDAwMDFdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIkluZGlhLCBUTiwgQ2hlbm5haSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbODAuMjcwNzE4LCAxMy4wODI2OF19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiSW5kaWEsIFRTLCBIeWRlcmFiYWQifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzc4LjQ4NjY3MSwgMTcuMzg1MDQ0XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJJcmVsYW5kLCBEVUJMSU4sIER1YmxpbiJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTYuMjYwMzEsIDUzLjM0OTgwNV19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiSXNyYWVsLCBIYWlmYSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbMzQuOTg5NTcxMDAwMDAwMDA1LCAzMi43OTQwNDZdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIklzcmFlbCwgVGVsIEF2aXYifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzM0Ljc4MTc2OCwgMzIuMDg1M119fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiSmFwYW4sIFRva3lvIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsxMzkuNjkxNzA2LCAzNS42ODk0ODhdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIkpvcmRhbiwgQW1tYW4ifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzM1LjkyODM3MTk5OTk5OTk5NiwgMzEuOTQ1MzY2OTk5OTk5OTk3XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJMdXhlbWJvdXJnLCBMdXhlbWJvdXJnIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFs2LjEzMTkzNDk5OTk5OTk5OTUsIDQ5LjYxMTYyMV19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiUG9sYW5kLCBHZGFuc2sifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzE4LjY0NjYzOCwgNTQuMzUyMDI1XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJSb21hbmlhLCBJYXNpIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFsyNy42MDE0NDIsIDQ3LjE1ODQ1NV19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiU2luZ2Fwb3JlLCBTaW5nYXBvcmUifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzEwMy44MTk4MzYsIDEuMzUyMDgzXX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJTb3V0aCBBZnJpY2EsIENhcGUgVG93biJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbMTguNDI0MDU1LCAtMzMuOTI0ODY4XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJTcGFpbiwgMjgsIE1hZHJpZCJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTMuNjg1NzU4MDAwMDAwMDAwMywgNDAuNDI3NTY2OTk5OTk5OTk2XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJTd2VkZW4sIFN0b2NraG9sbSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbMTguMDY4NTgxLCA1OS4zMjkzMjI5OTk5OTk5OTVdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVLLCBDYW1icmlkZ2UifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWzAuMTIxODE3MDAwMDAwMDAwMDEsIDUyLjIwNTMzN119fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiVUssIEVkaW5idXJnaCJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTMuMTg4MjY2OTk5OTk5OTk5NywgNTUuOTUzMjUyXX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVSywgTG9uZG9uIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMC4xMjc3NTc5OTk5OTk5OTk5OCwgNTEuNTA3MzUxXX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBBWiwgVGVtcGUifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWy0xMTEuOTQwMDA1LCAzMy40MjU1MDk5OTk5OTk5OTZdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIEJvc3RvbiwgTUEgQXJlYSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTcxLjEzNjc5NDk5OTk5OTk5LCA0Mi42NTgzMzZdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIENBLCBMb3MgQW5nZWxlcywgQ0EgQXJlYSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTExNy44MjY1MDUwMDAwMDAwMSwgMzMuNjg0NTY3XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBDQSwgU2FuIERpZWdvIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTE3LjE2MTA4NCwgMzIuNzE1NzM4XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBDQSwgU2FuIEZyYW5jaXNjbyJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTEyMi40MTk0MTYsIDM3Ljc3NDkzXX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBDQSwgU2FuIEx1aXMgT2Jpc3BvIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTIwLjY1OTYxNTk5OTk5OTk5LCAzNS4yODI3NTJdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIENBLCBTYW50YSBDcnV6In0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTIyLjAzMDc5NiwgMzYuOTc0MTE3XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBDTywgRGVudmVyIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTA0Ljk5MDI1MSwgMzkuNzM5MjM2XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBHQSwgQXRsYW50YSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTg0LjM4Nzk4MiwgMzMuNzQ4OTk1XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBJTCwgQ2hpY2FnbyJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTg3LjYyOTc5OCwgNDEuODc4MTE0MDAwMDAwMDA0XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBNSSwgRGV0cm9pdCJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTgzLjA0NTc1NCwgNDIuMzMxNDI3MDAwMDAwMDA1XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBNTiwgTWlubmVhcG9saXMifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWy05My4yNjUwMTEsIDQ0Ljk3Nzc1M119fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiVW5pdGVkIFN0YXRlcywgTlksIE5ldyBZb3JrIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstNzQuMTcyMzY3MDAwMDAwMDEsIDQwLjczNTY1N119fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiVW5pdGVkIFN0YXRlcywgT1IsIFBvcnRsYW5kIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTIyLjY1ODcxODk5OTk5OTk5LCA0NS41MTIyMzFdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIFBBLCBNYWx2ZXJuIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstNzUuNTEzODEyLCA0MC4wMzYyMThdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIFNhbiBKb3NlLCBDQSBBcmVhIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstMTIyLjAzMjE4MiwgMzcuMzIyOTk4XX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBUWCwgQXVzdGluIn0sICJnZW9tZXRyeSI6IHsidHlwZSI6ICJQb2ludCIsICJjb29yZGluYXRlcyI6IFstOTcuNzQzMDYxLCAzMC4yNjcxNTMwMDAwMDAwMDRdfX0sIHsidHlwZSI6ICJGZWF0dXJlIiwgInByb3BlcnRpZXMiOiB7InBkX2NvdW50IjogMSwgImxvY2F0aW9uIjogIlVuaXRlZCBTdGF0ZXMsIFRYLCBEYWxsYXMifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWy05Ni43OTY5ODgsIDMyLjc3NjY2NDAwMDAwMDAwNF19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiVW5pdGVkIFN0YXRlcywgVFgsIEhvdXN0b24ifSwgImdlb21ldHJ5IjogeyJ0eXBlIjogIlBvaW50IiwgImNvb3JkaW5hdGVzIjogWy05NS4zNjk4MDMsIDI5Ljc2MDQyNzAwMDAwMDAwNF19fSwgeyJ0eXBlIjogIkZlYXR1cmUiLCAicHJvcGVydGllcyI6IHsicGRfY291bnQiOiAxLCAibG9jYXRpb24iOiAiVW5pdGVkIFN0YXRlcywgVkEsIEFybGluZ3RvbiJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTc3LjEwNTM2NywgMzguODg1ODAxXX19LCB7InR5cGUiOiAiRmVhdHVyZSIsICJwcm9wZXJ0aWVzIjogeyJwZF9jb3VudCI6IDEsICJsb2NhdGlvbiI6ICJVbml0ZWQgU3RhdGVzLCBXQSwgU2VhdHRsZSJ9LCAiZ2VvbWV0cnkiOiB7InR5cGUiOiAiUG9pbnQiLCAiY29vcmRpbmF0ZXMiOiBbLTEyMi4yMDE1MTYsIDQ3LjYxMDE1XX19XX07CiAgICAgICAgZ2VvbXR5cGUgPSBkaXZpbmVHZW9tZXRyeVR5cGUobWFwZGF0YSk7CiAgICAgICAgCiAgICAgICAgICAgIHZhciBkcyA9IHsKICAgICAgICAgICAgICAgICJ0eXBlIjoiZ2VvanNvbiIsCiAgICAgICAgICAgICAgICAiZGF0YSI6bWFwZGF0YQogICAgICAgICAgICB9OwogICAgICAgICAgICB2YXIgY2x1c3Rlcm1lID0gZmFsc2U7CiAgICAgICAgICAgIGlmIChnZW9tdHlwZS5zdWJzdHIoLTUsNSkgPT0gIlBvaW50IikgewogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcm1lID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICBkc1siY2x1c3RlciJdID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICBkc1siY2x1c3Rlck1heFpvb20iXSA9IDE0OwogICAgICAgICAgICAgICAgICAgIGRzWyJjbHVzdGVyUmFkaXVzIl0gPSAyMDsKICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiSU0gQ0xVU1RFUkVEIik7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgfQogICAgICAgICAgICBtYXAuYWRkU291cmNlKCJweGRhdGFzb3VyY2UiLCBkcyk7CgogICAgICAgICAgICB2YXIgbWFwbGF5ZXJ0eXBlID0gImNpcmNsZSI7CiAgICAgICAgICAgIGlmIChnZW9tdHlwZS5zdWJzdHIoLTcsNykgPT0gIlBvbHlnb24iKSAKICAgICAgICAgICAgICAgIG1hcGxheWVydHlwZSA9ICJmaWxsIjsKICAgICAgICAgICAgZWxzZSBpZiAoZ2VvbXR5cGUuc3Vic3RyKC0xMCwxMCkgPT0gIkxpbmVTdHJpbmciKQogICAgICAgICAgICAgICAgbWFwbGF5ZXJ0eXBlID0gImxpbmUiOwogICAgICAgICAgICBtYXAuYWRkTGF5ZXIoewogICAgICAgICAgICAgICAgImlkIjoicHhsYXllciIsCiAgICAgICAgICAgICAgICAidHlwZSI6bWFwbGF5ZXJ0eXBlLCAKICAgICAgICAgICAgICAgICJzb3VyY2UiOiAicHhkYXRhc291cmNlIiwgCiAgICAgICAgICAgICAgICAicGFpbnQiOiB7ImNpcmNsZS1yYWRpdXMiOiAxMiwgImNpcmNsZS1jb2xvciI6IHsicHJvcGVydHkiOiAicGRfY291bnQiLCAic3RvcHMiOiBbWzEuMCwgIiNlNjYxMDEiXSwgWzEuMCwgIiNhY2Q2MGUiXSwgWzEuMCwgIiMxYWM2MWEiXSwgWzEuMCwgIiMyNmI3OTgiXSwgWzEuMCwgIiMzMTYzYTgiXSwgWzEuMCwgIiM1ZTNjOTkiXV19LCAiY2lyY2xlLW9wYWNpdHkiOiAxLjB9CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKGNsdXN0ZXJtZSAmJiBnZW9tdHlwZS5zdWJzdHIoLTUsNSkgPT0gIlBvaW50IikgewogICAgICAgICAgICAgICAgbWFwLmFkZExheWVyKHsKICAgICAgICAgICAgICAgICAgICAiaWQiOiAiY2x1c3Rlci1jb3VudC1sYWJlbHMiLCAKICAgICAgICAgICAgICAgICAgICAidHlwZSI6ICJzeW1ib2wiLCAKICAgICAgICAgICAgICAgICAgICAic291cmNlIjogInB4ZGF0YXNvdXJjZSIsIAogICAgICAgICAgICAgICAgICAgICJwYWludCI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgInRleHQtY29sb3IiOiAiI0ZGRiIKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICJsYXlvdXQiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJ0ZXh0LWZpZWxkIjogIntwb2ludF9jb3VudH0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgInRleHQtZm9udCI6IFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJESU4gT2ZmYyBQcm8gTWVkaXVtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJpYWwgVW5pY29kZSBNUyBCb2xkIgogICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAidGV4dC1zaXplIjogMTIKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgIAogICAgICAgIAoKICAgICAgICBjb21tZW50ID0gIkFkZCB1c2VyIGxheWVycyI7CiAgICAgICAgdmFyIGxheWVycyA9IFtdOwogICAgICAgIAogICAgICAgIGxheWVycy5zb3J0KGZ1bmN0aW9uKGEsYikgewogICAgICAgICAgICByZXR1cm4gYVsxXSAtIGJbMV07CiAgICAgICAgfSk7CiAgICAgICAgZm9yIChsYXllcnNpPWxheWVycy5sZW5ndGgtMTsgbGF5ZXJzaT49MDsgbGF5ZXJzaS0tKSB7CiAgICAgICAgICAgIG1hcC5hZGRMYXllcihsYXllcnNbbGF5ZXJzaV1bMF0pOwogICAgICAgICAgICBjb21tZW50ID0gIlVzZXIgbGF5ZXIgbGVnZW5kIjsKICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIAogICAgICAgIG1hcC5maXRCb3VuZHMoW1stMTIzLjEyMDczNzk5OTk5OTk5LCAtMzMuOTI0ODY4XSwgWzE1MS4yMDkyOTYsIDU5LjMyOTMyMjk5OTk5OTk5NV1dKTsKICAgICAgICAKICAgICAgICAKICAgIH0pOwo8L3NjcmlwdD4KPC9ib2R5Pgo8L2h0bWw+'));\n",
"</script>\n",
"\n",
" </div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(AmazonCitiesWithCoordinates)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" ## Fetching numbeo.com data using Amazon Mechanical Turk"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"pixiedust": {
"displayParams": {
"handlerId": "tableView",
"on": "jobSummary_Location",
"table_showrows": "All"
}
}
},
"outputs": [],
"source": [
"#I thought I'll compare it with Vancouver, that's why I requested Workers to get compareCityUrl from Numbeo.com as well.\n",
"#It turns it's not needed at all. Sorry guys.\n",
"numbeoMTurk = pd.read_csv(\"MTurk_CollectDataFromNumbeo_Preprocessed.csv\")\n",
"numbeoMTurk = numbeoMTurk.drop_duplicates(subset = 'location', keep='first')\n",
"for i in numbeoMTurk.index:\n",
" numbeoMTurk.at[i, 'location'] = unifyCity(numbeoMTurk.at[i, 'location'])\n",
"#numbeoMTurk = numbeoMTurk.groupby(['location', 'singleCityUrl', 'compareCityUrl']) \\\n",
"# .size() \\\n",
"# .to_frame('cnt') \\\n",
"# .reset_index() \\\n",
"# .sort_values(['cnt'], ascending=[True])\n",
"#numbeoMTurk\n",
"AmazonCitiesWithNumbeoLinks = AmazonCitiesWithCoordinates.join(numbeoMTurk.set_index('location'), on='location')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pixiedust": {
"displayParams": {
"handlerId": "tableView",
"table_showrows": "All"
}
},
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">.pd_warning{display:none;}</style><div class=\"pd_warning\"><em>Hey, there's something awesome here! To see it, open this notebook outside GitHub, in a viewer like Jupyter</em></div>\n",
" <div class=\"pd_save is-viewer-good\" style=\"padding-right:10px;text-align: center;line-height:initial !important;font-size: xx-large;font-weight: 500;color: coral;\">\n",
" \n",
" </div>\n",
" <div id=\"chartFigurec0cc7560\" class=\"pd_save is-viewer-good\" style=\"overflow-x:auto\">\n",
" <style type=\"text/css\" class=\"pd_save\">\n",
" .df-table-wrapper .panel-heading {\n",
" border-radius: 0;\n",
" padding: 0px;\n",
" }\n",
" .df-table-wrapper .panel-heading:hover {\n",
" border-color: #008571;\n",
" }\n",
" .df-table-wrapper .panel-title a {\n",
" background-color: #f9f9fb;\n",
" color: #333333;\n",
" display: block;\n",
" outline: none;\n",
" padding: 10px 15px;\n",
" text-decoration: none;\n",
" }\n",
" .df-table-wrapper .panel-title a:hover {\n",
" background-color: #337ab7;\n",
" border-color: #2e6da4;\n",
" color: #ffffff;\n",
" display: block;\n",
" padding: 10px 15px;\n",
" text-decoration: none;\n",
" }\n",
" .df-table-wrapper {\n",
" font-size: small;\n",
" font-weight: 300;\n",
" letter-spacing: 0.5px;\n",
" line-height: normal;\n",
" height: inherit;\n",
" overflow: auto;\n",
" }\n",
" .df-table-search {\n",
" margin: 0 0 20px 0;\n",
" }\n",
" .df-table-search-count {\n",
" display: inline-block;\n",
" margin: 0 0 20px 0;\n",
" }\n",
" .df-table-container {\n",
" max-height: 50vh;\n",
" max-width: 100%;\n",
" overflow-x: auto;\n",
" position: relative;\n",
" }\n",
" .df-table-wrapper table {\n",
" border: 0 none #ffffff;\n",
" border-collapse: collapse;\n",
" margin: 0;\n",
" min-width: 100%;\n",
" padding: 0;\n",
" table-layout: fixed;\n",
" height: inherit;\n",
" overflow: auto;\n",
" }\n",
" .df-table-wrapper tr.hidden {\n",
" display: none;\n",
" }\n",
" .df-table-wrapper tr:nth-child(even) {\n",
" background-color: #f9f9fb;\n",
" }\n",
" .df-table-wrapper tr.even {\n",
" background-color: #f9f9fb;\n",
" }\n",
" .df-table-wrapper tr.odd {\n",
" background-color: #ffffff;\n",
" }\n",
" .df-table-wrapper td + td {\n",
" border-left: 1px solid #e0e0e0;\n",
" }\n",
" \n",
" .df-table-wrapper thead,\n",
" .fixed-header {\n",
" font-weight: 600;\n",
" }\n",
" .df-table-wrapper tr,\n",
" .fixed-row {\n",
" border: 0 none #ffffff;\n",
" margin: 0;\n",
" padding: 0;\n",
" }\n",
" .df-table-wrapper th,\n",
" .df-table-wrapper td,\n",
" .fixed-cell {\n",
" border: 0 none #ffffff;\n",
" margin: 0;\n",
" min-width: 50px;\n",
" padding: 5px 20px 5px 10px;\n",
" text-align: left;\n",
" word-wrap: break-word;\n",
" }\n",
" .df-table-wrapper th {\n",
" padding-bottom: 0;\n",
" padding-top: 0;\n",
" }\n",
" .df-table-wrapper th div {\n",
" max-height: 1px;\n",
" visibility: hidden;\n",
" }\n",
" \n",
" .df-schema-field {\n",
" margin-left: 10px;\n",
" }\n",
" \n",
" .fixed-header-container {\n",
" overflow: hidden;\n",
" position: relative;\n",
" }\n",
" .fixed-header {\n",
" border-bottom: 2px solid #000;\n",
" display: table;\n",
" position: relative;\n",
" }\n",
" .fixed-row {\n",
" display: table-row;\n",
" }\n",
" .fixed-cell {\n",
" display: table-cell;\n",
" }\n",
" </style>\n",
" \n",
" \n",
" <div class=\"df-table-wrapper df-table-wrapper-c0cc7560 panel-group pd_save\">\n",
" <!-- dataframe schema -->\n",
" \n",
" <div class=\"panel panel-default\">\n",
" <div class=\"panel-heading\">\n",
" <h4 class=\"panel-title\" style=\"margin: 0px;\">\n",
" <a data-toggle=\"collapse\" href=\"#df-schema-c0cc7560\" data-parent=\"#df-table-wrapper-c0cc7560\">Schema</a>\n",
" </h4>\n",
" </div>\n",
" <div id=\"df-schema-c0cc7560\" class=\"panel-collapse collapse\">\n",
" <div class=\"panel-body\" style=\"font-family: monospace;\">\n",
" <div class=\"df-schema-fields\">\n",
" <div>Field types:</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>location: </strong> object</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>latitude: </strong> float64</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>longitude: </strong> float64</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>compareCityUrl: </strong> object</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>singleCityUrl: </strong> object</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>USD_net_monthly_avgSalary: </strong> float64</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>Native_net_monthly_avgSalary: </strong> float64</div>\n",
" \n",
" <div class=\"df-schema-field\"><strong>ExchangeRateToUSD: </strong> float64</div>\n",
" \n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" \n",
" <!-- dataframe table -->\n",
" <div class=\"panel panel-default\">\n",
" \n",
" <div class=\"panel-heading\">\n",
" <h4 class=\"panel-title\" style=\"margin: 0px;\">\n",
" <a data-toggle=\"collapse\" href=\"#df-table-c0cc7560\" data-parent=\"#df-table-wrapper-c0cc7560\"> Table</a>\n",
" </h4>\n",
" </div>\n",
" \n",
" <div id=\"df-table-c0cc7560\" class=\"panel-collapse collapse in\">\n",
" <div class=\"panel-body\">\n",
" \n",
" <input type=\"text\" class=\"df-table-search form-control input-sm\" placeholder=\"Search table\">\n",
" \n",
" <div>\n",
" \n",
" <span class=\"df-table-search-count\">Showing 51 of 51 rows</span>\n",
" \n",
" </div>\n",
" <!-- fixed header for when dataframe table scrolls -->\n",
" <div class=\"fixed-header-container\">\n",
" <div class=\"fixed-header\">\n",
" <div class=\"fixed-row\">\n",
" \n",
" <div class=\"fixed-cell\">location</div>\n",
" \n",
" <div class=\"fixed-cell\">latitude</div>\n",
" \n",
" <div class=\"fixed-cell\">longitude</div>\n",
" \n",
" <div class=\"fixed-cell\">compareCityUrl</div>\n",
" \n",
" <div class=\"fixed-cell\">singleCityUrl</div>\n",
" \n",
" <div class=\"fixed-cell\">USD_net_monthly_avgSalary</div>\n",
" \n",
" <div class=\"fixed-cell\">Native_net_monthly_avgSalary</div>\n",
" \n",
" <div class=\"fixed-cell\">ExchangeRateToUSD</div>\n",
" \n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class=\"df-table-container\">\n",
" <table class=\"df-table\">\n",
" <thead>\n",
" <tr>\n",
" \n",
" <th><div>location</div></th>\n",
" \n",
" <th><div>latitude</div></th>\n",
" \n",
" <th><div>longitude</div></th>\n",
" \n",
" <th><div>compareCityUrl</div></th>\n",
" \n",
" <th><div>singleCityUrl</div></th>\n",
" \n",
" <th><div>USD_net_monthly_avgSalary</div></th>\n",
" \n",
" <th><div>Native_net_monthly_avgSalary</div></th>\n",
" \n",
" <th><div>ExchangeRateToUSD</div></th>\n",
" \n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" \n",
" <tr>\n",
" \n",
" <td>Australia, NSW, Sydney</td>\n",
" \n",
" <td>-33.86882</td>\n",
" \n",
" <td>151.209296</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Australia&amp;city1=Vancouver&amp;city2=Sydney&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Australia&amp;city1=Vancouver&amp;city2=Sydney&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Sydney\">https://www.numbeo.com/cost-of-living/in/Sydney</a></td>\n",
" \n",
" <td>3897.55</td>\n",
" \n",
" <td>5389.44</td>\n",
" \n",
" <td>1.382776359507896</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Brazil, SP, Sao Paulo</td>\n",
" \n",
" <td>-23.550520000000002</td>\n",
" \n",
" <td>-46.633309000000004</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Brazil&amp;city1=Vancouver&amp;city2=Sao+Paulo&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Brazil&amp;city1=Vancouver&amp;city2=Sao+Paulo&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Sao-Paulo\">https://www.numbeo.com/cost-of-living/in/Sao-Paulo</a></td>\n",
" \n",
" <td>566.0</td>\n",
" \n",
" <td>2126.25</td>\n",
" \n",
" <td>3.756625441696113</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Canada, BC, Vancouver</td>\n",
" \n",
" <td>49.282728999999996</td>\n",
" \n",
" <td>-123.12073799999999</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Canada&amp;city1=Vancouver&amp;city2=Vancouver&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Canada&amp;city1=Vancouver&amp;city2=Vancouver&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Vancouver\">https://www.numbeo.com/cost-of-living/in/Vancouver</a></td>\n",
" \n",
" <td>2395.71</td>\n",
" \n",
" <td>3186.69</td>\n",
" \n",
" <td>1.3301651702418071</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Canada, ON, Toronto</td>\n",
" \n",
" <td>43.653226000000004</td>\n",
" \n",
" <td>-79.383184</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Canada&amp;city1=Vancouver&amp;city2=Toronto&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Canada&amp;city1=Vancouver&amp;city2=Toronto&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Toronto\">https://www.numbeo.com/cost-of-living/in/Toronto</a></td>\n",
" \n",
" <td>2518.09</td>\n",
" \n",
" <td>3349.47</td>\n",
" \n",
" <td>1.3301629409592188</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>China, 11, Beijing</td>\n",
" \n",
" <td>40.237352</td>\n",
" \n",
" <td>116.23046200000002</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=China&amp;city1=Vancouver&amp;city2=Beijing&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=China&amp;city1=Vancouver&amp;city2=Beijing&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Beijing\">https://www.numbeo.com/cost-of-living/in/Beijing</a></td>\n",
" \n",
" <td>1209.47</td>\n",
" \n",
" <td>8397.56</td>\n",
" \n",
" <td>6.943173456141946</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>China, 31, Shanghai</td>\n",
" \n",
" <td>42.768197</td>\n",
" \n",
" <td>-86.087644</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=China&amp;city1=Vancouver&amp;city2=Shanghai&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=China&amp;city1=Vancouver&amp;city2=Shanghai&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Shanghai\">https://www.numbeo.com/cost-of-living/in/Shanghai</a></td>\n",
" \n",
" <td>1171.6</td>\n",
" \n",
" <td>8134.67</td>\n",
" \n",
" <td>6.943214407647662</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>France, Courbevoie</td>\n",
" \n",
" <td>48.900552000000005</td>\n",
" \n",
" <td>2.25929</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=France&amp;city1=Vancouver&amp;city2=Paris&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=France&amp;city1=Vancouver&amp;city2=Paris&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Paris\">https://www.numbeo.com/cost-of-living/in/Paris</a></td>\n",
" \n",
" <td>2710.91</td>\n",
" \n",
" <td>2382.12</td>\n",
" \n",
" <td>0.8787160031133457</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Germany, Aachen</td>\n",
" \n",
" <td>50.775346</td>\n",
" \n",
" <td>6.083887</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Aachen&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Aachen&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Aachen\">https://www.numbeo.com/cost-of-living/in/Aachen</a></td>\n",
" \n",
" <td>2625.42</td>\n",
" \n",
" <td>2307.0</td>\n",
" \n",
" <td>0.8787165482094293</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Germany, BE, Berlin</td>\n",
" \n",
" <td>52.52000699999999</td>\n",
" \n",
" <td>13.404954</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Berlin&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Berlin&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Berlin\">https://www.numbeo.com/cost-of-living/in/Berlin</a></td>\n",
" \n",
" <td>2372.43</td>\n",
" \n",
" <td>2084.69</td>\n",
" \n",
" <td>0.8787150727313346</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Germany, BY, Munich</td>\n",
" \n",
" <td>48.135125</td>\n",
" \n",
" <td>11.58198</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Munich&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Germany&amp;city1=Vancouver&amp;city2=Munich&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Munich\">https://www.numbeo.com/cost-of-living/in/Munich</a></td>\n",
" \n",
" <td>2963.32</td>\n",
" \n",
" <td>2603.91</td>\n",
" \n",
" <td>0.8787137399943306</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Hong Kong, Causeway Bay</td>\n",
" \n",
" <td>22.285979</td>\n",
" \n",
" <td>114.191492</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Hong+Kong&amp;city1=Vancouver&amp;city2=Hong+Kong&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Hong+Kong&amp;city1=Vancouver&amp;city2=Hong+Kong&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Hong-Kong\">https://www.numbeo.com/cost-of-living/in/Hong-Kong</a></td>\n",
" \n",
" <td>2425.09</td>\n",
" \n",
" <td>18990.31</td>\n",
" \n",
" <td>7.830765043771572</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>India, HR, Gurgaon</td>\n",
" \n",
" <td>28.459497</td>\n",
" \n",
" <td>77.026638</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Gurgaon&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Gurgaon&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Gurgaon\">https://www.numbeo.com/cost-of-living/in/Gurgaon</a></td>\n",
" \n",
" <td>1026.1</td>\n",
" \n",
" <td>73021.97</td>\n",
" \n",
" <td>71.16457460286523</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>India, KA, Bangalore</td>\n",
" \n",
" <td>12.971599000000001</td>\n",
" \n",
" <td>77.594563</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Bangalore&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Bangalore&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Bangalore\">https://www.numbeo.com/cost-of-living/in/Bangalore</a></td>\n",
" \n",
" <td>714.88</td>\n",
" \n",
" <td>50874.06</td>\n",
" \n",
" <td>71.16447515666965</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>India, TN, Chennai</td>\n",
" \n",
" <td>13.08268</td>\n",
" \n",
" <td>80.270718</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Chennai&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Chennai&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Chennai\">https://www.numbeo.com/cost-of-living/in/Chennai</a></td>\n",
" \n",
" <td>468.8</td>\n",
" \n",
" <td>33361.65</td>\n",
" \n",
" <td>71.16392918088738</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>India, TS, Hyderabad</td>\n",
" \n",
" <td>17.385044</td>\n",
" \n",
" <td>78.486671</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Hyderabad&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=India&amp;city1=Vancouver&amp;city2=Hyderabad&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Hyderabad\">https://www.numbeo.com/cost-of-living/in/Hyderabad</a></td>\n",
" \n",
" <td>465.26</td>\n",
" \n",
" <td>33109.85</td>\n",
" \n",
" <td>71.16418776598032</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Ireland, DUBLIN, Dublin</td>\n",
" \n",
" <td>53.349805</td>\n",
" \n",
" <td>-6.26031</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Ireland&amp;city1=Vancouver&amp;city2=Dublin&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Ireland&amp;city1=Vancouver&amp;city2=Dublin&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Dublin\">https://www.numbeo.com/cost-of-living/in/Dublin</a></td>\n",
" \n",
" <td>2751.92</td>\n",
" \n",
" <td>2418.16</td>\n",
" \n",
" <td>0.8787174045757143</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Israel, Haifa</td>\n",
" \n",
" <td>32.794046</td>\n",
" \n",
" <td>34.989571000000005</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Israel&amp;city1=Vancouver&amp;city2=Haifa&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Israel&amp;city1=Vancouver&amp;city2=Haifa&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Haifa\">https://www.numbeo.com/cost-of-living/in/Haifa</a></td>\n",
" \n",
" <td>1935.99</td>\n",
" \n",
" <td>7221.45</td>\n",
" \n",
" <td>3.7301070769993645</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Israel, Tel Aviv</td>\n",
" \n",
" <td>32.0853</td>\n",
" \n",
" <td>34.781768</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Israel&amp;city1=Vancouver&amp;city2=Tel+Aviv-Yafo&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Israel&amp;city1=Vancouver&amp;city2=Tel+Aviv-Yafo&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Tel-Aviv-Yafo\">https://www.numbeo.com/cost-of-living/in/Tel-Aviv-Yafo</a></td>\n",
" \n",
" <td>2292.68</td>\n",
" \n",
" <td>8551.92</td>\n",
" \n",
" <td>3.7300975277840784</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Japan, Tokyo</td>\n",
" \n",
" <td>35.689488</td>\n",
" \n",
" <td>139.691706</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Japan&amp;city1=Vancouver&amp;city2=Tokyo&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Japan&amp;city1=Vancouver&amp;city2=Tokyo&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Tokyo\">https://www.numbeo.com/cost-of-living/in/Tokyo</a></td>\n",
" \n",
" <td>2899.93</td>\n",
" \n",
" <td>327182.96</td>\n",
" \n",
" <td>112.82443369322709</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Jordan, Amman</td>\n",
" \n",
" <td>31.945366999999997</td>\n",
" \n",
" <td>35.928371999999996</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Jordan&amp;city1=Vancouver&amp;city2=Amman&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Jordan&amp;city1=Vancouver&amp;city2=Amman&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Amman\">https://www.numbeo.com/cost-of-living/in/Amman</a></td>\n",
" \n",
" <td>647.19</td>\n",
" \n",
" <td>459.18</td>\n",
" \n",
" <td>0.7094979835905993</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Luxembourg, Luxembourg</td>\n",
" \n",
" <td>49.611621</td>\n",
" \n",
" <td>6.1319349999999995</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Luxembourg&amp;city1=Vancouver&amp;city2=Luxembourg&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Luxembourg&amp;city1=Vancouver&amp;city2=Luxembourg&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Luxembourg\">https://www.numbeo.com/cost-of-living/in/Luxembourg</a></td>\n",
" \n",
" <td>3825.77</td>\n",
" \n",
" <td>3361.76</td>\n",
" \n",
" <td>0.8787146116990828</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Poland, Gdansk</td>\n",
" \n",
" <td>54.352025</td>\n",
" \n",
" <td>18.646638</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Poland&amp;city1=Vancouver&amp;city2=Gdansk&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Poland&amp;city1=Vancouver&amp;city2=Gdansk&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Gdansk\">https://www.numbeo.com/cost-of-living/in/Gdansk</a></td>\n",
" \n",
" <td>957.82</td>\n",
" \n",
" <td>3616.67</td>\n",
" \n",
" <td>3.7759391117328933</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Romania, Iasi</td>\n",
" \n",
" <td>47.158455</td>\n",
" \n",
" <td>27.601442</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Romania&amp;city1=Vancouver&amp;city2=Iasi&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Romania&amp;city1=Vancouver&amp;city2=Iasi&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Iasi\">https://www.numbeo.com/cost-of-living/in/Iasi</a></td>\n",
" \n",
" <td>562.36</td>\n",
" \n",
" <td>2305.05</td>\n",
" \n",
" <td>4.098886834056477</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Singapore, Singapore</td>\n",
" \n",
" <td>1.352083</td>\n",
" \n",
" <td>103.819836</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Singapore&amp;city1=Vancouver&amp;city2=Singapore&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Singapore&amp;city1=Vancouver&amp;city2=Singapore&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Singapore\">https://www.numbeo.com/cost-of-living/in/Singapore</a></td>\n",
" \n",
" <td>2931.64</td>\n",
" \n",
" <td>4031.74</td>\n",
" \n",
" <td>1.3752507129115443</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>South Africa, Cape Town</td>\n",
" \n",
" <td>-33.924868</td>\n",
" \n",
" <td>18.424055</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=South+Africa&amp;city1=Vancouver&amp;city2=Cape+Town&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=South+Africa&amp;city1=Vancouver&amp;city2=Cape+Town&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Cape-Town\">https://www.numbeo.com/cost-of-living/in/Cape-Town</a></td>\n",
" \n",
" <td>1155.63</td>\n",
" \n",
" <td>16270.83</td>\n",
" \n",
" <td>14.079618909166427</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Spain, 28, Madrid</td>\n",
" \n",
" <td>40.427566999999996</td>\n",
" \n",
" <td>-3.6857580000000003</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Spain&amp;city1=Vancouver&amp;city2=Madrid&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Spain&amp;city1=Vancouver&amp;city2=Madrid&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Madrid\">https://www.numbeo.com/cost-of-living/in/Madrid</a></td>\n",
" \n",
" <td>1660.96</td>\n",
" \n",
" <td>1459.51</td>\n",
" \n",
" <td>0.8787147191985357</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>Sweden, Stockholm</td>\n",
" \n",
" <td>59.329322999999995</td>\n",
" \n",
" <td>18.068581</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Sweden&amp;city1=Vancouver&amp;city2=Stockholm&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=Sweden&amp;city1=Vancouver&amp;city2=Stockholm&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Stockholm\">https://www.numbeo.com/cost-of-living/in/Stockholm</a></td>\n",
" \n",
" <td>2859.53</td>\n",
" \n",
" <td>25974.04</td>\n",
" \n",
" <td>9.083324882061037</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>UK, Cambridge</td>\n",
" \n",
" <td>52.205337</td>\n",
" \n",
" <td>0.12181700000000001</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=Cambridge&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=Cambridge&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Cambridge\">https://www.numbeo.com/cost-of-living/in/Cambridge</a></td>\n",
" \n",
" <td>2407.66</td>\n",
" \n",
" <td>1881.25</td>\n",
" \n",
" <td>0.781360324962827</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>UK, Edinburgh</td>\n",
" \n",
" <td>55.953252</td>\n",
" \n",
" <td>-3.1882669999999997</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=Edinburgh&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=Edinburgh&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Edinburgh\">https://www.numbeo.com/cost-of-living/in/Edinburgh</a></td>\n",
" \n",
" <td>2408.68</td>\n",
" \n",
" <td>1882.05</td>\n",
" \n",
" <td>0.7813615756347876</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>UK, London</td>\n",
" \n",
" <td>51.507351</td>\n",
" \n",
" <td>-0.12775799999999998</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=London&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+Kingdom&amp;city1=Vancouver&amp;city2=London&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/London\">https://www.numbeo.com/cost-of-living/in/London</a></td>\n",
" \n",
" <td>3300.67</td>\n",
" \n",
" <td>2579.01</td>\n",
" \n",
" <td>0.7813595421535628</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, AZ, Tempe</td>\n",
" \n",
" <td>33.425509999999996</td>\n",
" \n",
" <td>-111.940005</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Tempe%2C+AZ&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Tempe%2C+AZ&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Tempe\">https://www.numbeo.com/cost-of-living/in/Tempe</a></td>\n",
" \n",
" <td>2861.02</td>\n",
" \n",
" <td>2861.02</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, San Jose, CA Area</td>\n",
" \n",
" <td>37.322998</td>\n",
" \n",
" <td>-122.032182</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Jose%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Jose%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/San-Jose\">https://www.numbeo.com/cost-of-living/in/San-Jose</a></td>\n",
" \n",
" <td>5853.61</td>\n",
" \n",
" <td>5853.61</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CA, Los Angeles, CA Area</td>\n",
" \n",
" <td>33.684567</td>\n",
" \n",
" <td>-117.82650500000001</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Los+Angeles%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Los+Angeles%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Los-Angeles\">https://www.numbeo.com/cost-of-living/in/Los-Angeles</a></td>\n",
" \n",
" <td>3670.37</td>\n",
" \n",
" <td>3670.37</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CA, San Diego</td>\n",
" \n",
" <td>32.715738</td>\n",
" \n",
" <td>-117.161084</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Diego%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Diego%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/San-Diego\">https://www.numbeo.com/cost-of-living/in/San-Diego</a></td>\n",
" \n",
" <td>4168.05</td>\n",
" \n",
" <td>4168.05</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CA, San Francisco</td>\n",
" \n",
" <td>37.77493</td>\n",
" \n",
" <td>-122.419416</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Francisco%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Francisco%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/San-Francisco\">https://www.numbeo.com/cost-of-living/in/San-Francisco</a></td>\n",
" \n",
" <td>5852.6</td>\n",
" \n",
" <td>5852.6</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CA, San Luis Obispo</td>\n",
" \n",
" <td>35.282752</td>\n",
" \n",
" <td>-120.65961599999999</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Luis+Obispo%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=San+Luis+Obispo%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/San-Luis-Obispo\">https://www.numbeo.com/cost-of-living/in/San-Luis-Obispo</a></td>\n",
" \n",
" <td>2866.67</td>\n",
" \n",
" <td>2866.67</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CA, Santa Cruz</td>\n",
" \n",
" <td>36.974117</td>\n",
" \n",
" <td>-122.030796</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Santa+Cruz%2C+CA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Santa+Cruz%2C+CA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Santa-Cruz\">https://www.numbeo.com/cost-of-living/in/Santa-Cruz</a></td>\n",
" \n",
" <td>4900.0</td>\n",
" \n",
" <td>4900.0</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, CO, Denver</td>\n",
" \n",
" <td>39.739236</td>\n",
" \n",
" <td>-104.990251</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Denver%2C+CO&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Denver%2C+CO&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Denver\">https://www.numbeo.com/cost-of-living/in/Denver</a></td>\n",
" \n",
" <td>3612.91</td>\n",
" \n",
" <td>3612.91</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, GA, Atlanta</td>\n",
" \n",
" <td>33.748995</td>\n",
" \n",
" <td>-84.387982</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Atlanta%2C+GA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Atlanta%2C+GA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Atlanta\">https://www.numbeo.com/cost-of-living/in/Atlanta</a></td>\n",
" \n",
" <td>3862.36</td>\n",
" \n",
" <td>3862.36</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, IL, Chicago</td>\n",
" \n",
" <td>41.878114000000004</td>\n",
" \n",
" <td>-87.629798</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Chicago%2C+IL&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Chicago%2C+IL&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Chicago\">https://www.numbeo.com/cost-of-living/in/Chicago</a></td>\n",
" \n",
" <td>3803.34</td>\n",
" \n",
" <td>3803.34</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, Boston, MA Area</td>\n",
" \n",
" <td>42.658336</td>\n",
" \n",
" <td>-71.13679499999999</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Boston%2C+MA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Boston%2C+MA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Boston\">https://www.numbeo.com/cost-of-living/in/Boston</a></td>\n",
" \n",
" <td>4194.17</td>\n",
" \n",
" <td>4194.17</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, MI, Detroit</td>\n",
" \n",
" <td>42.331427000000005</td>\n",
" \n",
" <td>-83.045754</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Detroit%2C+MI&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Detroit%2C+MI&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Detroit\">https://www.numbeo.com/cost-of-living/in/Detroit</a></td>\n",
" \n",
" <td>2121.31</td>\n",
" \n",
" <td>2121.31</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, MN, Minneapolis</td>\n",
" \n",
" <td>44.977753</td>\n",
" \n",
" <td>-93.265011</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Minneapolis%2C+MN&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Minneapolis%2C+MN&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Minneapolis\">https://www.numbeo.com/cost-of-living/in/Minneapolis</a></td>\n",
" \n",
" <td>3519.0</td>\n",
" \n",
" <td>3519.0</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, NY, New York</td>\n",
" \n",
" <td>40.735657</td>\n",
" \n",
" <td>-74.17236700000001</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=New+York%2C+NY&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=New+York%2C+NY&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/New-York\">https://www.numbeo.com/cost-of-living/in/New-York</a></td>\n",
" \n",
" <td>4490.77</td>\n",
" \n",
" <td>4490.77</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, OR, Portland</td>\n",
" \n",
" <td>45.512231</td>\n",
" \n",
" <td>-122.65871899999999</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Portland%2C+OR&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Portland%2C+OR&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Portland\">https://www.numbeo.com/cost-of-living/in/Portland</a></td>\n",
" \n",
" <td>3421.56</td>\n",
" \n",
" <td>3421.56</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, PA, Malvern</td>\n",
" \n",
" <td>40.036218</td>\n",
" \n",
" <td>-75.513812</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Philadelphia%2C+PA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Philadelphia%2C+PA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Philadelphia\">https://www.numbeo.com/cost-of-living/in/Philadelphia</a></td>\n",
" \n",
" <td>3314.83</td>\n",
" \n",
" <td>3314.83</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, TX, Austin</td>\n",
" \n",
" <td>30.267153000000004</td>\n",
" \n",
" <td>-97.743061</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Austin%2C+TX&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Austin%2C+TX&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Austin\">https://www.numbeo.com/cost-of-living/in/Austin</a></td>\n",
" \n",
" <td>3914.89</td>\n",
" \n",
" <td>3914.89</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, TX, Dallas</td>\n",
" \n",
" <td>32.776664000000004</td>\n",
" \n",
" <td>-96.796988</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Dallas%2C+TX&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Dallas%2C+TX&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Dallas\">https://www.numbeo.com/cost-of-living/in/Dallas</a></td>\n",
" \n",
" <td>3882.22</td>\n",
" \n",
" <td>3882.22</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, TX, Houston</td>\n",
" \n",
" <td>29.760427000000004</td>\n",
" \n",
" <td>-95.369803</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Houston%2C+TX&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Houston%2C+TX&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Houston\">https://www.numbeo.com/cost-of-living/in/Houston</a></td>\n",
" \n",
" <td>3589.62</td>\n",
" \n",
" <td>3589.62</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, VA, Arlington</td>\n",
" \n",
" <td>38.885801</td>\n",
" \n",
" <td>-77.105367</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Arlington%2C+VA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Arlington%2C+VA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Arlington\">https://www.numbeo.com/cost-of-living/in/Arlington</a></td>\n",
" \n",
" <td>3700.0</td>\n",
" \n",
" <td>3700.0</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" <tr>\n",
" \n",
" <td>United States, WA, Seattle</td>\n",
" \n",
" <td>47.61015</td>\n",
" \n",
" <td>-122.201516</td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Seattle%2C+WA&amp;tracking=getDispatchComparison\">https://www.numbeo.com/cost-of-living/compare_cities.jsp?country1=Canada&amp;country2=United+States&amp;city1=Vancouver&amp;city2=Seattle%2C+WA&amp;tracking=getDispatchComparison</a></td>\n",
" \n",
" <td><a target=\"_blank\" href=\"https://www.numbeo.com/cost-of-living/in/Seattle\">https://www.numbeo.com/cost-of-living/in/Seattle</a></td>\n",
" \n",
" <td>4646.86</td>\n",
" \n",
" <td>4646.86</td>\n",
" \n",
" <td>1.0</td>\n",
" \n",
" </tr>\n",
" \n",
" </tbody>\n",
" </table>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" \n",
" <script class=\"pd_save\">\n",
" $(function() {\n",
" var tableWrapper = $('.df-table-wrapper-c0cc7560');\n",
" var fixedHeader = $('.fixed-header', tableWrapper);\n",
" var tableContainer = $('.df-table-container', tableWrapper);\n",
" var table = $('.df-table', tableContainer);\n",
" var rows = $('tbody > tr', table);\n",
" var total = 51;\n",
" \n",
" fixedHeader\n",
" .css('width', table.width())\n",
" .find('.fixed-cell')\n",
" .each(function(i, e) {\n",
" $(this).css('width', $('.df-table-wrapper-c0cc7560 th:nth-child(' + (i+1) + ')').css('width'));\n",
" });\n",
" \n",
" tableContainer.scroll(function() {\n",
" fixedHeader.css({ left: table.position().left });\n",
" });\n",
" \n",
" rows.on(\"click\", function(e){\n",
" var txt = e.delegateTarget.innerText;\n",
" var splits = txt.split(\"\\t\");\n",
" var len = splits.length;\n",
" var hdrs = $(fixedHeader).find(\".fixed-cell\");\n",
" // Add all cells in the selected row as a map to be consumed by the target as needed\n",
" var payload = {type:\"select\", targetDivId: \"\" };\n",
" for (var i = 0; i < len; i++) {\n",
" payload[hdrs[i].innerHTML] = splits[i];\n",
" }\n",
" \n",
" //simple selection highlighting, client adds \"selected\" class\n",
" $(this).addClass(\"selected\").siblings().removeClass(\"selected\");\n",
" $(document).trigger('pd_event', payload);\n",
" });\n",
" \n",
" $('.df-table-search', tableWrapper).keyup(function() {\n",
" var val = '^(?=.*\\\\b' + $.trim($(this).val()).split(/\\s+/).join('\\\\b)(?=.*\\\\b') + ').*$';\n",
" var reg = RegExp(val, 'i');\n",
" var index = 0;\n",
" \n",
" rows.each(function(i, e) {\n",
" if (!reg.test($(this).text().replace(/\\s+/g, ' '))) {\n",
" $(this).attr('class', 'hidden');\n",
" }\n",
" else {\n",
" $(this).attr('class', (++index % 2 == 0 ? 'even' : 'odd'));\n",
" }\n",
" });\n",
" $('.df-table-search-count', tableWrapper).html('Showing ' + index + ' of ' + total + ' rows');\n",
" });\n",
" });\n",
" \n",
" $(\".df-table-wrapper td:contains('http://')\").each(function(){var tc = this.textContent; $(this).wrapInner(\"<a target='_blank' href='\" + tc + \"'></a>\");});\n",
" $(\".df-table-wrapper td:contains('https://')\").each(function(){var tc = this.textContent; $(this).wrapInner(\"<a target='_blank' href='\" + tc + \"'></a>\");});\n",
" </script>\n",
" \n",
" </div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(AmazonCitiesWithNumbeoLinks)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Downloading numbeo data locally for further processing"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Skipping download of numbeoData_2018_november/Australia_NSW_Sydney.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Brazil_SP_Sao_Paulo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Canada_BC_Vancouver.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Canada_ON_Toronto.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/China_Beijing.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/China_Shanghai.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/France_Courbevoie.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Germany_Aachen.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Germany_BE_Berlin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Germany_BY_Munich.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Hong_Kong_Causeway_Bay.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/India_HR_Gurgaon.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/India_KA_Bangalore.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/India_TN_Chennai.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/India_TS_Hyderabad.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Ireland_DUBLIN_Dublin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Israel_Haifa.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Israel_Tel_Aviv.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Japan_Tokyo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Jordan_Amman.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Luxembourg_Luxembourg.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Poland_Gdansk.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Romania_Iasi.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Singapore_Singapore.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/South_Africa_Cape_Town.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Spain_Madrid.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/Sweden_Stockholm.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/UK_Cambridge.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/UK_Edinburgh.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/UK_London.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_AZ_Tempe.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_San_Jose_CA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CA_Los_Angeles_CA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CA_San_Diego.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CA_San_Francisco.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CA_San_Luis_Obispo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CA_Santa_Cruz.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_CO_Denver.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_GA_Atlanta.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_IL_Chicago.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_Boston_MA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_MI_Detroit.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_MN_Minneapolis.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_NY_New_York.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_OR_Portland.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_PA_Malvern.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_TX_Austin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_TX_Dallas.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_TX_Houston.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_VA_Arlington.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/United_States_WA_Seattle.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Australia_NSW_Sydney.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Brazil_SP_Sao_Paulo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Canada_BC_Vancouver.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Canada_ON_Toronto.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_China_Beijing.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_China_Shanghai.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_France_Courbevoie.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Germany_Aachen.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Germany_BE_Berlin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Germany_BY_Munich.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Hong_Kong_Causeway_Bay.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_India_HR_Gurgaon.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_India_KA_Bangalore.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_India_TN_Chennai.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_India_TS_Hyderabad.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Ireland_DUBLIN_Dublin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Israel_Haifa.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Israel_Tel_Aviv.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Japan_Tokyo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Jordan_Amman.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Luxembourg_Luxembourg.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Poland_Gdansk.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Romania_Iasi.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Singapore_Singapore.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_South_Africa_Cape_Town.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Spain_Madrid.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_Sweden_Stockholm.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_UK_Cambridge.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_UK_Edinburgh.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_UK_London.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_AZ_Tempe.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_San_Jose_CA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CA_Los_Angeles_CA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CA_San_Diego.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CA_San_Francisco.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CA_San_Luis_Obispo.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CA_Santa_Cruz.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_CO_Denver.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_GA_Atlanta.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_IL_Chicago.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_Boston_MA_Area.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_MI_Detroit.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_MN_Minneapolis.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_NY_New_York.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_OR_Portland.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_PA_Malvern.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_TX_Austin.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_TX_Dallas.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_TX_Houston.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_VA_Arlington.html, as the file already exists.\n",
"Skipping download of numbeoData_2018_november/USD_United_States_WA_Seattle.html, as the file already exists.\n"
]
}
],
"source": [
"import re\n",
"\n",
"def normalizeToFileName(location):\n",
" result = re.sub('\\d', '', location)\n",
" result = re.sub(' ', '_', result)\n",
" result = re.sub(',', '', result)\n",
" result = re.sub('__', '_', result)\n",
" return result\n",
"\n",
"def locationToNumbeoFilePath(location, prefix):\n",
" fileName = normalizeToFileName(location) + \".html\"\n",
" filePath = \"numbeoData_2018_november/\" + prefix + fileName\n",
" return filePath\n",
"\n",
"import urllib.request\n",
"import time\n",
"import os.path\n",
"\n",
"def downloadNumbeoData(filePrefix, urlSuffix):\n",
" for i in AmazonCitiesWithNumbeoLinks.index:\n",
" filePath = locationToNumbeoFilePath(AmazonCitiesWithNumbeoLinks.at[i, 'location'], filePrefix)\n",
" url = AmazonCitiesWithNumbeoLinks.at[i, 'singleCityUrl'] + urlSuffix\n",
" if not os.path.isfile(filePath):\n",
" urllib.request.urlretrieve(url, filePath)\n",
" time.sleep(3) #be gentle and easy\n",
" else:\n",
" print(\"Skipping download of {}, as the file already exists.\".format(filePath))\n",
"\n",
"downloadNumbeoData(\"\", \"\") #downloads in native currency\n",
"downloadNumbeoData(\"USD_\", \"?displayCurrency=USD\") #downloads in USD currency"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fetching avg salary and exchange rate from numbeo data"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"from bs4 import BeautifulSoup\n",
"\n",
"def fetchFromNumbeo(location, fetchUSD, field):\n",
" filePrefix = \"\"\n",
" if fetchUSD:\n",
" filePrefix = \"USD_\"\n",
" filePath = locationToNumbeoFilePath(location, filePrefix)\n",
" with open(filePath) as fp:\n",
" soup = BeautifulSoup(fp)\n",
" for i, tr in enumerate(soup.select('tr')):\n",
" thisIsTheField = False\n",
" for j, td in enumerate(tr.select('td')):\n",
" if j == 0:\n",
" if field in td.text:\n",
" thisIsTheField = True\n",
" if j == 1 and thisIsTheField:\n",
" if \"?\" in td.text:\n",
" print(\"WARNING: NO DATA FOR: {} in {}\".format(field, location))\n",
" return 0\n",
" else:\n",
" return float(re.sub('[^0-9.]','', td.text))\n",
" #print(\"i: {} j:{} {}\".format(i, j, td.text))\n",
" return -1\n",
"\n",
"#for testing purposes\n",
"#usd = fetchFromNumbeo(\"Singapore, Singapore\", True, \"Average Monthly Net Salary (After Tax)\")\n",
"#notusd = fetchFromNumbeo(\"Singapore, Singapore\", false, \"Average Monthly Net Salary (After Tax)\")\n",
"#print(\"Salary in USD: {}, Salary in Native: {}, Exchange Rate: {}\".format( usd, notusd, notusd/usd))\n",
"AmazonCitiesWithNumbeoLinks['USD_net_monthly_avgSalary'] = AmazonCitiesWithNumbeoLinks \\\n",
" .apply(lambda row: fetchFromNumbeo(row.location, True, \"Average Monthly Net Salary (After Tax)\"), axis=1)\n",
"AmazonCitiesWithNumbeoLinks['Native_net_monthly_avgSalary'] = AmazonCitiesWithNumbeoLinks \\\n",
" .apply(lambda row: fetchFromNumbeo(row.location, False, \"Average Monthly Net Salary (After Tax)\"), axis=1)\n",
"AmazonCitiesWithNumbeoLinks['ExchangeRateToUSD'] = AmazonCitiesWithNumbeoLinks \\\n",
" .apply(lambda row: row.Native_net_monthly_avgSalary/row.USD_net_monthly_avgSalary, axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>location</th>\n",
" <th>latitude</th>\n",
" <th>longitude</th>\n",
" <th>compareCityUrl</th>\n",
" <th>singleCityUrl</th>\n",
" <th>USD_net_monthly_avgSalary</th>\n",
" <th>Native_net_monthly_avgSalary</th>\n",
" <th>ExchangeRateToUSD</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Australia, NSW, Sydney</td>\n",
" <td>-33.868820</td>\n",
" <td>151.209296</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Sydney</td>\n",
" <td>3897.55</td>\n",
" <td>5389.44</td>\n",
" <td>1.382776</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Brazil, SP, Sao Paulo</td>\n",
" <td>-23.550520</td>\n",
" <td>-46.633309</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Sao-P...</td>\n",
" <td>566.00</td>\n",
" <td>2126.25</td>\n",
" <td>3.756625</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Canada, BC, Vancouver</td>\n",
" <td>49.282729</td>\n",
" <td>-123.120738</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Vanco...</td>\n",
" <td>2395.71</td>\n",
" <td>3186.69</td>\n",
" <td>1.330165</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Canada, ON, Toronto</td>\n",
" <td>43.653226</td>\n",
" <td>-79.383184</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Toronto</td>\n",
" <td>2518.09</td>\n",
" <td>3349.47</td>\n",
" <td>1.330163</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>China, 11, Beijing</td>\n",
" <td>40.237352</td>\n",
" <td>116.230462</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Beijing</td>\n",
" <td>1209.47</td>\n",
" <td>8397.56</td>\n",
" <td>6.943173</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>China, 31, Shanghai</td>\n",
" <td>42.768197</td>\n",
" <td>-86.087644</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Shanghai</td>\n",
" <td>1171.60</td>\n",
" <td>8134.67</td>\n",
" <td>6.943214</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>France, Courbevoie</td>\n",
" <td>48.900552</td>\n",
" <td>2.259290</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Paris</td>\n",
" <td>2710.91</td>\n",
" <td>2382.12</td>\n",
" <td>0.878716</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>Germany, Aachen</td>\n",
" <td>50.775346</td>\n",
" <td>6.083887</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Aachen</td>\n",
" <td>2625.42</td>\n",
" <td>2307.00</td>\n",
" <td>0.878717</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>Germany, BE, Berlin</td>\n",
" <td>52.520007</td>\n",
" <td>13.404954</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Berlin</td>\n",
" <td>2372.43</td>\n",
" <td>2084.69</td>\n",
" <td>0.878715</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>Germany, BY, Munich</td>\n",
" <td>48.135125</td>\n",
" <td>11.581980</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Munich</td>\n",
" <td>2963.32</td>\n",
" <td>2603.91</td>\n",
" <td>0.878714</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>Hong Kong, Causeway Bay</td>\n",
" <td>22.285979</td>\n",
" <td>114.191492</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Hong-...</td>\n",
" <td>2425.09</td>\n",
" <td>18990.31</td>\n",
" <td>7.830765</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>India, HR, Gurgaon</td>\n",
" <td>28.459497</td>\n",
" <td>77.026638</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Gurgaon</td>\n",
" <td>1026.10</td>\n",
" <td>73021.97</td>\n",
" <td>71.164575</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>India, KA, Bangalore</td>\n",
" <td>12.971599</td>\n",
" <td>77.594563</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Banga...</td>\n",
" <td>714.88</td>\n",
" <td>50874.06</td>\n",
" <td>71.164475</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>India, TN, Chennai</td>\n",
" <td>13.082680</td>\n",
" <td>80.270718</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Chennai</td>\n",
" <td>468.80</td>\n",
" <td>33361.65</td>\n",
" <td>71.163929</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>India, TS, Hyderabad</td>\n",
" <td>17.385044</td>\n",
" <td>78.486671</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Hyder...</td>\n",
" <td>465.26</td>\n",
" <td>33109.85</td>\n",
" <td>71.164188</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>Ireland, DUBLIN, Dublin</td>\n",
" <td>53.349805</td>\n",
" <td>-6.260310</td>\n",
" <td>https://www.numbeo.com/cost-of-living/compare_...</td>\n",
" <td>https://www.numbeo.com/cost-of-living/in/Dublin</td>\n",
" <td>2751.92</td>\n",