// ==UserScript== // @name Geoguessr百度街景脚本 // @description Geoguessr Unity Script的简化版, 国内可直接玩 // @version 6.0.3 // @include https://www.geoguessr.com/* // @run-at document-start // @license MIT // @namespace https://greasyfork.org/users/838374 // @downloadURL none // ==/UserScript== myLog("Geoguessr百度街景脚本 v6.0.3"); // Store each player instance let BAIDU_INJECTED = false; let OBSERVER; // Game mode detection let isBattleRoyale = false; let isDuel = false; // Player detection and coordinate conversion let nextPlayer = "Google"; let global_lat = 0; let global_lng = 0; let global_panoID = null; let global_BDID, global_BDAh, global_BDBh; let global_heading = null; let global_pitch = null; let global_radi = 100 // Callback variables let playerLoaded = false; let defaultPanoIdChange = true; // Round check let ROUND = 0; let CURRENT_ROUND_DATA = null; let switch_call = true; let one_reset = false; // let cnt = 0; let cn_tips = false; var isFirefox = typeof InstallTrigger !== 'undefined'; let linksList = [] let fire1 = true; let borderPerChineseLaw = true; function ArisKakao() { // let radi = 100; const google = unsafeWindow.google; console.log(google); if (borderPerChineseLaw) { google.maps.Map = class extends google.maps.Map { constructor(...args) { super(...args); this.data.addGeoJson(tenDD); this.data.setStyle(function(feature) { return { clickable: false, strokeWeight: 1 } }); const imageBounds3 = { north: NW[0], west: NW[1], south: NW[2], east: NW[3], }; historicalOverlay3 = new google.maps.GroundOverlay( "https://www.countryflags.com/wp-content/uploads/china-flag-png-large.png", imageBounds3, {clickable: false, opacity: 1} ); historicalOverlay3.setMap(this); this.addListener("zoom_changed", () => { let zo = this.getZoom(); let opc = 1; // console.log(zo) if (historicalOverlay) { historicalOverlay.setMap(null); historicalOverlay2.setMap(null); //historicalOverlay3.setMap(null); } let bod = TW[0] let bod2 = TS[0] if (zo > 7 && zo < 14) { bod = TW[zo - 7]; bod2 = TS[1]; } if (zo >= 14) { opc = 0; } const imageBounds = { north: bod[0], west: bod[1], south: bod[2], east: bod[3], }; historicalOverlay = new google.maps.GroundOverlay( "https://www.countryflags.com/wp-content/uploads/china-flag-png-large.png", imageBounds, {clickable: false, opacity: opc} ); historicalOverlay.setMap(this); const imageBounds2 = { north: bod2[0], west: bod2[1], south: bod2[2], east: bod2[3], }; historicalOverlay2 = new google.maps.GroundOverlay( "https://www.countryflags.com/wp-content/uploads/china-flag-png-large.png", imageBounds2, {clickable: false, opacity: 1} ); historicalOverlay2.setMap(this); }); } } } } /** * Helper Functions */ // Pretty print function myLog(...args) { console.log(...args); } function myHighlight(...args) { console.log(`%c${[...args]}`, "color: dodgerblue; font-size: 24px;"); } const base62 = { charset: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' .split(''), encode: integer => { if (integer === 0) { return 0; } let s = []; while (integer > 0) { s = [base62.charset[integer % 62], ...s]; integer = Math.floor(integer / 62); } return s.join(''); }, decode: chars => chars.split('').reverse().reduce((prev, curr, i) => prev + (base62.charset.indexOf(curr) * (62 ** i)), 0) }; // Hex to number conversion for Baidu coordinate conversion function hex2a(hexx) { var hex = hexx.toString(); var str = ''; for (var i = 0; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); return str; } // Coordinate computation given heading, distance and current coordinates for teleport function FindPointAtDistanceFrom(lat, lng, initialBearingRadians, distanceKilometres) { const radiusEarthKilometres = 6371.01; var distRatio = distanceKilometres / radiusEarthKilometres; var distRatioSine = Math.sin(distRatio); var distRatioCosine = Math.cos(distRatio); var startLatRad = DegreesToRadians(lat); var startLonRad = DegreesToRadians(lng); var startLatCos = Math.cos(startLatRad); var startLatSin = Math.sin(startLatRad); var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(initialBearingRadians))); var endLonRads = startLonRad + Math.atan2( Math.sin(initialBearingRadians) * distRatioSine * startLatCos, distRatioCosine - startLatSin * Math.sin(endLatRads)); return { lat: RadiansToDegrees(endLatRads), lng: RadiansToDegrees(endLonRads) }; } function DegreesToRadians(degrees) { const degToRadFactor = Math.PI / 180; return degrees * degToRadFactor; } function RadiansToDegrees(radians) { const radToDegFactor = 180 / Math.PI; return radians * radToDegFactor; } // Check if two floating point numbers are really really really really close to each other (to 10 decimal points) function almostEqual (a, b) { return a.toFixed(10) === b.toFixed(10) } function almostEqual2 (a, b) { return a.toFixed(3) === b.toFixed(3) } // Script injection, extracted from extenssr: // https://gitlab.com/nonreviad/extenssr/-/blob/main/src/injected_scripts/maps_api_injecter.ts function overrideOnLoad(googleScript, observer, overrider) { const oldOnload = googleScript.onload googleScript.onload = (event) => { const google = unsafeWindow.google if (google) { observer.disconnect() overrider(google) } if (oldOnload) { oldOnload.call(googleScript, event) } } } function grabGoogleScript(mutations) { for (const mutation of mutations) { for (const newNode of mutation.addedNodes) { const asScript = newNode if (asScript && asScript.src && asScript.src.startsWith('https://maps.googleapis.com/')) { return asScript } } } return null } function injecter(overrider) { if (document.documentElement) { injecterCallback(overrider); } else { setTimeout(injecter(overrider), 1000); } } function injecterCallback(overrider) { new MutationObserver((mutations, observer) => { const googleScript = grabGoogleScript(mutations) if (googleScript) { overrideOnLoad(googleScript, observer, overrider) } }).observe(document.documentElement, { childList: true, subtree: true }) } /** * This observer stays alive while the script is running */ function launchObserver() { ArisKakao(); myHighlight("Main Observer"); OBSERVER = new MutationObserver((mutations, observer) => { detectGamePage(); }); obsCallback(); } function obsCallback() { if (document.head) { OBSERVER.observe(document.head, { attributes: true, childList: true, subtree: true }); } else { setTimeout(obsCallback, 500); } } injecter(() => { launchObserver(); }) /** * Check whether the current page is a game, if so which game mode */ function detectGamePage() { if (document.querySelector(".game-layout__panorama-message") !== null && !one_reset) { one_reset = true; myLog("Hide fail to load panorama canvas"); document.querySelector(".game-layout__panorama-message").style.visibility = "hidden"; } let toLoad = !playerLoaded const PATHNAME = window.location.pathname; if (PATHNAME.startsWith("/game/") || PATHNAME.startsWith("/challenge/")) { // myLog("Game page"); isBattleRoyale = false; isDuel = false; if (toLoad) { loadPlayers(); } waitLoad(); } else if (PATHNAME.startsWith("/battle-royale/")) { if (document.querySelector(".br-game-layout") == null) { // myLog("Battle Royale Lobby"); rstValues(); } else { // myLog("Battle Royale"); isBattleRoyale = true; isDuel = false; if (toLoad) { loadPlayers(); } waitLoad(); } } else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) { if (document.querySelector(".game_layout__TO_jf") == null) { // myLog("Battle Royale Lobby"); rstValues(); } else { // myLog("Duels"); isBattleRoyale = true; isDuel = true; if (toLoad) { loadPlayers(); } waitLoad(); } } else { rstValues(); //myLog("Not a Game page"); } } function rstValues() { ROUND = 0; BAIDU_INJECTED = false; nextPlayer = "Google" global_lat = 0; global_lng = 0; global_panoID = null; global_BDAh = null; global_BDBh = null; global_BDID = null; playerLoaded = false; one_reset = false; CURRENT_ROUND_DATA = null; linksList = []; } /** * Wait for various players to load */ function waitLoad() { checkRound(); } /** * Checks for round changes */ function checkRound() { if (!isBattleRoyale) { let currentRound = getRoundFromPage(); if (ROUND != currentRound) { fire1 = true; myHighlight("New round"); ROUND = currentRound; one_reset = false; getMapData(); nextButtonCallback(); } } else { getMapData(); } } /** * Add listeners if buttons have been created */ function finalDetail() { let target = document.querySelector("a[data-qa='play-same-map']"); if (target) { var div = document.createElement("div"); div.classList.add("buttons_buttons__0B3SB") document.querySelector('.result-layout_content__jAHfP').appendChild(div); for (var rd of linksList) { let cl = target.cloneNode( true ); let tx = "View R" + rd[0] + " in " + rd[1]; cl.querySelector('.button_label__kpJrA').innerHTML = tx; cl.removeAttribute('data-qa'); cl.addEventListener("click", (e) => { window.open(rd[2]); }) cl.style = "top:10px;right:-10px;"; div.appendChild(cl); } } else { setTimeout(finalDetail, 500); } } function nextButtonCallback() { let nextButton = document.querySelector("button[data-qa='close-round-result']"); if (nextButton != null && fire1) { fire1 = false; nextButton.addEventListener("click", (e) => { if (document.getElementById("Show Buttons") != null && !cn_tips && ROUND !== 5) { myLog("try to show show buttons") document.getElementById("Show Buttons").style.visibility = ""; } if (ROUND == 5) { myLog("Game Finished") if (linksList) { finalDetail(); } } }) if (nextPlayer !== "Google") { myLog("Clone buttons"); let clone = document.querySelector("button[data-qa='close-round-result']").cloneNode( true ); let tx = "View Location in " + nextPlayer; clone.querySelector('.button_label__kpJrA').innerHTML = tx; clone.setAttribute('id', "LinkBtn"); clone.removeAttribute('data-qa'); let urlStr = "" if (nextPlayer == "Baidu") { urlStr = "https://map.baidu.com/?panotype=street&pid=" + global_BDID + "&panoid=" + global_BDID + "&from=api"; } linksList.push([ROUND, nextPlayer, urlStr]); clone.addEventListener("click", (e) => { window.open(urlStr); }) if (ROUND == 5) { clone.style = "top:10px;"; } else { clone.style = "right:-10px;"; } document.querySelector('.round-result_actions__5j26U').appendChild(clone); } } else { setTimeout(nextButtonCallback, 500); } } function loadPlayers() { playerLoaded = true; if (!isBattleRoyale) { getSeed().then((data) => { if (!data.mapName.includes("China Tips for each province")) { cn_tips = false; } else { cn_tips = true; guaranteeUI(); } }).catch((error) => { myLog(error); }); } initializeCanvas(); } function guaranteeUI() { // myLog("UI") if (document.getElementById("GH-ui") !== null) { document.getElementById("GH-ui").style.display = "block"; } else { setTimeout(guaranteeUI, 500); } } /** * Handles Return to start and undo */ function handleReturnToStart() { let rtsButton = document.querySelector("button[data-qa='return-to-start']"); if (rtsButton != null) { myLog("handleReturnToStart listener attached"); rtsButton.addEventListener("click", (e) => { if (nextPlayer != "Baidu") { goToLocation(); } else { document.getElementById("PanoramaMap").src = "https://map.baidu.com/?panotype=street&pid=" + global_BDID + "&panoid=" + global_BDID + "&from=api"; } const elementClicked = e.target; elementClicked.setAttribute('listener', 'true'); myLog("Return to start"); }); } else { setTimeout(handleReturnToStart, 500); } } /** * Load game information */ function getMapData() { // myHighlight("Seed data"); getSeed().then((data) => { // myHighlight("Seed data"); // myLog(data); if (isBattleRoyale) { if ((document.querySelector(".br-game-layout") == null && document.querySelector(".version3-in-game_layout__Hi_Iw") == null) || typeof data.gameId == typeof undefined) { // myLog("Battle Royale Lobby"); } else { let origin = false; if (!CURRENT_ROUND_DATA) { CURRENT_ROUND_DATA = data origin = true; } if (origin || !(data.currentRoundNumber === CURRENT_ROUND_DATA.currentRoundNumber)) { // myHighlight("Battle Royale New round"); // NEW_ROUND_LOADED = true; one_reset = false; if (!origin) { CURRENT_ROUND_DATA = data; } locationCheck(data); // myLog(data); goToLocation(); handleReturnToStart(); if (isDuel) { hideButtons(); } } } } else { locationCheck(data); goToLocation(); handleReturnToStart(); hideButtons(); } }).catch((error) => { myLog(error); }); } /** * Hide unnecessary buttons for non-Google coverages */ function hideButtons() { let CHECKPOINT = document.querySelector("button[data-qa='set-checkpoint']"); let ZOOM_IN = document.querySelector("button[data-qa='pano-zoom-in']"); let ZOOM_OUT = document.querySelector("button[data-qa='pano-zoom-out']"); if (CHECKPOINT != null) { if (nextPlayer === "Google") { CHECKPOINT.style.visibility = ""; ZOOM_IN.style.visibility = ""; ZOOM_OUT.style.visibility = ""; myLog("Buttons Unhidden"); } else { CHECKPOINT.style.visibility = "hidden"; ZOOM_IN.style.visibility = "hidden"; ZOOM_OUT.style.visibility = "hidden"; myLog("Buttons Hidden"); } } else { setTimeout(hideButtons, 250); } } /** * Check which player to use for the next location */ function locationCheck(data) { // console.log(data); let round; if (isBattleRoyale) { if (isDuel) { round = data.rounds[data.currentRoundNumber - 1].panorama; } else { round = data.rounds[data.currentRoundNumber - 1]; } } else { round = data.rounds[data.round - 1]; } global_lat = round.lat; global_lng = round.lng; global_panoID = round.panoId; global_heading = round.heading; global_pitch = round.pitch; nextPlayer = "Google"; if (global_panoID) { let locInfo = hex2a(global_panoID); // myLog(locInfo) let mapType = locInfo.substring(0, 5); if (mapType === "BAIDU" ) { nextPlayer = "Baidu"; let lengths = [5, 7, 7, 3]; let toPiece = lengths.map((p => i => locInfo.slice(p, p += i))(0)); let panoId1 = base62.decode(toPiece[1]).toString().substring(1); let panoId2 = base62.decode(toPiece[2]).toString().substring(1); global_BDID = panoId1 + panoId2 + toPiece[3] } } myLog(nextPlayer); injectCanvas(); } /** * setID for canvas */ function initializeCanvas() { let GAME_CANVAS = ""; let DUEL_CANVAS = ""; //myLog("Is duels"); //myLog(duels); if (isBattleRoyale) { if (isDuel) { GAME_CANVAS = document.querySelector(".game-panorama_panorama__rdhFg"); DUEL_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__PNKve"); } else { GAME_CANVAS = document.querySelector(".br-game-layout__panorama-wrapper"); DUEL_CANVAS = "dummy"; } } else { GAME_CANVAS = document.querySelector(".game-layout__canvas"); DUEL_CANVAS = "dummy"; } if (GAME_CANVAS && DUEL_CANVAS) { myLog("Canvas injected"); GAME_CANVAS.id = "player"; if (isDuel) { DUEL_CANVAS.id = "default_player"; } injectBaiduScript(); } else { setTimeout(initializeCanvas, 250); } } /** * Hide or show players based on where the next location is */ function injectCanvas() { if (isDuel) { canvasSwitch(); } else { Google(); Baidu(); } } // for duels (class ID change) function canvasSwitch() { if (document.querySelector(".compass") !== null && document.querySelector("button[data-qa='undo-move']") !== null) { let GOOGLE_MAPS_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__PNKve"); if (nextPlayer === "Google") { document.getElementById("default_player").className = "game-panorama_panoramaCanvas__PNKve"; document.getElementById("PanoramaMap").className = "inactive"; document.getElementById("default_player").style.position = "absolute"; document.querySelector(".compass").style.visibility = ""; document.querySelector("button[data-qa='undo-move']").visibility = ""; myLog("Google Duel Canvas loaded"); } else if (nextPlayer === "Baidu") { document.getElementById("default_player").className = "inactive"; document.getElementById("PanoramaMap").className = "game-panorama_panorama__rdhFg"; document.getElementById("PanoramaMap").style.position = "absolute"; document.querySelector(".compass").style.visibility = "hidden"; document.querySelector("button[data-qa='undo-move']").visibility = "hidden"; myLog("Baidu Duel Canvas loaded"); } } else { setTimeout(canvasSwitch, 250); } } // for Battle Royale and classic (change visibility) function Google() { let GOOGLE_MAPS_CANVAS = "" if (isBattleRoyale) { GOOGLE_MAPS_CANVAS = document.querySelector(".br-game-layout__panorama-canvas"); } else { GOOGLE_MAPS_CANVAS = document.querySelector(".game-layout__panorama-canvas"); } if (nextPlayer === "Google") { GOOGLE_MAPS_CANVAS.style.visibility = ""; myLog("Google Canvas loaded"); } else { GOOGLE_MAPS_CANVAS.style.visibility = "hidden"; myLog("Google Canvas hidden"); } } function Baidu() { let BAIDU_MAPS_CANVAS = document.getElementById("PanoramaMap"); // myLog("Baidu canvas"); // document.getElementById("PanoramaMap").style.position = "absolute"; if (BAIDU_MAPS_CANVAS !== null && document.querySelector(".compass") !== null && document.querySelector("button[data-qa='undo-move']") !== null) { if (nextPlayer === "Baidu") { BAIDU_MAPS_CANVAS.style.visibility = ""; BAIDU_MAPS_CANVAS.style.position = "absolute"; document.querySelector(".compass").style.visibility = "hidden"; document.querySelector("button[data-qa='undo-move']").style.visibility = "hidden"; myLog("Baidu Canvas loaded"); } else { document.querySelector(".compass").style.visibility = ""; document.querySelector("button[data-qa='undo-move']").style.visibility = ""; BAIDU_MAPS_CANVAS.style.visibility = "hidden"; myLog("Baidu Canvas hidden"); } } else { setTimeout(Baidu, 250); } } /** * Open next location in streetview player given next player and next coordinate */ function goToLocation() { myLog("Going to location"); if (nextPlayer === "Baidu") { if (document.getElementById("PanoramaMap") !== null) { let urlStr2 = "https://map.baidu.com/?panotype=street&pid=" + global_BDID + "&panoid=" + global_BDID + "&from=api"; let urlStr = "https://map.baidu.com/@" + global_BDAh + "," + global_BDBh + "#panoid=" + global_BDID + "&panotype=street&l=12&tn=B_NORMAL_MAP&sc=0&newmap=1&shareurl=1&pid=" + global_BDID; if (global_BDAh != null) { document.getElementById("PanoramaMap").src = urlStr; } else { document.getElementById("PanoramaMap").src = urlStr2; } } else { setTimeout(goToLocation, 250); } } } /** * Gets the seed data for the current game * * @returns Promise with seed data as object */ function getSeed() { // myLog("getSeed called"); return new Promise((resolve, reject) => { let token = getToken(); let URL; let cred = "" const PATHNAME = window.location.pathname; if (PATHNAME.startsWith("/game/")) { URL = `https://www.geoguessr.com/api/v3/games/${token}`; } else if (PATHNAME.startsWith("/challenge/")) { URL = `https://www.geoguessr.com/api/v3/challenges/${token}/game`; } else if (PATHNAME.startsWith("/battle-royale/")) { URL = `https://game-server.geoguessr.com/api/battle-royale/${token}`; } else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) { URL = `https://game-server.geoguessr.com/api/duels/${token}`; } if (isBattleRoyale) { fetch(URL, { // Include credentials to GET from the endpoint credentials: 'include' }) .then((response) => response.json()) .then((data) => { resolve(data); }) .catch((error) => { reject(error); }); } else { fetch(URL) .then((response) => response.json()) .then((data) => { resolve(data); }) .catch((error) => { reject(error); }); } }); } /** * Gets the token from the current URL * * @returns token */ function getToken() { const PATHNAME = window.location.pathname; if (PATHNAME.startsWith("/game/")) { return PATHNAME.replace("/game/", ""); } else if (PATHNAME.startsWith("/challenge/")) { return PATHNAME.replace("/challenge/", ""); } else if (PATHNAME.startsWith("/battle-royale/")) { return PATHNAME.replace("/battle-royale/", ""); } else if (PATHNAME.startsWith("/duels/")) { return PATHNAME.replace("/duels/", ""); } else if (PATHNAME.startsWith("/team-duels/")) { return PATHNAME.replace("/team-duels/", ""); } } /** * Gets the round number from the ongoing game from the page itself * * @returns Round number */ function getRoundFromPage() { const roundData = document.querySelector("div[data-qa='round-number']"); if (roundData) { let roundElement = roundData.querySelector("div:last-child"); if (roundElement) { let round = parseInt(roundElement.innerText.charAt(0)); if (!isNaN(round) && round >= 1 && round <= 5) { return round; } } } else { return ROUND; } } /** * Injects Baidu script */ function reportWindowSize() { let iframeC = document.getElementById("PanoramaMap"); iframeC.style.top = '-60px'; iframeC.style.height = (window.innerHeight + 200) + 'px'; iframeC.style.right = '-55px'; iframeC.style.width = (window.innerWidth + 55) + 'px'; } window.onresize = reportWindowSize; function injectBaiduScript() { myLog("Iframe") const iframe = document.createElement('iframe'); // iframe.src = "https://map.baidu.com/" iframe.frameBorder = 0; iframe.style.position = "absolute"; iframe.id = "PanoramaMap"; if (!isFirefox) { iframe.style.top = '-60px'; iframe.style.height = (window.innerHeight + 200) + 'px'; } else { iframe.style.top = '-60px'; iframe.style.height = (window.innerHeight + 219) + 'px'; } if (!isFirefox) { iframe.style.right = '-55px'; iframe.style.width = (window.innerWidth + 55) + 'px'; } else { iframe.style.right = '-15px'; iframe.style.width = (window.innerWidth + 15) + 'px'; } if (isBattleRoyale) { if (isDuel) { iframe.className = "inactive"; } else { iframe.className = "br-game-layout__panorama"; } } else { iframe.className = "game-layout__panorama"; } var div = document.getElementById("player"); div.style.overflow = "hidden"; div.appendChild(iframe); // myLog(div) } /** * Display map per mainland Chinese laws and regulations */ let historicalOverlay, historicalOverlay2, historicalOverlay3; let TW = [[24.80, 119.00, 22.00, 123.20], [24.20, 119.90, 22.90, 121.85], [24.00, 120.90, 23.80, 121.20], [23.93, 121.03, 23.85, 121.15], [23.92, 121.055, 23.89, 121.10], [23.92, 121.055, 23.89, 121.10], [23.92, 121.055, 23.89, 121.10], ] let TS = [[30.40, 93.40, 28, 97.20], [29.40, 94.55, 28.20, 96.45]] let NW = [36.20, 77.70, 34.40, 80.70] let tenDD = { "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": { "adcode": "100000", "name": "", "center": null, "centroid": null, "childrenNum": null, "level": null, "parent": null, "subFeatureIndex": null, "acroutes": null, "adchar": "JD" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 122.51865306, 23.46078502 ], [ 122.51742454, 23.45790762 ], [ 122.51536697, 23.45555069 ], [ 122.51268178, 23.45394494 ], [ 122.50963181, 23.45324755 ], [ 122.5065156, 23.45352678 ], [ 122.5036382, 23.45475531 ], [ 122.50128127, 23.45681287 ], [ 122.49967552, 23.45949807 ], [ 122.49897813, 23.46254804 ], [ 122.49925737, 23.46566424 ], [ 122.77921829, 24.57855302 ], [ 122.78044682, 24.58143041 ], [ 122.78250438, 24.58378734 ], [ 122.78518957, 24.5853931 ], [ 122.78823955, 24.58609049 ], [ 122.79135575, 24.58581125 ], [ 122.79423315, 24.58458272 ], [ 122.79659008, 24.58252516 ], [ 122.79819583, 24.57983997 ], [ 122.79889322, 24.57678999 ], [ 122.79861399, 24.57367379 ], [ 122.51865306, 23.46078502 ] ] ], [ [ [ 121.17202617, 20.8054593 ], [ 121.16966862, 20.80340244 ], [ 121.16679085, 20.80217478 ], [ 121.16367457, 20.80189649 ], [ 121.1606248, 20.8025948 ], [ 121.1579401, 20.80420136 ], [ 121.15588324, 20.80655891 ], [ 121.15465558, 20.80943668 ], [ 121.15437729, 20.81255297 ], [ 121.1550756, 20.81560273 ], [ 121.15668216, 20.81828744 ], [ 121.89404403, 21.70026162 ], [ 121.89640158, 21.70231847 ], [ 121.89927934, 21.70354613 ], [ 121.90239563, 21.70382443 ], [ 121.9054454, 21.70312611 ], [ 121.9081301, 21.70151955 ], [ 121.91018696, 21.699162 ], [ 121.91141462, 21.69628423 ], [ 121.91169291, 21.69316794 ], [ 121.9109946, 21.69011818 ], [ 121.90938804, 21.68743347 ], [ 121.17202617, 20.8054593 ] ] ], [ [ [ 119.47366172, 18.00707291 ], [ 119.47175735, 18.00459056 ], [ 119.46917909, 18.0028182 ], [ 119.46617933, 18.0019293 ], [ 119.4630517, 18.00201089 ], [ 119.46010237, 18.00305497 ], [ 119.45762002, 18.00495935 ], [ 119.45584765, 18.00753761 ], [ 119.45495876, 18.01053737 ], [ 119.45504035, 18.01366499 ], [ 119.45608443, 18.01661433 ], [ 120.00812005, 19.0335793 ], [ 120.01002443, 19.03606165 ], [ 120.01260269, 19.03783401 ], [ 120.01560245, 19.03872291 ], [ 120.01873007, 19.03864132 ], [ 120.02167941, 19.03759723 ], [ 120.02416175, 19.03569286 ], [ 120.02593412, 19.0331146 ], [ 120.02682302, 19.03011484 ], [ 120.02674143, 19.02698721 ], [ 120.02569734, 19.02403788 ], [ 119.47366172, 18.00707291 ] ] ], [ [ [ 119.0726757, 15.04098494 ], [ 119.0726746, 15.04083704 ], [ 119.07218171, 15.00751424 ], [ 119.07164663, 15.00443165 ], [ 119.07018516, 15.00166528 ], [ 119.06794036, 14.99948592 ], [ 119.06513198, 14.99810691 ], [ 119.06203491, 14.99766324 ], [ 119.05895232, 14.99819832 ], [ 119.05618595, 14.99965979 ], [ 119.05400659, 15.00190458 ], [ 119.05262758, 15.00471297 ], [ 119.0521839, 15.00781004 ], [ 119.0526757, 15.04105889 ], [ 119.0526757, 16.04388528 ], [ 119.05316513, 16.04697545 ], [ 119.05458553, 16.04976313 ], [ 119.05679784, 16.05197545 ], [ 119.05958553, 16.05339584 ], [ 119.0626757, 16.05388528 ], [ 119.06576587, 16.05339584 ], [ 119.06855355, 16.05197545 ], [ 119.07076587, 16.04976313 ], [ 119.07218626, 16.04697545 ], [ 119.0726757, 16.04388528 ], [ 119.0726757, 15.04098494 ] ] ], [ [ [ 118.68646749, 11.18959191 ], [ 118.85557939, 11.6136711 ], [ 118.9698053, 11.99151854 ], [ 118.97116801, 11.99433487 ], [ 118.97333431, 11.99659227 ], [ 118.97609216, 11.99806975 ], [ 118.9791716, 11.99862269 ], [ 118.98227119, 11.99819697 ], [ 118.98508753, 11.99683427 ], [ 118.98734492, 11.99466796 ], [ 118.9888224, 11.99191011 ], [ 118.98937534, 11.98883067 ], [ 118.98894963, 11.98573108 ], [ 118.87459939, 11.60747236 ], [ 118.87431591, 11.606662 ], [ 118.70476212, 11.18147468 ], [ 118.70409227, 11.18010771 ], [ 118.54242469, 10.9053354 ], [ 118.54043581, 10.90292022 ], [ 118.53779795, 10.90123786 ], [ 118.53476931, 10.90045298 ], [ 118.53164636, 10.90064241 ], [ 118.5287348, 10.90178762 ], [ 118.52631962, 10.9037765 ], [ 118.52463726, 10.90641436 ], [ 118.52385237, 10.909443 ], [ 118.52404181, 10.91256595 ], [ 118.52518702, 10.91547751 ], [ 118.68646749, 11.18959191 ] ] ], [ [ [ 115.54466883, 7.14672265 ], [ 115.54229721, 7.14468204 ], [ 115.53941108, 7.14347417 ], [ 115.53629295, 7.14321728 ], [ 115.53324806, 7.14393652 ], [ 115.53057445, 7.14556148 ], [ 115.52853383, 7.1479331 ], [ 115.52732596, 7.15081924 ], [ 115.52706908, 7.15393736 ], [ 115.52778832, 7.15698226 ], [ 115.52941328, 7.15965587 ], [ 116.23523025, 7.99221221 ], [ 116.23760187, 7.99425282 ], [ 116.240488, 7.99546069 ], [ 116.24360613, 7.99571758 ], [ 116.24665102, 7.99499834 ], [ 116.24932463, 7.99337338 ], [ 116.25136525, 7.99100176 ], [ 116.25257312, 7.98811563 ], [ 116.25283001, 7.9849975 ], [ 116.25211077, 7.98195261 ], [ 116.2504858, 7.979279 ], [ 115.54466883, 7.14672265 ] ] ], [ [ [ 112.30705249, 3.53487257 ], [ 112.51501594, 3.59753306 ], [ 112.84361424, 3.7506962 ], [ 112.84662187, 3.75155809 ], [ 112.84974864, 3.7514484 ], [ 112.85268847, 3.75037785 ], [ 112.8551536, 3.74845124 ], [ 112.85690272, 3.74585715 ], [ 112.85776462, 3.74284952 ], [ 112.85765492, 3.73972276 ], [ 112.85658437, 3.73678292 ], [ 112.85465776, 3.7343178 ], [ 112.85206367, 3.73256867 ], [ 112.52281386, 3.57910186 ], [ 112.52147408, 3.5785908 ], [ 112.31248917, 3.51562254 ], [ 112.31181658, 3.51544515 ], [ 111.79132585, 3.39736822 ], [ 111.78820398, 3.39716187 ], [ 111.78517113, 3.39793033 ], [ 111.78252419, 3.39959839 ], [ 111.78052226, 3.40200275 ], [ 111.77936129, 3.40490807 ], [ 111.77915495, 3.40802995 ], [ 111.77992341, 3.41106279 ], [ 111.78159146, 3.41370973 ], [ 111.78399583, 3.41571167 ], [ 111.78690114, 3.41687263 ], [ 112.30705249, 3.53487257 ] ] ], [ [ [ 108.26055972, 6.08912451 ], [ 108.26004031, 6.09098419 ], [ 108.23638164, 6.22427602 ], [ 108.23630689, 6.22476797 ], [ 108.19687578, 6.53630242 ], [ 108.19679674, 6.53760583 ], [ 108.1987683, 6.95072469 ], [ 108.19897125, 6.95268198 ], [ 108.22460147, 7.07791743 ], [ 108.22570055, 7.08084671 ], [ 108.22765103, 7.083293 ], [ 108.230262, 7.08501682 ], [ 108.23327786, 7.08584944 ], [ 108.23640341, 7.08570936 ], [ 108.2393327, 7.08461028 ], [ 108.24177899, 7.0826598 ], [ 108.24350281, 7.08004883 ], [ 108.24433543, 7.07703297 ], [ 108.24419535, 7.07390742 ], [ 108.21876335, 6.94964057 ], [ 108.21679964, 6.53816468 ], [ 108.25611734, 6.22752625 ], [ 108.279563, 6.09543449 ], [ 108.30878645, 6.01987736 ], [ 108.30944469, 6.0168187 ], [ 108.30912553, 6.01370633 ], [ 108.30786022, 6.01084492 ], [ 108.30577262, 6.00851455 ], [ 108.30306706, 6.00694335 ], [ 108.3000084, 6.00628511 ], [ 108.29689603, 6.00660426 ], [ 108.29403462, 6.00786957 ], [ 108.29170425, 6.00995718 ], [ 108.29013305, 6.01266273 ], [ 108.26055972, 6.08912451 ] ] ], [ [ [ 110.12822847, 11.36894451 ], [ 110.18898148, 11.48996382 ], [ 110.23982347, 11.61066468 ], [ 110.28485499, 11.78705054 ], [ 110.3083549, 11.94803461 ], [ 110.3142445, 12.14195265 ], [ 110.312278, 12.23998238 ], [ 110.31270536, 12.24308175 ], [ 110.31406956, 12.24589736 ], [ 110.31623706, 12.2481536 ], [ 110.3189957, 12.24962962 ], [ 110.32207543, 12.25018094 ], [ 110.32517479, 12.24975358 ], [ 110.3279904, 12.24838938 ], [ 110.33024665, 12.24622187 ], [ 110.33172267, 12.24346324 ], [ 110.33227398, 12.24038351 ], [ 110.33424553, 12.14210167 ], [ 110.33424294, 12.14159753 ], [ 110.32832827, 11.94685414 ], [ 110.32822801, 11.94571326 ], [ 110.30456934, 11.78364161 ], [ 110.30436343, 11.7826124 ], [ 110.25901765, 11.60499559 ], [ 110.25854422, 11.60358735 ], [ 110.20728377, 11.48189306 ], [ 110.20700505, 11.48128846 ], [ 110.14588682, 11.35954163 ], [ 110.14541497, 11.35870461 ], [ 110.07246741, 11.24270688 ], [ 110.07040803, 11.24035153 ], [ 110.0677216, 11.23874785 ], [ 110.06467109, 11.23805281 ], [ 110.0615551, 11.23833444 ], [ 110.05867865, 11.23956519 ], [ 110.05632331, 11.24162456 ], [ 110.05471962, 11.24431099 ], [ 110.05402458, 11.2473615 ], [ 110.05430621, 11.25047749 ], [ 110.05553696, 11.25335394 ], [ 110.12822847, 11.36894451 ] ] ], [ [ [ 109.82951587, 15.22896754 ], [ 109.77065019, 15.44468789 ], [ 109.67264555, 15.66561455 ], [ 109.57455994, 15.82609887 ], [ 109.51574449, 15.91095759 ], [ 109.29314007, 16.19491896 ], [ 109.29161878, 16.19765288 ], [ 109.29101677, 16.20072311 ], [ 109.29139298, 16.2038291 ], [ 109.29271057, 16.20666681 ], [ 109.29484059, 16.20895848 ], [ 109.29757451, 16.21047978 ], [ 109.30064474, 16.21108179 ], [ 109.30375073, 16.21070558 ], [ 109.30658844, 16.20938798 ], [ 109.30888011, 16.20725797 ], [ 109.53166592, 15.92306523 ], [ 109.53201478, 15.92259221 ], [ 109.59116145, 15.8372556 ], [ 109.59147511, 15.83677407 ], [ 109.6900529, 15.67548445 ], [ 109.69066131, 15.67432448 ], [ 109.7892391, 15.45210582 ], [ 109.78974541, 15.45068337 ], [ 109.84889209, 15.23393326 ], [ 109.84903675, 15.23333003 ], [ 109.8648092, 15.15722425 ], [ 109.86495704, 15.15409906 ], [ 109.86413191, 15.15108113 ], [ 109.86241457, 15.1484659 ], [ 109.85997314, 15.14650935 ], [ 109.85704658, 15.145403 ], [ 109.85392139, 15.14525516 ], [ 109.85090347, 15.14608029 ], [ 109.84828823, 15.14779763 ], [ 109.84633168, 15.15023907 ], [ 109.84522534, 15.15316562 ], [ 109.82951587, 15.22896754 ] ] ] ] } }] }