-
-
Save 2Abendsegler/1f35557bcb032333bc5f4595f0a958aa to your computer and use it in GitHub Desktop.
GCTour
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name GC Tour | |
// @namespace https://gist.github.com/DieBatzen/5814dc7368c1034470c8/ | |
// @version 4.11 | |
// @description Cachetour planning made easy. Pick some Caches, sort the list and print it out. Free for all users of geocaching.com! | |
// @author madd.in, Die Batzen | |
// @run-at document-end | |
// @include http*://www.geocaching.com/* | |
// @include https://gctour.geocaching.cx/map/show* | |
// @exclude /^https?://www\.geocaching\.com/(login|jobs|promotions|blog)/ | |
// @updateURL https://gist.github.com/DieBatzen/5814dc7368c1034470c8/raw/gctour.version.js | |
// @downloadURL https://gist.github.com/DieBatzen/5814dc7368c1034470c8/raw/gctour.user.js | |
// @supportURL https://geoclub.de/forum/viewtopic.php?f=117&t=78798&start=9999 | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_deleteValue | |
// @grant GM_log | |
// @grant GM_addStyle | |
// @grant GM_xmlhttpRequest | |
// @grant GM_openInTab | |
// @grant GM_listValues | |
// @grant unsafeWindow | |
// @icon https://gctour.geocaching.cx/i/icon.png | |
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js | |
// @require https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js | |
// @require https://raw.githubusercontent.com/eligrey/FileSaver.js/1.3.4/FileSaver.min.js | |
// @require https://unpkg.com/[email protected]/dist/leaflet.js | |
// @connect gctour.geocaching.cx | |
// @connect geocaching.com | |
// @connect gist.github.com | |
// @connect gist.githubusercontent.com | |
// @connect nominatim.openstreetmap.org | |
// @connect * | |
// ==/UserScript== | |
/***************************************************************************** | |
* Copyright (C) 2008 - 2014 Martin Georgi, 2015 - 2019 Die Batzen | |
* | |
* This is free software; you can redistribute it and/or modify it under the | |
* terms of the GNU General Public License as published by the Free Software | |
* Foundation; either version 3 of the License, or (at your option) any later | |
* version. | |
* | |
* This is distributed in the hope that it will be useful, but WITHOUT ANY | |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
* | |
* To obtain a copy of the GNU General Public License, please see | |
* <https://www.gnu.org/licenses> | |
*****************************************************************************/ | |
(function () { // begin of immediately-invoked function expression --> own "GCTour namespace" | |
/* globals */ | |
let | |
VERSION = GM_info.script.version, // will be checked once a day | |
DEBUG_MODE = false, | |
GCTOUR_HOST = 'https://gctour.geocaching.cx/', | |
HTTP = window.location.protocol, // http or https | |
GS_HOST = HTTP + '//www.geocaching.com/', | |
GS_WPT_IMAGE_PATH = 'images/wpttypes/sm/', | |
// set $ to jQuery local (Greasemonkey) | |
$ = window.jQuery, | |
// are jQuery and UI loaded | |
IS_JQUERY = ( | |
(typeof $ !== "undefined") && (typeof $ === "function") && | |
(typeof $.fn === "object") && (typeof $.ui === "object")), | |
IS_FF = (IS_JQUERY && $.browser.mozilla) ? true : false, | |
IS_OPERA = (IS_JQUERY && $.browser.opera) ? true : false, | |
IS_GREASEMONKEY = (typeof GM_info.scriptHandler === "undefined") ? true : false, | |
TOURS, | |
CURRENT_TOUR, | |
USERNAME, | |
ROT13_ARRAY, | |
TIMEOUT, | |
STICKY = GM_getValue('sticky', false), | |
PROGRESS_BAR = {"progress" : 0, "total" : 0}, | |
FAVSCORE = true, | |
DELETED_STYLESHEET_RULES = [], | |
AUTOTOUR_NEW = false, // interesting filter parameters are PM only :( | |
//AUTOTOUR_NEW = isPremiumUser() ? true : false, | |
LM, // Leaflet Map for autoTour | |
WPT_ARRAY = [{ | |
wptTypeId : "2", | |
hash : "32bc9333-5e52-4957-b0f6-5a2c8fc7b257", | |
name : "Traditional Cache", | |
shortname: "traditional", | |
gsDisplayName: "Traditional Cache" | |
}, { | |
wptTypeId : "3", | |
hash : "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74", | |
name : "Multi-cache", | |
shortname: "multi", | |
gsDisplayName: "Multi-Cache" | |
}, { | |
wptTypeId : "8", | |
hash : "40861821-1835-4e11-b666-8d41064d03fe", | |
name : "Unknown Cache", | |
shortname: "mystery", | |
gsDisplayName: "Mystery Cache" | |
}, { | |
wptTypeId : "5", | |
hash : "4bdd8fb2-d7bc-453f-a9c5-968563b15d24", | |
name : "Letterbox Hybrid", | |
shortname: "letterbox", | |
gsDisplayName: "Letterbox Hybrid" | |
}, { | |
wptTypeId : "11", | |
hash : "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d", | |
name : "Webcam Cache", | |
gsDisplayName: "Webcam Cache" | |
}, { | |
wptTypeId : "4", | |
hash : "294d4360-ac86-4c83-84dd-8113ef678d7e", | |
name : "Virtual Cache", | |
shortname: "virtual", | |
gsDisplayName: "Virtual Cache" | |
}, { | |
wptTypeId : "1858", | |
hash : "0544fa55-772d-4e5c-96a9-36a51ebcf5c9", | |
name : "Wherigo Cache", | |
shortname: "wherigo", | |
gsDisplayName: "Wherigo Cache" | |
}, { | |
wptTypeId : "137", | |
hash : "c66f5cf3-9523-4549-b8dd-759cd2f18db8", | |
name : "Earthcache", | |
shortname: "earth", | |
gsDisplayName: "EarthCache" | |
}, { | |
wptTypeId : "6", | |
hash : "69eb8534-b718-4b35-ae3c-a856a55b0874", | |
name : "Event Cache", | |
shortname: "event", | |
gsDisplayName: "Event Cache" | |
}, { | |
wptTypeId : "13", | |
hash : "57150806-bc1a-42d6-9cf0-538d171a2d22", | |
name : "Cache In Trash Out Event", | |
shortname: "cito", | |
gsDisplayName: "Cache In Trash Out® Event Cache" | |
}, { | |
wptTypeId : "453", | |
hash : "69eb8535-b718-4b35-ae3c-a856a55b0874", | |
name : "Mega-Event Cache", | |
shortname: "mega", | |
gsDisplayName: "Mega-Event Cache" | |
}, { | |
wptTypeId : "7005", | |
hash : "", | |
name : "Giga-Event Cache", | |
shortname: "giga", | |
gsDisplayName: "Giga-Event Cache" | |
} | |
// {wptTypeId : "3653", hash : "3ea6533d-bb52-42fe-b2d2-79a3424d4728", name : "Lost and Found Event Cache", gsDisplayName: ""} | |
// {wptTypeId: "4738", hash: "", name: "Geocaching Block Party", gsDisplayName: "Geocaching Block Party"} | |
// {wptTypeId: "3773", hash: "", name: "Groundspeak Headquarters Cache", gsDisplayName: "Geocaching HQ"} // HQ_32.gif | |
// {wptTypeId: "1304", hash: "", name: "GPS Adventures Maze Exhibit", gsDisplayName: "GPS Adventures Exhibit Cache"} | |
// {wptTypeId: "12", hash: "", name: "Locationless (Reverse) Cache", gsDisplayName: "Locationless Cache"} | |
], | |
SIZES_ARRAY = [{ | |
sizeTypeId : "micro", | |
name : "Micro", | |
newSearchId : 2 | |
}, { | |
sizeTypeId : "small", | |
name : "Small", | |
newSearchId : 8 | |
}, { | |
sizeTypeId : "regular", | |
name : "Regular", | |
newSearchId : 3 | |
}, { | |
sizeTypeId : "large", | |
name : "Large", | |
newSearchId : 4 | |
}, { | |
sizeTypeId : "other", | |
name : "Other", | |
newSearchId : 6 | |
}, { | |
sizeTypeId : "not_chosen", // not supported in new Groundspeak search | |
name : "Not chosen" | |
}, { | |
sizeTypeId : "virtual", | |
name : "Virtual", | |
newSearchId : 5 | |
} | |
], | |
// https://www.geocaching.com/about/icons.aspx | |
ATTRIBUTES_ARRAY = [ | |
// Attribute: [array ID, image, name] | |
['1', 'dogs', 'Dogs'], | |
['2', 'fee', 'Access or parking fee'], | |
['3', 'rappelling', 'Climbing gear'], | |
['4', 'boat', 'Boat'], | |
['5', 'scuba', 'Scuba gear'], | |
['6', 'kids', 'Recommended for kids'], | |
['7', 'onehour', 'Takes less than an hour'], | |
['8', 'scenic', 'Scenic view'], | |
['9', 'hiking', 'Significant hike'], | |
['10', 'climbing', 'Difficult climbing'], | |
['11', 'wading', 'May require wading'], | |
['12', 'swimming', 'May require swimming'], | |
['13', 'available', 'Available at all times'], | |
['14', 'night', 'Recommended at night'], | |
['15', 'winter', 'Available during winter'], | |
['17', 'poisonoak', 'Poison plants'], | |
['18', 'dangerousanimals', 'Dangerous Animals'], | |
['19', 'ticks', 'Ticks'], | |
['20', 'mine', 'Abandoned mines'], | |
['21', 'cliff', 'Cliff / falling rocks'], | |
['22', 'hunting', 'Hunting'], | |
['23', 'danger', 'Dangerous area'], | |
['24', 'wheelchair', 'Wheelchair accessible'], | |
['25', 'parking', 'Parking available'], | |
['26', 'public', 'Public transportation'], | |
['27', 'water', 'Drinking water nearby'], | |
['28', 'restrooms', 'Public restrooms nearby'], | |
['29', 'phone', 'Telephone nearby'], | |
['30', 'picnic', 'Picnic tables nearby'], | |
['31', 'camping', 'Camping available'], | |
['32', 'bicycles', 'Bicycles'], | |
['33', 'motorcycles', 'Motorcycles'], | |
['34', 'quads', 'Quads'], | |
['35', 'jeeps', 'Off-road vehicles'], | |
['36', 'snowmobiles', 'Snowmobiles'], | |
['37', 'horses', 'Horses'], | |
['38', 'campfires', 'Campfires'], | |
['39', 'thorn', 'Thorns'], | |
['40', 'stealth', 'Stealth required'], | |
['41', 'stroller', 'Stroller accessible'], | |
['42', 'firstaid', 'Needs maintenance'], | |
['43', 'cow', 'Watch for livestock'], | |
['44', 'flashlight', 'Flashlight required'], | |
['45', 'landf', 'Lost And Found Tour'], | |
['46', 'rv', 'Truck Driver/RV'], | |
['47', 'field_puzzle', 'Field Puzzle'], | |
['48', 'UV', 'UV Light Required'], | |
['49', 'snowshoes', 'Snowshoes'], | |
['50', 'skiis', 'Cross Country Skis'], | |
['51', 's-tool', 'Special Tool Required'], // meanwhile image is 's-tool', but the minus would cause problems... | |
['52', 'nightcache', 'Night Cache'], | |
['53', 'parkngrab', 'Park and Grab'], | |
['54', 'abandonedbuilding', 'Abandoned structure'], | |
['55', 'hike_short', 'Short hike (less than 1km)'], | |
['56', 'hike_med', 'Medium hike (1km-10km)'], | |
['57', 'hike_long', 'Long hike (+10km)'], | |
['58', 'fuel', 'Fuel Nearby'], | |
['59', 'food', 'Food Nearby'], | |
// liste von http://forums.groundspeak.com/GC/index.php?s=5a098c310648d9f536ab03a85432e70d&showtopic=282652&view=findpost&p=4855718 | |
['60', 'wirelessbeacon', 'Wireless Beacon'], | |
['61', 'partnership', 'Partnership cache'], | |
['62', 'seasonal', 'Seasonal Access'], | |
['63', 'touristOK', 'Tourist Friendly'], | |
['64', 'treeclimbing', 'Tree Climbing'], | |
['65', 'frontyard', 'Front Yard (Private Residence)'], | |
['66', 'teamwork', 'Teamwork Required'], | |
['67', 'geotour', 'GeoTour'] | |
]; | |
/* | |
// TEST Anfang | |
// test3 | |
jQuery(function ($) { | |
alert("3. jQuery: " + $.fn.jquery); | |
}); | |
// test2 | |
if (typeof unsafeWindow.jQuery !== "undefined") { | |
unsafeWindow.jQuery(function ($) { | |
alert("2. unsafeWindow.jQuery: " + $.fn.jquery); | |
}); | |
} else { | |
alert("2. unsafeWindow.jQuery not available"); | |
} | |
// test1 | |
alert("1. $: " + $.fn.jquery); | |
// TEST ENDE | |
*/ | |
/* greasemonkey settings and functions */ | |
// debug output functions | |
function toLog(typ, msg) { | |
if (DEBUG_MODE) { | |
msg = 'GCTour: ' + msg; | |
//var console = unsafeWindow.console; //firebug console - http://getfirebug.com/wiki/index.php/Console_API | |
if (console && console[typ.toLowerCase()]) { | |
console[typ.toLowerCase()](msg); | |
} else { | |
GM_log(typ + ": " + msg.toString()); | |
} | |
} | |
} | |
function log(msg) { | |
toLog("Log", msg); | |
} | |
function debug(msg) { | |
toLog("Debug", msg); | |
} | |
function warn(msg) { | |
toLog("Warn", msg); | |
} | |
function error(msg) { | |
toLog("Error", msg); | |
} | |
function info(msg) { | |
toLog("Info", msg); | |
} | |
function log_exception(ex) { | |
toLog("Exception", ex); | |
} | |
// wrapper functions for persistence | |
function saveValue(name, value) { | |
GM_setValue(name, JSON.stringify(value)); | |
//return (GM_setValue(name, JSON.stringify(value))); | |
} | |
function loadValue(name, defaultValue) { | |
//debug("loadValue: '" + name + "', with default '" + defaultValue + "' (typeof " + (typeof defaultValue) + ")"); | |
var result = GM_getValue(name, ""); | |
//debug("loadValue: result -> '" + result.substr(0, 20) + "...'"); | |
try { | |
return result != "" ? JSON.parse(result) : defaultValue; | |
} catch (e) { // fallback eval | |
debug("loadValue: FALLBACK :-("); | |
return eval(result); | |
} | |
} | |
// GM_xmlhttpRequest response info | |
function responseInfo(r) { | |
debug([ "", | |
"finalUrl: \t\t" + (r.finalUrl || "-"), | |
"status: \t\t" + (r.status || "-"), | |
"statusText: \t\t" + (r.statusText || "-"), | |
"readyState: \t\t" + (r.readyState || "-"), | |
"responseHeaders: \n\t" + (r.responseHeaders || "-"), | |
"responseXML: \t\t" + (r.responseXML || "-"), | |
"responseText: \t\t" + (r.responseText || "-") | |
].join("\n")); | |
} | |
// set jquery and ui | |
(function () { | |
var str = ""; | |
str += "jQuery und UI geladen = " + IS_JQUERY; | |
if (IS_JQUERY) { | |
str += "\n\tjQuery Version = " + $.fn.jquery; | |
str += "\n\tjQueryUI Version = " + $.ui.version; | |
} | |
// str += "\n\tisunsafeWindow.jQuery = " + isjQueryWindow; | |
// str += "\n\tunsafeWindow.jQuery Version = " + ((isjQueryWindow) ? unsafeWindow.jQuery.fn.jquery : ""); | |
// debug(str); | |
// init gctour object | |
$.gctour = $.gctour || {}; | |
// init language object | |
$.gctour.i18n = $.gctour.i18n || {}; | |
// set default Language | |
$.gctour.defaultLang = 'en'; | |
// init current language = default language | |
$.gctour.currentLang = $.gctour.defaultLang; | |
// jquery ui dialog (default setting) | |
$.gctour.dialog = $.gctour.dialog || {}; | |
// default dialogs (http://api.jqueryui.com/dialog/) | |
$.extend($.gctour.dialog, { | |
buttons: { | |
'OK': { | |
text: 'OK', | |
disabled: false, | |
click: function () { | |
$(this).dialog("destroy"); | |
} | |
}, | |
'Schliessen': { | |
text: 'Schliessen', | |
disabled: false, | |
icons: { | |
primary: 'ui-icon-closethick' | |
}, | |
click: function () { | |
$(this).dialog("destroy"); | |
} | |
}, | |
'Abbrechen': { | |
text: 'Abbrechen', | |
disabled: false, | |
click: function () { | |
$(this).dialog("destroy"); | |
} | |
} | |
}, | |
/* | |
* Standard Optionen für ein Dialog | |
*/ | |
basis: function () { | |
return ({ | |
autoOpen: false, | |
resizable: true, | |
closeOnEscape: true, | |
modal: true, | |
closeText: $.gctour.lang('btn.Schliessen') || 'Schliessen', | |
show: 'drop', // blind, drop, scale | |
buttons: { | |
'Schliessen': this.buttons.Schliessen | |
}, | |
width: 700, | |
height: 500, | |
minWidth: 300, | |
minHeight: 200, | |
maxWidth: 1000, | |
maxHeight: 700, | |
title: 'GCTour', | |
dialogClass: 'gct gct_dialog', | |
open: function (event, ui) { | |
//$(".ui-dialog-titlebar-close").hide(); | |
// $(this).dialog( "widget" ).find(".ui-dialog-titlebar-close").hide(); // x oben rechts ausblenden | |
//$(".ui-widget-overlay").wrap('<div class="gct"></div>'); // wrap für bessere Trennung zu gc.com | |
}, | |
beforeClose: function (event, ui) { | |
//if ( $(".ui-widget-overlay").parent().hasClass( "gct" ) ) { | |
// $(".ui-widget-overlay").unwrap(); | |
//} | |
}, | |
close: function (event, ui) { | |
$(this).dialog("destroy"); // diesen Dialog killen, weil immer ein neuer erstellt wird | |
} | |
}); | |
}, | |
/* | |
* Info Optionen für ein Dialog | |
*/ | |
info: function () { | |
return ({ | |
autoOpen: true, | |
resizable: true, | |
closeOnEscape: true, | |
modal: true, | |
closeText: $.gctour.lang('general.close'), | |
show: true, // true, false, 'blind', 'drop', 'scale' | |
hide: true, | |
height: 'auto', | |
title: 'GCTour Info', | |
dialogClass: 'gct gct_dialog', | |
open: function (event, ui) { | |
addJqUiTheme(GM_getValue('theme', 'smoothness')); | |
// remove interfering rules from GS stylesheet "coreCSS" (present on (old) dashboard page and others) | |
var sheet = getStyleSheet("coreCSS"); | |
if(typeof sheet !== "undefined") { | |
DELETED_STYLESHEET_RULES = deleteStyleSheetRules(sheet,/.ui-|select/); | |
debug(DELETED_STYLESHEET_RULES.length + ' rules in stylesheet "coresCSS" temporarily removed'); | |
} | |
}, | |
close: function (event, ui) { | |
// remove jqui theme | |
$("head link#gct-ui-theme-link").remove(); | |
// restore deleted stylesheet rules (if necessary) | |
var sheet = getStyleSheet("coreCSS"); | |
if(typeof sheet !== "undefined") { | |
for (var i=0; i<DELETED_STYLESHEET_RULES.length; i++) { | |
sheet.insertRule(DELETED_STYLESHEET_RULES[i], sheet.cssRules.length); | |
} | |
debug(DELETED_STYLESHEET_RULES.length + ' rules in stylesheet "coresCSS" restored'); | |
DELETED_STYLESHEET_RULES = []; | |
} | |
} | |
}); | |
} | |
}); | |
$.fn.addShadowEffect = function () { | |
return this.each(function () { | |
$(this).bind({ | |
mouseenter : function () { | |
$(this).addClass("imgShadow"); | |
}, | |
mouseleave : function () { | |
$(this).removeClass("imgShadow"); | |
} | |
}); | |
}); | |
}; | |
$.fn.addOpacityEffect = function () { | |
return this.each(function () { | |
var $this = $(this); | |
$this | |
.css({ | |
opacity : "0.5" | |
}) | |
.bind({ | |
mouseenter : function () { | |
$this.stop().animate({ | |
opacity : '1' | |
}, 300); | |
}, | |
mouseleave : function () { | |
$this.stop().animate({ | |
opacity : '0.5' | |
}, 300); | |
} | |
}); | |
}); | |
}; | |
})(); | |
/* images */ | |
$.gctour.img = { | |
addToTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9kFFAUXKNiDRngAAAJmSURBVDjLjZPPS1RRFMc%2F972n1qiUpqMRaj8UXPVj46Igw0WrKIKkwEWSCC4jjKLoX5BoU5GUJg6KFrVpFYiBEAouAkH0Of4endHRKSSY53v3tHgzbyxddFb3Xu753O%2F3nHMVwOBw5LpSvBQtFQIggpAJkV1lGCOe53a13Ln7lYNicKg%2FtrWdlIMinU7LenxNPn4e%2Ft0%2F8P7Jv7kGgOu6x48eKWEzmWA9ESMWX2FlbYml1XnimzF%2BplLcuHbzcEW48mlfpOfxPoAWQRBcz2XWnsWetbFtmzl7jpmZWaILUQzD4MrlplBB%2FqFn73q7G7MAC0C0BgHPc6mprvaBotGiEa1ZXl7hw6ch8q0Czp09H%2Fo%2BPtYJjAYArTUArreLbUcR0YgIon2QJ5q8vDzCleUopXB33atv3r6y2u91uFbWgg%2FQVFdXAeIDBH5cbMTZ2AQgXV5GQzzB6LcRU0RbgJuzkGnfQnQeUf4awNnY5FJbGyjFWHc3%2FoMa0cI%2BC0opTp05jVIqqPJGVqEEk4FoHajOAPyNaZoszi%2BSuHUbN7nlXwiFfIVKkVdYSMQwKAJTGcYiUGFlJfkAi9q6WmLJLRpaW4MXdUbRhebm4Gy8pyf8dxsVWIaJPb8AwK%2BpKf4nAgsKMAyTuro61sNhpicmAMgvKuJkfT0AC9PTODs7mRE0EmjNHgsK0zQBaJqeyhRS8aXkWFAwZ2eHFtE8f9HliUgN9x%2F6AMu0Vre2kydKS8vI1T%2B30ns6kEqlsCwznk476cCC4zjtA4OR147jVOV%2BsZ9UXlxMdHLSBxUX09vXs%2BJ5bkfng0cC8AdIoVh%2Ffv3rlAAAAABJRU5ErkJggg%3D%3D', | |
autoTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAFMAIwADJfKnZwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9kKEg8hB1Dip48AAAJvSURBVDjLjdNLSFVBHMfx73%2FOued4r14wpSLQNj0JokUtFIKCgqIXPQgikqSijUrqoqA21lIkywoiCAqyRUZRFBGFoIEkFdHGoPcLF75S79Nz7sy0UK6kIf03s5j%2FfGZ%2BzIwwR7UecLYrl91a0yOiuxpu82Vmj8wFXDzopPedeRrtf98V9r24lRsf%2BpkRpbpzob43tlK3NzVhBODK0ZILYSZRa612ZiI1NzMEqRGUDciO%2FmDwUw8f3z7na9%2BLz3U3s0tdgCAzXlfV%2Bk3F4vPwPD%2B%2F%2BFKVB0B65DvhyAeYGKE4HqNy23E%2BvutcAuACYI1y%2FRjZbIZsNjOdTzlYnaMgXoprFhEMjRIM90GYAGuZBgCbHsCEKbBmatKwbN0ueu%2BcpGxFJb5fgHKL8OML0clf%2BU3yAAMvMalB%2FPmriC1aizgRNh1upvPaETrfPCOdGsOGKUoXLGbL9j0UFcWBsWlATyTo%2F9DL4KtuhpPwO4gxmnWpPtTAhtIyQAhTAwTj%2FSCQTCZmRLCa4iKX4rjHcnEQ16Oh%2FjqvO9r%2FupXmlmpiC1fPjqBzOYJsCqNDrMlhTI6zp9ajdci5ll5On1iD0SFDX3ooceOzAQuIAjGKx9eeA7D12EYcNfnWnIiP47oYrXFcfzagRCGiUI6ws2YHVmseXX3CtuObAYh4UazRWNf8G0AEpSIYDA%2Fb7k03RKKTo1%2BItQZrNK4XnQ2ICCKKB2132duwHwvcb%2B3A8QsmT%2BAXIlNRI35sBiBickFaxcorOHS%2BgluNjfmGwrJKoIPC8sopQNBhGkRM%2FjdeqY5eCIOg1lrr8B8lIjrieZdrbmTq%2FwA8AAC7ufHXbAAAAABJRU5ErkJggg%3D%3D', | |
bg : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAoCAYAAAAPOoFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPZJREFUeNq81tsOgjAMANB2ov7/7ypaN7IlIwi9rGuT8QSc9EIDAsAznxvY4pXPKr05RUE5MEVB+TyWfCEl9LZApYopCmo9C4FKSMtYoI8Bwv79aQJU4l6hXXCZrQbokJEksxHo9KMOgc6w1atHXM8K9DVC7FQnJ0i8iK3QooGgbnyKgMDygBWyYFZoqx4qS27KqLZJjA1D0jK6QJcYEQEiWv9PGkTsbqxQ8oT+ZtZB6AkdsJnQDnMoHXHLGKOgDYuCWmYhEERCI5gaamW0bnHdA3k2ltlIN+2qKRyCND0bhqSYCyTB3CAOc4WusBEIpkeBuPgJMAAX8Hs1NfqHRgAAAABJRU5ErkJggg==', | |
bottomArrow : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAMAAADKSsaaAAAAAXNSR0IArs4c6QAAAKtQTFRFHwAWEnMAFXUAIncAHXoDHnoHIHsAInwGI30AKH4TK4AAM4UGMYYLO4oQQ44VRI4XSZAbUZYhVpcnWpooYZ0wXZ45Yp4wW587ZJ4wXqBCZ6A0ZqA4YaJFaqI2baI4ZaRHZ6RFbaQ%2BbqQ8c6pOe65UgLJZf7JggbRmhLVlhLVpiLdqjbluj7tzlcB%2FlsGBl8GCncSHoMWJoMeJpMiMqMqPp8uPqcuQrM2Tr86VhHe%2ByAAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsRAAALEQF%2FZF%2BRAAAAB3RJTUUH2ggZCg4FgW6a6gAAAGBJREFUCNdjYGAQFBaTVWIAAQETcws5MIvPWNtcCsziNdQyEwHS7DyiBhqmKtKKDCySuppqOmaqEgwMnDJ66kbKQiB1rPL6CvxgdYxs4txcEHVMHMy41AEBUB0DFHCACADfrAlJwjTUvQAAAABJRU5ErkJggg%3D%3D', | |
closebutton : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAPCAYAAADphp8SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAFPwAABT8BE2RkrAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAK9SURBVDiNfZNLaBNRFIb%2FO5lJJjGSNtO0lNAm0xZaWxeCpMG4KSrUirpxI0TduLIIPkAQBXEhSBe6EEHQhYoNWKuID%2BgLfODGUrCIGlsKtmBfE1MjQ5Kaedzjog%2FGRjzwcy%2Fn3P%2FjHC4HRASnBurrz77Zvv11L%2BDfWCMiDKrq5Vfbto30Al5nXoQjBiORi2oicV6yLL9LkkZSjHUmifS1%2BnBDw1U1Hj8l2rbXJYrDKca6kkR5AGBEtAKpq7sU2bHjvJDJeEEEV2UlFjVtbHZsbO9hy%2Fo5pKrXou3t3dA0GURwKQpmZ2bez42P704SFdc7Mg1DM02z6GbMS7YNvrSE6lAohlhsZCAS%2BRCNxY7y%2BXmPYwBulUpZAMZfHQHAs2DwcF0icd2Tz9eSaQIAXIEASJaJaxpbeyeEQvb3dPpRdmrqSJKIl4EA4GlFxb5wLHbLZ1n1vFRCWSjK77nPn%2B92TU93O9NlIADo93p3qx0d%2FeKvX5Vw1KWaGnwbHX1wYHHx2EaPsDGRYkyuiEYviLZdaXMOm2hdRi6HYFPTzsc%2BX8t%2FQSnGPFVNTS%2BU2tpdZi4HzvmKAHDOYS0vQxaEBqW5uf%2BhJFX%2FE5RizB1U1WdKOLzH1HVwInAikN9vmm53hgQBnAhWsYjNgcDWYGPj8xRjvjKQv6rqnhKNdhq6Dptz2JyDb9pkLE5M3F74%2BPF4SRA0DsDmHIauoyIcjvtDoftlIKNQ6NGz2UmIIjjnIJ%2BvpH39evPgwsLJQ7r%2B8kc6fc50uXKcCJAk6JnMpJHPX1mfzbkvfbLcOtzWln6XSBSeKEoPAAmAZ1XuvkDgzNt4XB9qafnSJ8utTu%2F69zPGPADk06K4pdnj2X%2BiULgHwL0KEwBwAOYNny%2F5yTCG7ljWBIASgN9EVHKCGABx1bwmz%2BopALAAmFhZCcNxN4mI%2FgBbEHoE%2FKbG8wAAAABJRU5ErkJggg%3D%3D', | |
copy : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAATdEVYdFRpdGxlAE9wdGljYWwgRHJpdmU%2BZ7oMAAABg0lEQVQ4jZWSy2oUQRSGv6qucaXuRFwqvorOmB7fIgR0J0iDZCUowoCCFxS84EJ8BS%2BTCT6NqCE7jWZyTtfvonvGMd2LSUFBURTfOf9XJ7x7%2F%2Fa%2B1V4pK0lCEsqZxTlLSHgqisnW5o1tjq9Xb16Y1liPnz60ZYGVncw9AXz78ZUQQrsBAgCSOH%2FuAkdmqVMdSG7eHFJiNp1BCLQEAIZXrwCweNcBmFsLGLBRbhBCJKwAJAFgZv2ABbkoCqafp00EYpNAMLo2agDuvHz9XMfFLjsoYkFZlhSxIMZICLH5hVy3EYytzZv%2FFX%2Fy7FGVVrN9%2FPCJGCMxBsbj681lG8fc2dv%2F3hGbFtlyzgxHwyXA3RBCWTBoOtjd%2FdIRm%2BqcHUhnTp%2FtlbSUCYzLsiM2hRgmt6tbVV3X6Z%2BgpvJiWGIMXLp4mZ2dWUdsZ7Ikce%2FBXUnSr4Of%2Bv3nQPP5ocyO5O4yM83nh5KkO9uVeqfrJGJ7AScR2wtYV2yds%2FcC1hEbAj4YnJr8Bf6RZNsaEpA%2FAAAAAElFTkSuQmCC', | |
danger : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIwSURBVDiNjdO9T5NRHMXx7%2B%2Fe573tU%2FoUCpTy1kjlTTExIRol0ZiY4OTE0iZuuhgHIxvRuGhcUAeMcXNwcwH%2FARcHjUpYTExUEsWQ6CAEWiiFXhc1QYvhLHc593OXc8UYQ6MsXJACyn4mZqdcM%2FXzRx%2Bbz416quFtQDnBk47j431to%2BdGHMt5uGev4eslORvrOTIUtmQk2ZpRXnbw1EJRRvcHiIhOJGda%2BoZ98SOUl6Tl4CFPfP%2FBvoC3RSYSPSNZ11WojiFUtp%2FAtyWWGxiYL8n4f4Hnp8Vy48l7UbY9EMtBpbKo5jxYFs1dXYH2%2FRluitoTaOrgYjzXFzpSRbUXmJyeZXJ6Ft3ej6drxNvymfmPFBsCby5JoILErSgdBOIGqGQLzaFNpslBRR2I45LOhDFl%2B9Mfroj7D6A2uNaUydh2vYLuHMRsb5BN2WQjG7Ozie4cxmWDMJ32yytc3gW8m5DIcrzJVIJAEhESC2G7QnezTb7Vhe0KEqYRSxM5qzED11%2BWJPwD1DxuJELXsswGunsQamWorjHWH3CsV8P6EpS%2FojsL2PU1wgDLF6YAZKFIzmje53Nu4OQK2IfP%2FB4E%2BuRdAHZeXAVjwNTZej3H1vIin5ap7BgOWGjuNMWxtami23upb64iokAUS09LgGCq64DBmDq6awDr2yKpOPrHGrctYCzuYQNsvZrbNZLUr7P693qAwMNdKXPCMoZHX74zZQxug97eETaV4b7s9Z33m5%2BP5JF%2FA6jokgAAAABJRU5ErkJggg%3D%3D', | |
del : 'data:image/gif;base64,R0lGODlhEgASANUlAJaWluXl5dfX197e3pSUlNnZ2aampre3t3p6eubm5qioqLW1taenp9zc3LOzs7a2toGBgdra2t3d3YuLi3x8fKSkpHV1dc%2FPz%2BHh4ZiYmH5%2BfpeXl4qKioyMjMXFxaKior%2B%2Fv8vLy9DQ0LS0tDs7OwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAASABIAAAZ4wJJwSCwaj8gjaZkcLp9QJOkhGHgACM2EQzJCv9EiaQSKBEQGAiHT9Y5IGFKBpCAB2uJ3gNQgOUgfeEQkCyR7EmN0gk4PJAl8iQyLQiQHjnKRkyWEhiQCfiQbmiQVJAMkFyQGJBSjCAAHISMAHRAWmptgTE28vUdBADs%3D', | |
dialogMask : 'data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%08%00%00%00%08%08%06%00%00%00%C4%0F%BE%8B%00%00%00%01sRGB%00%AE%CE%1C%E9%00%00%00%06bKGD%00%FF%00%FF%00%FF%A0%BD%A7%93%00%00%00%09pHYs%00%00%0E%C4%00%00%0E%C4%01%95%2B%0E%1B%00%00%00%07tIME%07%DB%03%17%0C%03%0F%8C%CB%E4%8C%00%00%00%19tEXtComment%00Created%20with%20GIMPW%81%0E%17%00%00%00%26IDAT%18%D3c%F8%FF%FF%FF%FFMW%3E%FF%C7E3%FC%87%02%98%20%3A%9F%81%A0%09%B8t%C2%00%C3%20p%03%00%DA%B4%F2%A1%8A%CD%18%A3%00%00%00%00IEND%AEB%60%82', | |
downArrow : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAMAAADKSsaaAAAAAXNSR0IArs4c6QAAAKhQTFRFEnMAFXUAIncAHXoDHnoHIHsAInwGI30AKH4TK4AAM4UGMYYLO4oQQ44VRI4XSZAbUZYhVpcnWpooYZ0wXZ45Yp4wW587ZJ4wXqBCZ6A0ZqA4YaJFaqI2baI4ZaRHZ6RFbaQ%2BbqQ8c6pOe65UgLJZf7JggbRmhLVlhLVpiLdqjbluj7tzlcB%2FlsGBl8GCncSHoMWJoMeJpMiMqMqPp8uPqcuQrM2Tr86VayLUTgAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsRAAALEQF%2FZF%2BRAAAAB3RJTUUH2ggZCiMw9%2FcEJgAAAFZJREFUCNdjYGAQEBKVUWQAAX5jM3NZMIvXSMtMEsziMdA0FQbSbNwi%2BuomylIKDMwSOhqq2qYq4gwMHNK6aoZKgiB1LHJ68nxgHQysYlwMUMDOQAIAAGnkBmRhpsy5AAAAAElFTkSuQmCC', | |
download : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oIGQorAW7wjhQAAAMSSURBVDjLnZNNaFxlFIaf797v3tvMTOd%2FJjOZ%2FHSGhAyZmh%2FIlEhjSS00gihxoUatQqXqxoWFRkHBlVTcCi5ciBFLXQiiq0oRQw0qpoS0IaFiiyGJSabJOBPNZO783s%2BFaDBLHzibw%2Fs%2BiwNHcIjJ16dfAV7WpexTYCnH2VeKOU3Xrly9fO7jw3nxb%2FGNTwZNXfu6JxlrHenvIpkI4bIsiiWbe%2Bs7zC%2Bvc3dt%2B6YQ4sLVy%2BcW%2FyN46uJHWbe35aeJ0wNioCdKsWSzs7mG9EShJQDlHRKtIeaWN7g2u%2Fw7Qjz8j0QChEKeb86ezIgHUkEK%2BRzhzgy%2BcJxypU5u%2FVekU0Nr2pzJpmg6KnT9hzsfAg8CaC%2B%2B9ek7sWjAezrbjaE5NKQHNIEhJaYhcVmS1tBR4tEIEb%2BbbKadrrbgyLNvXjkPoHl9rgvDmU52i3nuV11E246hFDgKEBrCqbFV2OfLG0tcn53HZyn6utsAngSQe%2BV6pCsWYO7uNqmeKI46uGxpt8CJwQxCCJRSbGzdp2LbxCM%2BgGEAWak1NMsy0TxRdksVmo7CY%2Bk0m01qpR2ECANwa3wczeNh5aVXiXT0AgQBpK5rzh%2F7Fc1d2cQjLbb3w%2BQNk0bToVJoMFivc2t0FO%2FwMPbKCscSEbbtGkABQBqallv5Ld821B0j1RFndX2D2Xt%2FUsPErrn5dmSE9nSaowMDqGoV%2B%2BJrRAyDKdOMTE1MKH3ooSeSpWr9RKY7Qdjvxu%2Fz0hHQmVncou3tp0l1dhI4dYrq5ibuvj48x4%2F%2FPZkMpcVF9IXvvrjWnX3sktB10%2Bc2aDF1fpxfojb1Av3xOIGxMSqrqzTLZRrFIvVCgUaxiBEMsnf7NjpAsm%2FsztauPekgkVLj8%2B%2FX%2BaX%2FcZwbn9Fq27jTaZxKhSPt7UifDyMYBKXYW1g4%2BIVHz7%2F3TGeqY9rr85vpVIxY2ItlGSxNnuVkMol%2FdJTizAxr%2BTxHNA0JeKQ8EAD4g0lz%2FPlL07rlegRd%2BkEIpZzGma%2FelUOJBD%2Fncjy3tCT4P7zf26s%2BSKfV4f1fpUgaHTdq5X0AAAAASUVORK5CYII%3D', | |
downloadGPX : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oIGQotDqgVNAMAAAG4SURBVDjLlZPPaxNBFMc%2Fs41CD1oMlVp1FUIPBhR6UxCPestucvIiqPtn%2BAOyET2I5yoUAmL%2FgMwS9OTBH%2FGgqHgT%2FAF1QTwYLG01yezsjKeN3TS25J3mveH74715I5rN5qM4ji8xQbiuSxAEAoAwDO2kEYahzcgK2aHb7WKMAUAIMVRzHCenXiwWc%2FmQwBhDu90eXnieRxRFw9z3%2FbHtOKOFSqWC53m7ArcRZLaFEDllKeWOBIXRQgbOCHdzkCPIrI8D15%2FU6Kl1lq%2B%2B%2F38LURQhhEBKmXsJgIFWHJ0tc%2FHBiZ0dSCnxfZ%2F6Yw9rNMpoVKo5fGCB8vxpNvq%2FedFbGk%2BwdZDaKM6fvExqDalJMVi%2Br8Wccs%2ByqXr8uv3Mvr2uRGErWEpJtVql1WrRR5Faw%2BrPTyRGo01CkiasDzZYdM%2Bxmfxh7WbH5vYgG1qtVqOv%2B%2BhUMzdzjEP7jzM%2FU2LP1DQH9x3hXdyh87nDl1v8czC6oj094OGreyij6OuE0myZM6ULvFl9ydOPz%2Fl2BwFQcF13pdFobPuNi1zJ5a0fdxHONK%2B%2FfqC%2BcH8pIGCiKN3Ya91rU3a0%2FheAk99ghKc72QAAAABJRU5ErkJggg%3D%3D', | |
edit : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAKQ2lDQ1BJQ0MgcHJvZmlsZQAAeNqdU3dYk%2FcWPt%2F3ZQ9WQtjwsZdsgQAiI6wIyBBZohCSAGGEEBJAxYWIClYUFRGcSFXEgtUKSJ2I4qAouGdBiohai1VcOO4f3Ke1fXrv7e371%2Fu855zn%2FM55zw%2BAERImkeaiagA5UoU8Otgfj09IxMm9gAIVSOAEIBDmy8JnBcUAAPADeXh%2BdLA%2F%2FAGvbwACAHDVLiQSx%2BH%2Fg7pQJlcAIJEA4CIS5wsBkFIAyC5UyBQAyBgAsFOzZAoAlAAAbHl8QiIAqg0A7PRJPgUA2KmT3BcA2KIcqQgAjQEAmShHJAJAuwBgVYFSLALAwgCgrEAiLgTArgGAWbYyRwKAvQUAdo5YkA9AYACAmUIszAAgOAIAQx4TzQMgTAOgMNK%2F4KlfcIW4SAEAwMuVzZdL0jMUuJXQGnfy8ODiIeLCbLFCYRcpEGYJ5CKcl5sjE0jnA0zODAAAGvnRwf44P5Dn5uTh5mbnbO%2F0xaL%2Ba%2FBvIj4h8d%2F%2BvIwCBAAQTs%2Fv2l%2Fl5dYDcMcBsHW%2Fa6lbANpWAGjf%2BV0z2wmgWgrQevmLeTj8QB6eoVDIPB0cCgsL7SViob0w44s%2B%2FzPhb%2BCLfvb8QB7%2B23rwAHGaQJmtwKOD%2FXFhbnauUo7nywRCMW735yP%2Bx4V%2F%2FY4p0eI0sVwsFYrxWIm4UCJNx3m5UpFEIcmV4hLpfzLxH5b9CZN3DQCshk%2FATrYHtctswH7uAQKLDljSdgBAfvMtjBoLkQAQZzQyefcAAJO%2F%2BY9AKwEAzZek4wAAvOgYXKiUF0zGCAAARKCBKrBBBwzBFKzADpzBHbzAFwJhBkRADCTAPBBCBuSAHAqhGJZBGVTAOtgEtbADGqARmuEQtMExOA3n4BJcgetwFwZgGJ7CGLyGCQRByAgTYSE6iBFijtgizggXmY4EImFINJKApCDpiBRRIsXIcqQCqUJqkV1II%2FItchQ5jVxA%2BpDbyCAyivyKvEcxlIGyUQPUAnVAuagfGorGoHPRdDQPXYCWomvRGrQePYC2oqfRS%2Bh1dAB9io5jgNExDmaM2WFcjIdFYIlYGibHFmPlWDVWjzVjHVg3dhUbwJ5h7wgkAouAE%2BwIXoQQwmyCkJBHWExYQ6gl7CO0EroIVwmDhDHCJyKTqE%2B0JXoS%2BcR4YjqxkFhGrCbuIR4hniVeJw4TX5NIJA7JkuROCiElkDJJC0lrSNtILaRTpD7SEGmcTCbrkG3J3uQIsoCsIJeRt5APkE%2BS%2B8nD5LcUOsWI4kwJoiRSpJQSSjVlP%2BUEpZ8yQpmgqlHNqZ7UCKqIOp9aSW2gdlAvU4epEzR1miXNmxZDy6Qto9XQmmlnafdoL%2Bl0ugndgx5Fl9CX0mvoB%2Bnn6YP0dwwNhg2Dx0hiKBlrGXsZpxi3GS%2BZTKYF05eZyFQw1zIbmWeYD5hvVVgq9ip8FZHKEpU6lVaVfpXnqlRVc1U%2F1XmqC1SrVQ%2BrXlZ9pkZVs1DjqQnUFqvVqR1Vu6k2rs5Sd1KPUM9RX6O%2BX%2F2C%2BmMNsoaFRqCGSKNUY7fGGY0hFsYyZfFYQtZyVgPrLGuYTWJbsvnsTHYF%2Bxt2L3tMU0NzqmasZpFmneZxzQEOxrHg8DnZnErOIc4NznstAy0%2FLbHWaq1mrX6tN9p62r7aYu1y7Rbt69rvdXCdQJ0snfU6bTr3dQm6NrpRuoW623XP6j7TY%2Bt56Qn1yvUO6d3RR%2FVt9KP1F%2Brv1u%2FRHzcwNAg2kBlsMThj8MyQY%2BhrmGm40fCE4agRy2i6kcRoo9FJoye4Ju6HZ%2BM1eBc%2BZqxvHGKsNN5l3Gs8YWJpMtukxKTF5L4pzZRrmma60bTTdMzMyCzcrNisyeyOOdWca55hvtm82%2FyNhaVFnMVKizaLx5balnzLBZZNlvesmFY%2BVnlW9VbXrEnWXOss623WV2xQG1ebDJs6m8u2qK2brcR2m23fFOIUjynSKfVTbtox7PzsCuya7AbtOfZh9iX2bfbPHcwcEh3WO3Q7fHJ0dcx2bHC866ThNMOpxKnD6VdnG2ehc53zNRemS5DLEpd2lxdTbaeKp26fesuV5RruutK10%2FWjm7ub3K3ZbdTdzD3Ffav7TS6bG8ldwz3vQfTw91jicczjnaebp8LzkOcvXnZeWV77vR5Ps5wmntYwbcjbxFvgvct7YDo%2BPWX6zukDPsY%2BAp96n4e%2Bpr4i3z2%2BI37Wfpl%2BB%2Fye%2Bzv6y%2F2P%2BL%2FhefIW8U4FYAHBAeUBvYEagbMDawMfBJkEpQc1BY0FuwYvDD4VQgwJDVkfcpNvwBfyG%2FljM9xnLJrRFcoInRVaG%2FowzCZMHtYRjobPCN8Qfm%2Bm%2BUzpzLYIiOBHbIi4H2kZmRf5fRQpKjKqLupRtFN0cXT3LNas5Fn7Z72O8Y%2BpjLk722q2cnZnrGpsUmxj7Ju4gLiquIF4h%2FhF8ZcSdBMkCe2J5MTYxD2J43MC52yaM5zkmlSWdGOu5dyiuRfm6c7Lnnc8WTVZkHw4hZgSl7I%2F5YMgQlAvGE%2Flp25NHRPyhJuFT0W%2Boo2iUbG3uEo8kuadVpX2ON07fUP6aIZPRnXGMwlPUit5kRmSuSPzTVZE1t6sz9lx2S05lJyUnKNSDWmWtCvXMLcot09mKyuTDeR55m3KG5OHyvfkI%2Flz89sVbIVM0aO0Uq5QDhZML6greFsYW3i4SL1IWtQz32b%2B6vkjC4IWfL2QsFC4sLPYuHhZ8eAiv0W7FiOLUxd3LjFdUrpkeGnw0n3LaMuylv1Q4lhSVfJqedzyjlKD0qWlQyuCVzSVqZTJy26u9Fq5YxVhlWRV72qX1VtWfyoXlV%2BscKyorviwRrjm4ldOX9V89Xlt2treSrfK7etI66Trbqz3Wb%2BvSr1qQdXQhvANrRvxjeUbX21K3nShemr1js20zcrNAzVhNe1bzLas2%2FKhNqP2ep1%2FXctW%2Fa2rt77ZJtrWv913e%2FMOgx0VO97vlOy8tSt4V2u9RX31btLugt2PGmIbur%2Fmft24R3dPxZ6Pe6V7B%2FZF7%2BtqdG9s3K%2B%2Fv7IJbVI2jR5IOnDlm4Bv2pvtmne1cFoqDsJB5cEn36Z8e%2BNQ6KHOw9zDzd%2BZf7f1COtIeSvSOr91rC2jbaA9ob3v6IyjnR1eHUe%2Bt%2F9%2B7zHjY3XHNY9XnqCdKD3x%2BeSCk%2BOnZKeenU4%2FPdSZ3Hn3TPyZa11RXb1nQ8%2BePxd07ky3X%2FfJ897nj13wvHD0Ivdi2yW3S609rj1HfnD94UivW2%2FrZffL7Vc8rnT0Tes70e%2FTf%2FpqwNVz1%2FjXLl2feb3vxuwbt24m3Ry4Jbr1%2BHb27Rd3Cu5M3F16j3iv%2FL7a%2FeoH%2Bg%2Fqf7T%2BsWXAbeD4YMBgz8NZD%2B8OCYee%2FpT%2F04fh0kfMR9UjRiONj50fHxsNGr3yZM6T4aeypxPPyn5W%2F3nrc6vn3%2F3i%2B0vPWPzY8Av5i8%2B%2Frnmp83Lvq6mvOscjxx%2B8znk98ab8rc7bfe%2B477rfx70fmSj8QP5Q89H6Y8en0E%2F3Pud8%2Fvwv94Tz%2B4A5JREAAAAGYktHRADVAJ8AvxXHGoYAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfZBwcIASdkENZ8AAABgUlEQVQ4y5VTvUtCURT%2FmUmSWCqaSUtbEA1R4GRfFARBNfV%2FRNYUjY1JTY0N4VAiDdEgSNIQTUVDtgZBiPmBVkrq8%2FwaHj6VZ6%2B8cOGcc%2Fl9nHPvBbpckeAWW%2FOebsHjE6ttJKZGcH4WphHYVn3EqLKi5c9Pl9g4CJk0MEmKkPV6nYqisFarslqpsFL55tXpDpXXMJMnCSZPEmx10NvUINLplE75IX6I5blJpLNFjC0CF0f3CGwHgYNQO4EI4fEMgUKQ6o5H9jSw1z2I2M0j6J9GxyEKBZnMO7K5DHL5bEdwYH1X57B5C0K4XG44nS7V9oK%2FHby2C4p%2Bzs0WSOTzWe0g%2FZ6B1zuM2PUdppY2US6XYO2zGhCIwOFwQkhEo7dqMfmiKpMgBWLkABQUigUAwP5xRCuXyyUttlgsvxOQhN0%2BoN0AKZBGLKLVDVogPr8%2BDJ%2By2Ww2ciCw9dtUVaiqQgKi5oqigCI6gn%2F%2FhcaamZ2Hzzdi0hEAQCr19idJKxgAfgDG6PPJecMc5gAAAABJRU5ErkJggg%3D%3D', | |
gctourLogo : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIcAAAAYCAYAAADQ1%2B6cAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oIGQo6LQ%2FxwecAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAEBBJREFUaN7tW2tUVFeW%2Fu6jHlRB8S5eIo8SRFAQFaKxfSW2qBgjMmpixkfSJplMllkaku6OkzG2vZJxTDR20tMmrCahk8YsO3REDGjHFyrYohGiRsQSQZRnBSwKq6iqW3Xrzo%2Bcq8ebinavNT8GV%2B5aZ91bt86rzv7O3t%2Fe%2BxQDckmSxODOxQDgAKgAqAFoAGjJsxoAT75nSX0RgADABcBJ7m7yTgQgMQwjUf0rx%2FvBpax%2Fvzb%2FF%2F3%2FdCnWSLGQDBE4RwCgAaADoCclgAKJDBCGAscQADuAQQC3yGc3AK8MEMVY9P22XBX3H8z3n2hzL4BIPwHl3hdPhEWDQgaGmoBBDyDw1JtP5vdfOvVzdVConeVVrMdhCx%2F6riOJ5VWCPia5ZcTUxX9Pe%2BLX5xiOsxFAqUi%2FPrlIkkQDkC4MJTAfuYvkLinaMD%2FSRllfWY8GhUTNS5IkifkJIH52oiRJLAGDijIbKlI0AHRfPZe5Xh0UJjy0YdeRgPBY2cxwouDmzH%2Fdnta2v%2BQRR%2FfV0dqw6I7Uf3nls9FLik4D6AXQA%2BAmAAfRHrLAeGoc2jzJQvaQ%2Bl5K2Dw1T568k4Xspdr4KLOoNH%2ByCaTHEClA%2FlMmyJ%2FpepBAxkiSpFKYDy0lNO7o%2BmlLw9Ieupb1%2FDtXARiuH%2F1s9K0Oc0zGijeayOICAH%2F1yw%2FGXCp783FnX0ecccLsAzP%2B%2B%2BBOAJ0EJINEGBylkWgTxVGC8xDO4qI4C0fxHnp%2BEqnvJlzHTc1JBrGGApNP0b%2BTfJYB4s80SfcyyT9mrh4EkLBkoQMABAOIxMUDY%2FDJLxYCCDOXb09X6YOdWc%2B%2Fc44somegpTH86t7%2FWUgtsgOA07Tg38x5HzUVB8aOumZpODSv%2FXDZGACBFABkAIYAiAQQDSAOQJwgCPGCIMSTz7EAYgAYAYSTEgkginwXByDO5XLFezweum4kgFAABqqEkfcxVL9yvSAyHy0FIo0f7UlzK4bSShylyeh6HNl0zP1I8f97zkHKHaH9ZX0RHl1XBSDkRs3uvFm%2Fqy0mu8ELwGta%2BGLTlYr3g31eQWJ5tUjeswB8qoAgccrG8orrRz%2BLGzGtUOYeOgIiiTyHAQi5fPlyfHl5eUFHR8ckl8tlBACtVmuJi4trWLRo0d6xY8feIO188hzPnj2buG%2FfvkU9PT3j3W53KACfXq%2B%2FkZCQcGzlypXlUVFRfYQE%2BwCo1q5dWyyKYgTDMCxD2LAkST6DwdC4ZcuWN8i8XRRf8fm5eynzIykIuz%2BT6KW0kTTcwSFrDgOOf5iNXnMucp7cfe3gJxkBEXF2llNpyI%2FkAHD6qAQh1JTd0Fm7Jz5%2B5rI2SvvwADjDyDGu2MkLer67cDw%2BeuKcfmKqPKQPA4DwL7744mfV1dXrQkND22bNmrU7MzOzjed578WLF0eePn16xo4dO3bk5eX9YcmSJV%2BTdvyuXbsePnz48Jro6Ohz%2Bfn5Jenp6ddcLhfT0NCQfObMmQWbNm16dNWqVa9Onjy5lZgjdvr06R%2FxPB%2Fe39%2BfXFdXt2rJkiXveDyeIZ1O1000h1pBZH2KQpssgbzjKG0je23y5nETsDGySZQkadiaGP4ul%2FXUp7MQZLQgwKC9fmTX1JRFaw8S0yDzAh0AbfrKN05c%2B1tpZvzMZRar%2BWxga3Vx5kDr%2BVRHT9tIwdYXLvlEVmcc2Z5f1n6FtPcQEIXU1dWNq6qqenXChAl7XnjhhS9ZlnWQhZRGjRrV8fjjjzcUFxfn7d%2B%2Ff21iYuKbOTk5lhMnTiQfOnTouenTp5etXr36IHGX3QDEjIyMK0uXLj20cePG9aWlpb9NT09fYTAYvADEJUuWNAKIqK2tZevq6jB%2F%2FvwW0tZOwBFImQp%2F3pKL1LUR8%2Bkja6GnzJKa1HcR932Q0iK%2B4aw9%2BLtsZ0%2FzGESP7gagGeptT4jOmSsQM%2BDFd616BEcz8Lj0hoQMceBq45ivnh9v4hhIQRExAyHJmZbIzBm9nCYAnErraan8fa6rtzVCG5U8SHkqQRUVFStHjBhx9sUXX6wiiz5IdqYkg%2FS5556rioiI6Jd3aWVl5eLk5OT61atXHwZgJUUWFqvRaFQvvfTS5urq6rTu7m6vwWAYojiVSxRFjyK4FwBAe%2F78eWN5eXlhb2%2FvWFEUA%2FR6fU9GRsaxZ5555jjP8%2BK6deteXbx48dvTp0%2F%2FhjIxAVu3bl1qt9uzNm%2FevPvll1%2FePGXKlL0nT57MY1m2e9u2bS%2BT38PeJ84yLMBxJ%2FbAMAxC4gYBqCXRq2VYLhCA1nNqV8zA0Y8noevbUb1OlrkZnnEjMHbUTXVQ2FBuSswtXK4ZhcK3ziM%2B2wmAh3OQMx77r1nMe3OfxZvm3xBhMC0tLcb%2B%2Fv6MwsLC31C7cpDiJLdV9%2BLFixsAGNra2mL6%2BvqSly9f%2FikBhBVAH3mWPRlVXFwc9%2Byzz3bKxJkyd4IkSSIFFjUArra2Nqm0tLQoJibmXEFBQXFERMTghQsXRtfX1y%2Fu6uoat3HjxjKbzZYhCEIExZtYABqXyzXSbrenAgixWq1jDh48ODI%2BPv7o%2BPHj9yi00LDnHHfsLcP60NU0AoBKkny85PMFXvrsrdTmXW%2FlZxlc2oRglSd01ppj%2FNJt57w%2BH75akfiMqMu9yvW1xmLQ8r35%2BNMzD6G%2BLCfMJ%2FBuZ4CDsstobm5OYFnWnZub26Egej6K1NGBLO7KlSsxHMcJWVlZXZR35FCAg1e4w%2FJ7D7H7Eg0OURSZ3bt3%2F8JkMp167bXXPpWJ76RJkzpyc3Ovvvvuu69XVlZOBACO4%2BiUAQCoOY7jWZZlCegxevTo40VFRX8C0PWPxk6GCzjk2IKAxJyz%2BPbAPBzaYdKEGG%2FdNJ%2BJDEudZA9OzmwPmfpIG5%2B%2FzowvXpuA10et4tdW7dHGploua9MG0vlvRGTk2WC9ocPFA2kQBR4AOMGuozSTJIoiyzCM%2BP26fi%2F87du3z7NarZEMwzAsy3JqtVqj0WgC1Gp1gEqlCtDpdD6GYXwsyzL3iT3cKxIqXxwAtr6%2BPt5ut8esWrVqGwHGIFmHgIyMjE6TyXSmoaFhPACwLMtT7i0LQMNxHM8wjKyZkJWVdYEioy6ynsMeHCwVr7BjxR8roAvpx%2BcvF07RdIYO%2FnVTTnTOXOuj75%2FaH%2F7EW5cQZBTx5O8b4HFq0N8eFJY6qaf73IkkMCxQ91EizlfFwtYdKnfuSp19ilLzYnJycocoirrm5mYjYfwBLpdrpMvlSnU6nSlOpzPF4XCYbDZbQk9PT1p9ff2CiIgIh9fr1VJtdFSeR0dIpRzXCCLfqanYhBJAbHd3d7hGo7kVGxt76%2FbGoJKFRqOx69atW6FEcyiDhDqO41QEHCwAqNXqIQocbipSO6yDYTxZHAcAG4Kju%2FHGhY344%2FJ%2F1ZmPTU0avBEl%2FWpELDPz389gzi9bwPES9r0xFiwvImthX6wUJF0%2Fsisbr2w7is%2BLZsH%2BnUHuuMWh8iQ99d4hatHYcePGdQUHB7fu27dvRlpa2ucAxA0bNuyXXU8ihEAAhp07dy6w2%2B1ReXl55gMHDli%2B%2FPLLmWlpaddJAEsi4PDJYX5RFPn6%2BvqwpKSkzpiYmH7SJ6PQND4ACAkJuSUIgs5ut6sDAwNld17WLIzdbg%2FSaDRDLMv6vF5vAJmT7N7qJEkKIuDgSRjdR8YTFDERPAiaY4gQPQuCY9pRdPRDbLq4YcA0p85t6zOg4j%2Fm49cjVuDzoiycKH4IQUY7vt1vNPIubnxach%2F2vv4zGhj9YoD7Zubyo1x4vI0wd6fME2bPnl126dKlR%2Fbu3ZtNFj2YCDyEPOtrampSvv7669lz5szZx3Gcffbs2dVNTU0zKysrJxHvKUoR9YzasmXL2tLS0hKn0xlMhdcZkliTBeUFIEyePLmF53nX7t27pxCQBZGxAx0Oh85sNk80mUzNer2%2Bv7W1NYHMM5REa0MsFstowjk4Ag7RD9eQhnsIXeYcTmqHfR%2F4iRnjDvnl3%2F58%2FsOiHt%2BpP8%2FKFFwa9tD2mQAAp02P9%2BcvBYCRfkx%2Fv6h2T3h6099h7%2FciMNxFwCcBQH5%2B%2Fpne3t6SysrKZ5ubm2see%2ByxI%2Bnp6X0A0NnZadizZ8%2F0xsbGednZ2ZX5%2BfknAYgLFy480d7ebqioqHjBbDYnFxQUfGUymfoBSGfOnImtqKhY1NvbO76goGBDcnKyg%2BIbIgCRcmWdALx6vZ6ZNm1aWU1NzdMMw4hPPPFEnU6nE8xmc3hJSckKhmHEZcuW1bjdbpw%2BfXpuWlpa28MPP9w6NDTEl5SUzLVarUlGo7FNzuOQ%2FkVKuzwwiTc6gynb9GAq%2FxHVWlU88fIn%2F7lwaoSgMngHAv32xKm8Xaq474asluCECTMaVH3mcCTmHsGaXWXE9fSQ%2FkMBhB4%2FfnxsdXX1UovFksXzvIthGFEQBENwcHDrjBkzygsKCk7LwpTD53v37p147NixQqvVmqJSqQYlSWJFUdQZjcazhYWFH%2BXk5JgB9BMt6CZmKqyqqmpyeXn5Bx9%2F%2FHEBlenVlJWVTa2trX3K7XaHqVQqhyAIQdHR0Y1r1qwpNZlMNrfbrX777beXt7a2zuJ53i6KoiYkJKQ9Kiqqra%2BvL37r1q3vPf30039YtmzZS3Pnzq0FYCGxGzcA33DXHHRyiKWipYEAIm4nutyOGC%2BYoBvFL05N%2BrZ0qoUNHdRqtG6OESFIvKdP4MTrNi%2BrMU26NNkUfZO%2FejwNLGfDUx%2B8h5RpZkpYHCF1MoHUWa1W%2FYULF2IFQeBTUlIsCQkJVsoMDZEdyRP1HwhA29nZabh8%2BXI0y7K%2BjIyMrsjISBupayPFTkCgIeOEEGDKsRRJzg6LoqhtbGyMs1qtgSkpKT2JiYlWilByAFSdnZ2GpqammLCwMEd2draFZVmaw7jImP1UcE54EMyK8iSY7J7pAYRD9Mah69tUHP%2FwETy18yKGBrQoinxF2GrZ1NtwKMjrsnsCwmJtoaMn9WsM4e7bUcShAREttTwyF7SSBRukhKL1k7JnFSl1OgVPp%2BzlNjxpI7uqAqk%2FhDunz2SyqiPt1FSUU6L6VKb0vRQ4WCrFwCpC7LQZdhJAOqg5PxjgoADCULs0FDe%2BScJf1q%2FB1ZMFSJh4FppAJ9x2FX51skSxGN57JKwclO8v4e6TZjwlGIbiCbL7qxSSSkk2cfcBIQ91BgSKsVhFck1Or6sU4KRPldEn5FiKy9BCF6lx5TlLD8J5Dv42Sr7PaNOpZwHx4%2FuQMLEeEUmdMI4axLwNTZTA7WSXCpQQ7yKClMA8ioSWl3JfWT%2FBK3%2FH%2FgRKSMr4hU8hWCiA4KXA9GNHD3%2Fg8lIbiFGMKfmZr%2B9BcWH9RhWJ9mApdRxEipYIRs5UOnH3ySufQtX6S4Hf64CxUjjSPaKgyvYS7n0oGfdJgNH9%2BevH33jwA5QH5gTYDzSH4seKVDLMTal%2B%2BjCLQGkI6Ud21A8WTb7fCT34F%2BiP%2FDXhXgC411lPv3UIUO8nzH9I2A%2FiAeX%2FBUPhQRLDQ08NAAAAAElFTkSuQmCC', | |
gctourLogoSmall : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDGQg7CZXhIq0AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAD30lEQVQ4yy3M2W8UBRwH8O9vjj2ms92rpUsPutClLdjVQi0WS%2BHBNCq2QCKJhoemLxhr9QlTEhIjPIgxKiRINKSiQEKEBINIsVpSSRpQMLZKCU3tfQBdeyzda3Z3ZnZ%2Bvvj5Az5kWZaLiOwAFAAeZl6z%2BNevNRM%2FnGoB4JEUl5ReeuRNRaY9joKSZFnT%2Fpny5rYRu7tgEsA%2FAMaImSsBuP5P8mb7L25%2BfPvqzuo3D8%2F5qupVQ0sUyoqLLNPgse9Pls%2FevFCua3E5tOedBxWtHX2ykn9HAlDFM39uIFESkjZveuH367X1Xed%2FkZ15%2Fid3e8omrp1%2Brul47z1BklPVb3TFK%2FZ0LE799HVo%2BMz729jQ9eoDR2YkTixtxc3PX%2BP2s7cfnuiorDvUfUNyKGlmThc3tDy5d%2FzAbiLKAkgBEGWnyxXa%2B%2B5TpaAUeYGgJYhSoUBDVxqxMh2MR6MVzoISu%2Bx0qUTkJCKZmaXSptdnouNDfmZWcnpG1RNR1UhEHe4NYcHQ4r6ckQ2Q9UnjAoVeNEesYi0QbpzyVdWPA0gDUAEEsvGVwgfdh4Nrt7dGVifv58dnR%2FypyJRLj6%2BIejrFzWeGr0mIRVQE65%2Fqg4MeW76%2FAIDAc0OO5G%2BXS1aXI66Et9LKrC45kyMDtuJsxFa2721NKgpZDn%2BxOH%2BqzS5c%2F2CrBLaAlVkHBMkm2hyF030XSsa%2F6ija5taENTvbk4H9h%2BKr44P68qUjHq8tKiDPyXD7BZxvz1s3elk2fEESEN49hzvfuFQzJqXmR92e0BZ74KX2jHpiftn27KuWfLS6SFFdtmTx85wmhVASlhAZdfAfl2RiE5RNigL2fnSLFa9W8fCcU%2FiuU%2FUaS1K483RW8pWKqN1ngS2SVa%2FIVk7U3OsIfZ8pfOsLG1kGMjnAbO6akEhx3%2Bf3eon%2BvvqCMnCu0jz5ikuq3GFy01smhm%2FI8Ach%2B0ul4vUbybaQIP75Y5GMDHIWMO8OZ8sb26eImRuYOQSgiixz8%2FjFYw3ywJeBYD4IWpwgiIBdZTZ1gpEBLBNEQEwHzLZv53y72vqJmQPMXARgIxHVAtgy1tNdZ%2FR%2BWrCJZ0XkTBAIAMMCYAl2XvDWZO2ymCtSZY2D9UPEzA4AbgBBAHVs6ttJT4ZTpuB3HK1aG9vUkhB0zQDYyNjcmccJy%2FLW7Fhab08amLwro%2FXYFQmAwcwZIkrC1OP48cMAj%2FSVKU0Hl1BYHvMdPNuvJVZXQMKKR81PBACdmU0iymJXZ4yZ%2F5WYmYnIYGYNorwI1TeGZ142UBKOoLMnAuCRU3VHAESZWQNgEpHFzCYAnYhS%2FwF8odAV4EB4aAAAAABJRU5ErkJggg%3D%3D', | |
globe : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oLCAk1NEFBgZsAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAC40lEQVQoz12ST2hbdQDHP7%2F3Xt5rmixpmj9Nm7VdQ8vGimsrqyieVNTJULwoFbrDxnAguwjDHbxKQRTvO4gVpSDiPMlEvOhgamctK%2B1WtqyzaZtmeVn%2B5yXvveT9dhDn5vf8%2BXwPX76C%2F2Xug8VzwLuqph2VYEjPa0rJsqIqXy8tzH%2FxOCseSRe%2FnNZV5ceJseTAs8dGGUtF6TUMyo0WmR2TlY0d7mQL14UQZ5cW5tceyW%2B%2F%2F%2FlsIOT%2F480XpsTURIJyo4WZy6IFE%2BCPgGWSGoiyvLHHlasbDxDixaWF%2BTUNIBoN%2FvzK85PiqXQ%2FpWKe2Mgk4dggVtslv7OF5jko3RYvzabpejL607Vbl4Dn1DMffvXRwVTs5bkTM3Rsi5qrEgxHUBUFKcG1qsTCPaQGk4SCfnp6fGTzlYMj069ltVC49%2BzxyREq5SJFJ0BiaAgpQQIIBeE57Jc8VjLrRPySqSOHODo%2BxHau9JZWt9z4aDLC8p0C6YkEnvxvxUalxDPTkwghkFKyt3%2BfdqvFYDwMcFxpOx3FMHSUYIJKo41Zd7DsLnXLwWmYCPFPlRCCgXiUtc27GD4NoF9TVcWrNttKoJ0jqBkUmjGKPp1O16Nd6jDtuti2w4FgAMuyOJSKU2g5ACXNpyj5e7vFoZnxJOnhQbZ39riaqeGg03ICfPrdDQzR5b03jlGv11m9eRcOjAL8qchu9%2FLq5i6OpwEwOpzi5Eyc%2FUKJB9UmVVuwXfYwTZNqtUpPJMXmVh7gW3X118tXxmdfvyBUVQ8HfPh1ld9W1lnPS%2BpNm1rTpmbZzA6rFGoOu2WPm5nc70sL8%2Bc1gEqheOqX6973ngdPHx7ghxtVyo6O0%2BliOx0MnyBbkfxdcLn2V6YshDj3xLdPnv74nZH08GIo3KcfSSdJxkIYhg%2Br7bJvVrh9L89urnhLqNrcE9%2F%2BN339Y%2Fqrpy4sqkbvCVStD4SQ0uvIjrslhfLZN5%2BcvvQ4%2FxDbSUHA5o8CrwAAAABJRU5ErkJggg%3D%3D', | |
info : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACOElEQVR42mWOS0hUcRTGv7kzjdM44fuJ1SJE27RqFbUwirBCcFEtyowEwWrhqkXrSoiQFqYoEQyJllEmFC0qSCzIwsRoMjMfjc6DGWduM/feuf/7v4/T4obOjL/NOd/5znc4oCx+r8VEKbMpZaZPfflJucAu4XhKkdN2P/11/ljT5fFXH21pEQWWozmBYGRDTCQ2Ry3neoG2xuND2YefvZvbCoRC60TEiSSd7Gbkk5a0iIiiCon8f6ZnYJyInM1nLtVUVwpul6TCW4CZXxH/6KSbra8shRv275U4JBWWCwVOSFQ4ODTqUqQUd+wxNOgGMhZKdu18MLYQnFrYd7jhfOsRboCbSMrgPlSUFwMQuE4qBzPATCQk1NcU3715Eigtq6vlADPBLWgWZAZV47ENUVBNKEw3bM+ADMSSKmCCSAO4Dm7AtMA0iBIDBCEtZdLyX2bAAJgODjicAqA7HEQAJxgAB2Rmvn0/XeLzuAS3G0AsKhZXlTgEKMDMbAjwzv6Ifw+zAo+Hc6QSmfVw6Mmj5/Fvw0LbiYOri3/cTh4JJ00TgXktIfo67nefbW95PRllHElRWVoJ9t4ZbD16AICDiAA8fPwGgFFUXVReUVVb6dkheIsQXM6sBtfm5gITIxPNhxr8/Te2Ajad1/sionqhs62wtBrAxNMXY/6Rxrqyxvrd9jYA0DZOXe3vGfv8QaWmjr6LXbfyXBe28bKv6/S1gaji8lVUIZXKc3Neyqb9ym3T7R2+1503/wcT3Lkk5CgrKAAAAABJRU5ErkJggg==', | |
loader2 : 'data:image/gif;base64,R0lGODlh0AANAKUAAP///wAAAL6+vqamppycnLi4uLKyssjIyNjY2MTExNTU1Nzc3ODg4OTk5LCwsLy8vOjo6Ozs7MrKyvLy8vT09M7Ozvb29sbGxtDQ0O7u7tbW1sLCwqqqqvj4+KCgoJaWlv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAfACwAAAAA0AANAAAG/sCPYEAoGo/IpHLJbDqf0Kh0Sq1anwOBsGBwGB5gQWHA8Zq92Y16PSyf0Y+EfL5xd++ONF1Oxt/1e3Z+gHSCZ4Rzhn9xe3Vvi40bfX4GiHyKlYyBj3BiYQVDAl8SFRgKCp6pAhugGq4IsAgbX2xqrbGxCbS1t7iyu2y9uLq1tg++sMTFwrnAtci/xazHyMq81L7WwdjDzqu9GKQIRAYJCgsMDRALBQek7xIXD+oQ9fXs7vDx8/b2DJr6+PVbBxCewH7/8gWkh7Dgu4P+HO5jGFHfQ4r3JMrDSFChQY4JLSaAmA5DEQHn+skxxfKUgAUTYsrMsPKUTVQwZ8aseROn/s6d4nq+/DmB582hP43aRKpTqcucTYMehTrTqc+kUpdSlWmVadUiBxZAkCnrlVlSFtKqtbDAnFlXaNembfsWbgW5c92+jSuXbl2+a/3uvYtX8FnCffUexstW8SvAag0/RhzYsV3GbcEyiEDBAs2erzbI7EC6w+e6qEaXPl1XdOnVG0C7cv3adGzUtF+zfpsbtuzUtW3/7k16t1niwnGrLn679XLPsTVztpA1NAPG1Wdfx5tdQ4Ktabt/x559PPfy2+WKB08dPXnc7Ne/b51+rTjpFCSfgkyagWUF/HXgn2wBDghagf8hSKAEwQmYIIPBGdiTggdCWJuEN1E4oYWvmBkoHQQoyYZcUS0dlUGDCY7YnFAnBpdii7qtaCKKJS4Fo28i3shcjS7pmBxoKvKIQZCnEDAALBDEI2J8Byw5n1BMOnmelOo1CWSUVz45lZZacfmUl1dVaVMWBTSAipAHYCbjfmkWtiaAbSaGZmdyVkhnZXO6mWedG94Z2Zvx+JnXnnjaqadLWgxxxaKMNuroo5BGGkUWHwQBACH5BAkKAAEALAAAAADQAA0AAAb+wIBgQCgaj8ikcslsOp/QqHRKrVqfA4Gw4Pg4HmDBZjzgOAyOc3pQGLvJHHTaQGcn7olxgmNG0+sPdxt5g3x+ag4DgYKEZYdydnhujoiAeJeGan+Rg3h8c4h2g3p7fWd0iQWXjXF+qIqSnmaaawZhBUMCHhwSFRgKwBobBgUPAmJjxRoIzM3DY8h5ts3UCQZuYtIP1M3Wb8jF3MzPyG7h4t4b0cPb4s9veefc3uXJ7fPX0KPy1O/6G/y65VO3rwACDL0QENlVYQGDBhAiLihwoJeEixcfQIzIccGDAxUwJsi4kSMEBoEsYryg0WRElCMtxmzpEuXFkBgl0DTpseL+zZklOcLMeZFlUIkfMeLUefRkSpESjLp0qlTCSKk1kxLF+hBBEQ8bFnCcQPbOr1/MMAhYQLZtWQnA4jJLwHZCBrd34gJjttau2wx59SJQ0PcuXriCEfT1SxYwYrmE6zKeMFKvgrmSDQNOYJmvZMaBIS82bDd0XA2L/1ZOnNouhCIOxLqdgGADAg3LliFIUMGCb99kd+fGPbf3798LEtzGrRuD8d8TLCQnTlzBxePIEwzXzRt7cO3Di3uXDj63+ONkp1NP+/y4euKDe3mf8F43guvoaZeH73x+kQsMRECBBY1xpoEC1RFGVgcMRgcYgswxoyCDDZaG4HJpbZABhR3+FHjaMsBoyKGHy+mmgIgUOrgBhLcNNmGKFmSw4oHM4YZihQ8G09wGC+I4I3wH8TiihSW6eGOHHTwYXog9EthBBEUcEOCAvl2ko4QCMIBdlYhFqNgCW1pgJYQg0tXWcWPWKIyW+a3G4m5gtvkYfGuFmSZ8ZpIFnJhzlskmdHyWCGFYZ/52J3Mb/ImmBNt5Nl8CUU7pGwPl7aXASL9xSGmNl+32XIMdUPohe5l2SJ5eNOJngab7XWbdpx34ltyHwFzEIYWbMheXrbeGylliqrKKanG9+mpZrRKUyqCogl0qwa2yQkqAlALG+GswEh6pYmdBTjBijD8eaKS3KVpomQbZEhzZYAIY6JohuT7+AtmJ8JoqI7cnblhujsEEI4C+8SaGgZApPrlis/QOKaO8liZccAQbYEDAAMxAQBYGB4x6KQOFcqlxlnY+tteXhV6c8ZVwzofxqF+ONya2cJbcwcqnDQZyfjSjWueWOY+8M6Av+xwndBP0HNfPiyqQRQEQTUApw8GkG2ZyUA82EpV7Un1uulgTSB+7x0pwQNfeMnAwzBd1PenZll6d325QI6s2eXFbN/bbYMt1UAVzPx323diZjSqCXOOtlhZDXKH44ow37vjjkEeRRQBBAAAh+QQJCgAfACwAAAAA0AANAAAG/sCPYEAoGo/IpHLJbDqf0Kh0Sq1anwOBsODwEA0PwWY8HnAcDgMaPSiQ32a0YZ5uJxLje4JznvsNAw8beGR7a2p+gXiEg3yIh3aMZRxqaYkPeneTiH+Bg5l7lGlygAWEmWeWnZiaZHyqlnafmmaPaBweDgIFQ0N8BRgKwhoKGhsGAmJvBQ8Izs4KCMfKi8fNz8/HG2LVzNjPCQZjymNg387ab3jm2NHh1IMb3u0I4YVk89/pb/LX3/bcyLD7J27bMn/YAMZbZ0BCBQREBjgoYGBBAwgYMS4ocECCx48SHlzMqPFBRwkJUHoUSRIjgwcVQHq8wLLlS4cqU4YcSfJl/kyZNHlmXPDAY4WUKYO2hPDypMyaPYvi/KjUptScEqqSJIpTZ1aoGZuC1CmSQQMERTgUKKAB44S3b+8Eg4YAg4AFcOFmuCMsGgJ3CzLkjZugb0K8g/cWFvb3793BcSUYBhc4cUrDjBPgFZz3MmPKEzjD9ezXmea3oifwZTzsburQpIs5Rpx3r+TPphFngFBkTgLIE6RpQDAcXAULyPPW08CcboLjyJNPWJCAeXHT0C1M0D49AfHhfp9Hl768ufHoeal/f6bAI3ruy4k7z668uvzz49+Wp9ue/lsL1JnXmHjSvRWggPX411sBEFDAHWqFNeeXAgK81cF2qG1QzHXC/lTYwYV6aWheNBhskMGHtYkIXjEUToBiiBs6Q0yLKGpnwV7RrFjXBhZieKOKI5r4YoYxNlaiiyASeR00QiYZmop/kcgjiiBmAOWEQmp3YVoSROBgchZ4NCJg43EnJoKalfnWmeARc9p7YUpg3ZwbMIDeaJKZx1yaBaqW55J83skme49Jh5xHMYa3wHvbnblhMW8KKuecuakZp3UyKpCAnQUW4QADXkoXIGvuHPfhiwdOqEFKFlD5IQMRFleMezW+uhgxxYl36oUWwMpcNJmZ2gGYsD7al0e7nurrjMdKkKytk2HX6qkG3ppQBclW29dnulLb62LA/uXQqdIVUWeo/kTKBo0CTWL4ZLTCtGujlRgQE+WOSML1YzDDSIlkjX7aa+SUIKLoWWN/yZuuqnadmKR2GrIILLsOpzhZMSVWzCu9rDFZ8X8chxuvxqgRMIAzEPxnAQYHJDrbdney7HI9i5a5csufQYqXoTcXSWafErQ8ogZ33YmczOp2uDN3R+MMXqU8I9qXvYGCGfTFmtZs45o4l0az0T1vC7WgWRRw0QQOLhBxvwlaysDaUa4qwZfuUsevus/R/R+sdwPrEN28vh2MrHJ/KWoC/MYdtN7I8b2tMIvn113fpTIO4AaJR+mR4dE5LnbektvNYq4V6G1gMkIQccXqrLfu+uuwxw5FBBYfBAEAIfkECQoAHwAsAAAAANAADQAABv7Aj2BAKBqPyKRyyWw6n9CodEqtWp8DgbDg8AwGnoJgQyYPOQ6DY70eFMrwAdpATzvcCXJin+Bw6IB0eHB5aHaAdw8beWV9c2xqAw+McYaBBnh8ZXJpl5l8eQNrap2YiouaopeRk5SLc3V1kqh7r49rHGAPYllyagUKwRoKGhobBmOEBQ8IzQgKzcd6i2TLztfHY3mM1tfRBhvJet3e0o3VzM7QCObb6NfrCeDUZQbp3vJw9ffX8tqN5PqBE0fGnrdv//I8SFMBARFRDwQUYAChosUFBQ5I2MjxwoMGFi8W2JhAQskEHkGGhLDgAceXKVeyfFDBpE0JMVe2fEkyZ/5IBi4rnNzo86JLnig/ygQqoSbHpCpD7rRZEqfSlUBrViV6VeoDjSQlVGPQAEERDgUSMIMwoW3bDCXXrcMgYIFbt3AlBGu2boPdu23jrnOW4O/dvHuhQfMLOLDewc/qNkasGJqGuhkaC4aHGTBlfHYz390sDIFkz4KJPbtsGO9mbKEhFBkoofEEdgg04KtgwQLgBQmK8W2GgXdv322BC+9nfALyCcp1y216HLmF6N6K9/4dXPfwBM2fA889XAP158kTkL+m/bhb5cOhgd/etjf8+Oe5L29mvvmE2eFEgN4EcKk2GAYbTNCBc66pNhyCCt5lQYHeVSZABgseloCBxP4Ek2CGDXo3zDAXLuibbxQ+I1eJDPaWwQbELDfMhxK+6KBcNB4G40EQgvjWhtKtiGGEb8EonToJ+rbgbAVoQIF7vpVUYTwMVOeWlN4RtoCVjgnXITtbbnfcRsWUWcwGVaJnAZkiFpNAmoBhCRqXa0qwn3xh1ucbm89oKSaDZMaoml9cTsCmjG9auaedIuJJ338EcPBABE8i1wEDG1bWTE0ddJrhdcHJpVtJnSroKabLdbhRqRacCqSDCIDnqYnQhariM5x28Gd0wewl66wLxjpMr8GsCuylmcKTa6npwfpMU7O+l+leuUHrKYPAJdZnrvSdpQCllqb4II3W2TgYNP49tkggjJoikG596/Y6jIobYMjqhOzGp0C9GZZaoGJ80TXkc+byNSy/brloZGIzDqkjBqK6S6OJHRS8TsMgophsZQIvCCIBAzTElnOtYnCAlyrWVajJKDdTWHXHmUztoHmSPAHLFeam8oA4G6zAznrefMCN0ABNcgcyH+lyzTEPLYxiO4tpgcxyEQP0c1R7Y/R2VFMba5j0WZBFASBNUOkC7H6JAE6K1gqxisM09SSD6UHsYH9z6wmc3QBLcMDctO5d4agSVPpcrG8/bXLe2+1N7GJ/u+ec471GE7meyL6togI4GX4c2nwr5rfh0mIwojMbXH6XAFoMccXrsMcu+wnstNceRRYfBAEAIfkECQoAHwAsAAAAANAADQAABv7Aj2BAKBqPyKRyyWw6n9CodEqtWp8DgbDg8Aw4YE9hQy5vvhyHej0Ym8lfg8Exnw8em4R+H5fL6W1lCXkJA2p+h4GCeYZrdQZ3b3pgfn+QD3pmhRyVf217g4yOlXeghJSIcopke2mHdQ6lmWVfa2AcBQVDQ5wPDwYPChrCGsUbwIsJBQ8ICArNzcd4oXnL0NcJyKGDwNfQ0ovS3tEGrKzKzM7Y2mbW6tDZ1ITu3tmS6OMI8cn063hv3cYdGzQITwEOB4gY8nUhwQMGECJKXFDggISLGCU8lDgRk4QEHy86bMAxIoMCGUNqJFnyJEiQHxNc2FhywYOMe2ZCbOkRJv7GByw5MriJEebIkhCG4tQzM2jHlzhpCvVYVCZQpEMtgswj4ZiGIrgaVhCwYILZsxP0vGuGgSzasyCbPYNX9m3aBPncvs2g9tlcBXrfqoWmoHDgs3zxFkZQDHBdwRKuzU3wGHHccYfhRi6sQW7mCXwlCHM2zLHd0OPaIoBQpJzICnYtINiQLwFsuwvwrtVXwYIFtBZy14b9G63wv2x7Fy8uPPVt4M3fKbg4objZ4LqfdeZtd0J0udMl+H57fK3ts+O9Z1c3/blx3c0aU5/Q2nbb7hk2LCYMGH+CxX4ZBpxZ+RXmV2kC4KcfZ8T0d5p+jI2GAAYbZPCbdQXuV4wGFf5eWFyB221HYQboEQjhXGxV+CCK4Km414IoFraBXR3wtR80I3ZAHwEGXDDWAuMV18FFzvw1HQPpaebNMBIgaZ1ZRAqj3ZEeXnjRhlhuwMCAExDJWJaVVWeBl9AUk4CT100wZGRyfanldctFWSaHZV143ZXDbKcPkE+mJUEx8TVDWZBneTnMl2ee1Roe4gnZQQcMKGbkRY9e92ikcul53qOVQprdoRMSx6lZuUmIYwWVWnecX4IqV52anhoYIKWjXvqfrIXRyqmtkjkjAao6ovfdXBgAS96tgfKWKqyYstpqeosWAIGQJiJnYIdpgrYBBm2maOGrJmJw44QuUgvSofDEVqijb5XGxaqMZlVa7V+lYXuWjraRli6JYj6aIWlFzrgiwNdmsG6w+YkbKLzZaqswruoqOoAEBigA57py7kdWktXJSdjGvoU85gGZFtkknHeyOeWR3WFAsr5MbinmWS6DZ3Jd7PpWM4sYJCpmcS5LqU7PfP5sQc1FIljnW2TiSBnKHYuGYszpWZAFShBMQEGQpYLqq6uqJiCu0O1tfSwGISZHAdS5PWzyARSse1bbADMJd59tM/j12knmDeB0d6cJKYzgSQB3v6SKXaSUhm8tsgWRjr1443iLrafaaAmgxRBXdO7556CHLvroUWTxQRAAIfkECQoAHwAsAAAAANAADQAABv7Aj2BAKBqPyKRyyWw6n9CodEqtWp8DgbDA8Qw4YEe3sCmbN1+Hes0ZkM2JOEdtcNTVnEd8X/4a/nZqbhsJhIUJfnd1BoOEjohzi3+MD3CHkYB3A5WWkJN3DptxZYeJn2J6h6UcmZONe3GJgXZuhWdDc2AcBQVDBX4PqQYPChrGxggbw4+EBcQI0NHKnIYJw9HY06SO19jQytukzt7fy4ZlwwrkyrZwzure1pyjG+PrBpbND+QI8szT/MCdidPNm7ZKBQxIIOLB2YMLex4wgECx4oIHByRo3ChBYkWLeiQk4HjB40cIDB5sHLnxQYOTKEOKZFly4smUGvdoLPny5P5Flhw79vyIUyRJk0RVzmSZwCXMn0E1Or2pdObOqUkzEpr5oMguiBjCClgwoazZCXHIYRh71uxIeNjYtkWbgJ/csxnSwlPA9+7ZtAj4FlPgt2zeBOqMqSNMdu5IaHCTNcb7GFvfyX8lFIOsgfFctBICd4ZXeELe0NEwVKjQlQA+jXw1nrUwwUIyfrLnLkBMTkKF2bV34/7d1oLwwNhUl6Vt9ni02BKATxC+F5pys7SN89aAzfdn53yhedddF25n2RaY1+63GLmC3G2PK4ZexECCCpsTfM4bPrBgAXNZwN9i8GCwwXKULTYaXwfOlcEGgh3T134QbgYZYbW19SA8yP4gYCCCE3TQAX8IcFcigyAaVmE03GFY3IbPCbZBBg5C+Jx1DZbVgYqRyZhBfRfg9x4DGYZY1lsXfoPZchqxmB+Rc2nU2YnGJLBAetmVJeUxx1iZogVbctkPlLVl1yQ0HW7QGG07goZch2OlB2JlJY4mAZHMmamZiXV6ORuYqJlYJVnq1SZlYiayVZ9SF0QXoogiMsCbf9AtB2kHkloYjW+QGmlBplOmVkGnzdWl1m+FTsdbZN6x2eZu4Qn2ngQiPhopYrJCdymkkkJGKXy13eqrf8AuJ19yqD5aW69wVTpBfQVIRWObPBKIY4qmrXihAjOmCqOT3GbA3I4CbhDWXvkMimtBreVi4N611Nb2oLuD+WhWm3mdi2a66dWaLV8tjjZjjZvFym2w2M1bomj8zjavrP4N/OwAEghwQJzrFinBAf5deCdwgFoWGwNYyjkBBgcUPBjGy6W3cWJ84VfaBC93tuCdJjOpGYGdYdyBnCGLqoCVWJ6FcnsYXFYm0C/Xy5efbW2cnJImMyf1vtDIZUEW0ZZBAdDBTfprdKnupq8C+CVwAAXkucunhxV8XajZ9Aqm0dezSRrWibGt3faUdkuA91l0Uzor22ymp3fdfX8dr9kAFxh3yWWZTel5fuedgLveqMb2BAJoMcQVpJdu+umop656FFl8EAQAIfkECQoAHwAsAAAAANAADQAABv7Aj2BAKBqPyKRyyWw6n9CodEqtWp8DgbBQIHg4YIfY4SlszujNgDN2sMmPc2I+fxvahsGDvqGD73dieXFzfQlqdg6BeoeNfWEGkYuEjXUcgGODcnQJbJFtDnpyhp2KkoKihYVrpp+DnI2sgZKiaRtDYBxcQ52XD3t0Bg8axBoIxBvCfcsJBQ8I0NEICcqwwtLR1HvLZwLP2AjJcZvi4OHChWje5tRphc7sBoaj8ODJ8+/f2MmOy/XY2siVs+cgTgEDEoiE+nWBjoQEDxhAmEhxwYMDEjJmTHAhIsWKezRu7CjxIwQGDx6KfOjRJMqHCURCbGDyJLCYKjvSNGlxZf5MkjVR4twoQWdNiw41zjyaUuacBzs/MigAU6RRlwUOxKRTZICBhhjCIsAgYMGEs2gnzMGmgKzZtBMyrGVbFu7ZmODc2lUrAZqCv2Pr2p3zV4GGv3rhyk1ATAECxILhEpZ2ODJauX39OlZgGS3ex4f/do4bM3S0xJIzY6hQQULXDRkBh6tw1sIE2xammZNA2+6CBLt74z77O3ha3L8dS1PA2/bx4pof866dFrryv9Nva5/w21g07L3hFpdtOLt44NBCa2iO1nnyx6CZh6/OODTiIgYSVDDcWMBeuW0VZhhnx50FoGyPEWhXBhsE+Fdo/i2YAH/2KajYhN8NuEEGC/42SEyGG57VQQcGNojBMfwpEKJiJh5zDDIcUhdXgwkKuGJaDG7m12EbiIhjiw9qgAF+F+zH3wYM+IgWbwmmpwGSBfKFojHlJWkXk4cV8yQDw9XGm5bFJMBle2d9WcyLCZhlAW5rYukdMWnaRqKXfX2IogRvOddmneptSR1uGUVj5wZv3bamBV86CWeh2wVqJzL4NdUWbyNWOiIDwAmImAQWWHobdNhQOgGJ7mEYagVz0mecb6ZKM92IqgoIzauWdoCpprOiWqutGGqaXaeV3hodAubddiljbNGqnQWgAiYfflRh0JYAMf5YGIjVXkZjk3/dqK1yhyUYIqklXmdjBumwOsfgieaqWK26Hmrq7qjWpvegiqOmOuNm6uHb4bUDzlsbrHgNKO675Tpb2IYEDCCBAAdU4Ba5dJr7mGDDIZqZrwscWhuiByRoH54fAypBaEauZ+Vxsdl3GMlkaiwyZAt0sOaygY5lJGcdw6WxY9IWJqbHJlf4V5o+gwzNiUtjnJajygXWcRZU6XfAARkThx7AxaL1G7spS3AABawyba/YZJ8XtLO8pb3d1/ZJV4HbXifAroBtl60pBmiPejN3dsubt9rhgob231oHbR/fbh+KqdkJPkSBAFoMccXlmGeu+eacdx5FFh8EAQAh+QQJCgAfACwAAAAA0AANAAAG/sCPYEAoGo/IpHLJbDqf0Kh0Sq1anwOBsFBwGDwDjmM8/hY26PQmPBaTB4+EfJ4QG8iGvCe+mfc5HHdlenxyfXWBXmQOcAl9h2uBeYuNh3Nhgl55jXR/i5SFfnaCeQaVdIilmqZxhoZ2q5sPagIJD2BcQwkGAl2tfgUPGhoIw8MbvI+OCcEIzs8Iu7V0D83QzruPaI7W19KQaN3Qu45p3A/X2MmuyOjp5NuP4s/whn3z6uX6+AjI02r86hQwIIEILwm85khYKOFBAwgQIy54cIBhgoUXHEaU+IChhIsSMj7cCIFBR48MNZKcCHIhSJUbTYK8SBNmRAYFLHq0CdGk/k6MPCGwRBkyKE6Lcj4aLdCSoUiSQn8lKCIAA0UMWBFgcLZhwYSvYCfIeabAmVWvYSdkGEvWmQC0admaRaDgbdqvFxXo1coVbti8GvRu7ef361oJZQW7LYxXwrPAi+8eppu4712xCRQE1qvXbtq1mZ9hCOw5LGgMFSpIKHLAFuKyzzZUsDCBtu1o6RAsvGthQYLcEmbXDusbeIWvtmsXb6v1OFjaE4rvhY0a+nPfsPfqFm49+m9n03ffxQ6e2PbLxTcH1iC+O3nNsIPzjsZZAQaqBDUPgy/gcoYN9RHTGXKmZZYdfBvwthZn6w0oGYABkqYghHoZo0GCkoUGnlkJ/nbQgWkArmceBhtkkKFmxQioAIbWWfBfffrVlZaHC5bHoYmfGRhjEQ48UEGF5iXAwIdhWbAQbPtpICSBYB0p4H5LpmUkYhZqlsAC3VkwpYXGbMAAk40Nk2JgV9pm5kLmWeglkcNt6QxkhEGnZW1oAnkMA8nZtlCKb174pZZzTjmmeZ51h2afGhQBx5GDoebho19hV59ZFUAK3XLXODoccgx8R5YC4oHlYafGzdgBqeloKuqpOpK10KOwdsoZeKBKAOujssJYqwW3skpZeRchF6undDkT3Ie2jfrbdM7wmBMG1JX4IGzF6iXtZxRSFti1z70IWbQmtvjipNaGW+CB9Zux+JWHYkE7q1bcTsBuAqNVSFm8hoUIZLlhzbsVfAiGy65amX2rlwTqyvshvZRRR8AAEghwQAXuSoBlkRZgcMCvsL2V51caw9iXnLx2EPJmHWMZKJ2I/YgiYRhnfACDiVnMpJYnKwbqxXkuhNqsOxf5lc+TxtmmlkcW3dVzgGo8mFZWXlzkkaJZmUVOCVAM6gHJcZotdc4x3enPMSZwAAXjMVwMZwijnZZv7jYswdmb1sbABnGzLYHb655KYXh7Y3x3fdAqufectVkQjbv1zc03WHDb2NzjWo6NMqVoAxqp2uEJoMUQV4Qu+uikl2766VFk8UEQACH5BAkKAB8ALAAAAADQAA0AAAb+wI9gQCgaj8ikcslsOp/QqHRKrVqfA4GwUHAYCp6BYzw2ODyFjXo95DjcZMfgkajbExy418Cfb+x/eHp8fQ+Bh3lecXKGCYGOeXyLfnd1A4OSc3d/G4mLBpSACWJme2ahd5FmhKB0joCJrIVsdQUDX0MJBgISDw6VagUPGggaxsYbBpyvG8IIz9AIupV0ztHP02uv1te6h2oJ3NHe2sEP19jKdcvi0OTM4efo3uucAvLdypyc7en14P0Q+DIggcguBQoMXKgjoaEERw0gSJy4oMCBhgkcXngQcaLEBQ8uPsS4gaNHiQweOFyZwOTJlCwfbuzoESTGkQlmnoRQ8Sb+Rp0nQV7M+NOlR5grGwI9qvIhQwlLJyJNGvWjqwRFBChIeQEDBgRfEQpYMKGs2QyOnimAhmGs2bMZoa3FRvZt2bTPwgqs+xbtBoRg1bq1OyGjBoRfnz3gC3cDAsTPNAy2i/cwtMlwJQCeqwCzWUeHEQL2PAGtBLaWEzAui/ZChQoSihxY0BbwuAoTLOTObUEaOmm431qwsCDB7wS4db8tfjz5bt3M1boLvrts8c3T7Q6PbluBBOfLjT9eq0DDd8LExZfPTrh46MOHzys3y7z8XATnhU+4jriIBA0bYHDMehgkQFhpCYhGjGgbVAfXZuUd1qB+aCEE31oFZkBYhQr+EpMhhQlaaAxCE9pVoXTFKNBgByb+FaFcJfaVYDELPtbgfLpl4KKIYCWgYVkdsKijgjAeOGSECvhHB4/PCMCAdhY8FBl80pA1313/PTZildpN8NAxVKomnG5fgnmYW1dGmeWAklmp23BeimfmZG+qGdl9YvK2W0YiGoOAk8/t+R8xNFY5HJzDNQSmO1ZSdhqNGhQhTEMKJOZdBUEGWVZ6ouGJKYvzRdcNeLuJOh5wb2nKgHjRKFCBgWapyqpcr6bK4qq2PQZcpplOgCtnCDXEq6ydAobcsEH+qhYxyOXG636sevpcpsrOVcQcEmAwl4Q/9vWXdAx2e1aA5Nmnorj+OYaoq1o3mqVcAtpuxu2VCJYbWmcZKKfpBDsCu0G3mh65nn3/brjjlufGymJh2r7XY777lkbueBj6qO/C5OZKwAAJCHBABfEqkOemw2FwAHbFoOmgyZ0ySrKmJt/LKKK7mVyBhYLxdegELNunK6DKHRozZOWp/CbPH4v285Obbtpzdxs0eqgFT98HKG9wmszWeiM3rXVe62VRwEMgB2sgjpySp1Z+JEMb75YPUdAevCkaW4HcdhWnLcXeHUABjm6XazbeE2iqt9LB3u2ubqvG23Dff7d9eKfm+T13WIQCRzick98ngd87W0c3dg9oMcQVqKeu+uqst+56FFl8EAQAIfkEAQoAHwAsAAAAANAADQAABv7Aj2BAKBqPyKRyyWw6n9CodEqtWp8DgbBQcBge4AHHQTaQHZ7CZs3eiM9wzyNBr7vHhrx+ME9s6H8ceHp5fH6AfoJwZ3x/iAmKZ3t9j4p6XgaGh2sJb5KFlI6Qg2ZkmnWJpJOidYKEe2oCdGAbBUMJBgISFRi4dn8CthrDwwgIGwZ/yn+2xs7GyHWUzc/GuJyOtQLV1gZ+2NrcCNfLCcHb3L7KhwUP4tHr5u3i6vHz3PDl99XknPLuzzBIsEUkl4IFDBAUOCChoUMJDxpAmEhxwYMDCRxKk0hxokUJGUE2vBCx40QGFx86LGnyo8gEAiFy7Igyo02BJGdSrKlxpf5Oj3M04mTZ0SLDnjJNQqhJ52FOpShVNvSjs0EDDbmKCFDAYKIfBBgQKFCAc8GEs2gnZFTwjKwAs2knZMgo1hkGBW/jnqUblq3YvHr5GiOLF27ctWGdFdY7VwJZYxr+Gk6bUYPfwYAPS6hbd3Fgx2P9ek7bGKxlzJPPNpZQ5MACCBOO0aswwUJt27E3cFPQEK0F3ONm642dQLht3BMWFL8sdlftuMo5D+599vdZ5WMHW6OtFztbBZHHca9+PQH4ts71jgPPvvn4tMpPK07/vDzZIhIYRICwgXD4sQIMN9dj2QEooHljFWMgear1155YCmyQAWMOFgOhhAzK1R8Gw/6IFiBjCEJ2oYD9hTdYhBPGlcGGdRGDYX0aklWMixN20AFaK56nWIR6dTCgZfjp15CFmDHgG25DWvafAEbq1RB48o3TJIyVKelMAnBZN0EHSXY4zAZT1tcllBokwMBxyHVJjAZgPqflkMyNs4B1aKqJwDBmuolWQ5BFhuecaP6WpDN4holWlRrgtwBej3GWQAU2ktcBAyE+kxGMNlIqnKSTFgfhdNxFWl5bZFEXaaaenljqWaISp9h0Eth4aqeqjtWQrDeiGtplj+Iqq6Zi/bcLrqxqepmtEtTmq7HGtIZXBX5FNtaLpDn46bQkhnYathnmyBy3MHob7IgUJlggiuVb3thgdp2h22qO0v5HLatqSdDhiRuwqm6MCeK7pYoOsjttjfuK2+wAKD3AS2h3AfbbwwJxpkHDZiF31pPfvvVbqxjbtdhxezr2n2S3ISfQtqhV9+YBBErLpJ4Xg8YZXkbihqTMnb388M3sFrlzyGDpSLNvaGFwQNCRZbHQo3cRRt1tqM7cXLK3pctAiVFmREF3MIUG69bQde01bweAjZxyTbOrdbpoof3dd7tsrWWnGNxlWallV11e2tI2BDZ8MJnYXN50WkDpXTsKRAFyvx3+HQIPaDHEFZRXbvnlmGeueRRZfBAEADs=', | |
loader3 : 'data:image/gif;base64,R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gYGBgAAAC4uLoKCgmBgYLq6uiIiIkpKSoqKimRkZL6+viYmJgQEBE5OTubm5tjY2PT09Dg4ONzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA', | |
locateMe : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kKGwgzGjNX4ooAAAJcSURBVCjPhZE%2FaBNxFMe%2Fd7mUpnfpL71LQkg9IVr%2FZCikf9SC7WAJSRRrrUPpoMEiSRdxcwnoJOggRboIWhIc2qLE4iTYDqU4WB38Q6HqItKKtZfalMsld81d8nOqBGrqg7d9P%2B%2FzHo%2FBf6o6N3oF5tYY7LwflvUMHH%2BHjWQ0Zl%2Fo5cVJprx6DfJ5oNELUAY09%2BknTPOYbR9TO7P95jGkEMA2ALQKMCwYu%2BCEtm5ydXXU7MfOOlDeBsABpgFwRcDGA%2FrGhfpgefMkKmVAWwMcVcBWAmwaUMoBDJuvD1a046AA8l8AQwXsImDqgFEA5Ni9%2BqBVbAUFUK0AhTWgugY0eEB9fXfZSGZ%2BF2xvaWmZNgwjwPN8ibMxm9TSvQwFsNvC4Qp1d8fZc0%2BnAYAjhBwslUrvOzo6fg8MDFyfmZlx9ncf8rHW6xQoAMYO6u5SQIJRNpL5%2BHejzs7ORx6Pp5JOp0Wfz%2FdWkqSdG5fDOZpxUvrERxfHzxaDbQce7DklEok8F0VRBwBCiDUyMjJenRu9amVPa2OXThR6e3tHA4GA6na7T9VybDAYnFVVtdHv9%2Ff19PSsLiwsnPmxWfzONh9tXf5l%2F6AoSiIUCr0SBOHhHmssFlsnhGwkk8muaDSaFwRhixDymeO4yuDg4Gw4HL7t9Xq1WoYDgOHh4T5N05anpqbmnU5ncmJionllZWWI5%2FlFVVVvZbPZdy6Xq6goyt63pdPptng8%2Fk2SJMPhcOREUXwhiuJiU1NTgRBCE4nEzdo8848BQ0tLS6l8Pn9E13Uiy%2FJXWZbvp1KpydrcHyPz5blPQjIYAAAAAElFTkSuQmCC', | |
map : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9sBEQ0rMteXYLwAAAKiSURBVDjLlZPLaxRBEIe%2F3Z11N%2FvMxpFoXgfRQDBCRGIEEQQfIOJBEERRFG8eQvCg%2FgMiHjzpQcQHBvTiTRAVMSpqVAxEgxoMxmiMT5KY7EzPTM9Mz4yHmCwqItalmh%2FFr7%2FqroqtWrsqam5dipZI8L8xOPAarbl1KedOnftnsaOcP7TOg51oszfHgsuIW88o9diMH2kim88xNPSIQXGWrxMG2Vyeb5MGCS2JYUn2bYlIaSnis25GeZJyq4YhBPaNQYT4gmkKYm4%2Fjm1gCRPPETiOQElrjkKbPRSK84kin0yXDsf6SW3Xqa2rI%2BO%2FxVHN5Et50sk4WnIewpYkEhKgQlCe%2Fo6wppnSFUZJ4VwZhiAksh%2FguwJpOfiujSOm8Vz7T4Jidf3PXINxQFI6PYlat4iU7tLkTpDMN5LWYiRTSUzLA4wZgkRsxkNKF0vYGOVJzGzAVDPI7pGZIu86115s5fbIFqQQhF7lDeZaqKqqRq%2FWKRQbyOcWkNzTRtWoRtqrpV7%2FhKs8GvQWrg5vpq3%2BPMl4%2FNcWzLKFISQ6U%2FR9%2BsrNV31EGxTe42G8QFFXWkLLog5MaXG4p5uTO3b%2B9gvVCzGUy2Nh895No0KPja17CaKQIAwIifg8PcbyxjUIz2HPxQ7a2F0xeDL2jr6PQxRyGSxbIJVHEIWMTrzBDxUq9PEDH8M1aWtci%2FBt7skLMwaOchgPfLKpLKV0AS%2BjkEqiAkVtsQkVBARRyJfyB2pyC%2Bkf66V3uJf1xv4KQZ4CTsomEWXJxFwc5dL96ARe6CGVz2K9hdWLN9E3%2BpCe1%2Ffp6XrO8aMn0YJIAdBQs5KGmsqidCzZ9svi7DrTTixexdORAe4cGpjTY%2B1r2qNlK1qYnYe%2Fxd3iJfwwYJO5d057%2BewFPwAsnUE8ZPBqbQAAAABJRU5ErkJggg%3D%3D', | |
mapToAutoTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAeCAYAAADTsBuJAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAExgAABMYBQzIXCgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAA1rSURBVGiB7Zp5lFT1lcc%2F9%2Fdevdp6q%2B4GekGWRhYbg6IYCBqJo4i44IwBVBSPxkCjTkbHMzOZjMlxOjNzJqPRURmNoMQcF1yYk8kxGeMSd0QQjIqgLAo0SyM00NB7d9X73fnjVRfVbTXKYpyj%2BZ7zTr3ffn%2F3vt%2FdfiWqypHi6X86bl9jU8fSLa17Zt76kHYc8URfY5ijGdxv4MjY%2Bd%2B77cLhA6rX3jFLRh0ror5OOCwB1NaKqZ0pXndZ%2FC4Tsu0y5ZKaqlMmXrxswdzS6489iV9tuJ%2FV4e7ZMjLkFV0YjRVOP3XQeVWtQ9c3AcMBsF2qfhdd%2BzZSfcKoRFnl0DsXXVd%2BQefeTy69%2Filt%2BaKJ%2FyrgUwKYf6UMFDc2JRJLXJaXKB81burfxo8bdUZRUf8hEooW8tL9l2aMhvWtqigiQqq1gbho%2BOwLZk5989Vn1tw127vkpke6%2Fvin3c5BiIgBilV1z5dFw%2BeBZBvhB68re6B44Il%2FWVI1IVE2uNqJxIpAFQVc1yVW2J8Vj3y%2Fs6Gxc4%2FjiFaVRctGTrzcTe7fjJ%2FsINXVTirVgarDmjVrGj%2FeuHbCzU%2Fohi9lYyJFwC9U9fIvY%2F3Pi8wJmH%2B%2BhBPVw6cOGnN%2B6bpN9exqWkc4EscLR%2FHCEaKxGOUSo6ioODzsWxdXFhXE2f7WIlRcjBvG%2Bl2IcRAMNtXGiOHHJ3btqr8W%2BGHvRUXkBGATMAn4WFU%2FFpGzgKSqLu3V9xtAGbAUGK6qq0VkDLAdmAisVtWtvcbkAWcA%2FUXkNFVdma4fDFSq6rJjx8KjQ8YIayJ89pARYws%2B2bUT1wHPFbyQIew5hMMeYc%2FDcR38rmY6m7bS1bSV0iGnUffWYppbWnGipYgxwSMORjsJh9xpfax7C7AI6A%2FMF5HFwDTgVBF5HEBEEiLyG%2BAi4BvA48D89PglwKMEgrleRB7sNb8HDALiQKUE%2BCUwFzhJRP5HRI4%2FevYdPTInIJof%2F35Z5ZD8uvUHiMXi5Id9wmGLFxG8iCEaDeGFHEyqDduykyQRHGMoHTSGtsY66rYsp2jgaYQdxZouRITyivIBd8%2BSATcu1l051r5bVVeKyHvAXao6C0BEqkWkHJgOLFLV36brVwL%2FlR5bCUxU1b3ptr8TkUmq%2BiqAqu5LC%2FXbqvobEZkMvKuq96T7LyUQxj98ATw9LAQnQERcxxnbkVRcx%2BC4EdQrxomX4eVXgAitu99nxxv34RPGiRQRySsmmh88JYPGUDrsTPbu%2BJCdDY2kJA8xDhUDygtD4dh3%2B1h7U%2Fp3M1CfVb8NqABOB17Pql8JdKXfP%2BxmfhqvAd85xD7PBN7IKq8BRh%2Bi%2F58MLsB%2FzuK0EwZWFTTs78JxPaxN0tawgdYt29HWHdhkB0mTTzi%2FH4mikWiqHU2C2qwwwk%2FiFg1j375GdjRsIy8%2FweAExguHZwP3HQFtjwPXAneky5cTqBaAk0VktKquTZevAO49xFyPEXzxb6fL5wJ%2FOAKajjlcgLx40ayqquHFO%2FfvpsDvwvg%2BGAP5CSjsjxgH14sQj%2BWRlxcnFovhxeMYMYAP1iccbaMg1IIbLSHW2kxrcxPEBlBc3H9Iba2YW29Ve5i0%2FQ74qYg8SaDL64BuVbYS%2BHcRaQcUWKrat7elqutEZEtaLSWBZuAnh0nPFwIXwBgpi4ZdqgY4gAfiYETAcRHHQ4yHOB4YD3EMOBab7MCKA4C1KQQlHjHEXZfieBRbLBgxFCaKonyAB2RyRap6ZdZ7CzA7q%2FyvWfTdIiIOEFbVtqz6JlWdJiL5qtqca2Oqup%2Fg1HSX7wHuEZGoqrYfBc%2BOKTJG2KpF1KLWR9WSsj5kYgTFVxBVFEXTsQGqCIqqDR7ro9bH%2BinUphCvgGR76%2BF%2B%2BT2gqj7Q1qt6W7qtJ%2FOvkjhRdgATWKDr%2BpivB%2FOfPkPyO6M8krOvsHDm8%2FrMkdL%2BeZARgIigvo%2Bqj1qLtTbr3Wftig3U7WolFHbxW9vgQDMdrsfoCUM4riwOHBRe929IPFTtkadb%2B4CqzsnZkI%2BQohDF%2Bbxz%2BRE84OJcbaJfvJ3ICEAxWHtQAKoWTXahRli%2FegtN4TwmTxnI2ne2UT1pKDaV4q3ldex4%2FQPejCaYPnUwaLcAAuGBpJ%2F%2Fv4h4tLSkuAYAZT6QB9yO8IERln%2FR62cJQNJfbloAfor6FavJHzmUT1otp5%2BaQNVSt76e46v74znKN8dXsm9wHiue3c6Blk4KYhKcnO7TAxxSAHNlGvDXCGOBZpTluPwYnwsRjuN%2B%2FXvmyBgMC2nkdJ5Sv8f4GpkFTKKR60nwBhm3msXUSDtwdUYVzZOLsdyAcAqBEV6JUjv1GV0L%2FApgyWS5HchTeH7m83rw6xeRJecwB7gMOBHYJMLzkQg%2Fu%2FDpwDY9NVnmCFyB8vSMP%2Bid3UOfOkceEGE48OMPzmBZ9VJeAg4QRPY%2FOOhHiknr8ECFtK3byJY9nbzzdh0nVfdDsGAt5YOK%2Bai%2Bma6OLprq99JU38ikwQ6NLcngBGWEmOaV9KGB5sntCIsRXsFwAcLVGHbj8zpwAcrI9CeSD4xndE5JlqOMZgkW5S407e4qj6DchZP2mmrkbpSHEV7AMgX4HrAPYRVz5a9yExigtlbMknP4HbAAOAvoB4xX5Sft7ax%2B%2FBwZEMicKmCSGkZkjxdhHDBJldLqtQhB%2BuUi4Dag4mA2VAyqPtZarO%2BTrN%2BJFvajqaGFeNhAZyep%2FU1UloRY8%2FYmGsMOO1uVPV1ChZuk44%2B7qDy7LEsNBb%2FkunGbK%2Bcg3IhhPL%2FQd7JaXqNG3iLw2397KMb0QJBRfIIbJI8UDwG%2FZ2E6Rpgn5wHzgHEs0PezRr3MXPkQYSE18joLcmdNT1jKzcD5QKMI%2F6YuD5NkMvDPwHBXWEgfNuQQEIRlKvwoK5IymS%2FYaoqOpFLqKamUz56tu2l8aSX23Q9ZtqmdlBi%2BU5KkPRLhxskJbhiWZEhnM%2B2dyYwnpNZH%2FRQ5bbBwDfBoL%2BYHWKCLgRWHuaG%2BocwGHu3F%2FACVzCeIC87ta7gIVwfTcM%2F05%2FWOGc9ow4wXdLEoN6e7XPTY%2BVJw2GQJP5v5nL6WEYCIk2Ec1rI5WsrY1m2MCHfSLg4PNyZ4s6SKiV4TgwcX8H4jlISV4k92U%2BT47G6z7G1KBS5q%2BrF%2BirTD2hsnEwRTfeG9w93QIXASmomAe%2BJWtWjfaYmF4ySEcgKAwpPZbVrM74EmQNwk1SrpjWomWu9GONfcFt6F7CtJ4wbLAEaEseOrWNTYj6JUG6dt%2F4Cbxkf5i6ooWCXev5CdLcp1xY2U%2Bh2sbIDH6sNU9ovhuF7mMY5BVHNde%2B5CqcjJlABlmbdUOk%2B0m9Ic%2FUbkqOsJpR6hX5%2FtQgLIqX7mrtIksAPA9M41HeBkoAAg5FCHsjmYjhO7u9TWigGG5prb6wqYbQCsqjFOCMRBxAFjcF2H704bjf32t%2Fj5xgj1a3cw6uM1nFHYwaRd6%2FnBsE4KHEtzEpZsNfxo%2BkBCoTBOyMNxw7ihCMZxEEGWvEphr%2FWXIszkGol8irJrpYLszT6gm4HtJBmbYx9n5trcp9aCS6iVT1%2B%2F1sgwYAyHcDcF%2Fjf9euOSKXIqwJLJMgjlX9L1717yrO4UzST7xvz6PCmvrRVT%2FQZXAZ%2FeYxYMgG9xcUI4xoAxGONijItjHCpKYlxx9QRe0AEs2234uAnW77P8ehPUvufwq7owkyocNm9pwRLCdSO4XiAA13goxhxoIT99RRjA5TYghMejXC%2BJTP0cGYjLfwM9o2fhVYSbuErimbp5ciXdd9OHQog7gUJ2sIhrJT9Tf50MAZ5AeZr79c2%2Bhiv8I7AVGIll1ZLJshbYhDIV6LBOYCNmvMiHwF4g7Ptsrl7KRpSHPou8bgE4BoIckNN9ChyM6yImRKJ5PzUnehRWlHDLxiLu2l%2FJc94QuqqGMejMk9gxZBRVoyqIxmI44SiuF8ONxHE8DwySTBGFrOj0Xm3B51yUEnzqqJFXqJHXMWwAXkX5ZQ8qU9wC9CfKNmrkOWrkfZQfovz8MwVwr7bgMAXDUFy2MU9epEaWYVkHbCBJ7qg6jRkv6AFCjJMgO9sJVKebXrZwyqXPamCvVFUs0whUVpjALX0ZeOVQ8wfHUhFVP7jNUkUNGEl7d6Is225ZtbqN8hEDueLiGNWDCzGGwMUUGDX4YM6ILKNrXA%2FXGKzi0jsie1A%2FAs5ijoxBOAVDCljB%2FbqRGhmGIZrVt46%2FkQm0800MJyJsQHkTpRg3yzg20E4JZ2EDfZzBfboekUnUMAbL2CCBxaqMq3qQ2TltxYxntAGYtXCchBJFDO9wqJv9nLb27jf9RV0GDHzybBlmLK0zXtZPckzXgw%2BiqtwxO3%2F%2B9MuuvcExQaNaRcUiNtAEyVSKxqYOSgvDqAUxmvbvFVUfUVD8QB6ablMFo6x6a%2FmBa%2B7eMrGli42qmsy1wa8zXICnlrf8R370kQuKi4ti1oqAIt1yEjBWsaJs0qCc%2BdBFMYCKilXIqPn0IejoTJrVHzUubOmiBeiZRvgzgPQJEJEwUEJw43RU6eNeiBPcAzSm8%2FN%2FRi9k%2FhckIlEgBKSO4fwxgnvcZj2afwF%2FhfF%2F%2BkeeoREnKEoAAAAASUVORK5CYII%3D', | |
move : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAWElEQVQ4y7VTWw4AMAQbh+2hXNZ+l21eEf4IpcpakwZAAaiXQ17x6YsIpQGsrhaICfqh8ADwp7PH+dkJR2NHFKlafO+ERzXPxLgqUSa3JGP7kNqn3H6mtm0hKkEgnsN7egAAAABJRU5ErkJggg==', | |
newTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABmJLR0QA%2FADpAE8017ENAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QISDiYc07YZKQAAAWpJREFUOMutkE9LW1EQxX9z741WJH0lgtDKWxbc1O5cZqkb8w2ycVm%2FRd6y3XcjBMSC38BNN90qhVJKslJKSVqEEP9FYpved8eFJsYYk1R6NjMMc%2BacM1Iul7drtVqREZid%2FcvcXJtn0W%2Fyy5%2Ff5aJvH%2BHPvmTDGaVSScfh%2FHhTL0%2FfaOe8oJcnK52LxuKutrLr2jIzrqvSbDYJIQAgIj31jNlj2n4h474iZgnrTCbY9mrHt1tTzld7BwbJ3WrkCGvqiHmFuAJgMSpG01%2BL4F66%2FqyD5OtebzoLTIE4EAuCABduNFkIOk%2FQ59hQRdNpQNC0ot6besamFffQ57uHAq%2Fx4SfgsVoBFO9f6OlZ69PM%2FPeDkRFEBOUpHV1DdYE0%2FQE8YWvn0GxsbL8FcKPItzWL1zwiQhRFNBpJT9QwIfp%2F0497EYY5eIh8x8GwpcHZsB0zqd2xEXK5HI%2BBi%2BP4Q5IkxX8hxXH8nv%2BFK8w9mWB7rBTJAAAAAElFTkSuQmCC', | |
openTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH1QsVETINEBVQCwAAAaZJREFUOMulkb9PU1EUxz8vfajv0QYLDE1MNxlgc0ITIwODfwAIRgYkDBIQHNwMBAYXBxY2E34OBNQwA9FBRwYTEgxshGhMhCZtbeC95%2B279zi0aa15TTF%2BcpN7T8493%2FO951oPBvtmU6nUHH%2BhlCrtv9TYyvLaa%2BpgTT6bkJHh0chkEPgsrSxSKBQevXuztREpMP50TAb6Bzk8OgTAboqRSMRpRC6ffTn%2BZGrG1lrjOC7XW5IlxZjh4cBQQ4HNt%2BvTwIytlML3PfI%2FcwAkW1sA8LyLusWu21w522EY1jgAU0kelZ%2F1J52dXTWxDUQ6iLocxaUdxOMJ0ul0tIDve7z%2Fcs5BxgVg%2FsN6nX6fa6LeiSWxARzH5SDjsvD8PoHSXIZrV2JMze9WZwDwIxdwfHbRsFhrQ7rdrQ7RcUqBACKCZVmICCJgRNBGCLVQ1AYVGkIttCWu1v7CzaRP9lzxPeuDWBiE8kIEBEGkLAwERVMVOM2ccevOXfZP8uWiUncRMAiCBSIVV90drexu75AMvq1a9x6%2F%2Bug13ejhH2kuft37tPriNv%2FLbzdmyosZb3GLAAAAAElFTkSuQmCC', | |
pin : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89%2BbN%2FrXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz%2FSMBAPh%2BPDwrIsAHvgABeNMLCADATZvAMByH%2Fw%2FqQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf%2BbTAICd%2BJl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA%2Fg88wAAKCRFRHgg%2FP9eM4Ors7ONo62Dl8t6r8G%2FyJiYuP%2B5c%2BrcEAAAOF0ftH%2BLC%2BzGoA7BoBt%2FqIl7gRoXgugdfeLZrIPQLUAoOnaV%2FNw%2BH48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl%2FAV%2F1s%2BX48%2FPf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H%2FLcL%2F%2Fwd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s%2BwM%2B3zUAsGo%2BAXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93%2F%2B8%2F%2FUegJQCAZkmScQAAXkQkLlTKsz%2FHCAAARKCBKrBBG%2FTBGCzABhzBBdzBC%2FxgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD%2FphCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8%2BQ8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8%2BxdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR%2BcQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI%2BksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG%2BQh8lsKnWJAcaT4U%2BIoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr%2Bh0uhHdlR5Ol9BX0svpR%2BiX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK%2BYTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI%2BpXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q%2FpH5Z%2FYkGWcNMw09DpFGgsV%2FjvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY%2FR27iz2qqaE5QzNKM1ezUvOUZj8H45hx%2BJx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4%2FOBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up%2B6Ynr5egJ5Mb6feeb3n%2Bhx9L%2F1U%2FW36p%2FVHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm%2Beb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw%2B6TvZN9un2N%2FT0HDYfZDqsdWh1%2Bc7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc%2BLpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26%2FuNu5p7ofcn8w0nymeWTNz0MPIQ%2BBR5dE%2FC5%2BVMGvfrH5PQ0%2BBZ7XnIy9jL5FXrdewt6V3qvdh7xc%2B9j5yn%2BM%2B4zw33jLeWV%2FMN8C3yLfLT8Nvnl%2BF30N%2FI%2F9k%2F3r%2F0QCngCUBZwOJgUGBWwL7%2BHp8Ib%2BOPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo%2Bqi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt%2F87fOH4p3iC%2BN7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi%2FRNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z%2Bpn5mZ2y6xlhbL%2BxW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a%2FzYnKOZarnivN7cyzytuQN5zvn%2F%2FtEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1%2B1dT1gvWd%2B1YfqGnRs%2BFYmKrhTbF5cVf9go3HjlG4dvyr%2BZ3JS0qavEuWTPZtJm6ebeLZ5bDpaql%2BaXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO%2FPLi8ZafJzs07P1SkVPRU%2BlQ27tLdtWHX%2BG7R7ht7vPY07NXbW7z3%2FT7JvttVAVVN1WbVZftJ%2B7P3P66Jqun4lvttXa1ObXHtxwPSA%2F0HIw6217nU1R3SPVRSj9Yr60cOxx%2B%2B%2Fp3vdy0NNg1VjZzG4iNwRHnk6fcJ3%2FceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w%2B0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb%2B%2B6EHTh0kX%2Fi%2Bc7vDvOXPK4dPKy2%2BUTV7hXmq86X23qdOo8%2FpPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb%2F1tWeOT3dvfN6b%2FfF9%2FXfFt1%2Bcif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v%2B3Njv3H9qwHeg89HcR%2FcGhYPP%2FpH1jw9DBY%2BZj8uGDYbrnjg%2BOTniP3L96fynQ89kzyaeF%2F6i%2FsuuFxYvfvjV69fO0ZjRoZfyl5O%2FbXyl%2FerA6xmv28bCxh6%2ByXgzMV70VvvtwXfcdx3vo98PT%2BR8IH8o%2F2j5sfVT0Kf7kxmTk%2F8EA5jz%2FGMzLdsAAAAGYktHRAD%2FAP8A%2F6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfbBQcMJyOQosv2AAAD4UlEQVRYw8WXzU9cVRiHn3PuvXOH%2BWLK8FmhkDZltEAqdeHCnbGbmqgJqfEvcOMsTFyw6ca4mhgTE9HEhf9BiV8JqyZGo4AYDCpCIY0x6IAQmDIznZl758651wUXuWmwDJQpJ3lzc3PevOc5v%2Fc9X3DGTRzHeXAsG9E0%2BZ6uaa8p1015HniAEGLHVeq253nvrk6OV5oCMDiW7WwJh%2B4%2B%2B8xA4vLFPq2ORqFSp1Cpky9W%2BGd9QxV2NsuqXr%2B8Ojm%2B1WhcvVFHTZPLAz1t525ef45CVVGoOBiGg6bXkbqBGYlp24ab2NjY%2FBp4vtG4smFSTeb%2B%2BHubuYUVUlHJhY4Il7pjpJ%2BKMdIboVVts76xiRBi%2FjgpaFgBIdixanW%2B%2Bn6JL7%2F7HV3XEAKkAM%2F1qNoOSrkgZakpAHhsADiuIHVpiO4L%2FVzrj%2FFCH6hiiTezn6NJiXLd6nEAGk6Bo9wNKQ9qNhRuIRqL0tYaPQgmhQ0UmgKglLula7J%2BRJoU0BwFgLw%2Fw0esaeE2E6AoEMYRCoQA1RQAwzDeDptGKB4xD%2B1vT0aJtZghAR8OjmWTp7oKht744JNUZ%2BdQSNdIhBQXB2K0dxn0JjQcq8J2sUo8YrK5XcSQJBXiG2D0VLbiwbHs1Ugs9u2LN260SilZWfyNrfUcxUIJ8AjpGoYmcewauq9nte4VFXy0cnv81mMrEDaNt4bTA1Ep96Knh0cYuTZKe3sc6SpWfl3k55mf8ALJjIS0RM0TrwC3HrsGLNt5Z35hyes2ykTNPfdarU7%2Bfhl0jfTVYa6Mjvzn33EuxoXzKQdYbOiMOcphZ%2FlOre3plz69e2%2FtZVW%2BH073Js3z7XHCGkR0SUfCZHCgi85kC8loiJ2SXfhrq7hg1eo3d5bvOKd6H7jy%2BvvZSEvo1dIDKx2PHqyGUtnGNI2SFOLHilX7eHVy%2FIumXEj228TExG5rqqe15jjYtoVrP1jLZDL9J4klOVmbT0R0OpIRYnt1MXPSK9lJAeYcx8E0TTzPOxOAedu2MU0Tx3HOBGChWq1iGAaWZVWBhScKkMlk7lmWlbdtG2Auk8nUnrQCAPPlchlg7qSr6aitWPgblQyY2DfLshZLpdL13d3dX4A4e0%2BEh831j2fXt4YB9gcPAWH%2FawSBcrncn%2FF4nKmpqTWgJzCQB9R9s32rBaCOBWACUd%2FCPoQOyJmZmc2%2Bvr7c9PS0DnQFABTgABaw%2F0pSvnmN1oAX%2BD4sqQt4s7Oz6%2Fl8%2FofArIP9buCfwwZupAaUL5%2FwZxRMgQDk0tLSZ8B6YLBg3oMpUP8HIY4oQnlIERIoxsMU4xA13EepcKbtX%2BRcieZqbkRNAAAAAElFTkSuQmCC', | |
pinned : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89%2BbN%2FrXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz%2FSMBAPh%2BPDwrIsAHvgABeNMLCADATZvAMByH%2Fw%2FqQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf%2BbTAICd%2BJl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA%2Fg88wAAKCRFRHgg%2FP9eM4Ors7ONo62Dl8t6r8G%2FyJiYuP%2B5c%2BrcEAAAOF0ftH%2BLC%2BzGoA7BoBt%2FqIl7gRoXgugdfeLZrIPQLUAoOnaV%2FNw%2BH48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl%2FAV%2F1s%2BX48%2FPf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H%2FLcL%2F%2Fwd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s%2BwM%2B3zUAsGo%2BAXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93%2F%2B8%2F%2FUegJQCAZkmScQAAXkQkLlTKsz%2FHCAAARKCBKrBBG%2FTBGCzABhzBBdzBC%2FxgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD%2FphCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8%2BQ8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8%2BxdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR%2BcQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI%2BksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG%2BQh8lsKnWJAcaT4U%2BIoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr%2Bh0uhHdlR5Ol9BX0svpR%2BiX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK%2BYTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI%2BpXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q%2FpH5Z%2FYkGWcNMw09DpFGgsV%2FjvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY%2FR27iz2qqaE5QzNKM1ezUvOUZj8H45hx%2BJx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4%2FOBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up%2B6Ynr5egJ5Mb6feeb3n%2Bhx9L%2F1U%2FW36p%2FVHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm%2Beb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw%2B6TvZN9un2N%2FT0HDYfZDqsdWh1%2Bc7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc%2BLpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26%2FuNu5p7ofcn8w0nymeWTNz0MPIQ%2BBR5dE%2FC5%2BVMGvfrH5PQ0%2BBZ7XnIy9jL5FXrdewt6V3qvdh7xc%2B9j5yn%2BM%2B4zw33jLeWV%2FMN8C3yLfLT8Nvnl%2BF30N%2FI%2F9k%2F3r%2F0QCngCUBZwOJgUGBWwL7%2BHp8Ib%2BOPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo%2Bqi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt%2F87fOH4p3iC%2BN7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi%2FRNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z%2Bpn5mZ2y6xlhbL%2BxW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a%2FzYnKOZarnivN7cyzytuQN5zvn%2F%2FtEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1%2B1dT1gvWd%2B1YfqGnRs%2BFYmKrhTbF5cVf9go3HjlG4dvyr%2BZ3JS0qavEuWTPZtJm6ebeLZ5bDpaql%2BaXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO%2FPLi8ZafJzs07P1SkVPRU%2BlQ27tLdtWHX%2BG7R7ht7vPY07NXbW7z3%2FT7JvttVAVVN1WbVZftJ%2B7P3P66Jqun4lvttXa1ObXHtxwPSA%2F0HIw6217nU1R3SPVRSj9Yr60cOxx%2B%2B%2Fp3vdy0NNg1VjZzG4iNwRHnk6fcJ3%2FceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w%2B0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb%2B%2B6EHTh0kX%2Fi%2Bc7vDvOXPK4dPKy2%2BUTV7hXmq86X23qdOo8%2FpPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb%2F1tWeOT3dvfN6b%2FfF9%2FXfFt1%2Bcif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v%2B3Njv3H9qwHeg89HcR%2FcGhYPP%2FpH1jw9DBY%2BZj8uGDYbrnjg%2BOTniP3L96fynQ89kzyaeF%2F6i%2FsuuFxYvfvjV69fO0ZjRoZfyl5O%2FbXyl%2FerA6xmv28bCxh6%2ByXgzMV70VvvtwXfcdx3vo98PT%2BR8IH8o%2F2j5sfVT0Kf7kxmTk%2F8EA5jz%2FGMzLdsAAAAGYktHRAD%2FAP8A%2F6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfbBQcMJy13GubxAAADKElEQVRYw%2B2Wz4tbVRTHP%2Ffe915%2BvWTSJJNW7XTCDM0o08G2LlwIKoILuyozCP4F7irShbPppnSVhSAI%2FQNcSjv%2BWrhQFEWoWBTRtppBFH9M0kwzMyQxP9%2B797no04m2dDLYgGAOHC7cczn3e7%2Ffc857MLGJTWxiE%2Fu%2Fm9jP4eJKKa6UvGApdVobkw0CCAAhxJbR%2BlIQBOfXL692xgKguFLKx6LO98cfKaSOzs0oH0Wj49Po%2BGw3O9ysVHVjq9bWvn90%2FfLq5qh5rVEPKiW%2FKzyQOfD8s4%2FR6GoaHQ%2Fb9lCWj7RsInFX1W2TqlZr7wGPj5pXjoxUyY0ff6vzxddlsgnJkek484dcFh5yWTocZ0rXqVRrCCG%2B3I8EIzMgBFu9gc%2B7n93gnU%2BvY1kKIUAKCExAt%2B%2BhtQEpW2MBQEAVwDOC7Pwih47McnLW5YkZ0M0WL5beQkmJNqa7HwAjS%2BBpU5Vyt2adaIyEmyAzldhNJkUfaIwFgNZm01LS30MmDYyHAWA7fOE9elqYcQJoCoS9BwMOoMcCwLbtl6MR20nGI3eN59IJ3FjEEfBacaWUvq9dsPjCqxez%2BfyiYylSjmau4JI7aHM4pfB6HerNLsl4hFq9iS1Ja8THwIn7MoqLK6VH4677yTOnTk1JKSlf%2B5bNygbNRgsIcCyFrSRef4AV8tn1g6aG18uXVs%2F9GwYEoCK2OnNsoZCQ8nb2hWNLLJ08QS6XRBpN%2BZtrfHXlKsGQmHFHpfomOA1cCGvChH7niL%2FX5YAz6LavtmT2pSePF1RgR%2FF0gNYGzzfE3Qi5%2FDRGa2qVmwBMH3DJZpJ%2Bfafx%2Ba0bH73%2F1xi77SMDkCE7sd7Or86gtf32L83I0357J%2FLwTMZ%2BMJckqiBuSaZTEYqFg%2BTTMdIJh3qj%2B%2FvP1VvlHz68eFb3WiZk4E8WglFrQAAOEANcIAFE55975exUZvqpds%2FMJhO73dBq93Fs1Qn83vXtjfU3K1fe%2BADoA%2B0h9%2B4mg9hDAhuIhmDscE%2BGcbm8vDy3trb2U%2FgyM7RqwA9B9IFBuBfspwtEeNmwi6GY%2BNun6s7V%2FMOD%2F%2BQ%2F4R%2FRviSbeGCJRgAAAABJRU5ErkJggg%3D%3D', | |
plus : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFQSURBVDiNpZM7SwNBFIXPTB47TYioMAErLSz9BYJFIJ2FheA%2FEO2CTTB1go2ktrMSxFIQjFgIgkU6SxtthAyIGC0yz10LzSaz7AYlt7pzOXzcc7hDoijCLJVPG9aa5b5zIZ%2Bc5XJUdFuDyp8AzoW8tXvszZonBzxNmwoAAGMVnt%2FuAQDLi%2BtZsikAp2CdjfupgNphue%2FCsWcWBNIYxZx1PwCjwIJAVhulOPEcpaLbHlTyAODCkNd36pNgltxgb2ufAQB%2BEZ3zDvcsGKPw%2Bv6YuuaL6Hnvpfk13wIAaCNhrc30OlnayBSAlVgorXhC8fEEAOBzqz7AJgCUEnF6dRaHWCwU5PbG5jhELXFxdym1MWykoZSIGHDT%2FvQurNooRcqOQ1RWQRvDbo%2B%2BSNJO5h1oPcRoA62HWbJsgDJDsGI57v8FoISI694DT87StGTW7%2FwNezmaY41c7QEAAAAASUVORK5CYII%3D', | |
printer : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oIGQopDsx58QcAAAHySURBVDjLpZNNaxNRFIafuWYRQRCLoCnTQIsfFAwxGFGQLBVRXPqJQfFHCEqd2iIupK6q7lwIfiVZ6EKrVkRGjQUDlRJQIVqoRd0Ixk7aTGbm3uuqTYbUVPDC4XIOnOe897xc%2BM9jtCb5Qm4IsP6hb%2FjI4aODbdV8IacbjUbHcF1X5ws5vdgTWQ5fKpX%2BOjqdTofyZQGJRKL5RsMI3VrrzgClFOVyGQAhRBsolUqtrMA0TYQQGIbRFisq0Fpj2%2FbSRCEEmUyGkddZ6t4co8cn2m28YA0MAVY0GmXL5q0opULyAZ7PX6W7q5cP3yZJ%2Fsriui7A8KICa9C6iJQS3%2FcBOP9wP1oFeCrAkwHd6zbRH9uF487zsj7K7TNTXL9xzYq0LqlSqRCLxbBtm0B57N12CqkVUkkUmu%2FVWRI9e6h5dQ7ejHOAs80dOI6DW69TrVZJJpM8sj2kVsz8rOCrgED5%2BNJnruGwvSdDzV%2Fg7vSlJkAIwZzjMD7%2BjFqthtvrEsiADWvjBFIiteLH7690rdnI5GyR4uci2VUDYReklOxI7wTg45cct96O4CkPN%2FDpW9%2FP7r59lGbe8OLTK3KHJhh78rgJ8DwP0zSX7LscHwu5cOJBGkOs5t30FE9PvkcpFbLxHnCs0%2Fe7o67gK8npyLnW8v0%2F5Gb7fMJoZowAAAAASUVORK5CYII%3D', | |
refresh : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAyElEQVQ4T72TbQ+CIBSF67e3rFbO1GhiDNGROntxzfrSn7uJm2VCshaL7Xw5ynPPvcAYAEZGlgCZkBFI05WJNFrQLr8CSkrg5b3+9zUC4fUDKBOFaQU+O0lCyfnpaUGYX8ClB6liVNwav5UW5JBcgohNwu9qEBTUvds4lUDC62sQZOM9rAKuTKQ73bdhI3aEOYp/B4mqlkfNgJbbGKZrooR5JPtYRHmPZhsKEyeUtEDRd6B2sD7NwHIJsKLStvuft6Y78u53Y4keAkWNbhTM7xIAAAAASUVORK5CYII=', | |
save : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9sDHAwxAVECGvsAAAJVSURBVDjLpZBNS1RRGICfO15HZ1BsphDHclHYLoXA0NBqkdQu6EMNEvoiSDI37SpJaBERbSRCyMrIXT%2FAjLKwUMfEFMMPJL8tU9FRcu54557zthgdKTKIHg6czXue8%2FAap0pP3AoEAjX8hm3bsTuyejm0732dx0wi2Uwm2XRjutzUln8wAMxAIFBz%2FuxF%2FkQkYvH4aX1dxLYpy6vCTDBJMFy0fH4en3EppVheXqIj2E5HsJ2u7k6GhvsZGu5nfHKU4uLD2NrG0Yrx%2BWGUaGzt8LCu9jaAqZTC4%2FGyJc0HgJGgOV165peSB%2FcqcZQiqh2UVtjKwefz3wSqTdu2sawwoaVFAHz%2BNADC4RVy7vhJ8yayJyMXJRpHR9EImb5s3i4%2F4GrjQXE5jhMvWK9YJ6oVOZn5FOw6wrelCaIqykxoitysIjL9O7HsZVxAvGC9Yp3BG0t0jvTSNdGGPyUDl8uNLyWdztEW%2Bqe7qb%2FQY%2Fy1YGCgn8ZjTbwZbOXTZBvpqTto%2F%2FKa3qkgx%2F3VsZ2VlJ2UKxWVPHs1TN%2Bcl82YTy%2BnMLuQwa8fMcaeAJDmXsUE8Hi89M15qb12lIitNlHMcOlFBo9KZgBIdidQdb85JrCscGxkMcLI7MqmFRV5g3SPhlBKk7UtVhsvABBARDAMAxFBBLQISguOEqJKYzsaRwlbU5M2BJYVJttnsfDDZnrBAjHQCGsHERAEkTUxEInqDcH3uVn27i%2BiZyy09ij2uwhoBMEAkXhV%2Fm4%2FzU0v8YUnGowD5%2B6%2BsxK3H%2BIf8UYngq0N1wv4X34Ck8Uv%2BymvOfsAAAAASUVORK5CYII%3D', | |
send2cgeo : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AwZFBk3CuNDjQAAArlJREFUOMudk0tMlGcUhp/v//+ZYaDMKNQRSAcL6iBiS9MYbWy5aFK7VRfujFHX7kzbtCqZBSZtohsTFybddNW4oDZNSEvTNiDTi5naoIkC441BBBxu0xlm/tv3fW6kQejGvrtzkvPkPW/yimQyqfkf6unpEQAWQM3BG1USPnKlOGBLcdRRxDwFrgL5Am8KMR22xCcbauQ1+/oH9grIAogEzbijdJ+vFAFDoDVgCAQaBQgBpkG9s+x/nStUjlavcmIAjIz9tBiRMTYEKzCFImBC0NBUWIIKS4AtmcnmmRnXfHvp5qbVr1gAn+6fSM8WxvWsPSBMcZ+ck8cUBl7ZY2mhhFeM0ll3DB2MLO856pzJ56ZeduCPXY5bpZDY2XCM9kg3icomQssl1HyA3dHjnNp7kY5dhyhnhqo6o6n96xxoZ5Hsn1dpqb3I5uouxiczbA2eZHt7N1q4ZLMT/Pr9BULPfqF66z7WAUKVEcKlQQa+6eXIiR46dpwnNzfL0+kMvw/2Mz/Sh3+okbwbIxAKrwcQ3kLi7U7m/vibH/q+ouaNBGO3h1l4cotEg0nru438qH3q69r4eCpNG4k1AGcOig/YvUWRetDP8J0hinsW0A0+w8rHlT4N0W201u+lYC9zo3xlTQblKVRxAsol9jVV0toW42pphg93HUdqhVQShebp0iRvxd+n6JZZ7B30//rctSwAq7Ydo+pNAkaE0MY4jbWbsL87jdSKibkMnvLxlYcnPf5xCrwT76Dolcylc6mCBTD0KHZtPJN/dud2av7uvdFCy44WU3fZX/jSZ3O0EV9KpFZM57PUvFbHrckUqfup4uNeqkUymdQrxVitw1eatO26uMrF9j2aX2/lveaDpLO/8fPoUCl7wan6N4P/bGTu5fH6zJcII8zNhyP2yvErqflsMB3/zEyv3T8H2P86Vd9nqzEAAAAASUVORK5CYII=', | |
sendGPS : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oIGQooOW3fZUkAAAFtSURBVDjLrZPLK0RhGMZ%2Fx62UEimSo0wihSxphhXKwsLGdsrextKt2fAnsJGVlX%2FAwqXIIRPCSpHLjEjJdcJ857vYOBhzjhRPfX3f4n1%2Bve%2FT%2B1l8ynx5W%2FxSOfxRQQDzHx38CmJ9L3aTXQDk24tBtf4Az%2Bind5gvIM%2BnMEM%2FgbMAALHxGJG2MACdPZ%2FmwbkO8yIemRnYs34M0TN%2FV1oKqsoa6J%2BuN4EZ5NuLxMZjANzWLWG0RGiJUJLKklqa7Qjx0xX2L7ZYGrq2fEeItIVZ33SQWtDVGEUZjdIKjeHyPkmTHSYlXribWDU7I8LKAnhzD8y2oIzm%2FOYIV0ukdnGVy2P6iRa7nZT7zP2YY%2FKCEo8uJJFKUl5cjVQKZTRXDwlKiyrYTTo4xw5nE1hZGXh331QNr0IgtOBVuoTKGmgNdbOd2GD5cI3EZDozA8%2Fsab63NmM3nicPsHIKiZ%2Fsf5j9dj%2FoEBotMPZwbtb%2FeAM%2Bw7BUpUnjdQAAAABJRU5ErkJggg%3D%3D', | |
saveAsBookmarklist: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABwklEQVQ4y52TzUtUURiHnzuFEIRRDirZBIkbwYlAqMAP2hj6D7RoE+YqIReBq2g5s6lFOylqIelmNi5zYcZEEzSRZKs+BqeZyUSYTJ1h7txzz4eb43C5TYP0g5fzct7Dc37nnPc4wDgwCeT5t8Zs7DQrjttopafAc6AjXIhwNO0As8BDIPo/gAvAZWAFWAo6OQb02TxnRwdoB7wAoGpHF6jZNTmA46GdbgJDwCIQtwsPlQXWwtbCgCyQBjZtBAG/m50tDMjZY3UChWDh7sKoccU+z25/mmgFmAKuAE9sbzQceFJwLtrPjTn3ZerO1wbECfTAMtBjL688szBsjJYILRFKcvZ0Hxdjw2Tzq6z/fM/KvW2nmYNNoA2ISS0YG7iFMhqlFRrDr90S8dgQVeHyJ5E2H+8LJwyYBgaBx3UpUEZTKH/H1xKpfXzls+9VuBQboerX2H2QMWFACngBVOqyjlSSrlPnkUqhjGZrr8iZk92slTJkchl+JPjLQfkwcaXH/LtHCC2oS5/eaD9Xe6/zofCWV1/eUEzS9A4aWprOB3uAWvKzcSInyG6sU0x6E+FnnASutfoMezWf19/SlJIqFZw/AMBssOgBCdZnAAAAAElFTkSuQmCC', | |
settings : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QkaDBM5i2PCSAAAAfBJREFUOMulkktoE2EUhb%2BZ%2BEyKTRQKgkqwzMaFtt1FrC40FGJm60JwIVSkqLUtElICFQNDQqBrQXRlQIriwomN0GJXgtI2iUkXFYJVadOXhiBERDozbmaGMR3rwrP7ueece%2B%2B5P%2FwnBOcjnVGigArI8Vgi9xdNNJ1RbI7YUlT7r%2FYDqKaZq%2Fj6tQHNbLQd6YxiNBp1I51RDPdaw6pFAcR0RolaZKur19vmZhwFePDwPvFYQgZyACKgDt4cMp4%2BmzAA9fatETbX15A6Jer1r%2Fdas4ndGRUsMYBgFW8MDBqatiXoum7oukZhfk4ovC8CyDsFK7R0sBHpu0i5UmG59gUgGY8l7v7zjE68yr80SpUS3Sd7KJYLmBNMArqrQTCSOgzUrPeVkE7XCYmjR47RbDZ5N%2FcWtzU8TvH4cJi%2BUCcdAS%2FZmU2Ot39LLn1eOtd9qoeAP8BKbfnyhfD5%2Bemp11XAABCDkVQXUHs0JjNbXmS2vEjHQR8A5t5yLv8CSZI4e7rX%2BmR2HiJQHB8OM%2FWmxJamI%2B7zs1Fv2iOaI8vZJ4850O7nTKgXYMxpAMDuXR72%2BA7x88cvsvkFgHCrSS6vUv1Y%2FSNsEWBl4zv7fQHa9np4PvMBIPxpcnTaSTRNkmvrqwtA0r5CMJK6BEw4uNvEO%2BE3N%2BLV9uq8VLwAAAAASUVORK5CYII%3D', | |
startAutoTour : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAAAcCAYAAAAZSVOEAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKTgAACk4BGCrFqwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAiJSURBVGiB7Zl%2FjFxVFcc%2F571582t3ZnZ39vcWWnZpKW3X8qMtCogCIhUBoURChEIUAYEGY43aAEIwEPwRqbEICpGQ4h8qqIhGBBpsEEpLoKTQ1ha32x%2B7bEt32w77a3Zm3rvHP2aWvp3OtrNlIUH4JjeZe%2B455577nfvOvec9UVU%2BQWn86ZbELeHaaXd1dfVc%2Bq2He1ePp2d9iDF95GAFrGnzF95cdc4l1z%2B98tutP0NESupNxmQislREtvhacDL8HkUc04riuGIi9vddITMeWTLl1se%2Bc9wDABgv446kSAQz4fMWfXPpE7fPe2XF5VJXbBeYpPjrgRN8%2FZL%2F2IeAYFEc1YdT%2FsViaYpG6y%2BOV9ctSh479%2Fjzr7u%2Frv6Y2bGOl1buAW7yVEc818U2WUx%2Fp%2FXpz5w%2Bb0tNzYYHb6q%2F9sYH9j496meySPzIYeV3p6%2BeftrVsxqPOylZ3dBqWXYARfHUAvXif7jz9E3hxNQ4eACIWLjpPlqb4k3x6GmP3%2F%2BN5GVLHtn3DHxMSVxxlcyae9bX2rvSNTUDO3uJ9I4QilQSikSpq4dgwI6e%2FNnLZlXYwwz1dhBubMN4exDLBpRE2KuoqU4sAZ6BMnKiiIREZLaIJCZzIZJHm4i0vE8%2FSRFpmohNNFF3fTzZUoPnUulkiIVcYmFDLCyEg4JmD5Deuxl3aA%2B2pfRsepbBkSy2E0EsG8uyqK%2Btnjt60IxLooicICLPAkPARuCAiGwVkQt8Op8TkR3AjUXmW0Vkh4i0lvB7rYi8BPQDHUC3iOwVkb%2BKSLOILCjYjrZwwe48n2yriLSIyOtAH3CNiLwCPF803d0F%2FR%2F4heFQ6MyhdBbHAStUTSBaSyTRTLS6GZM%2BgJsZIBRNUFFZQ6J2Ki0nno2bHmB3Txc5qUQsm7ramsYVVzqnwTiPs4i0A%2BuAiF8MzAD%2BLiLLVPWnhfGpJVyMyhyfz0bgYeDCEvp1wMXAKcBPinyOHlJRn9wDVgPH%2B%2FSmAMU7ssbXAFh%2BubScePKC5v0DORwngpdNMdDdQf%2BWbnKDe7CClcRqmollBjBZ7z1H4cokqRGHjs7tWOEqjquOOPGa5A3A2vFy4krGEuiHAPeIyFPjjB9qIBIAngXaj6A6BfhlGS5txhJYNqJV8UVtx5%2FQ2N3XB54LBqxQBURasZpmEolUUBmLU1kZw4lGUQH1XILpYZLBdwnF6uhP7cOLVlCb3DEPSuzEQo46ySd6GrgZuBT4eUEWAM4FngS%2BDnwVuMBncx3gArsL%2Fe8xlsBh4E7guYLOp4BbgIuY2PXoDWBFwU8n0Arc6xtfCfwLeHNUYEugLuRY0tYQAkKIJfnUJgaxDNgZxDoAI0MMZwKICKoG4%2BWIkCUUyVAdCCCSIxQOx0fJKEZxHntZVbeLyHLgJd8i31bVt4FHRWQmY0l8TFUzkE%2F8wB2%2BsUFggar%2BxydbBawSkR8DY%2FLXYbAVmK%2Bq2UJ%2Fp4jMYCyJa1X10WJDNQbURY3B5DzU5JvxXN56Yye9qRFyQ2kCToD2eS2EQwKeh6ceeC7G87DDcbKZdA5Kk7gVUA6SdZuIRIE%2Fquq6MhfoxylA2Nf%2FURGBftwBLAKml%2BH3IR%2BBE4NYGPcgeWo8jHqsX%2FtfrOo4ba0hqmuaeWXdTlY%2F8SpespqF5xyD6kFdC0F1nNNZVfcCv%2FWJQsAyYL2IvCgiF8k4NeQ4KM6DfxlPsUDK38r0u30CMYydB0GNixoXY1x61m%2Bmq2M38eYkc1rjrP13J1nXZf6CZs5d1E5%2FKs07B9IYz8V4Luq5AIyyMN4V5yZgCdBbJD8DeAp4XkScQ6xKw1%2BGueRz1%2BGwuUy%2F6TL1SkAwxsMYj5HuHrq6U3TuPMC0xjDqucyeXc%2BWbfvo27aHTWu20RrOsmv3oI94D%2F%2FLr5IkqmpOVX8FtAH3AKkilc8DPywz4m7f7wBQewT993X5LgtioYVd1bvrHax4BdmRLJn9KYbWbmDX2yn2buwi1b2P3ZEEzS0x6Op9j%2Fj3iCTP5GErFlUdUNXbCwtbWjS8sMyQNxT1zzqC%2Fnll%2Bj1qqFgFMjyGIjGah%2FdjeS6rXtjJk1szJDVLLBFm34DLuVOFL9l9BIfSZLO5%2FCNtXNTL5g8oSpAoIneJyD8L7XERCarqsKouB172qTaXGfPrgP%2FN730iUlVKUUQuAc4s0%2B9RQ2wbUYOitM1q4i27ii84fSycarH48hM5NuSSaIhR40BbTxe7BmDlDodgMIgVcLDtICIWaowFpU%2Fnd4Dzff0OEbmX%2FInpPyReLSdgVe0SkYeAGwqiY4ANIrIUeAHYR%2F7ifBVw60TIOFqIhFCxsAC1lDPPnsH6znp612xk0eAbtDmG2ZlhYg2GzgF4rVdYfMEUHCeEUYMaDzsQALFsEYmWIvHP5C%2Bwo7t0GfB9Dt21v59A3MuArwCNhf6xwBOF3zl85eEHjUxOg5btYFkBjBosFYwqc9uSDNbO5%2FFVm5gjKbb1K9vSDsNOhFMTWbZ3j3DyrHosFNRgOxHUpAJA1SEkquqews67zSc%2BhEBVLZtEVU2JyIXA74CZRcN%2BAvcDDxbNPalwjQZAEUuwsVEVLMDyPDIb32LO9CQvdlVx6hebaQ3aNFWHAKU95%2BIE5eBh4oRQy7KBcMnaWVVvF5GN5Ms8f%2B4bLdeWTzR4VX1NRE4B7gauBBr8awPWANeQ36UfIIluP8bDqWhA8UBBUIwa3p05n%2Bb6Sq4%2BwyH%2FAc8UsrkSVs3nUQGMQSwb9VwDIEf62leopecCPcDmo64SDvXbWPC7H3hTVUcmw%2B%2BRcE67NFz%2F5RlrGmrrKgyIZRRPEEERLZSElqJGUdX8hVo1T7aQ34kKOdfV59Z1%2Fmb5PwZ%2FfUQS%2Fx9ReImbf0199IiSz%2Be9H1cSLfJ53rwPN0HAqGr2Y0niZOOTj%2FeTgE9InAT8D1d5WQk3kn0aAAAAAElFTkSuQmCC', | |
tabBg : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEcAAABWCAYAAACdOoshAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oKAwcSHqDAeZMAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAArElEQVR42u3XMQ5AUBRFwU9ESEgIlmn%2F5bMBt9Ap5ixhutNVVTXpa11V3RjeG1prF4aMc2LIOAeGjLNjyDgbhoyzYsg4C4aMM2PIOBOGjDNiyPtgPEM9Ajhw4MCBAwcOHDiCAwcOHDhw4MCBA0dw4MCBAwcOHDhwBAcOHDhw4MCBAweO4MCBAwcOHDhw4AgOHDhw4MCBAwcOHMGBAwcOHDhw4MARHDhw4MD5TQ9jZAyriwnP2QAAAABJRU5ErkJggg%3D%3D', | |
topArrow : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAMAAADKSsaaAAAAAXNSR0IArs4c6QAAAKtQTFRFOwAWEnMAFXUAIncAHXoDHnoHIHsAInwGI30AKH4TK4AAM4UGMYYLO4oQQ44VRI4XSZAbUZYhVpcnWpooYZ0wXZ45Yp4wW587ZJ4wXqBCZ6A0ZqA4YaJFaqI2baI4ZaRHZ6RFbaQ%2BbqQ8c6pOe65UgLJZf7JggbRmhLVlhLVpiLdqjbluj7tzlcB%2FlsGBl8GCncSHoMWJoMeJpMiMqMqPp8uPqcuQrM2Tr86Vse9UEgAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsRAAALEQF%2FZF%2BRAAAAB3RJTUUH2ggZChAKxZC4pAAAAF9JREFUCNdjYAACDgYoYBPnhjBY5fUV%2BEEMThk9dSNlIQYGFkldJg5mM1UJBnYeRqA6LmlFXOo01XQg6kQNNExVwOp4DbXMRMAm8xlrm0uBWQIm5hZyYJagsJisEgMDAC4YCUlXya0PAAAAAElFTkSuQmCC', | |
upArrow : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAMAAADKSsaaAAAAAXNSR0IArs4c6QAAAKhQTFRFEnMAFXUAIncAHXoDHnoHIHsAInwGI30AKH4TK4AAM4UGMYYLO4oQQ44VRI4XSZAbUZYhVpcnWpooYZ0wXZ45Yp4wW587ZJ4wXqBCZ6A0ZqA4YaJFaqI2baI4ZaRHZ6RFbaQ%2BbqQ8c6pOe65UgLJZf7JggbRmhLVlhLVpiLdqjbluj7tzlcB%2FlsGBl8GCncSHoMWJoMeJpMiMqMqPp8uPqcuQrM2Tr86VayLUTgAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsRAAALEQF%2FZF%2BRAAAAB3RJTUUH2ggZCiUstaz%2F7wAAAFNJREFUCNdjYCABsMMYrGJcEAaLnJ48H4jBIa2rZqgkyMDALKGjoaptqiLOwMYtoq9uoiylAJTmMdA0FQbr4DXSMpMEs%2FiNzcxlwSwBIVEZRQYGABF%2FBmSnRdN1AAAAAElFTkSuQmCC', | |
upload : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9oIGQoqEWpcrzEAAAMVSURBVDjLlZPfa1t1AMU%2F33tvE5pmSZvfSZfWXlNnF7sfsrjqnqq4OUUQRFHZkJWhD4ooDIXpg4gWhPkH%2BCBWHJtPUwYyGSpspdN1raOyYqWlW5N2bZqmTdsk9%2Fbm3vv1ycn65ufxcM55OHAE23jl%2FaE3gTdUTdstwStdtyYlo4qqnD03eOzr7X5xL%2FjBN%2Fs8qvJTd1ci3renk672MD6vl7WqwUyhxPhkgen88g0hxMlzg8f%2BvK%2Fg5fe%2ByrUEmq%2B%2F0L9X7O2OsVY1KN3No%2Flj0NwG9RLt8TCjkwtcGp4sI8ST%2F5ZoAOGw%2F%2BfDh7KiVw%2BxurJEpCNLMJKkbjZYKsyiuRaKY%2FBUTsdxZfjytb%2B%2BBB4HUAY%2B%2FPbTRKwt0J%2FL0KS42JofFEGTpuFp0vB5NeLhHSRjUaKtLeSyO%2BlMhfpeO332BIASCPpOHsh2UFlbobjlI5Z6ACnBlYBQEK7F4mqNH67c4vLwOEGvZHcmBfASgLZZb0Q7E22MTi%2Bjd8dw5X%2FLViurPLYvixACKSULi0VMwyAZDQIcANBMy1a8Xg%2BKP0alauK4Er9XxXEcrGoJISIAvHu%2BH8Pa4Nn4GaLpXQAhAEVVFXe9ZtJizuM38iyX1rhT3OB2cZO5so3VaLBZrbFlW%2ByM9PBd%2Fi1qhgWwCqA1KcrS7fmV1P5MAj2dZK6wwPDMBmOLA0jX5tfzNpZjk2rL0JM8yKZZ48zIE8T4YgxAk45z4ebU%2FNtZPQZAZ7qdwI51fl%2BwePqR13Gki%2BM6uEjuVgr0pg9RtQzGjIGjAOrNqxcuZXLPnxKq6gm2NNHsUflt%2FBYTqxfJxPcztzJNuVaiXC1St6psmBs8GO2lbhvU9xQ%2B1gAqyyvHr9xwv3ddeHRXnB8n1jF9JrZjEw92YDsOjnRZXM8T8if4ozDCyMwIdz5D3PvCcyc%2Bf7VDTw8Fgq2eh%2FUEF%2FMvYloWlmth2g30SA99%2BmHG8tf4Zeoq%2BcEtcd%2BZAFpDXZ4jx08NqV7fM6haKwghpWtLuzH7d%2Bidh3pTBxmdnWDqk7Lg%2F6J%2F5JHp06rcrv8D001PzAwk7SYAAAAASUVORK5CYII%3D', | |
userscript : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALZSURBVBgZBcFLiFVlAADg7zzuPLzjzDjOMINMitIie5gF+UAkIZSgRQuXLZIWrY021dYIggJdJURElJsoqlWRYA9GshGFCNQeOjoTk6bjeOd5zzn/f07flzRNA459ObcHJ3cM9+1fq2prVa2qa+uh7mAZ9xCxiAV8iu9zgDqEvU9ODOx//dkxALBa1kNrZT202I2TZcVyEd28t+Lb66uHcTwHqEMYH+xJwNyDqJUk8oQsp7eV2tqbytJUK+OpyX5bhtojH07Pv58CxKoabOeEmuUy0al4UNDp0umysM5/KxG8eWbW/u1tj4+2xnKAWFUjG3tSqwWr3ShNEzmyjDQjk8gSaiRxyYUbiy7PduZzgFiW40P9mc56sFY00rSRpaQxkaVkGlmGJnNnqXDq7N9LOJYDhLLcNj7Y0uk2AjRkMZE2iGQaeZOqG2IrCmXY/s1rB+6nALEstk0M9VotG0lKliRSpEjw+YUjPjq3RxkKoSjEsoiQwvMnvusXQ09vK1VGUg1qjVrUqDWKUJoc3emVj3dbWeuEUJZLkEMoyrF2u0+aUEPD19OHNXVQ1kEZgy2bHrZzYq/l7qr766/m3VC0ub+SQyyLDXm7R56SpYlYJ0JdOvzYy2JTi3VUa8x35jwxecBKue7S7E+dXW+nI/nB42dGcWLPI1vdXmrcvBO1++iGUmxqtxb+UtVBqCtVrCwVy3Y/dNBKtZb+OjO1kMeyfA4vXLo6Y3E9t1I0qtjo6goxGB/cKtRRbGr/dmaNDEy4PHfe+etTd8vgSB6r6ukXD+3qf+ulfQDg6OnCJ7+8p6xL3VDaMfqofTuOuHhryrk/fl4tokPz7zRX8lhVM7fvdXx29qrhgX7Dg32G271OHv3dxg09entSvXnqmXcHJGm/6Ru/ad89dmrm9AdXIK9D+GLq4rXJqYvXtmEzNmMTNmGor6fV6utr6YxWfvjzR0P/vDGTh7GvAP4H2uh1wse2x/0AAAAASUVORK5CYII%3D', | |
add_comment : GS_HOST + 'images/stockholm/16x16/add_comment.gif', | |
attribute_blank : GS_HOST + 'images/attributes/attribute-blank.png', | |
bearing : GS_HOST + 'images/icons/compass/###BEARING###.gif', | |
cache_size : GS_HOST + 'images/icons/container/###SIZE###.gif', | |
coord_update : GS_HOST + 'images/icons/coord_update.gif', | |
fav : GS_HOST + 'images/icons/icon_fav.png', | |
stars_d : GS_HOST + 'images/stars/stars###DIFFICULTY###.gif', | |
stars_t : GS_HOST + 'images/stars/stars###TERRAIN###.gif', | |
tb_coin : GS_HOST + GS_WPT_IMAGE_PATH + 'tb_coin.gif', | |
wpt_type : GS_HOST + GS_WPT_IMAGE_PATH + '###TYPE###.gif', | |
sad : HTTP + '//forums.geocaching.com/GC/public/style_emoticons/default/sad.gif' | |
// not used | |
//closedHand: 'data:image/x-icon;base64,AAACAAEAICACAAcABQAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAgAAAAAAAAAAAAAA%2F%2F%2F%2FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAA%2FAAAAfwAAAP%2BAAAH%2FgAAB%2F8AAAH%2FAAAB%2FwAAA%2F0AAANsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FgH%2F%2F%2F4B%2F%2F%2F8Af%2F%2F%2BAD%2F%2F%2FAA%2F%2F%2FwAH%2F%2F%2BAB%2F%2F%2FwAf%2F%2F4AH%2F%2F%2BAD%2F%2F%2FyT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8%3D', | |
//mail: 'data:image/gif,GIF89a%0F%00%0D%00%C6f%00PR%A4SS%9Dae%BAdh%B8nl%AAwv%B3uw%C2%7B%7D%CB~~%BC%7B~%CE%82%81%BE%7F%81%C8%87%87%C3%8B%8B%CA%8A%8C%D1%8C%8D%C6%90%8E%CF%90%8F%CD%8F%90%D5%8F%92%CF%91%94%D5%90%96%CF%93%96%D7%97%98%DE%97%99%D9%9D%A0%DC%A8%A7%D5%AE%B0%E4%A9%B2%EC%B3%B2%DC%B1%B3%E8%B0%B5%E3%AC%B6%E5%B7%B6%E4%B7%B9%E3%B7%B9%E4%B9%B9%E3%B9%BC%EC%BC%BE%EF%BF%BF%E8%C0%C3%F0%C4%C3%E9%C2%C4%EE%BF%C4%F8%C0%C6%F9%C7%C8%F6%C3%CB%F6%CD%CC%F3%CF%CE%F0%CE%CF%F6%CF%D0%F7%D2%D1%EF%D2%D1%F4%CB%D3%FC%D3%D3%EF%D3%D3%F8%D4%D4%F7%CF%D6%FC%D6%D5%F3%D5%D6%F4%D7%D6%F5%D7%D7%F8%D5%D8%FA%D9%D9%F4%D6%D9%FD%D9%DB%FA%DD%DD%F5%DA%DD%FE%DA%DD%FF%DD%E0%FA%DE%E0%FD%DF%E0%FC%E1%E2%FF%E4%E4%F8%E3%E4%FE%E5%E5%FF%E6%E6%FA%E6%E7%FA%E7%E7%FB%E8%E8%FA%E8%E8%FF%E9%E8%FE%EA%EB%FE%EC%EC%FF%ED%ED%FE%ED%ED%FF%ED%EE%FE%EE%EE%FE%F0%F0%FE%F0%F0%FF%F1%F1%FF%F2%F2%FE%F2%F2%FF%F2%F3%FD%F3%F3%FE%F3%F3%FF%F4%F4%FF%F5%F5%FE%F5%F5%FF%F6%F6%FE%F8%F8%FD%F9%F9%FE%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%FE%11Created%20with%20GIMP%00!%F9%04%01%0A%00%7F%00%2C%00%00%00%00%0F%00%0D%00%00%07%85%80%7F%82%83%84%85%86%83%0E%17%09%87%83%12%1E1%2B%1C%03%86%06%18%25AR2%2C5%14%84%0B%19(FVbL-%40C%26%93%7F%0F%22%3BM%5Ded47JKG%16%82%15%20%1F%23)30%2FQSUW*%02%7F%13.9%3E%3D%3C%3ANY%5C_%5EE%07%82%1BDHPTX_bcO\'%0D%00%82%108PUZ%60aI%24%0C%01%85!U%5B%5BB%1D%08%8C%11%3F6%1A%05%8C%83%0A%08%FC%0B%04%00%3B', | |
//preview: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQoAAAB4CAYAAAAKVry3AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKbAAACmwB9fwntgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7L15jKRnft%2F3%2FT3P895v3X0fczSHQ84MzyV3V1RE7W68sODE3iQOZq1AkJHDIATIGyQIEgQI4plBBERBpChZO3KWsOFAtuCEYzgRvJEcaANRkiWvY2kpc3nskHP23V131Xu%2Fz5E%2Fqqs5wz14zCx3FqkP8KKqp4vset%2B369u%2F%2B0fGGMyYMWPGD4L9qN%2FAjBkzHn5mQjFjxowPZCYUM2bM%2BEBmQjFjxowPRPyo38BHgYju%2BfL7ve7y5csAgEuXLhkiwixgO2PG%2FUE%2FLh%2BiK1euULPZpDfeeIPeeadPQJuCIECv18NoNDp6VRXVahXN0y2shqERQmBhYUEDMJcuXfrxONEZMx5CHmqhICK88sorFMcx7e3tidFoZG1ubvLt7Q6XUgrNBIujlJIkgVIKnm%2BjWqmiWQtMELg6rFdks1otHMcpHceR58%2BfN1%2F%2B8pfNw3zOM2Y8jDzUQnHlyhU2GAx4UZCdq8IrktzfP%2Bw5%2B%2B2BJSW3DRgvckNpKaGVhutwVEIbtdA2FV8oP7Rz33UTxigGeLq6Olc6jiMxszBmzPhIPHRCMbUi3nrrLXbz5r6VpokXp3kYp0WlKHk4HBt7EJEolCM0bKYUI6UJMARLGFR8Qj00phZo7bmy5JSnWuWx4%2FCo2awknPMky7J8Z2dHvfrqqzPrYsaMD8FDFcwkIly%2BfJlu3rzJDw8H7mDQD9v9pDYcm0qc2X6uA6dQNZ6qOlM6JEMODAQMYyAAJQNgDAQUHFZAYGgp1bON7nsmz8N%2BP4kNU0NVqJHneelLL71UEtFMLGbM%2BAAeKqG4ePEiDQYQqdrxOp1hrd1LGwc9Ux0mVTfVi5bEPNOsBc3qZJgLkIA5yvASAZqAFAArAVaUgEh4xR0wl7UFyQM3y7teWUSulJnNuelvbW1FFy9elESkZ2IxY8b356ERiitXrtCFCxf41ta%2B2%2BkP6wftrHXY49VePOclepVLtk6GNWGYD5CFSQnIexlSQ4ABoVAEnQHSeCh0CM0aZFXmeeg3mcq2mFK3ucoLVhQ5OC8BIL58%2BXIJQP9oznzGjIefh0YoAFAcx%2FYozmoH7bS132a1frbgJvoUl3yVDG8A5GIiDhowJQA1eQ4CDANIQBuOEgw6Y5BKoJQC0jhYbfpUq1a54%2FjOoHcDabIPrRlz3ZAARK%2B%2B%2Bmrx%2Bc9%2FfmZWzJjxPXgohOLq1auU27bob7eDwSCr9wa8Okibbmw2uBInyfAaAAuAAUwK0jGgY5DJDUEBAAwsGPLIsADGeFDGQWo4pGKQmsOgArHgYb7hk23bTq9NpNSQiEgrpeRbb72lfv%2F3f1%2FNsiEzZnw3P3KhmAYw%2B%2Fv7Yu%2Bg6x20i2CQVJ1Er3ElVsiw%2BsTVMBKkIzDdBtcHhqm%2B5izXjBSMAZTmJI1PhtdJs3kyfIG0CVEYC8N44qYI7sB1FqleMVRXuR2NboV5rorBYBy7rpt97nOfUz%2Fq6zFjxsPIj1woAOD27du4s7fHuweZdTAMxKhsMMmXybAGwCzAGJCOwdUOPHZb%2B85hyfUoA%2FKCCNpoQCrDtbEsaUI7V0tWaVKu%2BBoZ1FBKC6MY2OkQbEvAWpqDXzlJZTGy4njXbbe7HmN29O1vf7v8whe%2BMMuCzJjxPh4Kofj2t79N3W5GUSZYrCqstBqkRR0gB5OgZQHSQ9jYMi1%2Fv1xqyrHgrB%2BNy1jKUpZSEhdCcCa9oiwqoyyvjAvlpkpwRRYZqqCQhGGksdMhVDwHJ%2BfmyXaa1O9tiiQZiDwvGGPl9%2B0fmTHj%2F888FEKxt7eHwQAkWZ2k5cDYIcBcgDgAgKAgKIXPh7peyYr1ldpovrXQGwy60e7urhoOOZaXQy6E6yW5Ltq9gkzvkJdFlWldI8NcGDAUUmMUE3pjjqW6CyYClCUwGPVpNBrQ5ub1H%2FGVmDHj4eShEIrd3V3AmgezBDS8SXaDBAACESCYgcslfCFN4EIFnpW3WvP5yZNr5dmzZ9Wbb76JCxcuyPF4rAZxDM8d28pIr%2Bj2bKV6kLoKMAvGcJTSICuAQnE4sKANkEQJtE5Qq9V%2B1JdixoyHkodsHgUDGOHu%2BghGgGNxVHwblcAmwcDTNHY6nT17a2tLAKALFy7g0qVL%2BrOf%2Fax89NSpdGV1MVmaC%2FLQyxTHyJDJMC2TmAQ%2BDZQy0MbAGEBDoyx%2FJCc8Y8aPBQ%2BFUKysrMAPLNhCQyADmRQwEoABQOBcwPcrqFbmmWVV7Sgqq7u7nWa73a9sb2%2Fbb775JhER3nrrLVOtVmWtHua%2BxzPBc0kmNjDF0f8LIDKAUZAyQ1mkIDIIfd80m01j2%2FaP8jLMmPHQ8okIxXTgDBF913H58mVaXl7G6dUF02o4xrEyMDOc1EoYCWMMlOEAb8CtnCG%2FsmGBVcMkka3xOG4Oh7HfaDTY5cuX6dKlS8YYY7gRUikplZLaGDkxI2BAZMDIgEyKIm2bNOkYzrVqNOpyfX1JP%2F%2F887N0x4wZ34Mfeozi1Vdfpd%2F%2B7d%2BmX%2Fu1X6OXXnoJe3t7x99bXl4GALz44otsb6%2BDrZ2uFocw3bRnUt2F0j4MVVBKjrjwkZsVtAKXCUfYQ1VQnvdK2y4ix3GS5eVldfXqVSIiUkoK4kIwEoxIAEQgEBgZ2LwE033E403Y%2BlDaNqVhUM9arXrZarVmqdEZM74HPzShuHr1KsVxTMYYobW2RqMRL4oCaZpSURSwbRtRFJnRaISFhQUTBAFz3VALdyyxF5lOvGtS7ZEhASldjFOBXuxirjaHMEwpT%2Fe5kpFbrVa8%2Bfl5C0C5v79vksSIKEqdNC1daVxhKCCQDZABpwI2G4OpHVOk24qLURaEPG42a%2BnKyoo6f%2F48rly58ommSGeVoDN%2BHHjgQnHlyhU6efIkxXEsdnZ2LMuyPK213%2B127SiKmNaToKLWGkmSYDAY6CzLJICy0agwJixpzEDq%2FQPWjQXLlSFtGihyH%2BPYwiiW8FkJrTU4J7Ish1lWwJaWlujGjRtsPB65h72%2B3%2B5lTpy1uKIagSyQycHNGFztGZR3lCUGWRjyaH6%2BGZ85c1ouLy%2FzarVKP3H%2B%2FIO%2BJPcwuuu57%2Ft4%2BeWXTRzHZm1tTc%2Bmb814WHmgQnH16lXa2NhgeZ47%2FX7f73Q6QZZlAec81FrbQghqNBrHw26FEEjT1IxGoyLLstzzPFOp1PhSi6uyiLSWt6ifRijUEhk0UMQWhv3MWPmO0VlPGp1mSRKnUiZlFEWUZZl7cNCptDvjSm9EdiJrpFkVMAqkBuBmB7a1ZTw%2BLGsVipcXW8n6%2BjwqFSfQZYSD3RFpfXfY5kFUdPN7vlIAlAKM0Tg8hCnLVI5Gcf6nf%2Fqn2cWLFxWmUdcZMx4iHphQXLlyhc6fP8%2F39vbcOI6ro9GoURRFyBhzK5WKHQQBdxyHhBAgIpRliSzLkCSJGQ6HqixLGUWRLkvJLMvmjUphsjRSZCKK8i6VZQUm5SbuF8YpRtLh49iy1DDPkzhNUzUYDOxeL60c9sb1bt%2BEcV63pGmRMQQyHTjYNlV3H63KWM81TVmr2lKwmMejvMbUoR3bnDNDZBQApR%2BMRkzhADiDZoBUQJRqJKlBWRhdlGWW5%2BUgjmOdJEk2G6Qz42HkgQgFEeGrX%2F0qvf7663aSJNU4jueIqDY%2FP%2B8tLy%2Fz5eVl1mg04Hkecc5hjEGe54iiCMPh0PR6Pd7pdKxer2dGoxGSJIFWha74heasVJU8V3nR0wYwwmjJQVkYWmPXrQ6DwE2JiG5u7vh7B4PG%2FmFZ7458N5HzXEMQ04dwsGsa3r5ZbuZYmuPGt0sm856XmsTzmBRGMItpzqk0pBMNnWiYEtDG3N%2Ffd8KkNMRigE8oOcMwNdhra3T72qS51kWh47wo86KQ0WAQz0rIZzyUPBChuHz5Mn3zm9%2FknHPPGFNzXbe2srLinz17VjzyyCO0uLiIIAggxOTHaa0hpUSapoiiiIbDIXq9Hu3v72NnZwe7u7um0%2BlAykJxpot6jSWW5WTSUImyzG2b8larklWr1TzLuLmxuekOB2W121PV3a7rDrOmUMYljg4c2jMVa980%2FNiENiOSmpV6YHvW0Kr7BVttGbbQAHOYgUk08lKihIJSBuY%2BHQEiABbBMAbJGEaaoUw00rFCHhsUGdQ41mIwVjxPDNqD%2BEHcjhkzHjj3LRREhM9%2F%2FvMUhqGttQ4rlUpldXXVfeKJJ8T58%2BdpcXERYRhi6nIAgDEGWmsopVAUBbIsw2g0wtzcHBqNBur1Om1tbbHt7W3e7w8ZI2kaNSutVptjLZDKhJXz855mjFEU9dzOYVTbb2e1ztDzRnkoSuOC09D4%2FAAV5wCB3SOBFFlUktAZNasJa1VLzNeBekjkWgShDUqjYIyCIgXFAHO%2F4QJGMIJQGsIoInQSoB8Z2NxgdZFMXhD2D7VJM2WKWWhixkPMfQvFxYsXSUop8jz3hRDVer0ebGxsWI8%2B%2BigtLS3Bdd3j1zI2nW852d4lhIBlWbBt%2B%2Fi54zjwPA%2Bu65IQggO33eFwqEajUSaEGK%2BtrZXOvCOr1Srt7e3ZozitDcdlqz8W1XFatUvjEmcRQqurW2HX1IIxc%2FmIuBkR5zlVfYlmVaMaAowTxjEhywCjAJlpZJlBYQiaAYbu0xOgSbhjNDI4GChEGWDbhErA4ToMRKRcRxSVUJTccbRft83t27fv72fOmPFD4L6Egojwla98hba2toSU0guCwF9ZWbEfeeQRWlhYABFhOBxCKQXf9xEEASzLOhYMYwzKskQURUiSBMYYNBqNYyFRSrE8z0VRFH6WZWVZlnGWZempU6fUO%2B%2B8w7vdKBiO8vpgLKpRFrqFqXBGOXzRlY1gWDYrqamHidWqplYtyMh3FDzXIPAYHAcQnMDYkXfBAeYy2IKBazMt5rwvDICiNJBtjUEM5CWD69lQxkJ7yPU4oiJTVhw2qvFi0CxPnjxnvva1r93fD50x44fAfQnFxYsXiXPOhRAOEflBEDirq6tsdXWVgiBAlmXY29tDp9NBEARYXl7G%2FPw8fN%2BHMQZJkqDdbmNvbw9JkmB%2Bfh7z8%2FNoNps4Ks7CeDxmw%2BFQ9Ho9X2tdybIsvnPnjjw46Fv7hz3%2FoK2DfhS4mapzRkBoD1WzEmfzdSSepYhREvp2wZs18NAXsG0GwSddqUTv0wIOcAawadbBHLkf5uO5IcYA0mhoKJSKoIwPZrXAnIopU2OiIs3zwkTVaj1dWDglV1ZW7ud2zJjxQ%2BNDC8Xd8YUpX%2FziF7G5uSkcx%2FGMMV6z2bQWFxep0WjAcRwURYHRaIS33noLWZZhY2MD58%2Bfx9raGowx2NrawhtvvIE7d%2B4gCAJ4nofV1VVwzlGv1zEajdBqtTA3N8fiOLaTJPGIyDHGFGmauYNhHvbGrhsXdaaNC5f3VS1MspVFa9Sqh1GZKyuLbHHQFXycGKoEDgtDH7Ztv3c%2BdwvB0eM0hiKlRFmUUGrSc2ImF%2BD4%2FN%2F%2F9fTfaHLBYLRBlit0%2BxKDiKNaX0Fr6Rxac0sIupGRd7ZVp9Mu8nxcbm1t6d%2F4jd%2BYBSpmPJR8KKG4evUqvfLKK7S%2Fv4%2BXX37Z7O3t4dKlS2Zvb4%2FiOOaMMcf3fbfRaIhGo0Gu6x7HHIgIBwcHePfdd3Hnzh1kWXbsWnzrW9%2FCH%2F%2FxH6Pb7eLxxx8HANi2DcuyEIYhKpUKarUams0mHRwcsMFgYAFwwjAs81KFubKCXFVtaerMkDQWG8uqW8ZzjfpgebEVjfqwD4qMuiNjemMZLC0t2tWFUyys1cA5hwFgtD5qN38vwFqWJYo0wXDcR6%2FXQRyPoVT5nkjebWEcC8jxl9AGMIaglEFeEPKCYNkVtOY3cObRT2FhcQnb29sYjTMzHsem1%2BvpN9989UHe1xkzHigfKBRXr14lALzb7dpSSjoqt5Zf%2FvKXdaPRoOFwyJRSolariUajQZVKhaYCwRgDESFJEty%2BfRtbW1twXRetVgsA8Nprr%2BG1116DMQbr6%2BsAAM45LMuC67rwfR%2Be5x0%2FMsa4UsaO08KL08JPc%2BGVuiIMeWC6YyyWlraNOKh441otjJUqOOv1yrQQ0verfHHlgnjq2c%2Bw1dVV2JY1iYNoDa0UlFLIiwJxHKHf7%2BHwYBdFoWGPOyhFDk0FYI5mWtxzhd4TCq0nMYk8M4gSICsmcy8Ajjnfw9zcElbXTqLZbGA0iuA4Nji%2Ft3JzxoyHkQ9jUbDxeOwmSVLpdrsiSZKUiKKlpaXi2rVr0FqTEILq9TqCICDf948FArg3YJllGXZ3d9Hv9wEA%2B%2Fv7ODw8hOd5KIri%2BC82YwxCiOPjKCtCRMS0VjzLUitLczfPHavUjMEU4BQbS0jp2nZe8cLcsqxSKVUcHnZVFGVWszlfW1hYNo9sPGpOb2yQ4zjvuRdlgSRJ0Ot1kWcJ8nSIIt5BwHdRW%2BrDZjEEkwDdNVKH3js0AVIDaWbQ7Wts7yuUpYFWBpoRtHFgWwxhGKBarSIIQliWBc4figFjM2Z8ID%2FwN%2FXKlSt05swZStPUHg6H1YODA28wGERaayWEUJxzk6YpgIklME1zTrMaU44yGBOTvihQHo2TKooCUkoopSYxgLv8%2FffPrTgSHzLGcKOMgNGCKOc2hhA8gyeGphIYaXGW57ksl5eX1Ztvvon9%2FX0lhFCMcW3bNjzfRxiGcBwHUkokSYzxKEX7cA%2FbW9exdecNDNvvwlY7WKv1sFJNUXclLGZwnC2lo3GeNoOyCDkIw9TgoGsguEGWGRA0SkkoJTBOCLbNYNuT9O%2FUvSKimUUx48eCD%2FUnLc9z6vf71u7urt%2Fr9TjnvKzX66pWqxV5ntPUgrjbkvhevF8MpkzF4O7Xaa2PYwZHBxERc13X9n2P1UtjSSMp8BOAcoQeTKteV3MNX3leqL%2FxjW%2Fg6tWrqFarptlsHv8cYFIZWhQFxuMR9na3cfv2O9jdehvj3jtAdhvLdhvLTowVN0eLKbi5mWRCCCBGgAUYwaBsYCwYDlKD4digN5hYEtUKg2VxJBnDMBIolAfLciCEBcuyji2lmUjM%2BHHhBwrFpUuXzMsvv2yKopC9Xq%2FodDo0HA4D13W153kQQozn5uZ4mqZsMjBGQWv9XZbBNO4w%2FZBwzkFEsG0bruvCdd3j%2Bop7Mg5libIskSQJ0jQlrbXgnPvC4qZRDx3HlawoQYxxE%2Fi%2BaTRC02pUUK1W2RNPfBFXr16953wmlaA5BoM%2B4jjCzvZt3L75bRzsfBsmu4U5p42VxhgLPEe9LOEnElauwcqJSEAQyCNojyNjQE8ZbKcKt7oGB32DtACIJpZDoRyUsQ1pbAjHg%2BOGEGJyjh8kqDNmPGx8GItCt9vtot%2Fvp3mel0opVylVK8uSyrJ0ms2miqLIAcCmbsVULIwxsCwL9Xodi4uLSNMUrVbruO9jdXUV%2FX4fnudhYWHhuIpTSok8z6fdpRgMBuj3%2B4iiyNLGMCkVDARTmpFSDCCaBCPTnI%2BF5SilnDRN1UsvvSS%2F%2FvWvE2Ps2M042N%2FDaNjBwd4d7Gy%2BhWTwHVT4FlarI6z7OeZNCS%2BVEJECpZMuUnPUs6EFQbocscNxUBBuDgzu9AwGMQBiEJaA1C4KXYXhTQjPgW0AoRkcxz8%2BtzRNkaapUUrNBGPGjwUfKBR7e3sYDocSQOb7fk5Eoeu6juu6dQCelFIaY0SWZWI8HlOWZZMPbZ4jTVMIIbCxsQEAKMsSp0%2BfxurqKmzbxmc%2B8xmsrq5CCIETJ07A8zykaQrGGJIkQZIkGA6HODw8RKfToSiKUJZKjMYlcukhVwEZOPBcgYqneBxH3mA0qvuupcLQ0ysrK9kzzzzDd3Y2RRKP%2Bc72bVQCDc%2FKkAxvQcW3sczbOFlNsOqWqJUKViRBsQbKo2G8LsG4DIXNMBIMXcPQiQj7MbDbN%2BiNAA0Bz%2FchnAaI5uHaK3C8RYzjEocHXcRJDMY4kiTB3t4eiMjs7%2B%2Broiik7%2Ftqfn7%2Bh3mPZ8y4bz5QKC5fvmx%2B%2Fud%2FXgdBUBRFkdq2XVQqFWt%2Bft5xHMdOkkSPRiMwxni326UoipDnOYqiwPb2NobDIVZXV7G%2Bvg7bttFoNLCwsADOOarVKs6ePTvJeGiN0WiEOI7huu5RDGF8bE1Mxue5ZGBhMOYYpDXkZhXcnkOdu%2BQFKVc4cONoH0UWac6hiqKgtbUlKx73vWjcsfa236BQ3KKTiwVWvAGa3ggtnaKhJYKhAs80kE2sCLIABBymypF6DG3JcHtgsDUA%2BrmBBCAVA7gFKavQbAVh8wyac6dRb67BdkJsb%2B8gSQpkeY48z7GzswMAWilVDgaDFEDSarXKtbU18%2Bqrr86KrWY8tHygUBhjcOXKFbO1tVUURRELIZJKpeIsLi46tVqN9ft9XpYlRqMRBoMBjcdjZFmGfr%2BPa9eu4eDgAM1mE6dOnsTiwgIq1Sosa7JP1HNdFFmG0WCAnZ0dtDsd2I6D1dVVeJ6H8XiM8XgMYwzm5uYgLBf9kUE68jGWGyjZBgSa8JgD5pdUCatCJtIr8wOtlFGjUdcusp5dCbKaZ8XOUn3IVqsMZ%2Boa675ETRZwIgmeKlCmATmJRRifQVcYyorAyGbYLwi3ewZbXWCYGGgwMC6gjQvwJsLwFJbWzuORRy5gcWkNQViFLCVGowicc0gpMRqNTBzHut%2Fvl5ZlxUKIQa1WGy4sLOSj0UjPhtXMeJj5UFmPN99806yurso8zxPOeUxEAefcWlpa4idOnKBWq4Xr169Da42pUOR5jm63i7fefBMEYH9rC6dPnUKr2cS0hiGJInQODnD7zh3c2tpCUpY4ceoUqtUqiAhxHCNNU1QqFSwtLaMogX4cIdMtlLQOxRYB4yNXApoRwioR7BEfD2NPyqQx7LUDI%2FfFcqvvLTZL%2B8yaoo0FYNE2qBQSItEgBzBggEswADQjlDZD5DB0DMNOH9jsaRwODbKCwC0LnLmQpgrDF9FonMbaiQvYOHMBa6sn4Pn%2B8Xt3HAdlWZo4jk0URcoYUxhj4nq9PnBdtx8EQfzYY48VN2%2FenKnEjIeaD1vCbb761a8qIUQ%2BGAziNE3T4XDoJEnC19fX0Wq1IITA%2Fv4%2BxuMx0jSF53loNpsgALffeQedd97BTqOBVq02EQqlUEQRhv0%2Bdns9tJVCfX0dtWr1eLVfmqYoy3Liriwuot2JoIxEaSowrApDDrThKBVBagHLDmGxGmWJLbQ8CAQ78JqNDltfzPmJFU3ri4waHuAUGjpjKAQBgQH0pPTaGCBTQCcFNsfA7tCgHwNRBuSlgDI2YKrg9hJqlZNotDawtHIa6yc2sLKyimq1BmMMpJSQUkIIYcqyVHEcF8aYzLbtuFarjefm5oZBEMT1er28efOmBvChpn9funTJTMvfZ8z4JPlQQmGMwdWrV41SqgQQF0UxHgwG7vb2tlhYWOArKyu0srKC0Wh0fCwvL2NjYwM7m5vo376N7Pp1ZNevQwkBcA6uNURZgpUlGOeora%2FjzMYGzp07h4WFBfR6PRRFAaUU6vU6ms0m0tRAiP5k2xfuPo7fKIxRIJTMFin5boKKl8G1JUlJOOwBfcLExVAANMGY9z6fSgPjxGC3q7HT0UgKgmVxMG6DWSEMzcGvnsTS8lksr57B%2FMIKGo0W6vU6qtUabNuGlBIAjiovuTHGSK11HIbhqNFoRK1WK6lUKnmapubmzZs8TdMPtYQpCAL84i%2F%2BovnKV76ir1y5YmZj%2Fmd8knzoGuKLFy%2BaK1euKMdxUtu2h1EUOQcHB%2Fz69ese55xblkW%2B72M8HqPdbmNpaQmrKyt48oknMNrawt7%2BPha3t3Euz7FkDAhAF8C7to10cRHh2bP41PPP47HHHoNl2xgOh8c1FUQEwQUc10LoGbh8hLjsQ2sfjBkIJsBRosgHKLI2jO4j8BNy7RxlqXDYVeiPJntMCXhPW%2B7WGABSGgwjg3ZPI84YbNtGEIbwnHlUKifRaJ3B0sqjWFk9iVZr0i5v2w5c14XjOJjOAz2e3lUWAADXdeB5PizH4lEauXE8spVSRv%2Bg1KhSk%2Fm%2BCtCkjZRSK1LlQnMhD4KguHLlip6JxYxPio%2FUbHDp0iV95cqVMgzDSEpppWnKb926RQDcVqvFjTE0Ho9xeHiINE2xtLSEM2fPor%2B%2FD7mzAzEcoprnWJcSBkBsWZDVKqqPPorHPvMZXHjySSwtLSFOkuPCJGMMRqMRDg8PkUSJca3chE6EcWKRNiU41WBpGzpXNOofgMk7CKwOWtUh6mE%2BWSEIOrJC3sdxM%2BhkMIUyBKk1klwgzV1wZw5OeApLq49h%2FeQ5rKxtoNVaQBiGsCz7%2BD06jjMJ0B4hpZxka3o90kYJr%2BL6xDRPyqjyl5qv%2FVWfkj%2FfTdzf%2Bcbw2b%2F%2Fva7zpORdQxYKZT5pcbdtR0olU4usgWVZY9d1ZxO7Z3xifOSupPPnz%2BubN29mSqlhkiTU7%2FehtaZer%2BeWZcmiKKJGo4EkSWBZFuYXFrBx7hwO79xB5%2FAQB0mCufEYkgg7YYj05EksPfssHnvmGaysr8MPAuRFcdxByhjD%2Fv4%2But2uFsKSDIWs%2B6mJoltcp10GXSWkFrJBScOyR4HbZjU3JUY5YEoIbiDEUZn4XedhcDSVXwLGTLIYgjiEDXBLwOELWFy9gHPnP4VHzpzD8soaarU6bNu5p%2BGNMXZcVTpdQdDr9XBn8w6297dI8ZwHTcstUTjnxdbptUr2C0VJnCN%2B9N9gf%2FxTf1Sc%2FW9HrDqevjutDXSpkCcF4jRFOiqgtTGO4yilytRxHZqbm5PLy8vylVdeKTHbAzLjE%2BAjC8WXv%2Fxlc%2FnyZcU5TznnUEpRv9%2FnvV6PsiyzjTG82WzStFnMDwKsnjiBjaeeQrS7i61%2BH6oooBjD3tISKk8%2FjbPPP48TGxuoVCrHnaOO4yAMQ3iehzt37pgoispKpRI3Gs24VWdqOOqJPG3zorBJJZwKh4SytaPt0k0y4tv7INdSaFQ06lXAsSd9GoSjyVNq0go%2BGDGUykNYacEPZYk5YQAAIABJREFUaoDF4FU55isn8eTTL%2BCppz%2BFlZUVBEEAzsVxxem0%2BnRajp3nOfr9PnZ2d7C1tYl3b15De7QHCgvyfcYVY1jKozMOZ%2FzxL%2FwCxv0D%2FKvf%2F4ef%2Binz9te2qmu%2FvN967C2jgSItEQ9TZEpCsQJK5CAiKA6Ry5S0VgVjLAaQhmE4Xfk%2BY8YPlY8sFMYYEJG5fPmyHAwGqeM4LMsy3uv1TKfTCRljzmg0soqiIK01hBBoNJs4%2FdhjaO%2Fs4K2dHXTiGMyyUHnsMZx67jmcOXcOzVYLtm1j%2Bt94nodarYZGowHXdU2%2F35dpmibNJgaNWpDV%2Fb4ZDvusVIANl9XCmuv7Vr0sc9bJtGsUqO4D1QCohgyVkMCPwoZaA3EGRAnDOPWh2RrmahewvHoSpTQIezFqjUU8evYcTpw4iWq1etwRO21Wu7thbVo3cvPWTVx7521s722in7SRsiG0l0HZEppKSKmVZRGEcHDuJ%2F89LJ56Bt%2F4B5caq%2F07v1wvx%2F%2Fg9snP%2FqM8y02eFZBlCeEwVN1JulXlxjADmMkqM0az2u8ZnyAfayDC3WIBIDk8PMR4PC6llAVjrF6WJSvLkmutiYjgeR6WVlZw%2BsIF7Gxt4Xqew%2FN9nH3uOTz65JNYXF6G67rHXaS2bSMMQ9TrdczNzWFpaYnSNOVFUVhRFPGFhQX59NNnskajIW%2FcaJu1tZCdOrUajIddZ3e%2FH6ZJYjhJBDYDYwKMT%2F7qEwMAgtGA0hzgIWqtE2guPIPzFz6N1dV1RHGCra1tOI6HRqN5PBB4mpacfj6nAtHr93BwcICd3W3c2bqFzb1b6CdtSCuBclIUMkFZZFBaITOFtHwGLTMAGo3F0%2Fi3%2F%2FrL9Af%2Fx%2F%2BAW9%2F5k7965u3fffJfmlO%2FGo%2BsoTEGjjcZ2SdzbaRWCsQyECJpZJrnuVpYWJhZEzM%2BET725JSpWHzta18rB4NBDEBKKbUQQiil7LIsmdaagMmsimqlgpOPPILOpz8N43kIfB%2Fnnn8e6ydPIgzD445SxibZhkqlgmaziaWlJYxGIxRFYR0cHIR5nqs4jun06dPjRx99NH7hhaQAaqosO%2FJaNFBlKY2UBpbnwzAHvbGG2gIcm8DYZHWXNgzS%2BLDcNTxy9lmcffwz2Ng4iyCs4PDwEIPB%2BNgFmgYs70YphfF4jJ3dHVy%2F%2Fi5u3LqOdv8AiRwhwQC520emI%2BR5glLnkEdj9ApHlwCgZAEYIG%2B%2FDea38IWL%2FwWdeP338Pu%2F9beffYFu%2FK13ndZ%2F%2F6ZaeZ0ZDl0QirQwyFG6FX%2Fs2s6QNMW1Wq38%2Bte%2Fjueee%2B4%2Bbv%2BMGR%2BO%2BxqxNBWLixcvys3NTYzH47RSqeRaayWlxHRzOWMMtuNgYWEBTz%2F7LOaXluDYNtZPnECtXr9nORARQQiBIAjQarWQpimO3BhGRE673a5nWeYcHBx4URQNGGPjeh0lY4w5joNarYaFhTnMzzdQDS0w5ChMCaUJnDg4F%2BDCQuBVsbR8Cmcfewobj5xFq9mCPup2nc6JeP9A4Wnn5zRY%2BZ1rb%2BP6rXdw0N9FhjHglihYhNgMkZYxpCqgjT4%2BJwNWAhpa5jDQ0OUYstMGd1s49fjzWFj%2Fn%2FBP%2Fu7fqD1m2r%2B0wNL%2F%2FQ322X9ohTUdicSMh2NZqzby%2Bfm5JAiCwnXdWXp0xifGfc9im4rFhQsXjOM4xrZtY1mWmVoIUxhjCIIA6ydOYG5%2BHowx%2BL4Px3G%2Bq9WaMQbXdVGv16HUZFuwEII459y2bbfb7Vq9Xs%2Fu9%2FuWEMKO4zheWFigSqXCGWO0vr6Oxx9%2FDGHoI4knO0MAMxkcY1twHRd%2BEKLVmsPS0goajSZsx0ZRlHef0%2FHzaTfsYDDA%2Fv4%2B7mzexo1b13F7%2BwZ68SEYa7vrxZ0L9WT4dIXKZwUn823j%2FO0%2FE97bQgjYlg3H8cA1SSAGtAQMQCBAFSijHah8ANufx8Wv%2FCr9s3%2Fydwze%2FubP%2Fmv8m0%2BoUxd%2FZTdeO9za3DKe5%2BkwrOsgCPTFixdnIjHjE%2BOBDW0MwxBhGLIgCITv%2B9y2bdwtFtMBNr7v3xOPeL9Zf%2FdrPc9Dq9U6rlVwHIeCIKDNzU3a39%2F3hsMhH4%2FHdpIkjuM4hWVZolar0draGs6dO4dms3W0CHmAspTgnN01LMdDEARH2QwOY3A8rk8pBc45tNbI8xxxHOPw8BA3b93AjVs3sLd7k%2FPOH5xdzneePq2jZywtHwcMt4SFhbXHTDrYoqfK4kvfcby3XceFa3sQ5EBGeQnE0Hqa1ZwsFyFjoLIhVJmCJR385J%2F%2FK3Ty7Kfw6m%2F9%2BhPi9m%2F%2BzbXm87%2FSCx75PcbYcdftjBmfJA9EKI7WCrIoioTrupbnedxxHHq%2FCPwgcXg%2FU3N9OqzXdV0EQYBarYZWq0W3bt3i77zzjrOzs0NRFJnxeBz7vs8450ci46PRaCAIAjiOgzRNobU%2Bnu3pOM6xyzPNYEwH5uR5DsuyMB6PIaVEr92m7%2FzR3z05vPPNpyk7fHrJZE%2BS0S4RQ6W1ajae%2BRlaP%2F8i5taegO1V6eu%2F%2FDnkcT%2BsVxuwhQuUHPlQIk50iRpgtDya6P3eEE4igpYpZJlCFREWWjX85b%2F2S%2Fid%2F%2B1XQt3%2B55fPs7fP3eJ%2F7r95EPdrxoyPygMRihdffJFef%2F11IaV0LMuyfN9nnufdY1G8fzzeh%2BFuy8K2bXied7zrw7Is6vf7rNfrMaUUAVB5nsMYo%2BI4NtP9IUEQHA%2FCKcvyuPZhGoeY1kQA703WStMUg5t%2FsND55mvPlIPbT5t8%2BLTRZc0G4FWa5sS5n6H1Jz6HxVPPImwsE%2BMWcFwwJcEBCMaZywIUY4N0kCMZ5RhbsgAAo9Sk%2BOEua2uy55QAI6HyMajMQayLv%2FhX%2Fjp961%2F8P%2BbGG%2F%2F8Z8%2Fmv3VO7b7281j7z9%2B633s2Y8ZH4b6F4uWXX6bxeGxxzn3XdYMgCJxWq8XCMKT39z5orY8%2FpB92buRULO5%2BfZqm04YrZVlW4ft%2B4nlePB6PRVEU4eHhodnd3TWtVovq9frxZrC7J35Pmbob7dt%2FUn3z9%2F7OUwc3%2FuUz%2BfjgGah8EQCE7WP5sc%2Bak%2Bc%2Fh8Uzz6O%2BcJqE5QLEYIyCLlOofAStJIRbBUiAMw1OxKLDEnE%2FQ56WgCGUllUCgFbl8Y6Qo5PE1KowRCBMrAsDgipu4sknn6Sl9TP4o9%2F5%2B0%2Bz5PYfJX%2F4H%2F%2BHeOmlf3S%2F927GjA%2FLxxaKK1eu0Pnz52lvb09sb2%2F7cRzXhBDVpaUlZ319ndWOtnEppZCmKfr9PrIsg%2Bu6qFar8DzvnoXFHzS9ezo5ezAYYHt729y%2BfVv1er1Maz3inA9834%2BklL4xRnY6HfX2229zzjlWVlbo%2FQHTu4Wic%2F2ftV7%2FP%2F%2FL%2F6pMB2cAEOMW5pbPmPVzP4mVR57H3OpjsLwaEWOA0TA6h0zjI%2FcBALH31gpgYlEIBjBVnP3C6E%2F%2FF3AA4eR7jBEDAhgjj376va7HVCSOrQstoY0GkgINS%2BMv%2FLv%2FEf7gd%2F9xEI%2F6V%2F%2FHn%2BNX%2FpPfVJc%2F7v2bMeOj8LGE4tVXX6UXXniB3bx50zo8PPTa7XZNSllfWFgI1tfXrfX1dQqCAEopRFGE3d1dvPvuu%2Bh2u6jVajh58iQWFxdRrVbhuu49FsP7BWM6kTtJEnQ6Hdy8edO8%2Ffbb%2Btq1a3mv1xsbY%2Fqc86her8tarYZ2u60Gg4G8du0aH4%2FHfH5%2BnqY9I1P3RQhhABhjDPb%2B6aV%2FX%2BXRo49%2F%2Bt%2FE0sanYNdPw6%2B2jtwJYDSOoYdDaDX5cBPjIGJHjwQifvz%2BPQoAGFiWgOtW7XrLW2UEsKNiLzIawAhG6e%2FaWYq7RGJ6HQwRSBtoLUHGgCV7%2BOnPfZ79qz97HbtbN%2F7rv%2Fll%2Bp%2B%2F8oppf5x7OGPGR%2BEjC8XVq1fpxIkTvNvtuoeHh2Gv16sMh8Oq4ziVMAztRqNBQghEUYR%2Bv492u43vfOc75s033zSHh4emUqng1KlTdPr0aVpZWaF6vQ7P846Di9O4xt1pyWnr%2BtbWFm7duoXNzU3ZbrdTrXXseV6plBIHBwdOpVLxAYiiKEy%2F39e9Xo95nmcmW8YYXNdBo9EwlUpF2bYtKXq3YsXtn1p99Dn8xF%2F4a3j3ziFu3dyD1ttQSgIgcCEmtRdcgPHJ%2B2NcgHEOzjgY53AcG7ZlowkPtsXhh01U1x%2FBk4%2F%2FJTi2BdsWsC0BBok3XvkFeMFEUHBXUPdukTDTbAgIhhiINLRWMNBAEeHcufPY3brBpOB%2FEcDfe2C%2FDTNmfB8%2BslBsbGwgyzIRx7Hf6%2FXqnU6nHkWR7ziOzRjjw%2BEQN27cMIwxjMdj7O3t6c3NTbm%2Fv1%2FGcax6vR4bDodid3fXWlhYYM1mkyqVCgVBcLzfYxpPyPMcURSh2%2B2i3W5jMBggiiITRZGSUmqttYjjuHK0Nd2uVqs%2BY8w1xliWZXHGGFNK0WTqlMJoNES32zNB4KtarZaujf%2FvnzZGi0effBFGFrjx7jVIZcCFBc6tiUgQgTMCZwyMEThnYHxSrck4g%2BACnHFwzkDEJjUScgxTJijTAbgS4MqCVhaIGYAI2WAP0BIiXIGRKXSZAMC9IkHfQziOnttUgBgDtPoSZkIx4xPgY7kew%2BHQHBwcmE6nw6Io4lmWUZZlutfr6WvXrtH169eRZZlJksQkSVKWZZkyxuJms1lorXmSJN7m5mawu7vr2LYtbNsm27anYkEAaLrTI01TJElyNIV7soPUGCMA%2BFJK58iloCNhEJ7vi2azRZ7nket6k%2FgEY0jTFLs7O7h16yZtbt6B53nlydX9F7mwzPKJx2g07KMsS3BhgxGBcToKvLIjcZgEVadWBGNHVZ78veAsYwRjJIyMoVWBMu6CSwtcWRDaAnGGxtqz6G99C9%2F5p7%2BE9U%2F%2FHPz5J1AM7kCnHRit7hGEux%2Fvfq6VxMYjj%2BPGu2%2F%2FzJX%2FgNxLf89kD%2FbXYsaMe%2FnIQvHcc8%2Fh13%2F919XBwUE2Ho%2BHR0t%2F3OFwyHZ2dtButyGlnC4d1o7jFLVaLWk2m9Hi4qI0xohut%2Bt3u91iNBr5eZ47eZ4LYwxzHIdXq1XOGGNJktBRuvO4psLzfQS%2BT7ZtW47jcCGEcV2PXNeF53nkBwEFfkC%2BH8DzffieD9txwbhAEidgzMbNW7ewt7dPdSdxxar6yaWTT5CwLRzu7k3iCMwcicTkIIbjfg%2FGCWwqHEcWxcQNYRPxIDYZcKEng3mMLmE03juIYeHcF2GHLXTe%2FUO887v%2FHeqnPoO1p%2F4dcLcGObgFUyYwR1O9zF1BzknAk8HQ5Hsrq6u48e5bXi3jfw7A%2F%2FXAfzNmzLiLjywUR12jqiiKVGutjTFpWZaWUoqUUrAsC1prMsbQUfBQMcbKoihKzjlzXdc6yl6UZVnmRxvBdFEUvCxLc%2FSaSXDwKHYxPVzXhe8HCIKAgiDgvu9jKgquO3FdbMeFbTuwLRuWPdn3CeIYDgcI7myCMQ4pJb14dvyCgbFPPPIUoCX2DrtgIHAiMCJwAjgDOCMwAsSRePCjYyoYnE%2FcEcEnFoVWJYzRIC1hZArDJDQroZkFrSYxidrSOYTNU%2Bjc%2FCMM7vy%2FGG19C0tPfgmt05%2BFGWzCJIcw5v0icW9WJHCm8Q3zJcyEYsYPmY89j%2BLixYsqiqLUtu1cSklaa9RqNVpYWJiKgVWWpSAiPhwO3U6n48VxbDebzUBr7eZ5Lhhj7Mj14JzzqUVBlUoVnufC8%2Fzjkm%2FHORIN18ORBTH5t6Pv2bYH23EghH3kCkxcBAIhLwp0e30kSQatDSzbxnJd%2FTSIsHryLMosQRSlYMKaiAQzqPIBOHfAhQ3ObTBugwsLTNhHQU0LjFtgXEEwDU4KHAWMjCdDfvMeZP8d5BaH4hylxcDfl9HxaosQtofhwTvY%2FbN%2FjIPvfAMrT%2F9lVBqPoOjdgNIKPyh1urS0ag72d78Eol%2BYjeae8cPkY8%2BjAGBoMojyuBb5i1%2F8Irmu60ZR5JVlGZZl6TLGbGOMMMaw0WgkjDGO67rC931WqVTIsiw4jkue55HneQiCkIIwIM%2BbuA6OOxEI23Zh2e5RnMKGZdkQlgUhJgfn7wkEsaMPEwhKSYyjGJ32ITqdQwAazYrPQ4debC2uwvN87Hf7IBgwmiQiGGNQvAJwG2D25JFbIG6DuAUzPYQAuAVYFogLMMuDpqO6EBGAe3OwLH6U9ZgEPN%2BPW11EZfEMxoc30d9%2BHVv%2F4n%2BFt3AeK0%2F8DETRRxm17xGJu1Onp06fov39naVf%2B1k8958Cf%2FKxfgNmzPgQ3Heb%2BfQpEeH27dvctm27KIq6lLJhjHF937dc12W2bZPrehRWQhYGIYVhiCAI4Pk%2Bea4Hz%2FPhupOYguO6sKxJylFYk8G1wrJhWc4kG8GPAorEQcf1F%2B9Vbk4eJinWolAYDPrY2d7CcNCF53l44XT0BEFXTp46C9ISh53hRCCmNQ%2FEoEQdsCxAWCBhgYQ9eeQCJCxA2OC2N3m%2FR7EQLgQMJqXhzG3Aqp2A41hwbAHXsWAJ%2Fn2vZTh3BvWTL2D%2FnVcR730bt%2F94H9VH%2FnW05jcgB7egtPqu1GmtEkzOF%2BxLmAnFjB8iD6x7FADdvn2bOOcWEfmO4wSVSsURQjDf91GtVlGvN2h%2BfgH1RhOVShW%2BH8BxXNiOc%2BQ%2BTOIL%2FH3uA2PvZRuI7i7MomNR%2BF4opRDHMQ72d7G3twWtJFqtJlbz0U8CwNrJR2GMQneUgJg4DmAyRiBdgLQBaYAMgdOkFsJxA1iOB8v2wIQFGI20exv93jXknWuQnUkbhjYGOulAKQElJwcTP7gZzhQS1eWnIIJljHdew%2BD676G%2Fu4T5k8%2Bh4hcoosN7C7O0RBhUTJzE%2FxaAv%2FEA7%2BWMGffwIIUCvV4PjDHuuq7gnAvOOdNaU5qmIGJwPR%2FEBCrVBubmllCt1uC4HizLPhoYYx8VNrG7hOBeQfhBwnA3RmuUZYFet43trTsYDvoIwgCVSgXBbvZCENRMrblAwyiHVICwpm7LJO0pLAHL9eE4Piw3gGVPrJkijxAdvIW88y7U6Dp4vAnkXZij3g3DbOjgNLg7D6MLGKUnTWBKwdAHCIVSMFqC2QHs5Z9APtqGivax%2BfYfwqqdwNrqOkSxd491cebsWfqz1%2F70qV%2F9OTr5n%2F2muXOft3DGjO%2FJAxWK0WiESqUCy7LQaDRoeXkZnudBSomyLNHpdEFkgcgCFx5cr4IgdOC4PizLBr8rvvBhBeF7YYyBVArR%2F9femUdJltV1%2FnPfEntERkRm5L7U1lU0DfbC1mw9MpA6CCo6Js4cR9QGqpoeRT3qoCJ094jogAe0W6CrwWlGxeN0DnOG0TMKyYwCHqSBXqC32pesrNyXWDK2t9w7f9wXkZFrZWVXdQGV3zpR8d6N%2B27c9yLf9%2F3uby2VmJycYGryAkIourt6SFWf2CeU2zm07xBgsFAoaf8I08YORwmF49iRKJYdBgWV4iz1iWnc0gSydAHbncOUZWzhYiApyxh1owtppTHCaaxwnEho88uqVDNodPX%2B2lMVQLQbV2SQ5RnKS5M8Ob9IR88e%2BtJhRH0JIQS5jnYALIwfB%2F5sRxdsF7u4BK4oUaSCSuWJRILu7m72799PJpPB8zwKhSL5QoFCfpETtRr5QoGlxSV6%2BwbIdXaRTmeIRGJYwnpeJAGaKGq1KrOz04yPn6VUypPJZOgf2EPtsb%2B%2B3QcG9h0CIZgvOIElw8R16tQqRdxqEbc8j3CWMGQFizohoZPNVKRFnU5qKkZNauVlNGQTMSyiwsLc0Paggpz6CkOIVfn1DdGYc3Pyq%2BuPCBPH7sSTVZRfZHx8nDMXYrxoMEVntITpu9iWrVzP%2BQl2iWIXVwlXlCiAZmKYeDxOR0cHPT19WLZNrVpjcVG7Yi8tLXFx4izzc7NcuHCOwcG9DAzuobOrh1QyRTgSwTR3Thie51Es5BkfP8vU5AVMw6Cnt4%2Be3n7O%2FvPk7eFwRHXk%2BoRTqzI5NYnv1nFdB6UkJh4WLrZw0GVKbSoihqtC%2BCrIpcmKqUcggkRVBhgGhhkoP4N3ww5hhCzMkI1hN45fe04KocDAxVAuQrkIz0WYrq5FYoA0I9SEia%2BqOG6VJ0%2B5DN9%2BCNud49CNN4pnnv7uDz%2FwH0TqV%2F5KFXf%2B6%2B1iFxvjihMFrOSQsO0Q8USSZLINw7DIdfbQ2TnP9Mw0M9NTLOULTEycJZ9fYGZ2ioGBPfT3D9KR6yKRSOrlSOAevV3ocPQa8%2FOzTFw4x3KpQGdnJ319g1iV01nfWd43dMOL8WpLLFfq7G1XoEIII6LvfAUYhjaFaldNwGwSgTBsMEwwTAxMlGEG1pmQNtU2zLaB6da2Q1imhWXbmKYRSA5Kh6w3XTZ9lPSxPRfh1gk5LhHHwfM0gbmui%2Bc0th2UV0f6EtcXZLpvpMs1efqp79o%2B1iuBL1%2BN33QX1zeuClGA0Ux5p8mijVgshVKKdKaDTDZHLtfJ3OwMs3Oz5PMFzp4%2BxtzsFFOTE%2FQPDNHd3Ud7Ry6oEh5elS1rM%2BjgL5dCPs%2FFiXFmZ6ewbYve3j66unpZPv3tNEBPbz%2FSrRO1FQf7E0F8hYkwLRA2hmmCYQMWwjIRwgbT0uRh2Ppl2tCyLQxzZd%2BwwLAQwYvG2BiArjCG1OSA9JDSQ0mXkHSxPTdoc1C%2BB76jtz0H6dfB95B%2BHeXXQSo8CfFEqnH%2BfVfn99zF9Y6rRBQBhMAwTEKhCNF4EsuyicVTJJJp0pkOOnJd5OZmmJmeYnZ2hkKxyMkTzzA5eYHu7j6G9uyjv19XDo%2B3FAbejDCklFQqFSanJjh%2F7jS1apme7h56%2BwZIZzqoWTrHRMi2tdYgKA8olEIKCb6LEBWkEs1UdUIRKBKChYZhBtrH4F1o709laOlDYATthj5GBPvK2HAVpaWK1RKGUlKTiJKggrIHyteSh%2B8HfTwQFrbK4tWLjcu9Wz1sF1cFV5coIHhaG8FSJIxtay%2FLSDROPJEklcqQzXbQkcsxPTXJzMwMxdISZ8olFhfnmJmeon9giL6%2BATLZdqLRWOCJuVrCUEriOHUWFuY4d%2FY0U1MT2LZFd08fuVw3sXhCLx9ALy8CkkApJAqkWmeRECh8QEgR3OyBfiGoOKaJAWSDGIL4DBqOUc0s2wSu1wpU8C5AyYYGU%2BqPlNQEJmXQ10dJpWehJMiARJSvtw0Lw0uCriu0i11cNVx9omhCE4Z2aNLRliE7TDSaIJlM05bOks3m6OicZm52loX5OQr5eQr5RaamLjDZP0R%2F%2FxCdnd1ksx3EE8lVqfQa%2BSbOnz%2FDqRPPMT8%2FS39%2FP23pDPF4CtsOtZDACkm0Shag9I2p5Ko%2BND09QQiFaEoczf8aw2oe0HGfemyhjzMaSs9G1xUzRyBR6LkoJUHquUhkQGB%2BUBRZ6iWLkkhfYpg2WHHc%2Bm6U%2BS6uLq44UegsVcYWSwQRKDsFpmFi2SFC4SiRaJxEMk0m20Fnbp65uWmmJi8yMzPD1OQ4kxcvcPLEMYaG9rFv%2Fw309w9pk2o02syyPT11kZPHn%2BPcudMslwq0Z9upVKrUHSdIqqtnoIJ5KBqi%2FmrSWEckcoVIpFrfRyqF9CWO5%2BO4Pq6vcF0fJTTxCCWwbYjYAtvUPiJGMBMhFFKuIQqlaQKplyQyUH6unaOwohixGr6%2FK1Hs4uriihNFKBRqJJjRZLFJv4aIbqIlDMu0CIUjRKMJEok2Um0ZUqk0kUiU6vHnOHfuPJOTEyzMz7KwMMvs7DR9fYPkcl2EwiHyS4ucPPEcFy6cxXVq2CGb5eUS58%2BfJdWWxbJCeJ7XOoHgYb6xZLFKythC%2BvB9SbnmMH12hvL0ArJSBddFSU1APgauYeGFIphtceJdbaTjFpm4RSSkQ9i17LHxd66VOFr7CKVAmKvXSz%2BI%2BGXRjsvPAyB4lAfVv1zjGV13uOIOV7q4jo7wNI1LWypaJQxhmFimrfNJhKMoJVhYWNDmRdMAE3y%2FzvTkeQr5RSYunCOX6yYSiVAoLDExcR7XqTIw0E8oHKZWqzEzfRHDMHFdl3CpEHwjgbKRjQlgA6lhoz6eL5mbWmL60aeo%2BjATSkG8nXB7GMsAWakiCyXilRLZahEKUD5v8pSdJDrUyWB3jFzKIhoyAserLUhrozk2z%2BMHnCgcuhF8HADFHwBXnShGh8X%2FBgZ3cOj7R8bUD1x%2BkKvicKVf26vb0USQMEYIXUzHtBzqjsdSvki1ViOTzdLZ2Uk6ncZxHAqFItNT48xMTyCEgfQ9DFPQ29tNX%2B8A0VicxcUFLk5cYGpynFqtxoA9CbCiaGxIFBsSQkOhuLFk4XsrJHEh2oGfTNGTDZNN2rpyugAlU9TdDpZKLhcm85gzs%2FRQYa%2BXp3yyyBPn2mjfm%2BNAb5T2pEXIFGjN53YlGwIl6hX%2BEXcBcCNwYAfHZa70RL4XcNUcri6LJFqgQ8MdlhYXGR8%2Fz%2BTFCVAwODDEgRtuIJNpx3HqzM%2FPMT8%2Fx3KphOd7hOw4mWyWvv5BensGiEZjFIp5otEop0%2BfYn5uCtuYpLPxPSJQNrJeR7HuxlRKVyVXgNDLjfxSmZnHjzHduYdsW4T%2BXJRs0sYrV1maL2JlU7TFLCIhm55MiKFcmLlimonxAsbkFF1GjZv8JS48u8zXZru49WCK%2FlyYiNXw%2BmqVbDaZowjMND%2FoS49dXHO8gFaPS0NKSa1WZW5uhpMnj3Hq5HNUKiU6Ozs5cPBF7N93kFRbBt93yXX2UiwuUSkv43kelmWTSqXItneRznQQCkVIpfW7ZdmcOnWC%2BnQl%2BCaFwNC6QrX1U1tKRd31MJcW8NIZQpagVveZfPwYi7k%2BOrNxBjujpGIWAsX587NUjp%2FlZNc%2Bbr2xnb72MCFLYCUs4hGDzpTNzECC6ROz5BZnGAi5FCdn%2BGdX8sZb0vRmbUzBpXUmwbvA2OWJXVx1fM8QhVJKh4UvLnDq1DGee%2Fa7LC7MkkmnOXDDQfbtO0hXTz%2FRWAKlFG3pDuo76P5%2FAAAb7UlEQVS1Ko5Tx%2Fe9oOJ5hEgsQSQSwzQswpFYy1LIZLL8bSgATR8HLkkSjucjzp2lvlylYidIxiymT0xQCsVJpGMM5KK0xS1MoXUWJGIAzE%2FmmetN0JW2CFnaWGqbimTMIBqKkI33MP6UJDY7R1%2FY4%2FGZGkvLLl0pC2EFCs5L6kxAlza8Rj%2FaDza%2BCpxu2Q8DP7ymz0Xg6TVtk1dxTtcM3xNEoUnCpVDIc%2F7caY4fe5qZmYskE3H27NvPnr030NnVSyKRxrZDIAThcIxYLIUvvWbWap3oxmr6VpiYRKJxMpkcfX1VqmezqELwpcHafisdhZSS%2FGKJl82c4n8yRGfdxcCndH6SWv9e9rWFSMUMDBE83QXE25PkTZuE51JYdqk7Esswmje%2BQGGZkI6ZGC%2Ft5eSzFo9O%2BexPWzphrlABf11asUrDT%2BMHXZl5DTAypt7Zuj86LPqAiTXd%2FmFkTL3rhZvVtcM1J4oGSRQLec6fO8PxY08zPTVBNBJmz5697Nt3A13d%2FSSSaexQuCXDlfb2tJSNCqSCRo1S13XwXAfHqVOtVigW8pSWS0gpV26pwFNyM6WlkopK3SNz%2FgQRPC44IbqA2dOTFEJxUjGLdNLCNMQqM2YiYiBzWXIzRUpVj5rrEw0LDFaPrQTEIgZ7D3WQ6tWRqtmEGZAOG%2BhM5CaWGaHNpJeLI%2BKlKG4HbgNuQ3AQmEPfDF%2FC4G%2F4lDrX7H9Y3IlgEChwVH181ViHxZsQvC7Y%2BzhHm3S8nXm8C%2BhHscRD6k%2BD8V6B4C3NPga5psJWcAdHxL0tIzgcVR%2Fe8jvuEq8GXo7iVuBWoA8tCTyJ4gkkX%2BUzVz%2Fpz%2BiwiKCv9yuC1w8B54DH0KkMvzUypmYvMcbLgmNb8RcjY6qySX8DOLym%2BbsjY%2BrrLX3eAgy0fP4t4HHgncAdwK3XlCgaZQOXl0uMj5%2FluWe%2Fy4XxM9i2wZ6hPezff5Ce3kFSbVlCoUjTBVsFTlJSyqBSuofnujhOjWq1SrVaZrlUpFQqUCzmVX5pkaWlBZid8bUyUwArkZwbPbV9JSkUq9xem%2BeiY2GGLUBRuzBNsa2H3phJxDZWLREECtsSZPf3IOYWWXQl1bpPOmbgB%2FN2PUl5qUJ5aZl6qYZfriPrDrV4glpPmv4Om0TYQIj15LWhZNE4ne3iXSKLyZ8AP7%2FBcWngBuANSD7MXeJ%2BYvwOH1NVBO8EXgNcAD6%2B5rg3Ae8DwOdhggXedmcEvArBOeBPg%2FN5JXBPs0crDypeD7y%2BpaUMbEwU7xb9GDwILaSzgjcAb0CH7dQ5LO4jz0d4RPmXMfdtY3RYDAOfYb3J9aXAjwfb7uiw%2BCPgQyNjytlkqLcA961p%2BwKwIVGghYFPrWm7H%2Fh6y%2F57gR9p2b8HeEfQDqCuKVFI6VOtlJmamuD4sWc4d%2B4UKJ%2F%2BviH2BSSRTGaw7RCNyFDp%2B3i%2B15QY6vUa1WqF8nJJk0J%2BkWKhIPP5JUqlgqrXqsrzXOW6jt%2FuLFVpuB0EGsC1yszGtudJrJlposLnxHKYtqxFveoga3WMzhCxSMvTv%2BlRqT0tM202%2BUyKSL3CciVKUbgsTy1RnS2iiuUglkPDCF6lgse3puHNt7WxtyuEbcL65dAaxWZDktiuQHFEvA2TTwHdLa0TKB5DcArBIRS3Ab1oNcmvUuaN3C3ueB4%2F805QZzXZGECy5bNWn%2FXyuqOFEBzmMAYfAVJBqwJOIXgCxUX0DXobkAXCCD5Mhp%2FmPeKX%2BJRaq3fYMUaHRRL4KHBkG91t4APAT40OiztHxtS3rtQ8LhOH0VJXE9eMKHzfp1KpMDU1yYnjz3L2zHE8p0Z%2Ffx979x%2Bgp3eAeCKFAqrVCq7jrJBCeZlKucTyclGVl0uUSgVVKpVUoVCQhcKiVyqVvGql6rtu3bdty89ksjKdbnPTFZWgTlMJCGxqDq3UXJLFRQDOOTbxsEFtsUBFaI%2FKiL2y5PCVQvl%2B04piG4JQT5ae58apPpVn2nNwQmHmXYOCF6XqQt1T1H39qrmKt%2BXqzM05zORderO65umlPDZVoEtRyI0u8WocESPAIy0tX0JyF59WZ9f1PSwOIngI%2BFfAS5B8AYjs9Le%2BbBxVn0E%2FfRvzuQnRVBr%2BMUfV7215%2FGF%2BhYZ0ovEZfN7HZ9Tiur7vFq%2FH4GFgP%2FByJF%2FhPeJGPrX1EmA7GB0WFjo%2FyCsv89CXAP8yOixeNzKmvvF857EDrEtX8IITRWPJUK1WmJme5Pixpzlx%2FGkq5SK5XI7%2BgUHa23OYpsXycgnHWaBSXqZUKlAo5FWxkKdYLFAo5GW5vCyrtYqsV6u%2B73uelNKt1ar1SqVS8zzpAK5hRN1YLCp7enq8xPhykjqrgrnUBjEUUknqjg%2BuDzbMyCgHQwbOXI2abwQxG%2FpcPF9Sq7lkpiYo1iWFsstiwcGvO5iey4lKhFA8Qc6EiAlG1MKxonRFDUKWJhtDSQ6VL%2FLRzir%2FdS7KQIdFb8ZCJ%2B1ukINcNcdmm%2FKDILItcKfIYfOJYM9B8Cs8qB7atP9D6gRCvCG44T4WiPvfH7hL3AD8YbA3D%2FwcR9WXNu3%2FafU1%2FqO4BZdPIHgHkEVyP%2FDvrsBsfpeNSeI08H%2FReoAh4Ha0RaV1MWgCnx0dFreMjF3T2rLPAE9eNaJYUTBKpPSRvo%2FveUglqVarzM5Mcey5p3n2mSdZWJihLZUkk0ljmib5%2FBIL84tquVymWFxSxUJBFUsFVSmXlefWleM6frVScSqVsuO6ruv7yg2HbTcejzupVKpmWVZdCOEqpbxIJOKHw2HV2dkpa6fmKxK0scDQ6sXNRHspZfP%2B64jq4kC%2Bpy0sZmBZrSzXsE6dob1cYCjsMV%2BH%2FHKIR2ttyHAbabNEt1nmrBfmzu4SUUPywEI7PRmbAz0hEpYkWS6TKpfYF1I40uPpZ6v0t1tkYoJERDTns%2BnyQ25DorD4JJDTPwz3cnQLkmj9AeF%2Bjoge4Ld39EfwQuM%2BYSB5GEEsaLl7S5Jo4BNqmbeLO8nwUrSy82c5LP6Kh9Tf7XQqgdLxA2uaJfDHwAfW6iBGh8W%2FAT4LdLU0HwI%2BBPzmTufxPFAG3jkypv47XCWJoqFg9H1drLhWLWNaYYRRoby8zOzsDKdOHefZZ55kemqCcMgiEY%2BqQiFPpVrF96SqVGtyebnoFwsFr1qt%2BI7n%2BgLlJeIJP5VKupaZqHqeX%2FV931HK92zb9hOJhN%2Fe3u5Vq1XP9325tLSkAJXL5Th8%2BLD6k68ckWAEuSEC8%2BhGFg%2BltId3oMc4ZFWYcn2kYWLj4%2FmK4kKJ%2BW88A57PvhSUDUHRFXxj0aIeM3lRd4SQGSF1vEgmWmXZE1SVYLlQI9EeI2wJBktLdBaXiEqtPwsZMJ93WSh5uL5EKgNjy%2BWHTnCjtpIo7hKvRvAzACi%2BSZ6PXNaPGeZe6rwNeNHl%2Fh284LjIWxG8Ntj7W46q0W0f%2B4jyuUscRvENwETwYWDHRIHWS6y9v353ZEz9l406j4ypfxgdFncA32H1Mu%2FXR4fF%2FSNjavx5zGUn%2BMMGScBVIArf93Ech0qlokqlIouL89RqdSx7jlrdYWZmmrNnTnP27Ck1M30Rz3VUMpmUvu%2BpxcUFhRBSSeUJYfhK%2BfXl5eWq67p10zQ90zSdUMj2crmcF4vF3IWFBWd8fNyv1WoynU6rbDbLoUOH5Je%2F%2FGUeeeQRJYRgo5Kc64LCNlAaWgacJslrWOLWWJWpfAHXsokrj7zjUVRhqpi4nuJCVfDOJ6K8phvetcfhpsQMX0VRTGUpRyPkix5fdm1%2BtL3OsbLFkA1Jt0quVGiSBEDdh6GIT6Xua%2Bct1XAz33iOUiqU9EBtIVFIXtkUaAUfuGyt%2Fv2qzhHx%2B8DnLuu4awHBy5vbRovVZLt4UH2bI%2BILwE8DN3FExDi6sdlxK4wOCxN41Zrmx9DSxKYYGVMnRofFB2EVmRtoc%2BgLTRRHW3euKFFkMhkMw1Ce58mFhQV55swZf35%2BQRiGvqHK5bLOLzF1UeWXlpQQUkYiEa9cXq67ruNGIhEVDoc90zSdtrY2N5Foc2KxWNVxnHokEvFd1%2FXi8bhMp9Myk8morq4umclkuPfee5tsoJTi8OHDze3N0eJHseYGNIQiEhLUMxm%2BemGGOzJ1fso9wz%2B5WfKGol6o4GfDzPXv4bFTRUQN3vKqCD2ZEF%2Bq%2BVQqU9wSmuez0zHa4zG6qwt8sxymo1eSiJpEbJO22jKxNXkkFh24WIF%2BX%2BBLE53Ut%2BGoJbUzVjBXIXRyHKRCiC2IQnBr49IAj%2B7oh935cS80bgve68h1HpPbxeNoojDQlpGdnPtN0Fz%2BNPBXI2PbIuk%2Fh3VS323A53cwj52iODKm5lsbriRRqP7%2BfuU4juu6bnVxcXE5n8%2FbQhhI6eP72rxZr9epVCo%2BKD%2BdTnupVKruum65Xq%2FXfd%2F3bduW4XDYS6fTfjab9S3L8mZnZ%2F3Ozs7AMwpqtRqHDx9ussA991zew0MIAYYZFP8FpVqSTRp6PxKyGMzF%2BMpEN%2B3FCW5K%2BfxIaIH6IDxbnuJCNcKNgwkGuyJYpqAtahENC5arHv3npni6YDPpuGQyMQQL1B1JwlTc3V3EqfgIf%2F3fzIeeENQNi2xSh54LQye50S4VJg3JokkWhvbkbKTB2QS3BO8nL8sRqhVH1WmOiCW%2B9yMjNSkKnuZBtbNsPoqnWlSKt7AzothIgfn4dg4cGVOLo8PiPFrJ2cBtm%2FXfBnbitruwtuGKShQHDhyQCwsLtUKhsDgzM1NfWloyy%2BWykFJiGAaxWIx4PK7a2lKeUsrNZDJeR0eH47puvVQqeUIIGeTCVJ7nqc7OTrW4uKg6Ozu599571dYSwvahQGfdFiY6Ya5CqUbYuTZLGoZBR1uYQzfkeOAJePH8LEf2VAkbcGvS4ZbScc5V00zn%2BjAzSUKWwDAUycoyQ6LC54ppYimTeEcUf8IgbiruO5fmrdkyrzWXoCWHTt2Hx%2Bbh8xdMXnUozL7uKPGojWmuxHzod1ZIQgVE0eJE4csNGWNv8D79PC%2FbJFeDKNQGZU52gvuEAXQEY%2B483kJxbiVfYfPaXS7SG7RdzhJmLaH3XKL%2FWumlFfHL%2BN5NccWIQinFfffdp8LhcF0IIYvFYmVqakoUi0UBOvNVMplUHR0dJJNJ6bquF4lE5ODgoKxWq3J6elrddNNNAOuWEnD5UsNG8HxdJ1in5jdbEuGuwAhuSENAKCzY2x3jR17eyZOnw%2Fzis4vsVyXeMeRwMKXY6%2BXZM5XnwlyKqc4%2BRDzKSy6eAeCpZZvX7gnTkYkylUyS9hyyMcWN8fWSxNNL8NGnBB1tIV66J05fe5hwyGp6ZzbJIlC%2BNsjCMBsJ9fQZOJ6yhRCmUqtE3OPoNe7NbKa0uRTeLkJkOLjp54Jqc9skelljC9ovez4b4R4lOSKeRUsBN%2B14HJO9zT8Ig5M7HGWjyvK3bNK%2BCqPDIozOhdGKJ1q2SxsclmV1AFsrUpu0XxauqERxzz33qPvuu0%2FG4%2FG6aZqOUkpUKppI0%2Bk0qVSKjo4Ouru7VXt7u2ocs%2Fbv90qQwkYo1bEy0Ua%2BDCuo8tXIkt0MJtXvAixMEjGT%2FX0m2VSI%2Fb1xTl5c5n3nS7w1PMdrOySH0opBr8jgZJEaJhH0Pfq7%2FXmSskJ00uAlHS6d7TVMUV03J1fCN2bg0SWLV78oyqH%2BOKlYCFOvNJrKzBVdxQppaOX8SkiY42MBIaD1i55AE0Ub72Q%2FcOqyL1yaF6O9BjeGYrLlKdwFHLuM0bsv3WWbEDyJ4hZgL%2B8VKe7fQdU0xUta9r6zw5k8hjaFtkp4b6LViWxz3MH6a926%2FJlnPbJbjNexje%2B8JK641eOee%2B5RAEKIVU%2BuyclJJicneeyxx4DVisYrtaTYCkII8z%2F9GDbRFR1F0%2FIhdNCWJEilqYJ6HsF%2BJGSRazNoS4QY6orzooEk3zoWZXJighcvuRzKCl7SppokAfBDKRdwoWEt30C8lgqqHnzutGBvZ4Tb98foyUawbFOLNA1igI0lCyNYOgVmXC8gCiGEp1SwRtcuyxomP8pOiELwxkv0mGrZvpSYvIJfEmlCV0Y0BkDyZHCdBXVeD1x%2BSjrFK4IxfOo7U4iOjKnS6LA4Bry4pflnR4fFQyNj6v9tdlwgTdy%2FwUffbNme2%2BDz1wNf3GTYt15qvtvB9mv1XSZaIzo3el0D2DVXE6NecegKXga6aI8K3lFBdKqhSwgqYaAQmJZJOGTRmYlw05423viyLpYH9vK1Yoyn5xVfmd7%2BQnuxBn97Hp5agotV6EpZfPw2l9tSPlKCVFp%2FYhgmhmFhNrdNTMMK3s0gJylBBXjwJBb6abTyAJB8DZoeWR8KHKi2j%2FeIPuCDW%2FYRLToBwfC2xw7x7y9rLpeCwT%2Bxcq4f45fE5bmd3yXuQPATACge4%2BHn5RH5iQ3aHh4dFi%2FfoJ3RYZEC%2FoL1%2FirfZLVkM7PB4e8cHRbr9BSjw%2BIlwF3bm%2B7WuOZh5i8gTNdHVwlGE4GWLLQSExXEiRmAXKnJIRrrEpTOPCUFkbBgsDOObRo8HrP4wvE59hTz3JB06d3k%2BaiA00U4tgTLLkzXBN9eMvjVG30%2B8xoPw5T8fcGl4FXZN2SRS9pYVnAgLTkq1MpSwzAtTWoB3%2FsSE%2F2bWkIIQykleUg9wxHxceA3gDSKTwFv2%2FZV8%2FkE4hLr3CW%2BQ4ZxdGTkCO8Vv35Jsf%2FtwiTDL297HtvBg%2Bo7HBH3A78GHCTEB4D3b%2BvY94owiofQsp9ENCMnd4rGdW4lzkHg66PD4mPoGJDvAv3opeFvA3vWjFEBfn6NWfVJ4CQ6yreB7mDc3wzGHEBLGfewsWL1snFdEIXQ5o0mUQRGUbS5UW8bwVMZia7H0VTGN%2ByTIlAgaj1GNGTQn4vSqSrk0gM8eTrJgxOz%2FOdDy3z6GGRCEA6uri9hugJTVcFMTXC2anHRD3NzTvD5GY%2BapzjuRakg6O7yyVUk2YTAFtqPAlaUmKvOK5AoGnMPrB4WOk5AFzoFcPg9QrwZeDGCn%2BSI%2BDvg3RxVU2wGnSL%2FKIKfDFpcNtNTPKJ8DosHEHwUSFLnyxwRP8ZRtdF6Gt4rUmR5BLVKNL9SeD86bHs%2F8NscETYOH9xSOjgiBtHu04cAEDzAg%2Bp5%2BY6MjCk1OizuBJ5i9c1qo0Py37eNYX5rZEyd2GDcP2N10BvAzcDY85jylrguiAJ905ieDCQKwUqot7Gij2j2bDyjFYGrdEuJr%2BCGNdw6hlRk3TI37umjtyPGubMh4BgPnovhWTaxsBkoTrXgYhgC0xa0pS3e0BFlsDNKXsDUTBnLEPRGLPpyETKpCHbIxjADpzDYMDmNCCSKholUKX2ewWtlLfSwqvFu8Q4Mvoo2pb0FeJq7xPsx%2BEe6OMk9gXvnu8QQFq9H8RFW9A2fQNvyX73pFRZ8Gp2%2FYAD9hPwad4nfQPHNJmG8S2QxeBWCj6AjJGfQWvydZLveGEdVhbvEnSi%2BiHaF%2Fi1CvJW7xO%2Fg8i3%2BXOllkg5F3xcslf4IaAtGOEllm1LIJTAypiZGh8XbgL9kdWKYS8EDPjIypj65yecPA7%2FA9v0rgj%2FineN6IQoBiEaCq2b9TqFL%2Fa1YPETTiiAb4n5AJKppXRD4nkd08gLZpTlS9RLp%2BSmkbXN7yKXsmOwdynLzgTayiRCuJ1GAbQnCtkE0bBIJGSSjNsmoiQLyQylcT2Fb0Ba1ScZNbNNoropYRxJ6X5gmhhCoYOkhVTO9RZAUtAWfVo9xt3gpPkfRGvgsik%2FhA5OUOSKOA0OYtLP66%2F6SXt7LJF%2Fb8gofVQXeLV6B4PNBvMWLUIEy8Yg4CziYHGyZl4%2FgThQf5EoSBcCD6qvcLW7B5zPA64AbUfwvLOCImAfOcZiDQGrNuT5MmF%2FjqFqf42KHGBlTXwl0BR9DZ4y6FL4D3DkypjZ10AqUpa9H6zT%2B7RZjuegkN6%2BEQPeyQ1xXRLGyY6zcfEIQ5KkKOgmUUEFhYu3wJAyaegqkoK4EeTdEuRonUvE5rtooZrpQyufCYoUDfRa33dBOVyYCSuIrgSnAsgwsi6B%2BiX5XSpJJRPCDUoKG0ahvorTeBLXps8BYs%2FRQK%2Be58RGfVGeAYY6IX0DHHTRMZ3HWP50WgN%2FgqPpvABzZxgPp02qGt4t%2FTYYH0JmrGsrytY5LU8DP8aD6R46IrRWlO8Un1XGEuIPD3A38ASsSQwfrTYYXgSMc3bJwTx34ypq249uZysiYKgLvGh0Wf42%2BYV%2BG9qtIAD7wHNqk%2BnXg4ZGxS3uVjoypyuiwGAHuRmenehUrkafTaF3F%2B0fG1LdHh8Xvs3L%2BwDr%2FkO%2Bikwc3sM5hTVwjC8QLCiFEGEi847W88tZB4%2F8Mv%2FlnaB%2B6GSd%2FDrc8H%2FRp4Q7V0FOo5j40nu6CmuuxeHGBR8%2BUiCxMM2skSHdliUVNpIRsMsSBviRtCTuoBcKK74PRiDJZj0aC3vUSxCbnZZgYoQT1coEvfukfOLfAB%2F70S%2FJzwDJQUGrTdGpa9D7CgcDv4GYEL0ZSQjCNzkD9JY62%2FMG%2BR9wKtOFR49PbSKbyDhEnzG0YvBydr1JgcBHJVxB8sTn2EXEbBikkVY5uohc4ImIYgVu0x%2FkNk%2B1sBa04vQHFLQhuRnEAwSngcXye4M85%2FUKb4oJclnuAqZExtd7BZmdjDgDlkbENEvQ8T1wvRBECEr%2FwOl55y4Dx929880%2BTG7yZen4cWVkEoYJCwATOi40I00CJKVTz5lVK4Lo%2BS8sOZ6eXmVqokorZ9HZEScVDhExBOGwSC5mYho7XWM1Aq2ZGUwfRbGsoLzd%2Fgjd8SYUwwY5qovji33N%2Bgd%2F7kxWiKG5JFLvYxWXgell6SEDWHZ1f0fddUD5mNI1pR2m9WfU9HSg61cpTvqkrUBJTQXvcI9rmMlRxiYZN4tEQIbtRdFgvW5p6jYaJs5ljszEWTduECv6teFq2MopqjtG0gUiauT9VEKrueiw3znXlJHaxi%2BeP64ko%2FL%2F5JidfsU%2FMnj3%2BTK5z8KXCNCMoK6xjJ4IbsXHL0uIB2Ug%2F14AhFVZYEYlJ2lI%2BpiEwgkhPPYxs%2Bj00ZYZgOWOimiZYoUA2dBGqlSBWTKI0UnIpQEgtTShQhp6XUpK52WkA%2BehZ%2BS9ojbnPLlHs4griuiAKpZQUQniAV66p%2F3H%2B%2FJm7q3%2F7WTq7OoMq4q1ifsPBClByJfCjISGoRn%2FVekTz%2F8YnQptOgixZLRILjYhQmqUAN7RdrZpCoGxdiaegobosFIqMj49Trat%2F%2BvZZZtFE4Sm1VTabXezi8nBd6CgAhC6THo9B7H0%2FZdybivCLVyS8%2BXsAlbr65wf%2BUf3y9CIFtDdfRSlVv9bz2sUPDq4bogAQQsSAKNoRJ8xWEZHf%2B1Do%2Bftoe7mDrndRRRPFrkSxiyuG62Lp0QKHFa9FBc1wz%2B9XtvTQuggPfW51wNkliV1caVxXRKGU8oQQDZG8lSi%2BH28sgf79%2FODlAPVdk%2Bgurgauq6VHA4Ffhc1K8NRVqTd5ldFw125IFO4uSeziauG6JAoAoSseW%2Bgn8%2FcjUTSWUBLw16S%2F28Uurij%2BP4dVQiup8F5NAAAAAElFTkSuQmCC', | |
//send: 'data:image/gif;base64,R0lGODlhEgASAIQDADs7OxBpAI6OjjH%2FAMLCwtHR0dbW1tvb29zc3OLi4uPj4%2Bbm5urq6uzs7O%2Fv7%2FDw8PLy8vX19fb29vf39%2Fj4%2BPn5%2Bfr6%2Bvv7%2B%2Fz8%2FP39%2Ff7%2B%2Fv%2F%2F%2FzH%2FADH%2FADH%2FADH%2FACH%2BEUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAB8ALAAAAAASABIAAAV74CeOZGmeaAqsq8pGDqMA53oojERVEkSXAANi4ZhcBEjM5jdaMZDIzUYjZTYll4wUKsBYRQAMd2ORLk0AqtmCDLi%2FH8BmvAkMAvC0emu%2FB4ATAm6DbgN%2BJAAPE32GjYZ%2FiAyEg4%2BQTQcJDWUAfW5oBAUsH3aWQKIigyMhADs%3D', | |
//sendMessage: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAKLSURBVDiNfZPNbxNXFMV%2Fd2bMjDtYiZMYJRhivgoxiRtACV8SXXRLhdQdUrsICzb9D5DYVwWxqopYtkLdFLGBVt1WbVWh7mhiywgFMFEkKLKdEI8%2F5uPdLpwEVTE90tu8d9%2B595zznqgqg9BqncqJRCcskmlgHEbVUK84sf2nO7S4vFUngwiC4KMSxlwU0QNgJrq16iUAt1D8TdA1FetH3y%2F%2FAODs7Dw7I8bkxTJvgdlurXo2e7yDiEejLB97halVUd0TbMyk%2FMzSd%2F%2BZoNmcG3JTncvdWuXO1t7Q1F9q2%2FMCoLqmzUpWts52FYolVHV7tVrTJ%2BpLaBz%2B%2FMyY0Oj%2FIImfhPUl7smNWzc%2BtYW7URwNFyZXye99zfTIfbLHI0R2KNxGoyxE2flHjkmi7xeuXB3OjeUIw19Q85hg%2BT5h7zq73K8QkR2Xk6TSN7vjzVnGmBHPdXn40wNsywdsvAOfEyx%2FjZrmwO7r1WncQokg8BzLsiw%2B8H0OHTrMr78vYVkZRDL9jK3MeyUIWV79k8MCEBH25fPkxk7yePEltjXeL5IUqh0aZaFRFkzy5h2BTPCilt98Bwq2Y7M3f4SVlZNUqn9QnLpGo9zX7xVKQMRadQ8A7uSXWM4nNBpP%2BgSqSpzE9LodOt1xDk5%2Bxt%2BL99jtf4HrbuDUOwwP%2BcRjR0mlRuhF53DTl4CbmwQo7aBFc73J%2BTMXaLcDPG8%2FIk%2Bx5DnQwLY9RvwPefrMJZ0%2BQmbTnj6BUZLEMFOc5e3GOiZJQLIop0l0vh9dDL0IisdGeV5bRtX0CZyUU0%2BSeHT%2FvgJRFJL20ttG7fxmShj2OFg4TLvTxkk5dccYWfj29jd34yQefm9mA%2BDYzppBFv4FO4Au%2FTAT%2FmYAAAAASUVORK5CYII%3D', | |
//zoom_in : GS_HOST + 'images/zoom_in.png', | |
//zoom_out : GS_HOST + 'images/zoom_out.png', | |
}; | |
/* translations */ | |
$.gctour.i18n.de = { | |
'name': 'Deutsch', | |
'general': { | |
'save': 'Speichern', | |
'copy': 'Kopie', | |
'cancel': 'Abbrechen', | |
'close': 'Schließen', | |
'edit': 'bearbeiten', | |
'rename': 'umbenennen', | |
'remove': 'entfernen', | |
'load': 'laden', | |
'install': 'Installieren', | |
'findMe': 'Finde mich!', | |
'exampleCoords': 'z.B. N49° 26.082 E7° 46.587 oder 49.434701 7.776446', | |
'notLoggedIn': 'Sie müssen sich auf einer Seite von geocaching.com befinden und dort angemeldet sein.', | |
'pleaseWait': 'Bitte warten - Daten werden geladen...' | |
}, | |
'container': { | |
'toolbar': { | |
'newList': 'Neue Tour erstellen', | |
'openTour': 'Eine Tour laden', | |
'downloadTour': { | |
'caption': 'Tour runterladen', | |
'webcodeDownloadHelp': 'Bitte gib hier den Webcode an, den du von deinem Freund bekommen hast und drücke dann auf "Tour runterladen".', | |
'webcodeerror': 'Der angegebene Webcode existiert leider nicht!', | |
'webcodesuccess': ' wurde erfolgreich geladen!', | |
'webcodeOld': '\n !!ACHTUNG!!\nEs handelt sich bei diesem Webcode um eine alte Tour. Um sie auch mit den Vorzügen von GCTour 2.0 nutzen zu können musst du sie bitte jetzt erneut hochladen.' | |
}, | |
'showSettings': 'Einstellungen anzeigen', | |
'saveSettings': 'Touren und Einstellungen sichern' | |
}, | |
'tourHeader': { | |
'sendToGps': 'an GPSr senden', | |
'downloadGpx': 'GPX downloaden', | |
'saveAsBookmarklist': { | |
'title': 'als Bookmarkliste speichern (PMO)', | |
'caption': 'Tour als Bookmarkliste speichern', | |
'success': 'Tour als Bookmarkliste gespeichert', | |
'duplicate': 'Die Bookmarkliste dieser Tour wurde bereits angelegt' | |
}, | |
'makeMap': { | |
'caption': 'auf Karte anzeigen', | |
'wait': 'Verfügbarkeit der Karte wird getestet.' | |
}, | |
'upload': { | |
'caption': 'Tour hochladen', | |
'tourUploaded1': '<br>Die Tour wurde erfolgreich hochgeladen! Der Webcode lautet:<br><b>', | |
'tourUploaded2': '</b><br><br>Die Onlineabfrage kann unter <a href="' + GCTOUR_HOST + 'tour/xWEBCODEx" target="_blank">' + GCTOUR_HOST + 'tour/xWEBCODEx</a> geschehen.<br>Wichtig: Bitte Webcode notieren um die Tour wieder aufzurufen!!', | |
'tourUploadPMO': ' PM Only Cache(s) wurden nicht hochgeladen (leider kein Zugriff als Basis-Mitglied)' | |
}, | |
'addOwnWaypoint': 'eigenen Wegpunkt hinzufügen' | |
}, | |
'cacheList': { | |
'logYourVisit': 'logge deinen Besuch', | |
'moveToList': 'in andere Tour verschieben', | |
'removeFromList': 'aus Tour entfernen' | |
} | |
}, | |
'settings': { | |
'caption': 'Einstellungen', | |
'language': { | |
'header': 'Sprache', | |
'select': 'Sprache wählen' | |
}, | |
'printview': { | |
'header': 'Druckansicht', | |
'printMinimal': 'Minimierte Druckansicht', | |
'printMinimalDesc': 'Beinhaltet nur noch Hint und Spoiler zu jedem Geocache.', | |
'logCount': 'Anzahl der Logs in Druckansicht', | |
'logCounts': ['keine', 'alle', 'anzeigen'], | |
'fontSize': 'Schriftgröße', | |
'decryptHints': 'Hints entschlüsseln', | |
'decryptHintsDesc': 'Die Hinweise werden schon mittels Rot13 auf der Druckansicht entschlüsselt.', | |
'editDescription': 'Beschreibung editierbar', | |
'editDescriptionDesc': 'Die Beschreibung lässt sich komplett nach eigenem Belieben anpassen.', | |
'showSpoiler': 'Spoiler Bilder anzeigen', | |
'showSpoilerDesc': 'Es werden die Spoiler mitgedruckt.', | |
'additionalWaypoints': 'Eigene Wegpunkte anzeigen', | |
'additionalWaypointsDesc': 'In der Druckansicht findet sich eine Tabelle mit allen "eigenen Wegpunkten".', | |
'additionalWaypoints2': 'Eigene Wegpunkte auf Titelseite einsortieren', | |
'additionalWaypoints2Desc': 'Eigene Wegpunkte werden auf der Titelseite in die Cache-Tabelle einsortiert. Ansonsten wird eine eigene Tabelle angelegt.', | |
'loggedVisits': 'Log-Counter anzeigen', | |
'loggedVisitsDesc': 'Eine Übersicht wie oft der Geocache schon gefunden wurde.', | |
'pageBreak': 'Seitenumbruch nach Geocache', | |
'pageBreakDesc': 'Es wird nach jedem Geocache eine neue Seite angefangen. Sieht man erst beim Ausdrucken.', | |
'pageBreakAfterMap': 'Seitenumbruch nach Übersichtskarte', | |
'pageBreakAfterMapDesc': 'Es wird ein Seitenumbruch nach der Übersichtseite gemacht, um das Deckblatt abzuheben.', | |
'frontPage': 'Titelseite', | |
'frontPageDesc': 'Es wird eine Titelseite erzeugt mit allen Geocaches, Index und Platz für Notizen.', | |
'outlineMap': 'Übersichtskarte für alle Caches', | |
'outlineMapDesc': 'Auf der Titelseite wird eine Karte mit allen Geocaches in der Tour angezeigt.', | |
'outlineMapSingle': 'Übersichtskarte für jeden Cache', | |
'outlineMapSingleDesc': 'Unter jedem Geocache erscheint eine Karte mit seinen "Additional Waypoints".', | |
'showCacheDetails': 'Cache-Listings und eigene Wegpunkte drucken', | |
'showCacheDetailsDesc': 'Alle Geocache-Listings und eigene Wegpunkte der Tour werden mitgedruckt (wenn deaktiviert, wird nur die Titelseite gedruckt).' | |
}, | |
'map': { | |
'header': 'Karte', | |
'type': 'Standard Kartentyp', | |
'types': { | |
'Google Karte': 'roadmap', | |
'Google Satellit': 'satellite', | |
'Google Hybrid': 'hybrid', | |
'Google Gelände': 'terrain', | |
'Topo Deutschland': 'oda', | |
'OSM Mapnik': 'mapnik', | |
'OSM DE': 'osmde', | |
'OSM Fahrrad': 'osmaC', | |
'OSM ÖPNV': 'osmaP' | |
}, | |
'size': 'Standard Kartengröße', | |
'geocacheid': 'Geocache Code anzeigen', | |
'geocacheidDesc': 'Es wird immer der GCCode (z.B. GC0815) mit auf der Karte angezeigt.', | |
'geocachename': 'Geocache Namen anzeigen', | |
'geocachenameDesc': 'Der Name eines Geocache wird zusätzlich mit eingeblendet.', | |
'geocacheindex': 'Geocache Index anzeigen', | |
'geocacheindexDesc': 'Die Postion innerhalb der Tour wird mit angezeigt.', | |
'awpts': 'Additional Waypoints anzeigen', | |
'awptsDesc': 'Wenn aktiviert, dann werden die "Additional Waypoints" eines Geocaches mit angezeigt.', | |
'awpt_name': 'Additional Waypoints Namen einblenden', | |
'awpt_nameDesc': 'Der Name eines "Additional Waypoints" wird mit angezeigt.', | |
'awpt_lookup': 'Additional Waypoints Lookup einblenden', | |
'awpt_lookupDesc': 'Der Lookupcode eines "Additional Waypoints" wird mit angezeigt.', | |
'owpts': 'Eigene Wegpunkte einblenden', | |
'owptsDesc': 'Wenn du "Eigene Wegpunkte" mit in deiner Tour hast, so werden diese auch mit auf der Karte angezeigt.', | |
'owpt_name': 'Namen eigener Wegpunkte anzeigen', | |
'owpt_nameDesc': 'Zusätzlich kann man sich noch den Namen zu jedem Wegpunkt anzeigen lassen.' | |
}, | |
'gpx': { | |
'html': 'Beschreibung mit HTML', | |
'htmlDesc': 'Manche Geräte/Programme haben Probleme beim Anzeigen eines Geocaches mit HTML-Formatierung. Wenn du nur noch kryptische Beschreibungen siehst, dann Bitte diese Option deaktivieren.', | |
'wpts': 'Additional-Waypoints exportieren', | |
'wptsDesc': 'Additional-Waypoints werden als extra Wegpunkt mit in die GPX exportiert. Damit hat man jeden Parkplatz direkt auf dem Gerät.', | |
'attributesToLog': 'Cache-Attribute als erster Logeintrag', | |
'attributesToLogDesc': 'Cache Attribute werden zusätzlich als erster Log eingetragen.', | |
'stripGC': 'Entferne "GC" in GC-Code', | |
'stripGCDesc': 'Alte Geräte haben Probleme mit Wegpunkten deren Name länger als 8 Zeichen sind. Wenn du so ein altes Garmin hast, dann bitte diese Option anwählen!', | |
'maxLogCount': 'Max. Anzahl der Logs', | |
'prefixFavScore': 'Zeige den Prozentwert der Favoritenpunkte vor dem Cachenamen', | |
'prefixFavScoreDesc': 'Im Geocaching-Menü des GPSr wird vor dem Cachenamen der Prozentwert der Favoritenpunkte angezeigt (z.B. "8%GC10000 - A New Beginning"). Damit lässt sich leicht erkennen, wie ein Cache bewertet wurde.' | |
}, | |
'gps': { | |
'header': 'An GPSr senden', | |
'selectSend2GPS': 'Methode wählen' | |
}, | |
'theme': { | |
'select': 'Theme wählen' | |
}, | |
'exportimport': { | |
'export': 'Export der GCTour-Einstellungen (inklusive aller Touren)', | |
'import': 'Import der GCTour-Einstellungen (inklusive aller Touren)' | |
} | |
}, | |
'autoTour': { | |
'wait': 'Bitte warten - autoTour wird erzeugt!', | |
'radius': 'Radius', | |
'center': 'Mittelpunkt', | |
'help': 'Koordinaten oder Adresse: <i>N52° 30.757 E13° 19.309</i> oder <i>Berlin Ernst-Reuter-Platz</i>', | |
'refresh': 'Berechne eine autoTour mit diesen Werten!', | |
'cacheCounts': 'Geschätzte Anzahl <i>aller</i> Caches in dieser Region:', | |
'duration': 'Geschätzte Dauer der Erzeugung dieser autoTour:', | |
'filter': { | |
'type': 'Typ', | |
'size': 'Größe', | |
'difficulty': 'Schwierigkeit', | |
'terrain': 'Gelände', | |
'special': { | |
'caption': 'Spezial', | |
'pm': { | |
'not': 'Ist kein PM Cache', | |
'ignore': 'Ist PM oder kein PM Cache', | |
'only': 'Ist PM Cache' | |
}, | |
'notfound': 'Nicht gefunden', | |
'isActive': 'Aktiv', | |
'minFavorites': 'Mindestzahl Favoriten' | |
} | |
} | |
}, | |
'dlg': { | |
'newVersion': { | |
'caption': 'Neue Version verfügbar', | |
'content': 'Es gibt eine neue Version von GCTour.\nZum update gehen? \n\n', //ohne Anwendung | |
'changelog': 'Neue GCTour-Version ' + VERSION + ' installiert. Übersicht der Änderungen: ' | |
}, | |
'error': { | |
'content': '<img src="' + $.gctour.img.sad + '"> Leider ist ein Fehler aufgetreten!<br/>' + | |
'Versuch es einfach noch einmal oder suche nach einem <a href="#" id="gctour_update_error_dialog">Update</a>!<br/><br/>' | |
} | |
}, | |
'notifications': { | |
'addgeocache': { | |
'success': { | |
'caption': '{0} wurde hinzugefügt!', | |
'content': '<b>{0}</b> enthält jetzt auch <b>{1}</b>.' | |
}, | |
'contains': { | |
'caption': '{0} wurde <i>nicht</i> hinzugefügt!', | |
'content': '<b>{0}</b> enthält <b>{1}</b> schon.' | |
} | |
} | |
}, | |
'units': { | |
'km': 'Kilometer', | |
'mi': 'Meilen' | |
}, | |
'send2cgeo': { | |
'title': 'an c:geo senden', | |
'noWP': 'ohne eigene Wegpunkte', | |
'usage': '<li>c:geo auf dem Mobilgerät starten und in eine Cacheliste wechseln</li>' + | |
'<li><i>Menü → Importieren → Importiere von send2cgeo</i></li>' + | |
'<li>Die Tour (ohne eigene Wegpunkte) wird automatisch in die ausgewählte Liste geladen</li>' + | |
'<li>c:geo wartet noch 3 Minuten, um weitere Caches herunterzuladen</li>', | |
'overview': 'Übersicht', | |
'setup': { | |
'header': 'Setup', | |
'registerBrowser': 'Hier klicken um den Browser für Send2cgeo zu registrieren', | |
'desc1': '<li>c:geo auf dem Androidgerät starten, dann <i>Menu → Einstellungen → Dienste → Send to c:geo</i></li>' + | |
'<li><i>Registrierung anfordern</i> wählen, es öffnet sich ein Fenster mit einer fünfstelligen PIN</li>', | |
'desc2': 'PIN hier eingeben:', | |
'desc3': 'PIN senden und damit Gerät hinzufügen' | |
}, | |
'register': 'Browser noch nicht für Send2cgeo registriert - bitte zum "Setup" Tab wechseln und den Browser registrieren.', | |
'senderror': 'Ein Fehler ist aufgetreten, bitte später noch einmal versuchen.' | |
}, | |
'marker': { | |
'coord': 'Koordinaten', | |
'content': 'Inhalt', | |
'contentHint': 'wird in Druckansicht angezeigt', | |
'type': 'Typ' | |
}, | |
'update': { | |
'dialog': '<div><p>Es ist eine neue Version von <a target="_blank" href="https://gctour.geocaching.cx/"><b>GCTour</b></a> verfügbar.</p><p>Du verwendest Version <b>###VERSION_OLD###</b>, die aktuellste Version ist <b>###VERSION_NEW###</b>.</p><div class="dialogFooter"></div>', | |
'upToDate': 'GCTour ' + VERSION + ' ist aktuell!' | |
}, | |
'printview': { | |
'found': 'Fund', | |
'note': 'Notiz', | |
'marker': 'Eigene Wegpunkte', | |
'removeMap': 'Karte entfernen', | |
'zoomMap': 'Diese Karte in einem neuem Tab öffnen.', | |
'dontPrintHint': '<b>Hinweis:</b><br/>Elemente in einem solchen Kasten werden <u>nicht</u> mit gedruckt!', | |
'reloadMap': 'Karte neu laden', | |
'print': 'Druck starten', | |
'mapHeight': 'Höhe', | |
'printWidth': 'Breite' | |
}, | |
'cache': { | |
'addToTour': 'Zur Tour hinzufügen', | |
'directPrint': 'Drucke diesen Geocache', | |
'moveCoords': 'Verschiebe die Koordinaten', | |
'movedCoords': 'Die Koordinaten zu diesem Geocache wurden verschoben!', | |
'moveCoordsHelp': 'Hier hast du die Möglichkeit die original Koordinaten dieses Geocaches durch neue zu ersetzen. Diese werden dann in der Druckansicht, wie auch in der GPX verwendet. Praktisch bei der Lösung eines Mysteries.', | |
'deleteCoords': 'Koordinaten löschen', | |
'originalCoords': 'Originale Koordinaten', | |
'newCoords': 'Neue Koordinaten', | |
'addToCurrentTour': 'Zur <b>aktuellen</b> Tour hinzufügen', | |
'addToNewTour': 'Zu <b>neuer</b> Tour hinzufügen', | |
'shown': 'Angezeigte Caches', | |
'marked': 'Markierte Caches', | |
'all': 'Alle Caches' | |
}, | |
'tour': { | |
'newDialog': 'Bitte gib einen Namen für die neue Tour ein ...', | |
'copy': 'Tour kopieren', | |
'remove': 'diese Tour löschen', | |
'removeDialog': 'Soll die Tour wirklich gelöscht werden?', | |
'empty': 'Die Tour ist leer.' | |
} | |
}; | |
$.gctour.i18n.en = { | |
'name': 'English', | |
'general': { | |
'save': 'Save', | |
'copy': 'Copy', | |
'cancel': 'Cancel', | |
'close': 'Close', | |
'edit': 'Edit', | |
'rename': 'Rename', | |
'remove': 'Remove', | |
'load': 'load', | |
'install': 'Install', | |
'findMe': 'Find me!', | |
'exampleCoords': 'e.g. N49° 26.082 E7° 46.587 or 49.434701 7.776446', | |
'notLoggedIn': 'You must be on a geocaching.com page and logged in there.', | |
'pleaseWait': 'Please wait - loading data ...' | |
}, | |
'container': { | |
'toolbar': { | |
'newList': 'New tour', | |
'openTour': 'Load a tour', | |
'downloadTour': { | |
'caption': 'Download Tour', | |
'webcodeDownloadHelp': 'Please enter here the webcode you receive from your friend and click on "Download tour".', | |
'webcodeerror': 'The choosen webcode does not exist!', | |
'webcodesuccess': ' was successfully loaded!', | |
'webcodeOld': '\n !!ATTENTION!!\nThis webcode is connected with an old tour. To get all benefits of GCTour 2.0 you must upload this tour again.' | |
}, | |
'showSettings': 'Show settings', | |
'saveSettings': 'Backup tours and settings', | |
'homepage': 'GCTour Home' | |
}, | |
'tourHeader': { | |
'sendToGps': 'Send to GPSr', | |
'downloadGpx': 'Download GPX', | |
'saveAsBookmarklist': { | |
'title': 'Save as bookmark list (PMO)', | |
'caption': 'Save tour as bookmark list', | |
'success': 'Tour saved as bookmark list', | |
'duplicate': 'A bookmark list for this tour already exists' | |
}, | |
'makeMap': { | |
'caption': 'View on map', | |
'wait': 'Testing availablity of this map' | |
}, | |
'upload': { | |
'caption': 'Upload Tour', | |
'tourUploaded1': '<br>Uploading tour was successful! Webcode:<br><b>', | |
'tourUploaded2': '</b><br><br>You can view the tour at <a href="' + GCTOUR_HOST + 'tour/xWEBCODEx" target="_blank">' + GCTOUR_HOST + 'tour/xWEBCODEx</a>.<br>Important: Please note webcode in order to retrieve the tour!!', | |
'tourUploadPMO': ' PM Only Cache(s) not uploaded (unfortunately no access as Base Member)' | |
}, | |
'addOwnWaypoint': 'Add own waypoint' | |
}, | |
'cacheList': { | |
'logYourVisit': 'Log your visit', | |
'moveToList': 'Move to another tour', | |
'removeFromList': 'Remove from tour' | |
} | |
}, | |
'settings': { | |
'caption': 'Settings', | |
'language': { | |
'header': 'Language', | |
'select': 'Select language' | |
}, | |
'printview': { | |
'header': 'Printview', | |
'printMinimal': 'Minimal printview', | |
'printMinimalDesc': 'This contains only the hint and spoiler of a geocache.', | |
'logCount': 'Number of logs in printview', | |
'logCounts': ['none', 'all', 'show'], | |
'fontSize': 'Font size', | |
'fontSizes': ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'], | |
'decryptHints': 'Decrypt hints', | |
'decryptHintsDesc': 'Hints will be already decrypted in the printout.', | |
'editDescription': 'Description editable', | |
'editDescriptionDesc': 'The description can be edited in the way you want it.', | |
'showSpoiler': 'Display spoiler', | |
'showSpoilerDesc': 'Spoiler images will be on the printout.', | |
'additionalWaypoints': 'Show additional waypoints', | |
'additionalWaypointsDesc': 'The printview will contain a table with all "Additional waypoints" from a geocache.', | |
'additionalWaypoints2': 'Add own waypoints to cache table', | |
'additionalWaypoints2Desc': 'Own waypoints will be added to the cache table on front page. Otherwise an extra table will be added.', | |
'loggedVisits': 'Show log counter', | |
'loggedVisitsDesc': 'This will show the "Find counts" overview.', | |
'pageBreak': 'Page break after cache', | |
'pageBreakDesc': 'After each geocache there will be a page break. Visiable after printing.', | |
'pageBreakAfterMap': 'Page break after map', | |
'pageBreakAfterMapDesc': 'It will be a page break after the overview to separate it from the geocaches.', | |
'frontPage': 'Front page', | |
'frontPageDesc': 'An overview will be generated containing the complete list of geocaches including index and space to take notes. ', | |
'outlineMap': 'Outline map for all caches', | |
'outlineMapDesc': 'The overview will contain a map with all geocaches.', | |
'outlineMapSingle': 'Outline map for every cache', | |
'outlineMapSingleDesc': 'After each geocache a map containing the geocache and its "Additional waypoints" will be shown.', | |
'showCacheDetails': 'Print cache listings and own waypoints', | |
'showCacheDetailsDesc': 'All geocache listings and own waypoints will be printed (if not set just the front page will be printed).' | |
}, | |
'map': { | |
'header': 'Map', | |
'type': 'Default map type', | |
'types': { | |
'Google Map': 'roadmap', | |
'Google Satellite': 'satellite', | |
'Google Hybrid': 'hybrid', | |
'Google Terrain': 'terrain', | |
'Topo Germany': 'oda', | |
'OSM Mapnik': 'mapnik', | |
'OSM German style': 'osmde', | |
'OSM Cycle': 'osmaC', | |
'OSM Public Transport': 'osmaP' | |
}, | |
'size': 'Default map size', | |
'sizes': ['large', 'medium', 'small'], | |
'geocacheid': 'Show geocache id', | |
'geocacheidDesc': 'The GCCode (eg. GC0815) will be shown on the map.', | |
'geocacheindex': 'Show geocache index', | |
'geocacheindexDesc': 'The position of each waypoint in the current tour will be shown on the map.', | |
'geocachename': 'Show geocache name', | |
'geocachenameDesc': 'The name of an geocache will be shown on the map.', | |
'awpts': 'Display addtional waypoints', | |
'awptsDesc': 'If enabled, additional waypoints will be shown on the map.', | |
'awpt_name': 'Show name of the additional waypoints', | |
'awpt_nameDesc': 'The name of the additional waypoints will be shown on the map.', | |
'awpt_lookup': 'Show lookup code of additional waypoints', | |
'awpt_lookupDesc': 'The lookup code of the additional waypoints will be shown on the map.', | |
'owpts': 'Display own waypoints', | |
'owptsDesc': 'Own waypoints in the current tour will be shown on the map.', | |
'owpt_name': 'Show name of own waypoints', | |
'owpt_nameDesc': 'Display the name of your own waypoints' | |
}, | |
'gpx': { | |
'header': 'GPX', | |
'html': 'Description with HTML', | |
'htmlDesc': 'Some programs/GPSr have problems to show geocaches when their description is HTML formatted. If you only see scrabbled descriptions then please disable this option.', | |
'wpts': 'Export additional waypoints', | |
'wptsDesc': 'Additional waypoints will be exported as extra waypoint to the GPX. You will see every parking place on your unit.', | |
'attributesToLog': 'Create log with cache attributes', | |
'attributesToLogDesc': 'Cache attributes are also included as a first log.', | |
'stripGC': 'Strip "GC" in GC-Code', | |
'stripGCDesc': 'Older GPSr still have problems with waypoints having names longer than 8 characters. Please use this option if you own such an unit.', | |
'maxLogCount': 'max number of logs', | |
'prefixFavScore': 'Show favorite score in front of cache name', | |
'prefixFavScoreDesc': 'When in Geocaching menu of GPSr, the favorite score is shown in front of the cache name (e.g. "8%GC10000 - A New Beginning"). Thereby it\'s easy to see how a cache has been rated.' | |
}, | |
'gps': { | |
'header': 'Send to GPSr', | |
'selectSend2GPS': 'Select method' | |
}, | |
'theme': { | |
'header': 'Themes', | |
'select': 'Select Theme' | |
}, | |
'exportimport': { | |
'header': 'Export/Import', | |
'export': 'Export of GCTour settings (including all tours)', | |
'import': 'Import of GCTour settings (including all tours)' | |
} | |
}, | |
'autoTour': { | |
'title': 'autoTour', | |
'wait': 'Please wait - generating autoTour!', | |
'radius': 'Radius', | |
'center': 'Center', | |
'help': 'Coordinates or address: <i>N51° 30.348 W0° 04.509</i> or <i>London Tower Bridge</i>', | |
'refresh': 'Calculate an autoTour with these values!', | |
'cacheCounts': 'Estimated <i>total number</i> of caches in this region:', | |
'duration': 'Estimated time to generate this autoTour:', | |
'filter': { | |
'type': 'Type', | |
'size': 'Size', | |
'difficulty': 'Difficulty', | |
'terrain': 'Terrain', | |
'special': { | |
'caption': 'Special', | |
'pm': { | |
'not': 'Is not a PM cache', | |
'ignore': 'Is PM or not PM cache', | |
'only': 'Is PM cache' | |
}, | |
'notfound': 'I haven\'t found ', | |
'isActive': 'is Active', | |
'minFavorites': 'min. Favorites' | |
} | |
} | |
}, | |
'dlg': { | |
'newVersion': { | |
'caption': 'New version available', | |
'content': 'There is a new version of GCTour.\nDo you want to update? \n\n', | |
'changelog': 'New GCTour version ' + VERSION + ' installed. Overview of changes: ' | |
}, | |
'error': { | |
'content': '<img src="' + $.gctour.img.sad + '"> I\'m sorry but an error occurs.<br/>' + | |
'Please just try again, or look for an <a href="#" id="gctour_update_error_dialog">update</a>!<br/><br/>' | |
} | |
}, | |
'notifications': { | |
'addgeocache': { | |
'success': { | |
'caption': '{0} added successfully!', | |
'content': '<b>{0}</b> now also contains <b>{1}</b>.' | |
}, | |
'contains': { | |
'caption': '{0} was <i>not</i> added!', | |
'content': '<b>{0}</b> contains <b>{1}</b>.' | |
} | |
} | |
}, | |
'units': { | |
'km': 'Kilometer', | |
'mi': 'Miles' | |
}, | |
'send2cgeo': { | |
'title': 'Send to c:geo', | |
'noWP': 'no own waypoints', | |
'usage': '<li>Start c:geo on your device and go to a list of saved caches</li>' + | |
'<li>Select Menu → Import → Import from send2cgeo</li>' + | |
'<li>The tour (without own waypoints) will automatically be downloaded from geocaching.com to the list of saved caches</li>' + | |
'<li>c:geo will continue to wait for more caches to be downloaded for 3 minutes</li>', | |
'overview': 'Overview', | |
'setup': { | |
'header': 'Setup', | |
'registerBrowser': 'Click to register this browser for Send2cgeo', | |
'desc1': '<li>Run c:geo on your android device and select <i>Menu → Settings → Services → Send to c:geo</i></li>' + | |
'<li>Select <i>Request Registration</i>, you will get an info window showing a five digit PIN</li>', | |
'desc2': 'Enter PIN here:', | |
'desc3': 'Send PIN and add device' | |
}, | |
'register': 'Browser is not registered for Send2cgeo yet - please switch to "Setup" tab and register your browser.', | |
'senderror': 'An error occurred, please try again later.' | |
}, | |
'marker': { | |
'coord': 'Coordinates', | |
'content': 'Content', | |
'contentHint': 'will be shown in printview', | |
'type': 'Type' | |
}, | |
'update': { | |
'dialog': '<div><p>There is a new version of <a target="_blank" href="https://gctour.geocaching.cx/"><b>GCTour</b></a> available for installation.</p><p>You currently have installed version <b>###VERSION_OLD###</b>, the latest version is <b>###VERSION_NEW###</b>.</p><div class="dialogFooter"></div>', | |
'upToDate': 'GCTour ' + VERSION + ' is up to date!' | |
}, | |
'printview': { | |
'found': 'Found', | |
'note': 'Note', | |
'marker': 'Own waypoints', | |
'removeMap': 'Remove map', | |
'zoomMap': 'Open this map in a new tab.', | |
'dontPrintHint': '<b>Information:</b><br/>Elements in such a box will <u>not</u> be printed!', | |
'reloadMap': 'Reload map', | |
'print': 'Start printing', | |
'mapHeight': 'Height', | |
'printWidth': 'Width' | |
}, | |
'cache': { | |
'addToTour': 'Add to tour', | |
'directPrint': 'Print this geocache', | |
'moveCoords': 'Move the coordinates', | |
'movedCoords': 'The coordinates to this geocaches are moved.', | |
'moveCoordsHelp': 'You have the possibility to change the original coordinates of this geocache. These will then be used in printview and also in the GPX file. This is quiet handy if you solve a mystery.', | |
'deleteCoords': 'Delete coordinates', | |
'originalCoords': 'Original coordinates', | |
'newCoords': 'New coordinates', | |
'addToCurrentTour': 'Add to <b>current</b> tour', | |
'addToNewTour': 'Add to <b>new</b> tour', | |
'shown': 'Shown geocaches', | |
'marked': 'Marked geocaches', | |
'all': 'All caches' | |
}, | |
'tour': { | |
'newDialog': 'Please enter a name for the new tour ...', | |
'copy': 'Copy tour', | |
'remove': 'Delete this tour', | |
'removeDialog': 'Are you sure to delete this tour?', | |
'empty': 'The tour is empty.' | |
} | |
}; | |
$.gctour.i18n.fr = { | |
'name': 'Français', | |
'general': { | |
'save': 'Enregistrer', | |
'copy': 'Dupliquer', | |
'cancel': 'Abandonner', | |
'close': 'Fermer', | |
'edit': 'Editer', | |
'rename': 'Renommer', | |
'load': 'charger', | |
'install': 'Installer', | |
'findMe': 'Localisez-moi!', | |
'exampleCoords': 'p. ex. N49° 26.082 E7° 46.587 ou 49.434701 7.776446', | |
'notLoggedIn': 'Vous devez être connecté à geocaching.com, merci de vous connecter.', | |
'pleaseWait': 'Veuillez patienter...' | |
}, | |
'container': { | |
'toolbar': { | |
'newList': 'Nouveau tour', | |
'openTour': 'Ouvrir un Tour', | |
'downloadTour': { | |
'caption': 'Télécharger un Tour', | |
'webcodeDownloadHelp': 'Entrer ici le webcode que vous avez reçu et cliquer sur "Télécharger le Tour".', | |
'webcodeerror': 'Le webcode saisi est inexistant!', | |
'webcodesuccess': ' a été chargé avec succès!', | |
'webcodeOld': '\n !!ATTENTION!!\nCe webcode corrrespond à un ancien tour. Pour profiter pleinement de GCTour 2.0 vous devez soumettre de nouveau ce Tour.' | |
}, | |
'showSettings': 'Configurer' | |
}, | |
'tourHeader': { | |
'sendToGps': 'Transférer vers le GPSr', | |
'downloadGpx': 'Télécharger le GPX', | |
'makeMap': { | |
'caption': 'Voir sur la carte', | |
'wait': 'Vérification de la disponibilité et création de la carte... ' | |
}, | |
'upload': { | |
'caption': 'Soumettre un Tour', | |
'tourUploaded1': '<br>Le Tour a été correctement transféré! Webcode:<br><b>', | |
'tourUploaded2': '</b><br><br>Vous pouvez visualiser ce Tour sur <a href="' + GCTOUR_HOST + 'tour/xWEBCODEx" target="_blank">' + GCTOUR_HOST + 'tour/xWEBCODEx</a>.<br>Important: Notez bien le webcode pour une utilisation ultérieure!!' | |
}, | |
'addOwnWaypoint': 'Ajouter un Waypoint personnel' | |
}, | |
'cacheList': { | |
'logYourVisit': 'Loguer votre visite', | |
'removeFromList': 'Supprimer du tour' | |
} | |
}, | |
'settings': { | |
'caption': 'Configuration', | |
'language': { | |
'header': 'Langue', | |
'select': 'Choisir langue' | |
}, | |
'printview': { | |
'header': 'Version imprimable', | |
'printMinimal': 'Version imprimable minimaliste', | |
'printMinimalDesc': 'Ne contient que l\'indice et le spoiler de la cache.', | |
'logCount': 'Nombre de logs à inclure dans la version imprimable', | |
'logCounts': ['aucun', 'tous', 'afficher'], | |
'fontSize': 'Taille des caractères', | |
'decryptHints': 'Decryptage des hints', | |
'decryptHintsDesc': 'Les indices seront décryptés dans la version imprimable.', | |
'editDescription': 'Description éditable', | |
'editDescriptionDesc': 'La description est éditable comme bon vous semble.', | |
'showSpoiler': 'Affichage des spoilers', | |
'showSpoilerDesc': 'Les images Spoiler seront visibles dans la version imprimables.', | |
'additionalWaypoints': 'Affichage des Waypoints additionnels', | |
'additionalWaypointsDesc': 'La version imprimable contiendra un tableau avec tous les "Waypoints additionnels" de la cache.', | |
'loggedVisits': 'Affichage du nombre de logs', | |
'loggedVisitsDesc': 'Affiche un récapitulatif des "Trouvé(s)".', | |
'pageBreak': 'Saut de page entre les caches', | |
'pageBreakDesc': 'Il y aura un saut de page après chaque cache. Visible seulement à l\'impression.', | |
'pageBreakAfterMap': 'Saut de page après la carte', | |
'pageBreakAfterMapDesc': 'Il y aura un saut de page après la vue globale du Tour pour la séparer des pages de caches qui suivent.', | |
'frontPage': 'Page d\'accueil', | |
'frontPageDesc': 'Une vue d\'ensemble sera générée et incluera un index avec des cases dédiées à la prise de notes.', | |
'outlineMap': 'Vue d\'ensemble de toutes les caches du Tour', | |
'outlineMapDesc': 'La vue d\'ensemble incluera une carte avec toutes les caches.', | |
'outlineMapSingle': 'Vue d\'ensemble pour chaque cache', | |
'outlineMapSingleDesc': 'Après chaque cache, une carte indiquant l\'emplacement de la cache et de ses Waypoints additionnels sera affichée.' | |
}, | |
'map': { | |
'header': 'Carte', | |
'type': 'Type de carte par défaut', | |
'size': 'Taille de carte par défaut', | |
'geocacheid': 'Afficher l\'Id de la cache sur la carte', | |
'geocacheidDesc': 'Les codes GC (eg. GC1S5ZE) seront affichés sur la carte.', | |
'geocacheindex': 'Afficher les Waypoints des caches sur la vue générale', | |
'geocacheindexDesc': 'Les Waypoints seront affichés sur la carte.', | |
'geocachename': 'Afficher le nom des caches sur la vue générale', | |
'geocachenameDesc': 'Les noms des caches seront affichés sur la carte.', | |
'awpts': 'Afficher les Waypoints', | |
'awptsDesc': 'Si cette option est cochée les Waypoints associées aux caches seront affichés sur la carte.', | |
'awpt_name': 'Afficher les noms des Waypoints additionnels', | |
'awpt_nameDesc': 'Les noms des Waypoints additionnels seront affichés sur la carte.', | |
'awpt_lookup': 'Afficher les codes lookup des Waypoints additionnels', | |
'awpt_lookupDesc': 'Les codes lookup des Waypoints seront affichés sur la carte.', | |
'owpts': 'Afficher les Waypoints personnels', | |
'owptsDesc': 'Les Waypoints personnels seront visibles sur la carte.', | |
'owpt_name': 'Afficher le nom des Waypoints personnels', | |
'owpt_nameDesc': 'Affiche le nom des Waypoints personnels sur la carte' | |
}, | |
'gpx': { | |
'html': 'Description des caches au format HTML', | |
'htmlDesc': 'Certains programmes/GPSr ont des problèmes pour afficher les descriptions au format HTML. Si vous ne voyez qu\'une description tronquée de la cache, désactivez cette option.', | |
'wpts': 'Exporter les Waypoints additionnels', | |
'wptsDesc': 'Les Waypoints additionnels seront exportés vers votres GPS. Les parkings conseillés seront visibles sur votre GPS.', | |
'attributesToLog': 'Créer connecter avec les attributs du cache', | |
'attributesToLogDesc': 'Attributs de mise en cache sont également enregistrés comme un premier signe.', | |
'stripGC': 'Tronquer le préfixe "GC" dans le GC-Code', | |
'stripGCDesc': 'Les anciens GPSr ont parfois des problèmes avec les noms de Waypoints de plus de 8 caractères. Dans ce cas cochez cette option.', | |
'maxLogCount': 'nombre maximum de journaux' | |
}, | |
'gps': { | |
'header': 'Envoyer vers le GPSr', | |
'selectSend2GPS': 'Choisir méthode' | |
}, | |
'theme': { | |
'select': 'Choisir Theme' | |
} | |
}, | |
'autoTour': { | |
'wait': 'Veuillez patienter pendant la génération automatique du Tour ...', | |
'radius': 'Rayon', | |
'center': 'Centre', | |
'help': 'Coordonnées ou adresse: <i>N48° 51.478 E2° 17.670</i> ou <i>Paris Tour Eiffel</i>', | |
'refresh': 'Continuer pour cette zone !', | |
'cacheCounts': 'Estimation du<i>nombre total</i> de cache dans cette zone:', | |
'duration': 'Durée estimée de création de cet autoTour:', | |
'filter': { | |
'type': 'Type', | |
'size': 'Taille', | |
'difficulty': 'Difficulté', | |
'terrain': 'Terrain', | |
'special': { | |
'caption': 'Spécial' | |
} | |
} | |
}, | |
'dlg': { | |
'newVersion': { | |
'caption': 'Nouvelle version disponible', | |
'content': 'Une nouvelle version de GCTour est disponible.\n Voulez-vous mettre à jour? \n\n' | |
}, | |
'error': { | |
'content': '<img src="' + $.gctour.img.sad + '"> Désolé une erreur est survenue.<br/>' + | |
'Réessayez SVP, ou vérifier les <a href="#" id="gctour_update_error_dialog">mises à jour</a> du script!<br/><br/>' | |
} | |
}, | |
'notifications': { | |
'addgeocache': { | |
'success': { | |
'caption': '{0} a été ajouté', | |
'content': '<b>{0}</b> contient désormais aussi <b>{1}</b>.' | |
}, | |
'contains': { | |
'caption': '{0} n\'a pas été ajouté', | |
'content': '<b>{0}</b> contient <b>{1}</b>.' | |
} | |
} | |
}, | |
'units': { | |
'km': 'Kilomètre', | |
'mi': 'Miles' | |
}, | |
'send2cgeo': { | |
'title': 'Transférer vers le c:geo' | |
}, | |
'marker': { | |
'coord': 'Coordonnées', | |
'content': 'Description', | |
'contentHint': 'sera visble dans la version imprimable' | |
}, | |
'update': { | |
'dialog': '<div><p>Une nouvelle version de <a target="_blank" href="https://gctour.geocaching.cx/"><b>GCTour</b></a> est disponible.</p><p>Version installée: <b>###VERSION_OLD###</b>, version la plus récente disponible: <b>###VERSION_NEW###</b>.</p><div class="dialogFooter"></div>', | |
'upToDate': 'GCTour ' + VERSION + ' est à jour!' | |
}, | |
'printview': { | |
'found': 'Trouvée', | |
'note': 'Note', | |
'marker': 'Waypoint personnel', | |
'removeMap': 'Supprimer la carte', | |
'zoomMap': 'Ouvrir la carte dans un nouvel onglet.', | |
'dontPrintHint': '<b>Information:</b><br/>Les éléménts ayant cette apparence ne seront <u>pas</u> imprimés!', | |
'print': 'Lancez l\'impression' | |
}, | |
'cache': { | |
'addToTour': 'Ajouter au tour', | |
'directPrint': 'Imprimer cette cache', | |
'moveCoords': 'Ajuster les coordonnées', | |
'movedCoords': 'Les coordonnées de cette cache ont été ajustées.', | |
'moveCoordsHelp': 'Vous avez la possibilité d\'ajuster les coordonnées de cette cache. Ces coordonnées seront utilisées dans la version imprimable et dans le fichier GPX . Très utile pour la saisie des solutions des caches Mystery.', | |
'deleteCoords': 'Supprimer les coordonnées', | |
'originalCoords': 'Coordonnées initiales', | |
'newCoords': 'Nouvelles coordonnées', | |
'addToCurrentTour': 'Ajouter au tour <b>actuel</b>', | |
'addToNewTour': 'Ajouter à un <b>nouveau</b> tour', | |
'shown': 'Caches affichées', | |
'marked': 'Caches marquées', | |
'all': 'Tous caches' | |
}, | |
'tour': { | |
'newDialog': 'Veuillez saisir un nom pour ce nouveau tour ...', | |
'copy': 'Dupliquer le tour', | |
'remove': 'Supprimer ce tour', | |
'removeDialog': 'Etes-vous sûrs de vouloir supprimer ce tour?', | |
'empty': 'Le tour est vide.' | |
} | |
}; | |
$.gctour.i18n.nl = { | |
'name': 'Nederlands', | |
'general': { | |
'save': 'Bewaren', | |
'copy': 'Kopiëren', | |
'cancel': 'Annuleren', | |
'close': 'Sluiten', | |
'edit': 'Bewerken', | |
'rename': 'Hernoem', | |
'load': 'laden', | |
'install': 'Installeren', | |
'findMe': 'Vind me!', | |
'exampleCoords': 'bv. N49° 26.082 E7° 46.587 of 49.434701 7.776446', | |
'notLoggedIn': 'U dient ingelogd te zijn, gelieve in te loggen.', | |
'pleaseWait': 'Even geduld - gegevens worden geladen ...' | |
}, | |
'container': { | |
'toolbar': { | |
'newList': 'Nieuwe toer', | |
'openTour': 'Een toer laden', | |
'downloadTour': { | |
'caption': 'Toer downloaden', | |
'webcodeDownloadHelp': 'Gelieve de ontvangen webcode in te vullen en klik op "Toer downloaden".', | |
'webcodeerror': 'De gekozen webcode bestaat niet!', | |
'webcodesuccess': ' is succesvol geladen!', | |
'webcodeOld': '\n !!AANDACHT!!\nDeze webcode bevat een oude toer. Om alle voordelen van GCTour 2.0 te benutten moet deze toer opnieuw worden geüpload worden.' | |
}, | |
'showSettings': 'Instellingen tonen' | |
}, | |
'tourHeader': { | |
'sendToGps': 'Naar GPSr versturen', | |
'downloadGpx': 'GPX downloaden', | |
'makeMap': { | |
'caption': 'Bekijk op de kaart', | |
'wait': 'Beschikbaarheid kaart wordt getest' | |
}, | |
'upload': { | |
'caption': 'Toer uploaden', | |
'tourUploaded1': '<br>Uploaden toer was succesvol! Webcode:<br><b>', | |
'tourUploaded2': '</b><br><br>Je kan de toer bekijken op <a href="' + GCTOUR_HOST + 'tour/xWEBCODEx" target="_blank">' + GCTOUR_HOST + 'tour/xWEBCODEx</a>.<br>Belangrijk gelieve de webcode te noteren om deze later op te kunnen opvragen!!', | |
}, | |
'addOwnWaypoint': 'Eigen waypoint toevoegen' | |
}, | |
'cacheList': { | |
'logYourVisit': 'Log je bezoek', | |
'removeFromList': 'Van toer verwijderen' | |
} | |
}, | |
'settings': { | |
'caption': 'Instellingen', | |
'language': { | |
'header': 'Taal', | |
'select': 'Taal kiezen' | |
}, | |
'printview': { | |
'header': 'Afdrukweergave', | |
'printMinimal': 'Minimale afdrukweergave', | |
'printMinimalDesc': 'Dit bevat enkel de hint en spoiler van een geocache.', | |
'logCount': 'Aantal logs in afdrukweergave', | |
'logCounts': ['geen', 'alle', 'tonen'], | |
'fontSize': 'Fontgrootte', | |
'decryptHints': 'Decodeer hints', | |
'decryptHintsDesc': 'Hints worden gedecodeerd bij het afdrukken.', | |
'editDescription': 'Beschrijving wijzigbaar', | |
'editDescriptionDesc': 'De beschrijving van de geocache kan aangepast worden.', | |
'showSpoiler': 'Spoiler tonen', | |
'showSpoilerDesc': 'Spoilers worden afgedrukt.', | |
'additionalWaypoints': 'Additional waypoints tonen', | |
'additionalWaypointsDesc': 'De afdrukweergave zal een tabel met de "additional waypoints" van een geocache bevatten.', | |
'loggedVisits': 'Log teller tonen', | |
'loggedVisitsDesc': 'Dit toont een "Find Counts" overzicht.', | |
'pageBreak': 'Pagina einde achter cache', | |
'pageBreakDesc': 'Bij het afdrukken komt achter elke geocache een nieuwe pagina.', | |
'pageBreakAfterMap': 'Pagina einde achter kaart', | |
'pageBreakAfterMapDesc': 'Er komt een nieuwe pagina tussen het overzicht en de geocaches.', | |
'frontPage': 'Frontpagina', | |
'frontPageDesc': 'Een overzicht wordt gemaakt met de volledige lijst van de geocaches met een index en plaats voor notities.', | |
'outlineMap': 'Kaart maken voor alle geocaches', | |
'outlineMapDesc': 'Het overzicht zal een kaart met alle geocaches bevatten.', | |
'outlineMapSingle': 'Kaart maken voor elke cache afzonderlijk', | |
'outlineMapSingleDesc': 'Na iedere geocache komt een kaart met de geocache en de additional waypoints.' | |
}, | |
'map': { | |
'header': 'Kaart', | |
'type': 'Standaard kaarttype', | |
'size': 'Standaard kaartgrootte', | |
'geocacheid': 'Toon geocache id', | |
'geocacheidDesc': 'De GCCode (eg. GC2NTTG) wordt getoond op de kaart.', | |
'geocacheindex': 'Toon geocache index', | |
'geocacheindexDesc': 'De volgorde binnen de toer wordt getoond op de kaart.', | |
'geocachename': 'Toon geocache naam', | |
'geocachenameDesc': 'De naam van de geocache wordt getoond op de kaart.', | |
'awpts': 'Toon additional waypoints', | |
'awptsDesc': 'Additional waypoints worden getoond op de kaart.', | |
'awpt_name': 'Toon naam additional waypoints', | |
'awpt_nameDesc': 'De naam van het additional waypoint wordt getoond op de kaart.', | |
'awpt_lookup': 'Toon lookup code additional waypoints', | |
'awpt_lookupDesc': 'De lookup code van het additional waypoints wordt getoond op de kaart.', | |
'owpts': 'Toon eigen waypoints', | |
'owptsDesc': 'Eigen waypoints worden getoond op de kaart.', | |
'owpt_name': 'Toon naam eigen waypoints', | |
'owpt_nameDesc': 'De naam van het eigen waypoint wordt getoond op de kaart.' | |
}, | |
'gpx': { | |
'html': 'Beschrijving met HTML', | |
'htmlDesc': 'Sommige programma\'s en GPS toestellen hebben problemen met geocache beschrijvingen in HTML. Indien dit het geval is, kan je best deze optie afzetten.', | |
'wpts': 'Exporteer additional waypoints', | |
'wptsDesc': 'Additional waypoints worden geëxporteerd als extra waypoint naar GPX. Alle paarkeerplaatsen zullen zichtbaar zijn op je toestel.', | |
'attributesToLog': 'Maken te loggen met cache attributen', | |
'attributesToLogDesc': 'Cache attributen worden ook geregistreerd als een eerste teken.', | |
'stripGC': '"GC" in GC-Code verwijderen', | |
'stripGCDesc': 'Oudere GPS toestellen kunnen problemen hebben met waypoints waarvan de naam langer is dan 8 tekens. Gebruik deze optie indien dit het geval is.', | |
'maxLogCount': 'Max aantal logs' | |
}, | |
'gps': { | |
'header': 'Naar GPSr versturen', | |
'selectSend2GPS': 'Methode kiezen' | |
}, | |
'theme': { | |
'select': 'Theme kiezen' | |
} | |
}, | |
'autoTour': { | |
'wait': 'Even geduld – autoTour wordt aangemaakt!', | |
'radius': 'Radius', | |
'center': 'Middelpunt', | |
'help': 'Coördinaten of adres: <i>N52° 22.472 E4° 53.879</i> of <i>Amsterdam</i>', | |
'refresh': 'Bereken een autoTour aan met deze waarden!', | |
'cacheCounts': 'Geschat <i>aantal</i> geocaches in deze regio:', | |
'duration': 'Geschatte tijd om deze autoTour aan te maken:', | |
'filter': { | |
'type': 'Type', | |
'size': 'Grootte', | |
'difficulty': 'Moeilijkheid', | |
'terrain': 'Terrein', | |
'special': { | |
'caption': 'Speciaal' | |
} | |
} | |
}, | |
'dlg': { | |
'newVersion': { | |
'caption': 'Nieuwe versie beschikbaar', | |
'content': 'Er is een nieuwe versie van GCTour beschikbaar.\nWil je upgraden? \n\n' | |
}, | |
'error': { | |
'content': '<img src="' + $.gctour.img.sad + '"> Spijtig genoeg is er een fout gebeurd.<br/>' + | |
'Probeer het opnieuw proberen, of kijk voor <a href="#" id="gctour_update_error_dialog">update</a>!<br/><br/>' | |
} | |
}, | |
'notifications': { | |
'addgeocache': { | |
'success': { | |
'caption': '{0} werd toegevoegd', | |
'content': '<b>{0}</b> bevat nu <b>{1}</b>.' | |
}, | |
'contains': { | |
'caption': '{0} werd <i>niet</i> toegevoegd', | |
'content': '<b>{0}</b> bevat <b>{1}</b> reeds.' | |
} | |
} | |
}, | |
'units': { | |
'km': 'Kilometer', | |
'mi': 'Miles' | |
}, | |
'send2cgeo': { | |
'title': 'Naar c:geo versturen' | |
}, | |
'marker': { | |
'coord': 'Coördinaten', | |
'content': 'Inhoud', | |
'contentHint': 'zal getoond worden in afdrukweergave' | |
}, | |
'update': { | |
'dialog': '<div><p>Er is een nieuwe versie van <a target="_blank" href="https://gctour.geocaching.cx/"><b>GCTour</b></a> beschikbaar voor installatie.</p><p>Versie <b>###VERSION_OLD###</b> is momenteel geïnstalleerd, de recentste versie is <b>###VERSION_NEW###</b>.</p><div class="dialogFooter"></div>', | |
'upToDate': 'GCTour ' + VERSION + ' is op dit moment!' | |
}, | |
'printview': { | |
'found': 'Gevonden', | |
'note': 'Note', | |
'marker': 'Eigen waypoint', | |
'removeMap': 'Kaart verwijderen', | |
'zoomMap': 'Open deze kaart in een nieuwe tab.', | |
'dontPrintHint': '<b>Ter info:</b><br/>Gegevens in dit kader worden <u>niet</u> afgedrukt!', | |
'print': 'Begin met afdrukken' | |
}, | |
'cache': { | |
'addToTour': 'Aan toer toevoegen', | |
'directPrint': 'Deze geocache afdrukken', | |
'moveCoords': 'Verplaats de coördinaten', | |
'movedCoords': 'De coördinaten voor deze geocache zijn verplaatst.', | |
'moveCoordsHelp': 'Je kan de originele coördinaten van deze geocache verplaatsen. Deze worden dan gebruikt in de afdrukweergave en in het GPX bestand. Dit kan handig zijn bij een opgeloste mystery.', | |
'deleteCoords': 'Verwijderen coördinaten', | |
'originalCoords': 'Originele coördinaten', | |
'newCoords': 'Nieuwe coördinaten', | |
'addToCurrentTour': 'aan <b>huidige</b> toer', | |
'addToNewTour': 'aan <b>nieuwe</b> toer', | |
'shown': 'Getoonde geocaches', | |
'marked': 'Gemarkeerde geocaches', | |
'all': 'Alle caches' | |
}, | |
'tour': { | |
'newDialog': 'Gelieve de naam van de nieuwe toer in te vullen ...', | |
'copy': 'Toer kopiëren', | |
'remove': 'Deze toer wissen', | |
'removeDialog': 'Weet je zeker dat je deze toer wil verwijderen?', | |
'empty': 'De toer is leeg.' | |
} | |
}; | |
$.gctour.i18n.pt = { | |
'name': 'Português', | |
'general': { | |
'save': 'Guardar', | |
'copy': 'Copiar', | |
'cancel': 'Cancelar', | |
'close': 'Fechar', | |
'edit': 'Editar', | |
'rename': 'Renomear', | |
'load': 'carregar', | |
'install': 'Instalar', | |
'findMe': 'Encontra-me!', | |
'exampleCoords': 'p.ex. N49° 26.082 E7° 46.587 ou 49.434701 7.776446', | |
'notLoggedIn': 'Você precisa estar logado, faça o login.', | |
'pleaseWait': 'Por favor aguarde - a carregar conteúdo ...' | |
}, | |
'container': { | |
'toolbar': { | |
'newList': 'Nova Rota', | |
'openTour': 'Carregar uma Rota', | |
'downloadTour': { | |
'caption': 'Transferir Rota', | |
'webcodeDownloadHelp': 'Por favor introduza aqui o código que recebeu e clique em "Transferir Rota".', | |
'webcodeerror': 'O Código escolhido não existe!', | |
'webcodesuccess': ' foi carregada!', | |
'webcodeOld': '\n !!ATENÇÃO!!\nEste código está conectado com uma rota antiga. Para obter todos os benefícios do GCTour 2.0, tem de enviar a rota novamente.' | |
}, | |
'showSettings': 'Mostrar Configurações' | |
}, | |
'tourHeader': { | |
'sendToGps': 'Enviar para o GPSr', | |
'downloadGpx': 'Transferir GPX', | |
'makeMap': { | |
'caption': 'Visualizar no mapa', | |
'wait': 'A testar disponibilidade deste mapa' | |
}, | |
'upload': { | |
'caption': 'Enviar rota', | |
'tourUploaded1': '<br>Rota enviada com sucesso! Código:<br><b>', | |
'tourUploaded2': '</b><br><br>Pode ver a rota em <a href="' + GCTOUR_HOST + 'tour/xWEBCODEx" target="_blank">' + GCTOUR_HOST + 'tour/xWEBCODEx</a>.<br>Importante: Por favor anote o código para retirar a rota!!', | |
}, | |
'addOwnWaypoint': 'Adicionar o seu Waypoint' | |
}, | |
'cacheList': { | |
'logYourVisit': 'Registe a sua visita', | |
'removeFromList': 'Remover da lista' | |
} | |
}, | |
'settings': { | |
'caption': 'Configurações', | |
'language': { | |
'header': 'Idioma', | |
'select': 'Escolha idioma' | |
}, | |
'printview': { | |
'header': 'Modo de impressão', | |
'printMinimal': 'Modo de Impressão mínimo', | |
'printMinimalDesc': 'Contém apenas a dica e o spoiler da geocache.', | |
'logCount': 'Número de logs no modo de impressão', | |
'logCounts': ['nenhum', 'tudo', 'mostrar'], | |
'fontSize': 'Tamanho da letra', | |
'decryptHints': 'Decifrar dicas', | |
'decryptHintsDesc': 'As dicas vão estar decifradas no modo de impressão.', | |
'editDescription': 'Descrição editável', | |
'editDescriptionDesc': 'A descrição pode ser editada da forma como quiser.', | |
'showSpoiler': 'Mostrar spoiler', | |
'showSpoilerDesc': 'Imagens de spoiler vão estar no modo de impressão.', | |
'additionalWaypoints': 'Mostrar Waypoints Adicionais', | |
'additionalWaypointsDesc': 'O modo de impressão vai conter uma tabela com todos os "Waypoints Adicionais" de uma geocache.', | |
'loggedVisits': 'Mostrar contador de log', | |
'loggedVisitsDesc': 'Vai mostrar um resumo do "Contador de Visitas".', | |
'pageBreak': 'Espaço na pagina depois da cache', | |
'pageBreakDesc': 'Depois de cada geocache vai existir uma espaçamento. Visível depois da impressão.', | |
'pageBreakAfterMap': 'Espaço na página depois do mapa', | |
'pageBreakAfterMapDesc': 'Vai existir um espaçamento depois do resumo para separar as geocaches.', | |
'frontPage': 'Primeira página', | |
'frontPageDesc': 'Um resumo vai ser gerado incluindo uma lista completa de todas as geocaches com um índice e um espaço para colocar notas.', | |
'outlineMap': 'Mapa com todas as caches', | |
'outlineMapDesc': 'O resumo vai conter um mapa com todas as geocaches.', | |
'outlineMapSingle': 'Mapa para todas as caches', | |
'outlineMapSingleDesc': 'Depois de cada geocache está um mapa contendo a geocache e os seus "Waypoints Adicionais".' | |
}, | |
'map': { | |
'header': 'Mapa', | |
'type': 'Tipo de Mapa padrão', | |
'size': 'Tamanho de Mapa padrão', | |
'geocacheid': 'Mostrar id da Geocache', | |
'geocacheidDesc': 'O código GCCode (eg. GC0815) estará visivel no mapa.', | |
'geocacheindex': 'Mostrar indíce da Geocache', | |
'geocacheindexDesc': 'A posição de cada waypoint estará visível na rota seleccionada.', | |
'geocachename': 'Mostrar nome da Geocache', | |
'geocachenameDesc': 'O nome da geocache estará visivel.', | |
'awpts': 'Mostrar Waypoints Adicionais', | |
'awptsDesc': 'Se seleccionada, os Waypoints-Adicionais vão estar visíveis.', | |
'awpt_name': 'Mostrar o nome dos Waypoints Adicionais', | |
'awpt_nameDesc': 'O nome dos Waypoints-Adicionais vão estar no mapa.', | |
'awpt_lookup': 'Mostrar código dos Waypoints Adicionais', | |
'awpt_lookupDesc': 'Os códigos dos Waypoints-Adicionais vão estar visíveis.', | |
'owpts': 'Mostrar os nossos waypoints', | |
'owptsDesc': 'Se tem Waypoints seus na rota seleccionada e se esta opção estiver marcada, vão estar visíveis no mapa.', | |
'owpt_name': 'Mostrar o nome dos nossos waypoints', | |
'owpt_nameDesc': 'Mostrar o nome dos seus Waypoints' | |
}, | |
'gpx': { | |
'html': 'Descrição com HTML', | |
'htmlDesc': 'Alguns programas/GPSr tem problemas em mostrar as geocaches se a descrição estiver no formato HTML. Se a descrição estiver confusa, desactive este opção.', | |
'wpts': 'Exportar waypoints adicionais', | |
'wptsDesc': 'Os waypoints-adicionais vão ser exportados como waypoint extra no GPX. Irá ver cada lugar de estacionamento na sua unidade.', | |
'attributesToLog': 'Criar login com atributos de cache', | |
'attributesToLogDesc': 'Atributos de cache também são registrados como um primeiro sinal.', | |
'stripGC': 'Remover "GC" no GC-Code', | |
'stripGCDesc': 'GPSr antigos tem problemas com os waypoints com nome maior que 8 caracteres. Use esta opção se tem uma unidade destas.', | |
'maxLogCount': 'Número máximo de logs' | |
}, | |
'gps': { | |
'header': 'Enviar para o GPSr', | |
'selectSend2GPS': 'Escolha método' | |
}, | |
'theme': { | |
'select': 'Escolha Theme' | |
} | |
}, | |
'autoTour': { | |
'title': 'autoRota', | |
'wait': 'Por favor aguarde - criando a autoRota!', | |
'radius': 'Raio', | |
'center': 'Centro', | |
'help': 'Coordenadas ou Endereço: <i>N38° 42.465 W9° 08.196</i> ou <i>Lisboa</i>', | |
'refresh': 'Oblicz autoRota com estes valores!', | |
'cacheCounts': '<i>Número</i> estimado de caches na região:', | |
'duration': 'Previsão do tempo de criação desta autoRota:', | |
'filter': { | |
'type': 'Typ', | |
'size': 'Rozmiar', | |
'difficulty': 'Trudność', | |
'terrain': 'Teren', | |
'special': { | |
'caption': 'Specjalne' | |
} | |
} | |
}, | |
'dlg': { | |
'newVersion': { | |
'caption': 'Nova versão disponível', | |
'content': 'Existe uma nova versão de GCTour.\nDeseja actualizar? \n\n' | |
}, | |
'error': { | |
'content': '<img src="' + $.gctour.img.sad + '"> Lamento mas ocorreu um erro.<br/>' + | |
'Por favor tente outra vez, ou procure por uma <a href="#" id="gctour_update_error_dialog">atualização</a>!<br/><br/>' | |
} | |
}, | |
'notifications': { | |
'addgeocache': { | |
'success': { | |
'caption': '{0} foi adicionada!', | |
'content': '<b>{0}</b> agora inclui <b>{1}</b>.' | |
}, | |
'contains': { | |
'caption': '{0} não foi adicionada', | |
'content': '<b>{0}</b> contém <b>{1}</b> já.' | |
} | |
} | |
}, | |
'units': { | |
'km': 'Quilometros', | |
'mi': 'Milhas' | |
}, | |
'send2cgeo': { | |
'title': 'Enviar para o c:geo' | |
}, | |
'marker': { | |
'coord': 'Coordenadas', | |
'content': 'Conteúdo', | |
'contentHint': 'estará visivel no modo de impressão', | |
'type': 'Tipo' | |
}, | |
'update': { | |
'dialog': '<div><p>Existe uma nova versão de <a target="_blank" href="https://gctour.geocaching.cx/"><b>GCTour</b></a> disponível para instalar.</p><p>Tem a versão <b>###VERSION_OLD###</b> instalada, a última versão é <b>###VERSION_NEW###</b>.</p><div class="dialogFooter"></div>', | |
'upToDate': 'GCTour ' + VERSION + ' está atualmente!' | |
}, | |
'printview': { | |
'found': 'Encontrada', | |
'note': 'Nota', | |
'marker': 'Waypoint próprio', | |
'removeMap': 'Remover mapa', | |
'zoomMap': 'Abrir este mapa num novo separador.', | |
'dontPrintHint': '<b>Informação:</b><br />Elementos na caixa <u>não</u> vão ser impressos!', | |
'print': 'Iniciar a impressão' | |
}, | |
'cache': { | |
'addToTour': 'Adicionar à rota', | |
'directPrint': 'Imprimir esta Geocache', | |
'moveCoords': 'Mover as coordenadas', | |
'movedCoords': 'As coordenadas desta geocache foram mudadas.', | |
'moveCoordsHelp': 'Tens a oportunidade de mudar as coordenadas originais desta geocache. Serão usadas no modo de impressão e também no ficheiro GPX. É util se resolver o enigma.', | |
'deleteCoords': 'Coordenadas para deletar', | |
'originalCoords': 'Coordenadas Originais', | |
'newCoords': 'Novas Coordenadas', | |
'addToCurrentTour': 'para a rota <b>seleccionada</b>', | |
'addToNewTour': 'para uma <b>nova</b> rota', | |
'shown': 'Geocaches visíveis', | |
'marked': 'Geocaches marcados', | |
'all': 'Tudo Caches' | |
}, | |
'tour': { | |
'newDialog': 'Introduza um nome para a nova rota ...', | |
'copy': 'Copiar rota', | |
'remove': 'Apagar esta rota', | |
'removeDialog': 'Deseja mesmo remover esta rota?', | |
'empty': 'A lista está vazia.' | |
} | |
}; | |
// init translations | |
(function () { | |
/*$.each($.gctour.i18n, function (l, o) { | |
console.table(o); | |
});*/ | |
/* | |
return translate from [language][str] | |
is language or str undefined = return "" | |
*/ | |
$.gctour.lang = function (str) { | |
var i18n = $.gctour.i18n, | |
cur = $.gctour.currentLang, | |
def = $.gctour.defaultLang, | |
i, | |
arr, | |
lang, | |
trans, | |
cur_trans, | |
def_trans; | |
// try to get current and default translation | |
cur_trans = i18n[cur] || false; | |
def_trans = i18n[def] || false; | |
arr = str.split('.'); | |
for (i = 0; i < arr.length; i++) { | |
cur_trans = cur_trans ? cur_trans[arr[i]] : undefined; | |
def_trans = def_trans ? def_trans[arr[i]] : undefined; | |
} | |
// use default language as fallback | |
trans = (cur_trans !== undefined) ? cur_trans : | |
(def_trans !== undefined) ? def_trans : | |
((DEBUG_MODE === true) ? "MISSING TRANSLATION" : ""); | |
/* | |
// debug info current language | |
if (!i18n[cur]) { | |
debug("ERROR: language '" + cur + "' is undefined"); | |
} else if (cur_trans === undefined) { | |
debug("ERROR: active language (" + cur + "), search '" + str + "' is undefined"); | |
} | |
// debug info default language | |
if (!i18n[def]) { | |
debug("ERROR: language '" + def + "' is undefined"); | |
} else if (def_trans === undefined) { | |
debug("ERROR: default language (" + def + "), search '" + str + "' is undefined"); | |
} | |
*/ | |
return trans; | |
}; | |
})(); | |
/* styles: CSS Container, run before init() */ | |
function initStyle() { | |
// adding styles: | |
GM_addStyle(("" + | |
"/* GCTour - Container */\n" + | |
"" + | |
"#gctourButtonWrapper {" + | |
" height: 32px !important;" + | |
" padding: 0 !important;" + | |
" position: fixed !important;" + | |
" top: 30px !important;" + | |
" width: 35px !important;" + | |
" background-color: #fff;" + | |
" z-index: 10000 !important;" + | |
" border: 1px solid #333;" + | |
" border-width: 1px 1px 1px 0;" + | |
" border-radius: 0 5px 5px 0;" + | |
" -moz-user-select: none;" + | |
"}" + | |
"" + | |
"#gctourButtonWrapper img {" + | |
" position: relative;" + | |
" top: 8px;" + | |
" left: 8px;" + | |
" vertical-align: top;" + | |
"}" + | |
"" + | |
"#gctourContainer {" + | |
" background-color: #fff;" + | |
" overflow: hidden;" + | |
" left: -210px;" + | |
" padding: 0 !important;" + | |
" position: fixed !important;" + | |
" top: 15px !important;" + | |
" width: 200px;" + | |
" z-index: 10001 !important;" + | |
" border: 1px solid #333;" + | |
" border-left: 0px;" + | |
" border-radius: 0 5px 5px 0;" + | |
" font-size: 12px;" + | |
" font-family: Arial;" + | |
" line-height: 1.5;" + | |
"}" + | |
"" + | |
"#gctourContainer .cachelist {" + | |
" width: 100%;" + | |
" margin: 0;" + | |
" padding:0;" + | |
" font-size:80%;" + | |
" list-style-type:none;" + | |
"}" + | |
"" + | |
"#gctourContainer .cachelist li {" + | |
" color:#000;" + | |
" margin:0.5em;" + | |
" padding:3px;" + | |
" width:120px;" + | |
" min-height:44px;" + | |
" list-style-position:inside;" + | |
" border:1pt dashed gray;" + | |
" background-color:#FFF;" + | |
" -moz-background-clip:border;" + | |
" -moz-background-inline-policy:continuous;" + | |
" -moz-background-origin:padding;" + | |
" -moz-border-radius:8px 0 8px 0;" + | |
" border-radius:8px 0 8px 0;" + | |
"}" + | |
"" + | |
"#gctourContainer img.imgShadow {" + | |
" -moz-box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.2);" + | |
" box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.2);" + | |
" background-color: lightgray;" + | |
"}" + | |
"" + | |
"#gctourContainer img.tourImage {" + | |
" cursor: pointer;" + | |
" margin: 0 2px 0 2px;" + | |
"}" + | |
"" + | |
"/* Styling the placeholder for when the user starts dragging an item */\n" + | |
"" + | |
"#gctourContainer li.ui-sortable-placeholder {" + | |
" min-height:50px;" + | |
" max-height:80px;" + | |
" width: 90%;" + | |
" background-color: rgba(0, 0, 0, 0.03);" + | |
"}" + | |
"/* GCTour - Grand */\n" + | |
"" + | |
".gctour-grand-default {" + | |
" /* http://www.colorzilla.com/gradient-editor/#a7cfef+0,c9dded+3,ffffff+10;gctour-grand-default" + | |
" * http://css3please.com/" + | |
" */" + | |
" background: rgb(167,207,239); /* Old browsers */" + | |
" background: -moz-linear-gradient(top, rgba(167,207,239,1) 0%, rgba(201,221,237,1) 3px, rgba(255,255,255,1) 10px); /* FF3.6+ */" + | |
" background: -webkit-linear-gradient(top, rgba(167,207,239,1) 0%,rgba(201,221,237,1) 3px,rgba(255,255,255,1) 10px); /* Chrome10+,Safari5.1+ */" + | |
" background: -o-linear-gradient(top, rgba(167,207,239,1) 0%,rgba(201,221,237,1) 3px,rgba(255,255,255,1) 10px); /* Opera 11.10+ */" + | |
" background: linear-gradient(top, rgba(167,207,239,1) 0%,rgba(201,221,237,1) 3px,rgba(255,255,255,1) 10px); /* W3C */" + | |
"}" + | |
"" + | |
".gctour-grand-hover {" + | |
" /* http://www.colorzilla.com/gradient-editor/#ffad32+0,ffd699+3,ffffff+10;gctour-grand-hover */" + | |
" background: rgb(255,173,50); /* Old browsers */" + | |
" background: -moz-linear-gradient(top, rgba(255,173,50,1) 0%, rgba(255,214,153,1) 3px, rgba(255,255,255,1) 10px); /* FF3.6+ */" + | |
" background: -webkit-linear-gradient(top, rgba(255,173,50,1) 0%,rgba(255,214,153,1) 3px,rgba(255,255,255,1) 10px); /* Chrome10+,Safari5.1+ */" + | |
" background: -o-linear-gradient(top, rgba(255,173,50,1) 0%,rgba(255,214,153,1) 3px,rgba(255,255,255,1) 10px); /* Opera 11.10+ */" + | |
" background: linear-gradient(top, rgba(255,173,50,1) 0%,rgba(255,214,153,1) 3px,rgba(255,255,255,1) 10px); /* W3C */" + | |
"}" + | |
"" + | |
".gctour-grand-highlight {" + | |
" /* http://www.colorzilla.com/gradient-editor/#ffe000+0,ffee7f+3,ffffff+10;gctour-grand-highlight */" + | |
" background: rgb(255,224,0); /* Old browsers */" + | |
" background: -moz-linear-gradient(top, rgba(255,224,0,1) 0%, rgba(255,238,127,1) 3px, rgba(255,255,255,1) 10px); /* FF3.6+ */" + | |
" background: -webkit-linear-gradient(top, rgba(255,224,0,1) 0%,rgba(255,238,127,1) 3px,rgba(255,255,255,1) 10px); /* Chrome10+,Safari5.1+ */" + | |
" background: -o-linear-gradient(top, rgba(255,224,0,1) 0%,rgba(255,238,127,1) 3px,rgba(255,255,255,1) 10px); /* Opera 11.10+ */" + | |
" background: linear-gradient(top, rgba(255,224,0,1) 0%,rgba(255,238,127,1) 3px,rgba(255,255,255,1) 10px); /* W3C */" + | |
"}" + | |
"" + | |
".gctour-grand-active {" + | |
" /* Grün http://www.colorzilla.com/gradient-editor/#3dff32+0,9eff99+3,ffffff+10;gctour-grand-active */" + | |
" background: rgb(61,255,50); /* Old browsers */" + | |
" background: -moz-linear-gradient(top, rgba(61,255,50,1) 0%, rgba(158,255,153,1) 3px, rgba(255,255,255,1) 10px); /* FF3.6+ */" + | |
" background: -webkit-linear-gradient(top, rgba(61,255,50,1) 0%,rgba(158,255,153,1) 3px,rgba(255,255,255,1) 10px); /* Chrome10+,Safari5.1+ */" + | |
" background: linear-gradient(top, rgba(61,255,50,1) 0%,rgba(158,255,153,1) 3px,rgba(255,255,255,1) 10px); /* W3C */$$$$" + | |
" background: -o-linear-gradient(top, rgba(61,255,50,1) 0%,rgba(158,255,153,1) 3px,rgba(255,255,255,1) 10px); /* Opera 11.10+ */" + | |
"}" + | |
"" + | |
".gctour-grand-error {" + | |
" /* http://www.colorzilla.com/gradient-editor/#ff3232+0,ff9999+3,ffffff+10;gctour-grand-error */" + | |
" background: rgb(255,50,50); /* Old browsers */" + | |
" background: -moz-linear-gradient(top, rgba(255,50,50,1) 0%, rgba(255,153,153,1) 3px, rgba(255,255,255,1) 10px); /* FF3.6+ */" + | |
" background: -webkit-linear-gradient(top, rgba(255,50,50,1) 0%,rgba(255,153,153,1) 3px,rgba(255,255,255,1) 10px); /* Chrome10+,Safari5.1+ */" + | |
" background: -o-linear-gradient(top, rgba(255,50,50,1) 0%,rgba(255,153,153,1) 3px,rgba(255,255,255,1) 10px); /* Opera 11.10+ */" + | |
" background: linear-gradient(top, rgba(255,50,50,1) 0%,rgba(255,153,153,1) 3px,rgba(255,255,255,1) 10px); /* W3C */" + | |
"}" + | |
"" + | |
"/* GCTour Slider */\n" + | |
"" + | |
".gct_scrollbar {" + | |
" background-color:pink;" + | |
" height: 20px;" + | |
" left: 0;" + | |
" position: absolute;" + | |
" top: 0;" + | |
" width: 100%;" + | |
"}" + | |
"" + | |
".gct_scroller{" + | |
" background-color:lime;" + | |
" height: 20px;" + | |
" left: 0;" + | |
" position: absolute;" + | |
" top: 0;" + | |
" width: 20px; " + | |
"}" + | |
"" + | |
"" + | |
"/* GCTour Pop-Up */\n" + | |
"" + | |
".gct_popup{" + | |
" position:absolute;" + | |
" z-index:10; " + | |
" width:172px;" + | |
" height:102px;" + | |
" text-align:center;" + | |
" color:#FF0000;" + | |
" font: 14px Verdana, Arial, Helvetica, sans-serif;" + | |
" background-color:lime;" + | |
" border-radius: 5px;" + | |
"}" + | |
"" + | |
".gct_popup_header{" + | |
" border-radius: 5px 5px 0px 0px;" + | |
"}" + | |
"" + | |
".dialogMask {" + | |
" background-image:url(##dialogMaskImage##);" + | |
" height:100%;" + | |
" left:0;" + | |
" opacity:0.7;" + | |
" position:fixed;" + | |
" top:0;" + | |
" width:100%;" + | |
" z-index:1100;" + | |
"}" + | |
"" + | |
".dialogBody {" + | |
" -moz-border-radius:5px;" + | |
" border-radius:5px;" + | |
" background:none repeat scroll 0 0 #fff;" + | |
" border:1px solid #333333;" + | |
" color:#333333;" + | |
" cursor:default;" + | |
" font-family:Arial;" + | |
" font-size:12px;" + | |
" left:50%;" + | |
" margin-left:-250px;" + | |
" margin-top:20px;" + | |
" padding:0 0 1em;" + | |
" position:fixed;" + | |
" text-align:left;" + | |
" top:0;" + | |
//" width:600px;" + | |
" width:625px;" + | |
" z-index:1101;" + | |
" max-height:85%;" + | |
" min-height:440px;" + | |
" overflow:auto;" + | |
"}" + | |
"" + | |
".dialogBody p {" + | |
" font-size:12px;" + | |
" font-weight:normal;" + | |
" margin:1em 0;" + | |
"}" + | |
"" + | |
".dialogBody button {" + | |
" background: none no-repeat scroll 4px center #eeeeee;" + | |
" border: 1px outset #666666" + | |
"}" + | |
"" + | |
".dialogBody button:hover {" + | |
" background-color: #f9f9f9;" + | |
"}" + | |
"" + | |
"/* autoTour */\n" + | |
"" + | |
".dialogBody select {" + | |
" width: auto;" + | |
" display: initial;" + | |
" padding: initial;" + | |
" -moz-appearance: menulist;" + | |
" -webkit-appearance: menulist;" + | |
"}" + | |
"" + | |
".dialogBody label {" + | |
" text-transform: none;" + | |
"}" + | |
"" + | |
".header h1 {" + | |
" background-color:#B2D4F3;" + | |
" background-repeat:repeat-x;" + | |
" font-size:110% !important;" + | |
" font-family:Helvetica Neue,Arial,Helvetica,sans-serif;" + | |
" margin-bottom:0.2em;" + | |
" margin-top:0;" + | |
" padding:0.5em;" + | |
" -moz-border-radius: 5px;" + | |
" border-radius: 5px;" + | |
" color:#333333;" + | |
" background-image:url(##tabBgImage##)" + | |
"}" + | |
"" + | |
"/*" + | |
".dialogBody h1 {" + | |
" background-color:#7A7A7A;" + | |
" border-bottom:1px solid #333333;" + | |
" font-size:110%;" + | |
" font-family:Helvetica Neue,Arial,Helvetica,sans-serif;" + | |
" margin-bottom:0.2em;" + | |
" padding:0.5em;" + | |
" -moz-border-radius:5px;" + | |
" border-radius:5px;" + | |
" color:#fff;" + | |
"}" + | |
"*/" + | |
"" + | |
".dialogHistory {" + | |
" border:1px inset #999999;" + | |
" margin:0 1em 1em;" + | |
" padding-bottom: 1em;" + | |
" max-height: 200px;" + | |
" overflow-y:auto;" + | |
" width:518px;" + | |
" padding-left:1em;" + | |
"}" + | |
"" + | |
".dialogHistory ul {" + | |
" margin-left:2em;" + | |
"}" + | |
"" + | |
".dialogHistory li {" + | |
" list-style-type:circle;" + | |
"}" + | |
"" + | |
".dialogFooter input {" + | |
" -moz-border-radius:3px;" + | |
" border-radius:3px;" + | |
" background:none no-repeat scroll 4px center #EEEEEE;" + | |
" border:1px outset #666666;" + | |
" cursor:pointer;" + | |
" float:right;" + | |
" margin-left:0.5em;" + | |
" padding:3px 5px 5px 20px;" + | |
" min-width:100px;" + | |
" font-size: 12px;" + | |
"}" + | |
"" + | |
".dialogFooter input:hover {" + | |
" background-color:#f9f9f9;" + | |
"}" + | |
"" + | |
".dialogContent {" + | |
" padding:0 10px 0 10px;" + | |
"}" + | |
"" + | |
".dialogMin {" + | |
" min-height:0 !important" + | |
"}" + | |
"" + | |
"" + | |
"/* neuer Dialog-Style mit jQuery-ui + gcTour Header (.gct_dialog) */\n" + | |
"" + | |
".gct_dialog {" + | |
" font-size: 100% !important;" + | |
" font-family: Arial !important;" + | |
"}" + | |
".gct_dialog .ui-widget {" + | |
"}" + | |
".gct_dialog.ui-dialog {" + | |
" padding: 0;" + | |
"}" + | |
".gct_dialog.ui-dialog .ui-widget-header {" + | |
" border: 0;" + | |
"}" + | |
".gct_dialog.ui-dialog .ui-dialog-titlebar {" + | |
" padding: 0.2em 0.1em;" + | |
//" background: -moz-linear-gradient(center top, #A7CFEF 0%, #C9DDED 3px, #FFFFFF 10px) repeat scroll 0 0 transparent;" + | |
" color: #000;" + | |
"}" + | |
".gct_dialog.ui-dialog .ui-dialog-title {" + | |
" padding-top: 4px;" + | |
" text-align: left;" + | |
" padding-left: 120px;" + | |
" width: 75%;" + | |
" background: url(##gctourLogo##) 2px 2px no-repeat;" + | |
"}" + | |
".gct_dialog.ui-dialog .ui-dialog-buttonpane {" + | |
" padding: 0 0.4em 0 0.4em;" + | |
"}" + | |
".gct_dialog .ui-button-text-only .ui-button-text {" + | |
" padding: 0.2em 0.8em;" + | |
"}" + | |
".gct_dialog .ui-progressbar .ui-progressbar-value {" + | |
" margin: 0;" + | |
"}" + | |
".gct_dialog .progressbar-label {" + | |
" width: 80%;" + | |
" text-align: center;" + | |
"}" + | |
"" + | |
"/* jqui settings dialog */\n" + | |
"" + | |
"div.gct_dialog select {" + | |
" width: auto;" + | |
" display: initial;" + | |
" padding: initial;" + | |
" -moz-appearance: menulist;" + | |
" -webkit-appearance: menulist;" + | |
"}" + | |
"div.gct_dialog label {" + | |
" text-transform: none;" + | |
" font-size: 100%;" + | |
"}" + | |
"div.gct_dialog input[type='radio'] {" + | |
" display: initial;" + | |
"}" + | |
"" + | |
"#dialogDetails {" + | |
" height:364px;" + | |
" padding:3px;" + | |
" overflow:auto;" + | |
" background-color:#eff4f9;" + | |
" border:1px solid #C0CEE3;" + | |
" -moz-border-radius: 0 5px 5px 0;" + | |
" border-radius: 0 5px 5px 0;" + | |
" width:424px;" + | |
" position: absolute;" + | |
" right: 10px;" + | |
"}" + | |
"" + | |
".dialogList {" + | |
" margin:0;" + | |
" padding:0;" + | |
"}" + | |
".dialogList li {" + | |
" font-size:10px;" + | |
" padding:3px;" + | |
" clear:both;" + | |
" list-style-type: none;" + | |
"}" + | |
"" + | |
".activeTour, .gct_sortable-placeholder {" + | |
" border: 1px solid #C0CEE3;" + | |
" -moz-border-radius: 5px 0 0 5px;" + | |
" border-radius: 5px 0 0 5px;" + | |
" background-color: #eff4f9;" + | |
" padding: 1px;" + | |
"}" + | |
".gct_sortable-placeholder {" + | |
" background-color: rgba(0, 0, 0, 0.03);" + | |
" height: 3em;" + | |
"}" + | |
"" + | |
"#dialogListContainer {" + | |
" height:374px;" + | |
" overflow:auto;" + | |
" width:146px;" + | |
" position: absolute;" + | |
" left: 10px;" + | |
"}" + | |
"" + | |
"#dialogListContainer a{" + | |
" text-decoration:underline;" + | |
"}" + | |
"" + | |
".unselectable {" + | |
" -o-user-select: none;" + | |
" -webkit-user-select: none;" + | |
" -moz-user-select: -none;" + | |
" -khtml-user-select: none;" + | |
" user-select: none;" + | |
"}" + | |
"" + | |
"#cacheList .counter {" + | |
" position:absolute;" + | |
" right:4px;" + | |
" bottom: 0;" + | |
" z-index:0;" + | |
" overflow:hidden;" + | |
" font: normal 24px arial,sans-serif;" + | |
" color: #d5d5d5;" + | |
" text-align:right;" + | |
" text-shadow: 1px 1px 1px #C0C0C0;" + | |
" vertical-align: text-bottom;" + | |
" background-color: transparent;" + | |
" margin-right:0;" + | |
" margin-bottom:0;" + | |
" padding: 0;" + | |
"}" + | |
"" + | |
"#gctour-notification-box {" + | |
" position: fixed;" + | |
" right: 4px;" + | |
" bottom: 2%;" + | |
" width: 220px;" + | |
" height: auto;" + | |
" max-height: 96%;" + | |
" overflow: hidden;" + | |
" overflow-y: auto;" + | |
" list-style-type: none;" + | |
" margin: 0;" + | |
" padding: 0;" + | |
" z-index: 1100;" + | |
"}" + | |
"" + | |
"#gctour-notification-box li {" + | |
" overflow: hidden;" + | |
" background-image: url('" + $.gctour.img.bg + "');" + | |
" background-repeat: repeat-x;" + | |
" background-attachment: scroll;" + | |
" background-position: left top;" + | |
" box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);" + | |
" width: 220px;" + | |
" cursor: pointer;" + | |
"}" + | |
"" + | |
".gctour-notification-green {" + | |
" background-color: lightgreen;" + | |
" color: #000000;" + | |
" border: 1px solid #50C24E;" + | |
" text-shadow: 0 1px 0 #FFFFFF;" + | |
"}" + | |
"" + | |
".gctour-notification-red {" + | |
" background-color: red;" + | |
" border: 1px solid #8B0000;" + | |
" color: #FFFFFF;" + | |
" text-shadow: 0 1px 0 #000000;" + | |
"}" + | |
"" + | |
".gctour-notification-blue {" + | |
" background-color: #57B7E2;" + | |
" border: 1px solid #0B90C4;" + | |
" color: #000000;" + | |
" text-shadow: 0 1px 0 #FFFFFF;" + | |
"}" + | |
"" + | |
".gctour-notification-yellow {" + | |
" background-color: #FFFC00;" + | |
" border: 1px solid #FFC237;" + | |
" color: #000000;" + | |
" text-shadow: 0 1px 0 #FFFFFF;" + | |
"}" + | |
"" + | |
"/* jquery ui overwrite */\n" + | |
"" + | |
".ui-front {" + | |
" z-index: 1100 !important;" + | |
"}" + | |
"" + | |
".ui-button-icon-only .ui-icon {" + | |
" margin-top: -8px !important;" + | |
" margin-left: -8px !important;" + | |
"}" + | |
"" + | |
".gct .ui-widget-content {" + | |
" background: #FFFFFF;" + | |
" /* border: 0; */" + | |
"}" + | |
"" + | |
".gct .ui-widget-content a {" + | |
" color: #00447c;" + // blue color | |
" text-decoration: underline;" + // underline text | |
"}" + | |
"" + | |
".ui-button-text-only .ui-button-text {" + | |
" padding: .2em .6em;" + | |
"}" + | |
"" + | |
"input.ui-button {" + | |
" padding: .2em .6em;" + | |
"}" + | |
"" + | |
".ui-dialog .ui-dialog-buttonpane {" + | |
" margin-top: 0;" + | |
"}" + | |
"" + | |
"/* Handling of Groundspeak's stylesheets: different sites use different stylesheets */\n" + | |
"" + | |
".gctour-input-checkbox {" + | |
" position: relative !important;" + | |
" opacity: 1 !important;" + | |
" width: 14px !important;" + | |
" height: 14px !important;" + | |
"}" + | |
"" + | |
".gctour-input-text {" + | |
" padding: unset !important;" + | |
" font-size: 1em !important;" + | |
" font-family: inherit !important;" + | |
" border: 1px solid #ccc !important;" + | |
" border-radius: 3px !important;" + | |
" height: auto !important;" + | |
"}" + | |
"" + | |
".gctour-label {" + | |
" display: unset !important;" + | |
"}" + | |
"" + | |
".gctour-small {" + | |
" font-size: 0.6875rem !important;" + | |
"}" + | |
"") | |
.replace("##gctourLogo##", $.gctour.img.gctourLogo) | |
.replace("##dialogMaskImage##", $.gctour.img.dialogMask) | |
.replace("##tabBgImage##", $.gctour.img.tabBg)); | |
} | |
/* utilities */ | |
// Read all GET URL variables and return them as an associative array. | |
function getUrlVars(url) { | |
var vars = [], | |
hash; | |
var hashes = url.slice(url.indexOf('?') + 1).split('&'); | |
for (var i = 0; i < hashes.length; i++) { | |
hash = hashes[i].split('='); | |
vars.push(hash[0]); | |
vars[hash[0]] = hash[1]; | |
} | |
return vars; | |
} | |
// USAGE: createElement('table',{style:"border-collapse:separate;"});append(image_table,dummy_images); | |
function createElement(type, attributes) { | |
var node = document.createElement(type), | |
attr; | |
for (attr in attributes) { | |
if (attributes.hasOwnProperty(attr)) { | |
node.setAttribute(attr, attributes[attr]); | |
} | |
} | |
return node; | |
} | |
function append(thisElement, toThis) { | |
return toThis.appendChild(thisElement); | |
} | |
function fillTemplate(mapping, template) { | |
var j, | |
dummy; | |
for (j = 0; j < mapping.length; j++) { | |
template = template.replaceAll("###" + mapping[j][0] + "###", mapping[j][1]); | |
} | |
dummy = createElement('div'); | |
dummy.innerHTML = template; | |
return dummy.firstChild; | |
} | |
// rot13.js from gc.com | |
function createROT13array() { | |
var A = 0, | |
C = [], | |
D = "abcdefghijklmnopqrstuvwxyz", | |
B = D.length; | |
for (A = 0; A < B; A++) { | |
C[D.charAt(A)] = D.charAt((A + 13) % 26); | |
} | |
for (A = 0; A < B; A++) { | |
C[D.charAt(A).toUpperCase()] = D.charAt((A + 13) % 26).toUpperCase(); | |
} | |
return C; | |
} | |
function convertROT13Char(A) { | |
return (A >= "A" && A <= "Z" || A >= "a" && A <= "z" ? ROT13_ARRAY[A] : A); | |
} | |
function convertROT13String(C) { | |
var A = 0, | |
B = C.length, | |
D = ""; | |
if (!ROT13_ARRAY) { | |
ROT13_ARRAY = createROT13array(); | |
} | |
for (A = 0; A < B; A++) { | |
D += convertROT13Char(C.charAt(A)); | |
} | |
return D; | |
} | |
function convertROTStringWithBrackets(C) { | |
var F = "", | |
D = "", | |
E = true, | |
A = 0, | |
B = C.length; | |
if (!ROT13_ARRAY) { | |
ROT13_ARRAY = createROT13array(); | |
} | |
for (A = 0; A < B; A++) { | |
F = C.charAt(A); | |
if (A < (B - 4)) { | |
if (C.toLowerCase().substr(A, 4) == "<br/>") { | |
D += "<br/>"; | |
A += 3; | |
continue; | |
} | |
} | |
if (F == "[" || F == "<") { | |
E = false; | |
} else { | |
if (F == "]" || F == ">") { | |
E = true; | |
} else { | |
if ((F === " ") || (F === "&dhbg;")) {} | |
else { | |
if (E) { | |
F = convertROT13Char(F); | |
} | |
} | |
} | |
} | |
D += F; | |
} | |
return D; | |
} | |
// Replace all &,< and > with their HTML tag; additionally replace <br> by <br /> (may cause problems on Garmin units) | |
function escapeHTML(htmlString) { | |
return (!htmlString) ? "" : htmlString.replace(/<br[^>]*>/gi, '<br />').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | |
} | |
// strip all ASCII control codes (range 0-31) from a string, except LF and CR | |
function stripASCIIcodes(s) { | |
return s.split('').filter(function(x) { | |
var n = x.charCodeAt(0); | |
return n==10 || n==13 || n>31; // keep LF and CR | |
}).join(''); | |
} | |
function xsdDateTime(date) { | |
function pad(n) { | |
var s = n.toString(); | |
return (s.length < 2) ? '0' + s : s; | |
} | |
var yyyy = date.getFullYear(), | |
mm1 = pad(date.getMonth() + 1), | |
dd = pad(date.getDate()), | |
hh = pad(date.getHours()), | |
mm2 = pad(date.getMinutes()), | |
ss = pad(date.getSeconds()); | |
return yyyy + '-' + mm1 + '-' + dd + 'T' + hh + ':' + mm2 + ':' + ss + 'Z'; | |
} | |
// GET, POST, PUT, DELETE | |
function promiseRequest(method, url, headers, data) { | |
log(["---PROMISEREQUEST---", | |
"\tmethod: " + method, | |
"\turl: " + url, | |
"\theaders: " + JSON.stringify(headers), | |
"\tdata (URI-decoded): " + decodeURI(data), | |
"---PROMISEREQUEST---" | |
].join("\n")); | |
// return a promise | |
return new Promise(function (resolve, reject) { | |
GM_xmlhttpRequest({ | |
method : method, | |
url : url, | |
headers : headers, | |
data : data, | |
timeout: 0, // infinity | |
onload : function (result) { | |
if (result.status >= 200 && result.status < 300) { // ok | |
responseInfo(result); | |
resolve(result); | |
} else { // error | |
responseInfo(result); | |
reject(' error: ' + result.status + ', message: ' + result.statusText); | |
} | |
}, | |
ontimeout : function () { | |
let l = new URL(url); | |
reject(' timeout detected: "no answer from ' + l.origin + ' - maybe down?"'); | |
}, | |
onerror : function (result) { // network error | |
responseInfo(result); | |
reject(' error: ' + result.status + ', message: ' + result.statusText); | |
} | |
}); | |
}); | |
} | |
// inspiration: dojo.date.difference (http://jsfiddle.net/fr4Na/) | |
function DateDiff(date1, date2, einheit) { | |
var ms = date1.getTime() - date2.getTime(); // milliseconds | |
var diff; | |
switch (einheit) { | |
case "second": | |
diff = ms / 1000; | |
break; | |
case "minute": | |
diff = ms / 60000; // 1000 * 60 | |
break; | |
case "hour": | |
diff = ms / 3600000; // 1000 * 60 * 60 | |
break; | |
case "day": | |
diff = ms / 86400000; // 1000 * 60 * 60 * 24 | |
break; | |
case "week": | |
diff = ms / 604800000; // 1000 * 60 * 60 * 24 * 7 | |
break; | |
default: | |
diff = ms; | |
break; | |
} | |
return diff; | |
} | |
async function getDateFormat(force) { | |
var myUrl = GS_HOST + 'account/settings/preferences', | |
response_div, | |
date_format; | |
// update locally stored date format, but only if necessary | |
if (force || !GM_getValue('date_format')) { | |
// get GS preferences | |
var response = await promiseRequest('GET', myUrl); | |
// get date format | |
response_div = createElement('div'); | |
response_div.innerHTML = response.responseText; | |
date_format = $('select#SelectedDateFormat option:selected', response_div).val(); | |
if (date_format !== "undefined") { | |
// store date format locally | |
GM_setValue('date_format', date_format); | |
debug("fn getDateFormat - GM_setValue: 'date_format' = " + date_format); | |
} else { | |
error("fn getDateFormat - select#SelectedDateFormat is undefined"); | |
} | |
} | |
return GM_getValue('date_format'); | |
} | |
function dateFormatConversion(format) { | |
return format.replace(/yy/g,'y').replace(/M/g,'m').replace(/mmm/,'M'); | |
/* GS dateformat to jqui datepicker dateformat: | |
https://www.geocaching.com/account/settings/preferences#SelectedDateFormat | |
http://api.jqueryui.com/datepicker/#utility-parseDate | |
GS --> jqui: d-->d,dd-->dd,M-->m,MM-->mm,MMM-->M,yy-->y,yyyy-->yy | |
"d. M. yyyy" : "d. m. yy", 3. 1. 2017 | |
"d.M.yyyy" : "d.m.yy", 3.1.2017 | |
"d.MM.yyyy" : "d.mm.yy", 3.01.2017 | |
"d/M/yy" : "d/m/y", 3/1/17 | |
"d/M/yyyy" : "d/m/yy", 3/1/2017 | |
"d/MM/yyyy" : "d/mm/yy", 3/01/2017 | |
"dd MMM yy" : "dd M y", 03 Jan 17 | |
"dd.MM.yy" : "dd.mm.y", 03.01.17 | |
"dd.MM.yyyy" : "dd.mm.yy", 03.01.2017 | |
"dd.MM.yyyy." : "dd.mm.yy.", 03.01.2017. | |
"dd.MMM.yyyy" : "dd.M.yy", 03.Jan.2017 | |
"dd/MM/yy" : "dd/mm/y", 03/01/17 | |
"dd/MM/yyyy" : "dd/mm/yy", 03/01/2017 | |
"dd/MMM/yyyy" : "dd/M/yy", 03/Jan/2017 | |
"dd-MM-yy" : "dd-mm-y", 03-01-17 | |
"dd-MM-yyyy" : "dd-mm-yy", 03-01-2017 | |
"d-M-yyyy" : "d-m-yy", 3-1-2017 | |
"M/d/yyyy" : "m/d/yy", 1/3/2017 | |
"MM/dd/yyyy" : "mm/dd/yy", 01/03/2017 | |
"MMM/dd/yyyy" : "M/dd/yy", Jan/03/2017 | |
"yyyy.MM.dd." : "yy.mm.dd.", 2017.01.03. | |
"yyyy/MM/dd" : "yy/mm/dd", 2017/01/03 | |
"yyyy-MM-dd" : "yy-mm-dd" 2017-01-03 */ | |
} | |
async function parseDate(date_string) { | |
var gs_date_format = await getDateFormat(), | |
jqui_date_format = dateFormatConversion(gs_date_format), | |
date, | |
debugStr = "date to parse: '" + date_string + "'\nGS format: '" + gs_date_format + "'\njqui format: '" + jqui_date_format; | |
try { | |
date = $.datepicker.parseDate(jqui_date_format, date_string); | |
debug(debugStr + "'\nParsed date: '" + date + "'"); | |
} catch (e) { | |
getDateFormat(true); // force internal update of GS date format | |
var err = 'Date format mismatch in fn parseDate - "' + e + '"<br> date format: ' + gs_date_format + '<br> date to parse: ' + date_string; | |
if (gs_date_format === 'undefined') { // most probably third-party cookies are not accepted by Firefox | |
err += '<br><br><u>Bitte Firefox-Einstellungen prüfen: Cookies von Drittanbietern müssen akzeptiert werden.</u>'; | |
err += '<br><u>Please check Firefox settings: third-party cookies need to be accepted.</u>'; | |
} | |
throw err; | |
} | |
return date; | |
} | |
async function formatDate(date) { | |
var gs_date_format = await getDateFormat(), | |
jqui_date_format = dateFormatConversion(gs_date_format); | |
try { | |
var date_string = $.datepicker.formatDate(jqui_date_format, date); | |
debug("date to format: '" + date + "'\nGS format: '" + gs_date_format + "'\njqui format: '" + jqui_date_format + "'\nDatestring: '" + date_string + "'"); | |
} catch(e) { | |
throw 'Date format mismatch in fn formatDate - "' + e + '"<br> date to format: ' + date + '<br> GS format: ' + gs_date_format; | |
} | |
return date_string; | |
} | |
/* geo utilities*/ | |
/** Orientiert an Geodesy representation conversion functions (c) Chris Veness 2002-2011 **/ | |
var Geo = {}; // Geo namespace, representing static class | |
/** | |
* Interpretiert einen String als Gradzahl. Diese Funktion verarbeitet alle 3 möglichen Formate (d, dm, dms) | |
* Limitiert auf eine Komponente pro Aufruf. | |
* | |
* @param {String} dmsStr: Koordinaten String | |
* @returns {Number} deg: Degrees | |
*/ | |
Geo.parseDMS = function (dmsStr) { | |
// entferne alle nicht Zahlen (Regex:[^\d.\s]) und teile den String an den verbleibenden Leerzeichen (Regex:[^0-9.,]) | |
var dms = dmsStr.replace(/[^\d.\s]/g, ' ').trim().split(/[^0-9.,]+/); | |
var deg; | |
// wenn nix mehr übrig bleibt -> keine Koordinate | |
if (dms == '') { | |
return NaN; | |
} | |
// Anhand der Länge von dms wird ermittelt im welchem Format die Koordinaten vorliegen | |
switch (dms.length) { | |
case 3: // interpret 3-part result as d/m/s | |
deg = dms[0] / 1 + dms[1] / 60 + dms[2] / 3600; | |
break; | |
case 2: // interpret 2-part result as d/m | |
deg = dms[0] / 1 + dms[1] / 60; | |
break; | |
case 1: // just d (possibly decimal) or non-separated dddmmss | |
deg = dms[0]; | |
break; | |
default: | |
return NaN; | |
} | |
// anschließend negiere Wert wenn der String ein S oder W beinhaltet | |
if (/^-|^[WS]/i.test(dmsStr.trim())) { | |
deg = -deg; | |
} | |
return deg; | |
}; | |
/** | |
* Konvertiert dezimal Gradzahlen zu dem festgelgegten Format ('d', 'dm', 'dms') - Vorangestellt N/S | |
* | |
* @param {Number} deg: Degrees | |
* @param {String} [format=dms]: Return value as 'd', 'dm', 'dms' | |
* @param {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d | |
* @returns {String} Deg/min/seconds | |
*/ | |
Geo.toLat = function (deg, format) { | |
var lat = Geo.toDMS(deg, format); | |
return lat == '' ? '' : (deg < 0 ? 'S' : 'N') + " " + lat.slice(1); // erste '0' abschneiden für Lat | |
}; | |
/** | |
* Konvertiert dezimal Gradzahlen zu dem festgelgegten Format ('d', 'dm', 'dms') - Vorangestellt E/W | |
* | |
* @param {Number} deg: Degrees | |
* @param {String} [format=dms]: Return value as 'd', 'dm', 'dms' | |
* @returns {String} Deg/min/seconds | |
*/ | |
Geo.toLon = function (deg, format) { | |
var lon = Geo.toDMS(deg, format); | |
return lon == '' ? '' : (deg < 0 ? 'W' : 'E') + " " + lon; | |
}; | |
/** | |
* Konvertiert dezimal Gradzahlen in das "deg°"(d), "deg° min" (dm) oder "deg°min'sec''"(dms) Format | |
* | |
* @private | |
* @param {Number} deg: Degrees | |
* @param {String} [format=dm]: Return Format 'd', 'dm', 'dms' | |
* @returns {String} Koordinaten String in dem festgelegten Format | |
* @throws {TypeError} wenn deg ein Object ist | |
*/ | |
Geo.toDMS = function (deg, format) { | |
if (typeof deg == 'object') { | |
throw new TypeError('Geo.toDMS - deg is an object'); | |
} | |
if (isNaN(deg)) { | |
return 'NaN'; | |
} // give up here if we can't make a number from deg | |
// default value of format = dms | |
if (typeof format == 'undefined') { | |
format = 'dm'; | |
} | |
deg = Math.abs(deg); // (unsigned result ready for appending NS|WE) | |
var dms, | |
d, | |
m, | |
s, | |
min, | |
sec, | |
tmpD, | |
tmpM; | |
switch (format) { | |
case 'd': | |
d = deg.toFixed(8); // round degrees | |
tmpD = d; | |
if (d < 100) { | |
tmpD = '0' + tmpD; | |
} // pad with leading zeros | |
if (d < 10) { | |
tmpD = '0' + tmpD; | |
} | |
dms = tmpD; // add ° symbol | |
break; | |
case 'dm': | |
min = (deg * 60).toFixed(8); // convert degrees to minutes & round | |
d = Math.floor(min / 60); // get component deg/min | |
m = (min % 60).toFixed(3); // pad with trailing zeros | |
tmpD = d; | |
tmpM = m; | |
if (d < 100) { | |
tmpD = '0' + tmpD; | |
} // pad with leading zeros | |
if (d < 10) { | |
tmpD = '0' + tmpD; | |
} | |
if (m < 10) { | |
tmpM = '0' + tmpM; | |
} | |
dms = tmpD + '\u00B0' + tmpM; // add ° symbols | |
break; | |
case 'dms': | |
sec = (deg * 3600).toFixed(0); // convert degrees to seconds & round | |
d = Math.floor(sec / 3600); // get component deg/min/sec | |
m = Math.floor(sec / 60) % 60; | |
s = (sec % 60).toFixed(0); // pad with trailing zeros | |
if (d < 100) { | |
d = '0' + d; | |
} // pad with leading zeros | |
if (d < 10) { | |
d = '0' + d; | |
} | |
if (m < 10) { | |
m = '0' + m; | |
} | |
if (s < 10) { | |
s = '0' + s; | |
} | |
dms = d + '\u00B0' + m + '\u2032' + s + '\u2033'; // add °, ', " symbols | |
break; | |
} | |
return dms; | |
}; | |
/** | |
* Erzeugt einen Punkt mit den gegebenen Latitude und Longitude | |
* @constructor | |
* @param {Number} lat: latitude in numeric degrees | |
* @param {Number} lon: longitude in numeric degrees | |
*/ | |
function LatLon(lat, lon) { | |
// only accept numbers or valid numeric strings | |
this._lat = typeof(lat) == 'number' ? lat : typeof(lat) == 'string' && lat.trim() != '' ? +lat : NaN; | |
this._lon = typeof(lon) == 'number' ? lon : typeof(lon) == 'string' && lon.trim() != '' ? +lon : NaN; | |
} | |
/** | |
* Gibt einen String mit "lat() lon()" von diesem Punkt zurück | |
* | |
* @param {String} [format]: Return value als 'd', 'dm', 'dms' | |
* @returns {String} Space-separated latitude/longitude | |
* | |
*/ | |
LatLon.prototype.toString = function (format) { | |
if (typeof format == 'undefined') { | |
format = 'dm'; | |
} | |
if (isNaN(this._lat) || isNaN(this._lon)) { | |
return '-,-'; | |
} | |
return Geo.toLat(this._lat, format) + ' ' + Geo.toLon(this._lon, format); | |
}; | |
/** | |
* Interpretiert eine Koordinaten Eingabe des Formats "N51° 12.123 E010° 23.123" oder "51.123 10.123" bzw. benutzt Geocoding API um die Koordinaten zu finden. | |
* | |
* @param {String} coord_string: Koordinaten in einem Format | |
* @param {Boolean} [force_Geocoding=false]: Wenn gesetzt sucht die Methode bei nicht numerischer Eingabe mittels Geocoding nach den Koordinaten | |
* @returns {LatLon} Koordinaten Object | |
*/ | |
async function parseCoordinates(coord_string, force_Geocoding) { | |
// entferne alle "," in Koordinaten String | |
if (typeof coord_string == "string") { | |
coord_string = coord_string.replace(/,/g, "."); | |
} | |
var lat, | |
lon; | |
// regex for N51° 12.123 E12° 34.123 | |
var regex_coord_ns = new RegExp(/(N|S)\s*(\d{0,2})\s*°\s*(\d{0,2}[\.,]\d+)/); | |
var regex_coord_ew = new RegExp(/(E|W)\s*(\d{0,3})\s*°\s*(\d{0,2}[\.,]\d+)/); | |
//regex for 51.123 12.123 | |
var regex_coord_dec = new RegExp(/(-{0,1}\d{0,2}[\.,]\d+)\s*(-{0,1}\d{0,3}[\.,]\d+)/); | |
var result_coord_ns = regex_coord_ns.exec(coord_string); | |
var result_coord_ew = regex_coord_ew.exec(coord_string); | |
var result_coord_dec = regex_coord_dec.exec(coord_string); | |
// Koordinate ist keins der beiden numerischen Formate | |
if (!(result_coord_ns && result_coord_ew) && !result_coord_dec) { | |
// ... now only a geocoding service can help ... | |
if (force_Geocoding) { | |
// search in OSM data | |
var response = await promiseRequest('GET', "https://nominatim.openstreetmap.org/search?format=json&limit=1&q=" + coord_string); | |
var geocoding_obj = JSON.parse(response.responseText); | |
if (geocoding_obj.length === 0) { // no result found | |
return false; | |
} | |
lat = geocoding_obj[0].lat; | |
lon = geocoding_obj[0].lon; | |
return new LatLon(lat, lon); | |
} else { | |
return false; | |
} | |
} else if (result_coord_ns && result_coord_ew) { | |
// result_coord_ns[0] = "N51° 12.123" | |
// result_coord_ew[0] = "E010° 23.123" | |
lat = Geo.parseDMS(result_coord_ns[0]); | |
lon = Geo.parseDMS(result_coord_ew[0]); | |
return new LatLon(lat, lon); | |
} else { | |
// result enthält beide Teile der Koordinate | |
lat = Geo.parseDMS(result_coord_dec[1]); | |
lon = Geo.parseDMS(result_coord_dec[2]); | |
return new LatLon(lat, lon); | |
} | |
} | |
function distanceBetween(lat1, lon1, lat2, lon2) { | |
var R = 6371000; // meters (change this constant to get miles) | |
var dLat = (lat2 - lat1) * Math.PI / 180; | |
var dLon = (lon2 - lon1) * Math.PI / 180; | |
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
var d = R * c; | |
return d; | |
} | |
/* helpers */ | |
// for map page: return center and radius | |
var getMapCenterAndRadius = function () { | |
var newMap = false; | |
if(location.pathname === '/play/map') { | |
newMap = true; | |
} | |
if (newMap) { | |
var search = location.search.substring(1); | |
var params = JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key === "" ? value : decodeURIComponent(value) }); | |
var ret = {}; | |
ret.center = {}; | |
ret.center.lat = params.lat; | |
ret.center.lng = params.lng; | |
// https://gis.stackexchange.com/questions/7430/what-ratio-scales-do-google-maps-zoom-levels-correspond-to#answer-127949 | |
var metersPerPx = 156543.03392*Math.cos(params.lat/180*Math.PI )/Math.pow(2, params.zoom); | |
var $map =$('div.app-main'); | |
var dim = Math.min($map.width(), $map.height()); | |
ret.radius = (metersPerPx*(dim/2)/1000).toFixed(3); // km | |
/* | |
///////////////////////////////////////////// | |
// get search results by repeating GS search | |
// center, width an height of rectangle | |
var center = [params.lat,params.lng]; | |
var width = metersPerPx*($map.width()); // m | |
var height = metersPerPx*($map.height()); // m | |
// waypoint projections to get bounds of rectangle | |
var dist_miles = 0.5*Math.sqrt(width**2 + height**2)/1609.344; // miles | |
var angle_nw = 360 - Math.atan(width/height)/Math.PI*180; // deg | |
var angle_se = proj_nw - 180; | |
var nw = CalcPrjWP(center[0], center[1], dist_miles, angle_nw); | |
var se = CalcPrjWP(center[0], center[1], dist_miles, angle_se); | |
//alert(nw+' '+se); | |
(async function() { | |
let url = GS_HOST + 'account/oauth/token'; | |
let response = await promiseRequest("GET", url); | |
response = JSON.parse(response.responseText); | |
let auth = response.token_type + ' ' + response.access_token; | |
url = GS_HOST + 'api/proxy/web/search?box='+nw+','+se+'&take=500&asc=false&skip=0&sort=favoritepoint'; | |
let headers = { | |
'Authorization': auth | |
}; | |
response = await promiseRequest("GET", url, headers); | |
let res = (JSON.parse(response.responseText)).results; | |
alert(res.length+' | '+res[0].name); | |
} | |
)(); | |
///////////////////////////////////////////// | |
*/ | |
} else { // old map | |
var googleMap = unsafeWindow.MapSettings ? unsafeWindow.MapSettings.Map : undefined, | |
ret = {}, | |
bounds; | |
ret.center = ""; | |
ret.radius = ""; | |
if (typeof(googleMap) !== "undefined") { | |
bounds = googleMap.getBounds(); | |
ret.center = googleMap.getCenter(); | |
ret.radius = Math.floor( | |
distanceBetween( | |
ret.center.lat, ret.center.lng, | |
bounds.getNorthEast().lat, | |
bounds.getNorthEast().lng - (bounds.getNorthEast().lng - bounds.getSouthWest().lng) / 2)) / 1000; | |
} | |
} | |
return ret; | |
}; | |
// is string json, isJSON(response.responseText) | |
// fn from js-Framework prototype v1.7 | |
var isJSON = function (str) { | |
if (str.length === 0) { | |
return false; | |
} | |
str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') | |
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') | |
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); | |
return (/^[\],:{}\s]*$/).test(str); | |
}; | |
// is String a GCCode ? | |
// begin with 'GC' + 1 to 6 chars, current is 5 (01.2017) | |
// return Boolean | |
var isGCCode = function (gccode) { | |
return (/^\s*(GC[0-9A-Z]{1,6})\s*$/).test(gccode); | |
}; | |
// find GCID (GCCode) in String | |
// first 'GC' + 1 to 6 chars in a string, current is 5 (01.2017) | |
// return String | |
// example: http://jsfiddle.net/NUFGq/15/ | |
var findGCCodeFromString = function (str) { | |
if (!str || str.length === 0) { | |
return false; | |
} | |
var treffer = str.match(/\bGC([0-9A-Z]{1,6})\b/) || []; | |
return (treffer[0] || ""); | |
}; | |
/* | |
2017-02-27: correct old paths to own waypoint icons (may still be present in stored tours); | |
run only once and for all | |
(temporary correction, can be deleted at a later point in time) | |
*/ | |
function correctOldOwnWaypointIconsPath() { | |
if (GM_getValue('correctOldOwnWaypointIconsPath')) { // already corrected | |
return; | |
} | |
debug('correctOldOwnWaypointIconsPath()'); | |
var allTours = GM_getValue('tours', ''), // JSON string | |
oldPath = 'http://www.madd.in/geocaching/gm/gctourextension/map/icons/neu/', | |
newPath = GCTOUR_HOST + 'i/'; | |
allTours = allTours.replaceAll(oldPath,newPath,true); | |
GM_setValue('tours',allTours); | |
GM_setValue('correctOldOwnWaypointIconsPath','true'); | |
} | |
// retrieve stylesheet from document | |
function getStyleSheet(name) { | |
for (var i = 0; i < document.styleSheets.length; i++) { | |
var sheet = document.styleSheets[i]; | |
if (sheet.href && sheet.href.includes(name)) { | |
return sheet; | |
} | |
} | |
} | |
// delete stylesheet rules by pattern | |
function deleteStyleSheetRules(sheet, pattern) { | |
var length = sheet.cssRules.length; | |
var deletedRules = []; | |
for (var i = 0; i < length; i++) { | |
var rule = sheet.cssRules[i]; | |
if (pattern.test(rule.cssText)) { | |
deletedRules.push(rule.cssText); | |
sheet.deleteRule(i); | |
i -= 1; | |
length -= 1; | |
} | |
} | |
return deletedRules; | |
} | |
/* initialize */ | |
// init core variables | |
function initCore() { | |
debug("initCore()"); | |
// setting up the language | |
$.gctour.currentLang = GM_getValue('language', $.gctour.defaultLang); | |
// temporary correction of own waypoint icon paths | |
correctOldOwnWaypointIconsPath(); | |
// getting all tours | |
TOURS = loadValue('tours', []); | |
// go get the current tour from the tour list | |
var currentTourId = GM_getValue('currentTour', -1); | |
CURRENT_TOUR = getTourById(currentTourId); | |
// oh - there is no current tour!? create one! | |
if (!CURRENT_TOUR) { | |
CURRENT_TOUR = {}; | |
CURRENT_TOUR.id = getNewTourId(); | |
CURRENT_TOUR.name = "Tour " + CURRENT_TOUR.id; | |
CURRENT_TOUR.geocaches = []; | |
TOURS.push(CURRENT_TOUR); | |
log("found no currentTour! Creating new one: " + CURRENT_TOUR.id + " ; " + CURRENT_TOUR.name); | |
saveCurrentTour(); | |
} | |
} | |
function init() { | |
debug("init()"); | |
var i; | |
// set Styles (GM_addStyle) | |
initStyle(); | |
// add global styles | |
var head = document.getElementsByTagName('head')[0], | |
style = document.createElement('style'); | |
style.type = 'text/css'; | |
head.appendChild(style); | |
// process "add to GCTour" link from GCTOUR_HOST | |
if (document.URL.search("webcode") >= 0) { | |
document.title = "GCTour"; | |
document.getElementsByTagName('body')[0].innerHTML = "<div align='center'><a href='" + GS_HOST + "'><img border='0' src='" + $.gctour.img.gctourLogo + "'/></a></div>"; | |
downloadTour(document.URL.split("webcode/")[1]); | |
return; | |
} | |
// start special script on send-to-gps page | |
if (document.URL.search("sendtogps.aspx") >= 0) { | |
// show the GPX box, if the option is set | |
if (GM_getValue('showGpx', false)) { | |
document.getElementById('dataString').parentNode.style.visibility = 'visible'; | |
document.getElementById('dataString').style.width = '100%'; | |
} | |
// see, whether this window is opened by the tour or by something else | |
var qsParm = []; | |
var query = window.location.search.substring(1); | |
var parms = query.split('&'); | |
for (i = 0; i < parms.length; i++) { | |
var pos = parms[i].indexOf('='); | |
if (pos > 0) { | |
var key = parms[i].substring(0, pos); | |
var val = parms[i].substring(pos + 1); | |
qsParm[key] = val; | |
} | |
} | |
if (qsParm['tour']) { | |
sendToGPS(); | |
} | |
return; | |
} | |
$(window).bind({ | |
// update the complete gui if the tab gets focus | |
'focus' : function (e) { | |
updateTour(); | |
}, | |
'resize' : function (e) { | |
handleResize(e); | |
} | |
}); | |
// process autoTour | |
if (GM_getValue('tq_url')) { | |
// if the cancel button is pressed | |
if (GM_getValue("stopTask", false)) { | |
GM_deleteValue('tq_url'); | |
GM_deleteValue('tq_caches'); | |
GM_setValue('stopTask', false); | |
document.location.href = GM_getValue('tq_StartUrl', GS_HOST); | |
return; // then return! | |
} | |
var tq_url = GM_getValue('tq_url'); | |
// remove protocols when comparing URLs | |
// (autoTour didn't work from map called with http, now it does) | |
if (tq_url.replace(/^https?\:\/\//i, "") == document.location.href.replace(/^https?\:\/\//i, "")) { | |
addProgressbar({ | |
caption : $.gctour.lang('autoTour.wait'), | |
closeCallback : function () { | |
return function () { | |
GM_setValue("stopTask", true); | |
closeOverlayRemote(document)(); | |
}; | |
} | |
}); | |
var tq_caches = loadValue('tq_caches', []), | |
tq_typeFilter = JSON.parse(GM_getValue('tq_typeFilter')), | |
tq_sizeFilter = JSON.parse(GM_getValue('tq_sizeFilter')), | |
tq_dFilter = JSON.parse(GM_getValue('tq_dFilter')), | |
tq_tFilter = JSON.parse(GM_getValue('tq_tFilter')), | |
tq_specialFilter = JSON.parse(GM_getValue('tq_specialFilter')), | |
pagesSpan = $("td.PageBuilderWidget > span:first"), | |
pagesSpanBolds = $('b', pagesSpan), | |
entries = getEntriesFromOldSearchpage(), | |
addBool; | |
if (pagesSpan.length <= 0) { | |
alert("no caches here :-("); | |
GM_deleteValue('tq_url'); | |
GM_deleteValue('tq_caches'); | |
document.location.href = GM_getValue('tq_StartUrl', GS_HOST); | |
return; | |
} | |
setProgress( | |
parseFloat(pagesSpanBolds.eq(1).text()) - 1, | |
parseFloat(pagesSpanBolds.eq(2).text()), | |
document); | |
log("entries: " + JSON.stringify(entries)); | |
// BEGIN for each cache | |
$.each(entries, function (i, entry) { | |
debug("entry[" + i + "]: " + JSON.stringify(entry)); | |
debug("##### 0 " + | |
"type:\t" + tq_typeFilter[entry.type] + "\n" + | |
"size:\t" + tq_sizeFilter[entry.size] + "\n" + | |
"difficulty: " + tq_dFilter[entry.difficulty] + "\n" + | |
"terrain:\t" + tq_tFilter[entry.terrain]); | |
// autoTour magic starts here (filter) | |
// check whether the caches match against the given type, size and D/T values | |
addBool = tq_typeFilter[entry.type] && | |
tq_sizeFilter[entry.size] && | |
tq_dFilter[entry.difficulty] && | |
tq_tFilter[entry.terrain]; | |
if (tq_specialFilter['is Active']) { | |
log("Check if " + entry.name + " is active:\n" + | |
"available: " + entry.available); | |
addBool = addBool && (entry.available); // only add if active! | |
} | |
if (tq_specialFilter['pm'] == "only") { // PM only | |
addBool = addBool && entry.pm_only; | |
} else { | |
if (tq_specialFilter['pm'] == "not") { // not PM | |
addBool = addBool && !entry.pm_only; | |
} | |
} | |
// autoTour parameter "haven't found" is not checked here because of URL parameter | |
addBool = addBool && | |
(parseInt(((tq_specialFilter['minFavorites']) ? tq_specialFilter['minFavorites'] : 0), 10) <= parseInt(entry.favorites, 10)); // minimal Favorites | |
// if all parameters match - add the cache | |
if (addBool) { | |
// 8.gif --> https://www.geocaching.com/images/wpttypes/sm/8.gif | |
entry.image = GS_HOST + GS_WPT_IMAGE_PATH + entry.image; | |
tq_caches.push(entry); | |
} | |
debug(entry.id + " " + entry.name + " filter:" + | |
"\n\ttype:" + entry.type + " = " + tq_typeFilter[entry.type] + | |
"\n\tsize:" + entry.size + " = " + tq_sizeFilter[entry.size] + | |
"\n\tdifficulty:" + entry.difficulty + " = " + tq_dFilter[entry.difficulty + ""] + | |
"\n\tterrain:" + entry.terrain + " = " + tq_tFilter[entry.terrain + ""] + | |
"\n\tavailable:" + entry.available + | |
"\n\tpm only:" + entry.pm_only + | |
"\n\t ==> Add to tour: " + addBool); | |
}); // END for each cache | |
GM_setValue('tq_caches', JSON.stringify(tq_caches)); | |
var gcComLinks = $("td.PageBuilderWidget > a", document), | |
nextLink = false; | |
// next Link finden | |
gcComLinks.each(function (index) { | |
if ($(this).html() == "<b>>></b>") { | |
nextLink = gcComLinks.eq(index + 1); | |
return false; // each schleife verlassen | |
} | |
}); | |
// check if there are some caches on this page (next link is not there) | |
if (!nextLink) { | |
alert("no caches here :-("); | |
GM_deleteValue('tq_url'); | |
GM_deleteValue('tq_caches'); | |
document.location.href = GM_getValue('tq_StartUrl', GS_HOST); | |
return; | |
} | |
// find next link | |
if (nextLink.attr("href")) { | |
var u = 500, | |
l = 2000, | |
waitingTime = Math.floor((Math.random() * (u - l + 1)) + l); | |
// wait between 0.5 -> 2 seconds to do the next request | |
setTimeout(function () { | |
nextLink[0].click(); | |
}, waitingTime); | |
} else { | |
CURRENT_TOUR = {}; | |
CURRENT_TOUR.id = getNewTourId(); | |
CURRENT_TOUR.name = "autoTour " + CURRENT_TOUR.id; | |
CURRENT_TOUR.geocaches = tq_caches; | |
TOURS.push(CURRENT_TOUR); | |
log("autoTour done - create new Tour: " + CURRENT_TOUR.id + " ; " + CURRENT_TOUR.name); | |
saveCurrentTour(); | |
document.location.href = GM_getValue('tq_StartUrl', GS_HOST); | |
} | |
} else { | |
GM_deleteValue('tq_url'); | |
GM_deleteValue('tq_caches'); | |
} | |
} | |
// maps | |
// old (browse) map: /map/default.aspx | |
if (document.URL.search("\/map\/") >= 0) { | |
//var $header = $("ul#uxLoginStatus_divSignedIn"); // new header layout (Aug 2017) | |
var $header = $("li.messagecenterheaderwidget"); | |
// autoTour button | |
$("<div>", { | |
//"class" : "header", | |
"css" : { | |
//'width' : 100, | |
//'height' : 30, | |
//'margin-top' : 10, | |
'overflow' : "hidden", | |
'border-radius' : 5, | |
'background-color' : "#FFF", | |
'border' : "2px solid #999", | |
'cursor' : 'pointer', | |
'float' : 'right' | |
}, | |
"html" : $("<h1>", { | |
"css" : { | |
'padding' : 0 | |
}, | |
click : function (e) { | |
var gooMap = getMapCenterAndRadius(); | |
showAutoTourDialog(gooMap.center, gooMap.radius); | |
}, | |
"html" : $("<img>", { | |
"src" : $.gctour.img.mapToAutoTour, | |
"width" : "70px" | |
}) | |
}) | |
.hover( | |
function () { | |
$(this).css({ | |
'backgroundColor' : 'orange' | |
}); | |
}, | |
function () { | |
$(this).css({ | |
//'backgroundColor' : '#B2D4F3' | |
'backgroundColor' : '#FFF' | |
}); | |
}) | |
}).prependTo($header); | |
// add to tour in cache pop-up; | |
// setTimeout is necessary since GCLH2 changes this template, too | |
setTimeout(function () { | |
$('#cacheDetailsTemplate').text( | |
function (index, text) { | |
var tmpAddToTour = '{{#if $ctx.userIsLoggedIn() }}' + | |
'<a class="lnk" id="attKnopf" href="javascript:add2tour();">' + | |
'<img src="' + $.gctour.img.addToTour + '"><span>' + $.gctour.lang('cache.addToTour') + '</span>' + | |
'</a>'; | |
return text.replace(/\{\{\#if \$ctx.userIsLoggedIn\(\) \}\}/g, tmpAddToTour); | |
}); | |
}, 0); | |
var add2tour = function () { | |
setTimeout(function () { | |
var gccode = $('#gmCacheInfo div[class="code"]:visible:first').text().trim(); | |
var name = $("#gmCacheInfo a[href*='cache_details.aspx']:visible:first").text().trim(); | |
var guid = getUrlVars($("#gmCacheInfo a[href*='/seek/log.aspx?guid']:visible:first").attr("href"))["guid"]; | |
var imageUrl = $("#gmCacheInfo img[src*='images/mapicons/']:visible:first").attr("src") || | |
$("#gmCacheInfo img[src*='"+GS_WPT_IMAGE_PATH+"']:visible:first").attr("src"); | |
var cacheTypeImage = imageUrl.split('/').pop(); | |
debug("map add2tour: gccode:'" + gccode + "' name:'" + name + "' image:'" + cacheTypeImage + "' guid:'" + guid + "'"); | |
addGeocache(gccode, guid, name, cacheTypeImage)(); | |
saveCurrentTourRefreshGUI(); | |
}, 0); | |
}; | |
// workaround for Violentmonkey in Firefox if "exportFunction" does not exist | |
// (see https://github.com/violentmonkey/violentmonkey/issues/168#issuecomment-321573665) | |
// nonetheless, this doesn't work for Chrome/Violentmonkey | |
if (typeof exportFunction !== 'function') { | |
exportFunction = function(func, scope, options) { | |
if (options && options.defineAs) { | |
scope[options.defineAs] = func; | |
} | |
return func; | |
}; | |
} | |
exportFunction(add2tour, unsafeWindow, { | |
defineAs : "add2tour" | |
}); | |
// make GS scrollbar in search section work | |
setTimeout(function() { | |
// show working scrollbar | |
$('div#scrollbar').css('overflow',''); | |
// remove non-working scrollbar | |
$('div#scroller').next().remove(); | |
},0); | |
} | |
// new (search) map: /play/map | |
if (document.URL.search("\/play\/map") >= 0) { | |
function addAutoTourButton() { | |
//let $autoTourAnchor = $("li.profile-panel-user").parent(); | |
let $autoTourAnchor = $("li.profile-panel-message-center"); | |
$("<li>", { | |
"css": { | |
'height': 26, | |
'overflow': "hidden", | |
'border-radius': 5, | |
'background-color': "#FFF", | |
'border': "2px solid #999", | |
'cursor': 'pointer' | |
}, | |
"html": $("<h1>", { | |
click: function(e) { | |
let map = getMapCenterAndRadius(); | |
showAutoTourDialog(map.center, map.radius); | |
}, | |
"html": $("<img>", { | |
"src": $.gctour.img.mapToAutoTour, | |
"width": "70px" | |
}) | |
}) | |
.hover( | |
function() { | |
$(this).css({'backgroundColor': 'orange'}); | |
}, | |
function() { | |
$(this).css({'backgroundColor': '#FFF'}); | |
} | |
) | |
}).insertBefore($autoTourAnchor); | |
} | |
// add cache to tour from cache details in sidebar | |
function add2tour_cacheDetails() { | |
let gccode = $('span.cache-metadata-code:first').text().trim(); | |
let name = $('div.header-top-left h1').text().trim(); | |
let guid = '0'; // must be present, but not really needed | |
let type = $('p.status-and-type'); | |
$('span.status', type).remove(); // remove status (if present): Premium, Disabled, ... | |
type = type.text().trim(); | |
let cacheTypeImage; | |
for (let i=0; i<WPT_ARRAY.length; i++) { | |
if (WPT_ARRAY[i].gsDisplayName == type) { | |
cacheTypeImage = WPT_ARRAY[i].wptTypeId + '.png'; | |
break; | |
} | |
} | |
debug("add2tour_cacheDetails: gccode:'" + gccode + "' name:'" + name + "' image:'" + cacheTypeImage + "' guid:'" + guid + "'"); | |
addGeocache(gccode, guid, name, cacheTypeImage)(); | |
saveCurrentTourRefreshGUI(); | |
}; | |
// add cache to tour from search list in sidebar | |
function add2tour_searchList($cacheitem) { | |
let guid = '0'; | |
let name = $('span.geocache-item-name', $cacheitem).text().trim(); | |
let gccode = $('span.geocache-item-code', $cacheitem).text().trim(); | |
let type = $('div.geocache-item-icon', $cacheitem).find('.geocache-item-type-icon use').attr("xlink:href").split('#').pop().split('_')[0]; | |
let cacheTypeImage; | |
for (let i=0; i<WPT_ARRAY.length; i++) { | |
if (WPT_ARRAY[i].shortname == type) { | |
cacheTypeImage = WPT_ARRAY[i].wptTypeId + '.png'; | |
break; | |
} | |
} | |
//debug("add2tour_searchList: gccode:'" + gccode + "' name:'" + name + "' image:'" + cacheTypeImage + "' guid:'" + guid + "'"); | |
addGeocache(gccode, guid, name, cacheTypeImage)(); | |
} | |
function addAllCachesFromSearchList(newTour) { | |
if (newTour && !newTourFunction()()) { | |
return; // exit on cancel | |
} | |
let $lastPage = $('ul.pagination>li>a[aria-label*="Page"]:last'); | |
let lastPage = ($lastPage.length > 0) ? parseInt( $($lastPage).text(), 10) : 1; | |
if (lastPage > 1) { // if pages are present, add progressbar | |
addProgressbar({ | |
_document: document, | |
closeCallback: function() { | |
return function() { | |
closeOverlayRemote(document)(); | |
}; | |
} | |
}); | |
} | |
let $caches='', i=0, timeout=100; | |
function loop() { // necessary to see updated progressbar | |
setProgress(i, lastPage, document); | |
if (lastPage > 1) { // if pages are present, click one by one, starting at page 1 | |
$('ul.pagination>li>a[aria-label*="Page '+(i+1)+'"]')[0].click(); | |
} | |
// for each page add all caches to tour | |
$caches = $('div.geocache-item'); | |
$.each($caches, function(i, obj) { | |
add2tour_searchList($(obj)); | |
}); | |
// when finished, return to 1st page | |
if (i === lastPage-1 && lastPage > 1) { | |
setTimeout(function() { // otherwise last page is not displayed | |
$('ul.pagination>li>a[aria-label*="Page 1"]')[0].click(); | |
}, timeout); | |
} | |
// save and update tour, close progressbar | |
if (i === lastPage-1) { | |
setTimeout(function() { // otherwise progressbar closes too early | |
saveCurrentTourRefreshGUI(); | |
closeOverlayRemote(document)(); | |
}, timeout); | |
} | |
i++; | |
if(i < lastPage) { // next page | |
setTimeout(loop, timeout); | |
} | |
} | |
setTimeout(loop, timeout); | |
} | |
let add2TourButton = | |
'<li>' + | |
'<button id="add2TourButton">' + | |
'<img class="action-icon" src="' + $.gctour.img.addToTour + '" style="width:20px;height:20px;">' + | |
'<span>' + $.gctour.lang('cache.addToTour') + '</span>' + | |
'</button>' + | |
'</li>'; | |
// observer callback for checking existence of autoTour anchor and sidebar (add2tour buttons will be added there) | |
let cb_body = function(mutationsList, observer) { | |
//if ($("li.profile-panel-user").length===0 || $('div#sidebar').length===0) { | |
if ($("li.profile-panel-message-center").length===0 || $('div#sidebar').length===0) { | |
return; | |
} | |
// buttons are present, thus no need to continue observing body further | |
observer_body.disconnect(); | |
// add autoTour button | |
addAutoTourButton(); | |
// start observing sidebar for switches between search list and cache details view | |
let target_sidebar = $('div#sidebar')[0]; | |
let config_sidebar = { | |
childList: true, | |
subtree: true | |
}; | |
observer_sidebar.observe(target_sidebar, config_sidebar); | |
} | |
// observer callback when sidebar switches between search list and cache details view | |
let cb_sidebar = function(mutationsList, observer) { | |
if ($('div#geocache-list').length > 0) { // list view | |
// buttons to add all caches to current or new tour | |
if ($('button#addAll2CurrentTourButton').length === 0) { // only add once | |
let addAll2CurrentTourButton = | |
'<button id="addAll2CurrentTourButton" class="gc-button" title="(' + $.gctour.lang('cache.all') + ') ' + $.gctour.lang('cache.addToCurrentTour').replace('<b>', '').replace('</b>', '') + '">' + | |
'<img src="' + $.gctour.img.addToTour + '" style="vertical-align: bottom;"/>' + | |
'</button>'; | |
let addAll2NewTourButton = | |
'<button id="addAll2NewTourButton" class="gc-button" title="(' + $.gctour.lang('cache.all') + ') ' + $.gctour.lang('cache.addToNewTour').replace('<b>', '').replace('</b>', '') + '">' + | |
'<img src="' + $.gctour.img.newTour + '" style="vertical-align: bottom;"/>' + | |
'+' + | |
'<img src="' + $.gctour.img.addToTour + '" style="vertical-align: bottom;"/>' + | |
'</button>'; | |
let divAddAll2TourButtons = | |
'<div class="geocache-action-bar" style="display:grid;grid-template-columns:50px 30px;justify-content:end;justify-items:start; padding-bottom:2px;">' + | |
addAll2NewTourButton + | |
addAll2CurrentTourButton + | |
'</div>'; | |
$('div.geocache-action-bar').after(divAddAll2TourButtons); | |
$('button#addAll2CurrentTourButton').on('click', function() { | |
addAllCachesFromSearchList(false); | |
}); | |
$('button#addAll2NewTourButton').on('click', function() { | |
addAllCachesFromSearchList(true); | |
}); | |
} | |
} else if ($('div.has-active-cache').length > 0 ) { // cache details view | |
if ($('button#add2TourButton').length === 0) { // only add once | |
// add "add2tour" button | |
$('div.cache-preview-action-menu ul').prepend(add2TourButton); | |
$('button#add2TourButton').on('click', function(e) { | |
add2tour_cacheDetails(); | |
}); | |
} | |
} | |
} | |
// create observer instances linked to callback functions | |
let observer_body = new MutationObserver(cb_body); | |
let observer_sidebar = new MutationObserver(cb_sidebar); // ATTENTION: the order matters here | |
// observe body for changes of child nodes until required anchors exist: | |
// 1) <li class="profile-panel-user">: autoTour button | |
// 2) <div id="sidebar">: add2Tour buttons | |
let target_body = $('body')[0]; | |
let config_body = { | |
childList: true, | |
subtree: true | |
}; | |
observer_body.observe(target_body, config_body); | |
} | |
// helper function to add buttons to bookmark and search list | |
let addButtonsToAddAllOrSelectedCaches = function(addEntriesFromList) { | |
let selectMenu = | |
'<select name="add2tour" id="add2tour">' + | |
' <option value="all">' + $.gctour.lang("cache.shown") + '</option>' + | |
' <option value="selected">' + $.gctour.lang("cache.marked") + '</option>' + | |
'</select>'; | |
// buttons | |
let $buttons = $("<div>", { | |
"css" : { | |
"margin" : "10px 0 10px 0", | |
"float": "left", | |
"width": "100%" | |
}, | |
html : selectMenu | |
}) | |
.append( | |
// button to add caches to current tour | |
$("<button>", { | |
"css" : { | |
"margin-left" : 10, | |
"cursor" : "pointer", | |
"background-color" : "#EEE" | |
}, | |
"html" : "<img src='" + $.gctour.img.addToTour + "'/> " + $.gctour.lang('cache.addToCurrentTour') | |
}) | |
.on('click', { | |
bLs: (bookmarkLines) ? bookmarkLines : '', | |
newTour: false | |
}, function(e) { | |
e.data["checkedOnly"] = ( $("select#add2tour option:selected").text() === $.gctour.lang('cache.marked') ) ? true : false; | |
e.preventDefault(); | |
addEntriesFromList(e); | |
})) | |
.append( | |
// button to add caches to a new tour | |
$("<button>", { | |
"css" : { | |
"margin-left" : 10, | |
"cursor" : "pointer", | |
"background-color" : "#EEE" | |
}, | |
"html" : "<img src='" + $.gctour.img.newTour + "'/> + <img src='" + $.gctour.img.addToTour + "'/> " + $.gctour.lang('cache.addToNewTour') | |
}) | |
.on('click', { | |
bLs: (bookmarkLines) ? bookmarkLines : '', | |
newTour: true | |
}, function(e) { | |
e.data["checkedOnly"] = ( $("select#add2tour option:selected").text() === $.gctour.lang('cache.marked') ) ? true : false; | |
e.preventDefault(); | |
addEntriesFromList(e); | |
}) | |
); | |
return $buttons; | |
} | |
// add buttons to bookmark list | |
if ( document.URL.search("\/bookmarks\/(view.aspx|bulk.aspx)") >= 0 && | |
$('input#ctl00_ContentBody_btnConfirm').length === 0 ) { // don't add to "delete selected items" page | |
var k, | |
bookmarkLine, | |
entry; | |
var bookmarkLines = $('tr[id$="Row"]'); // id muss mit Row enden | |
debug("bookmarkLines.length = " + bookmarkLines.length); | |
for (k = 0; k < bookmarkLines.length; k++) { | |
bookmarkLine = $("td", bookmarkLines[k]); | |
entry = getEntryFromBookmarkTd(bookmarkLine); | |
$("<img>", { | |
"alt" : $.gctour.lang('cache.addToTour'), | |
"title" : $.gctour.lang('cache.addToTour'), | |
"src" : $.gctour.img.addToTour, | |
"css" : { | |
"cursor" : "pointer", | |
"margin" : "0 0 0 5px" | |
} | |
}) | |
.on('click', { | |
entry : entry | |
}, function (e) { | |
addGeocache(e.data.entry.id, e.data.entry.guid, e.data.entry.name, e.data.entry.image)(); | |
saveCurrentTourRefreshGUI(); | |
}) | |
.appendTo(bookmarkLine[0]); // add buttons to first column | |
} | |
// helper function | |
var addEntryFromBookmark = function (e) { | |
var ck = e.data.checkedOnly || false; | |
var nt = e.data.newTour || false; | |
var listName = nt ? $("span#ctl00_ContentBody_lbHeading").html().split('<a')[0].trim() : ""; | |
if (!nt || (nt && newTourFunction(listName)())) { | |
$.each(e.data.bLs, function (i, v) { | |
var bookmarkLine = $("td", v); | |
var entry = getEntryFromBookmarkTd(bookmarkLine); | |
if ((entry) && (!ck || (ck && entry.checked))) { | |
addGeocache(entry.id, entry.guid, entry.name, entry.image)(); | |
} | |
}); | |
saveCurrentTourRefreshGUI(); | |
} | |
}; | |
// buttons to add marked or all caches in list to current or new tour | |
let $buttons = addButtonsToAddAllOrSelectedCaches(addEntryFromBookmark); | |
$buttons.insertBefore('table.Table'); | |
// remove unnecessary space at copy button | |
$('input#ctl00_ContentBody_ListInfo_btnCopyList').css('margin-bottom', '0px'); | |
} | |
// add buttons to nearest list | |
if (document.URL.search("\/seek\/nearest.aspx") >= 0) { | |
var entry_i, | |
entry; | |
var entries = getEntriesFromOldSearchpage(); | |
for (entry_i = 0; entry_i < entries.length; entry_i++) { | |
entry = entries[entry_i]; | |
$("<img>", { | |
"alt" : $.gctour.lang('cache.addToTour'), | |
"title" : $.gctour.lang('cache.addToTour'), | |
"src" : $.gctour.img.addToTour, | |
"css" : { | |
"cursor" : "pointer", | |
"margin" : "0px" | |
} | |
}) | |
.on('click', { | |
entry : entry | |
}, function (e) { | |
addGeocache(e.data.entry.id, e.data.entry.guid, e.data.entry.name, e.data.entry.image)(); | |
saveCurrentTourRefreshGUI(); | |
}) | |
.appendTo(entry.addBtnPosition); | |
// keep button in same line | |
entry.addBtnPosition.css('white-space','nowrap'); | |
} | |
// helper function | |
var addEntryFromSearchpage = function (e) { | |
var i, entry; | |
var ck = e.data.checkedOnly || false; | |
var nt = e.data.newTour || false; | |
var entries = getEntriesFromOldSearchpage(); | |
if (!nt || (nt && newTourFunction()())) { | |
for (i = 0; i < entries.length; i++) { | |
entry = entries[i]; | |
if ((entry) && (!ck || (ck && entry.checked))) { | |
addGeocache(entry.id, entry.guid, entry.name, entry.image)(); | |
} | |
} | |
saveCurrentTourRefreshGUI(); | |
} | |
}; | |
//buttons to add marked or all caches in list to current or new tour | |
let $buttons = addButtonsToAddAllOrSelectedCaches(addEntryFromSearchpage); | |
$buttons.prependTo("div#ctl00_ContentBody_ResultsPanel"); | |
} | |
// don't display the list on the sendtogpx page | |
if (document.URL.search("sendtogps.aspx") <= 0) { | |
initComponents(); | |
// add buttons to the cache details page | |
if (document.URL.search(GS_HOST + "geocache\/GC") >= 0 || document.URL.search("cache_details.aspx") >= 0) { | |
initButton(); | |
} | |
setTimeout(function () { // important since old and new map page are loaded with delay | |
// get user name | |
USERNAME = | |
$('span.user-name').text() || // premium | |
$('span.username').text() || // non-premium | |
$('span.cache-count').prev().text() || | |
$('span.find-count').prev().text(); // new map | |
}, 1000); | |
} | |
// ensure that the correct Groundspeak date format will be used (user setting in Groundspeak profile) | |
// - can only be changed by users here: https://www.geocaching.com/account/settings/preferences | |
// - if the site is called, simply update the locally stored date format | |
if (document.URL.search("\/account\/settings\/preferences") >= 0) { | |
getDateFormat(true); | |
} | |
} | |
/* init gui */ | |
function initButton() { | |
// if we are on a cache page the buttonGroup != null - so add the 'to tour'-button | |
var cacheControl = $("div.CacheInformationTable:first"); | |
if (cacheControl.length > 0) { | |
var div_element = createElement('div', { | |
style : "border-top: 1px solid rgb(192, 206, 227);" | |
}); | |
cacheControl.append(div_element); | |
var gcTourFieldset = createElement('fieldset', { | |
style : "background-color: #EFF4F9;border-color: #C0CEE3 !important;margin-top:0;padding: 0.5em;" | |
}); | |
append(gcTourFieldset, div_element); | |
gcTourFieldset.setAttribute('class', 'dialogFooter'); | |
gcTourFieldset.innerHTML = "<legend class='note' style='background:url(\"" + $.gctour.img.gctourLogoSmall + "\") no-repeat scroll 0 0 transparent;padding-left:20px;'>GCTour</legend>"; | |
// 1) add to tour button | |
var newButton = createElement('input', { | |
type : "button", | |
value : " " + $.gctour.lang('cache.addToTour'), | |
style : "float:left;background-image:url(" + $.gctour.img.addToTour + ")" | |
}); | |
append(newButton, gcTourFieldset); | |
newButton.setAttribute('onclick', 'return false;'); | |
// locate the values and save it | |
var minimal_geocache = getMinimalGeocacheDetails(document.getElementsByTagName('html')[0]); | |
var cacheId = minimal_geocache.gccode; | |
var guidId = minimal_geocache.guid; | |
var cacheName = minimal_geocache.name; | |
var cacheTypeImage = minimal_geocache.type; | |
// on click add an element | |
newButton.addEventListener('click', function() { | |
addGeocache(cacheId, guidId, cacheName, cacheTypeImage)(); | |
saveCurrentTourRefreshGUI(); | |
}, false); | |
// 2) direct print button | |
newButton = createElement('input', { | |
type : "button", | |
value : " " + $.gctour.lang('cache.directPrint'), | |
style : "float:left;background-image:url(" + $.gctour.img.printer + ")" | |
}); | |
append(newButton, gcTourFieldset); | |
newButton.setAttribute('onclick', 'return false;'); | |
// on click add an element | |
newButton.addEventListener('click', function () { | |
var entry = {}; | |
entry.id = cacheId; | |
entry.name = escapeHTML(cacheName); | |
entry.guid = guidId; | |
entry.image = GS_HOST + GS_WPT_IMAGE_PATH + cacheTypeImage; | |
var temp_tour = {}; | |
temp_tour.name = entry.name; | |
temp_tour.geocaches = [entry]; | |
printPageFunction(temp_tour); | |
}, false); | |
append(newButton, gcTourFieldset); | |
// 3) change coordinates button | |
newButton = createElement('input', { | |
type : "button", | |
value : " " + $.gctour.lang('cache.moveCoords'), | |
style : "float:left;background-image:url(" + $.gctour.img.coord_update + ")" | |
}); | |
append(newButton, gcTourFieldset); | |
newButton.setAttribute('onclick', 'return false;'); | |
newButton.addEventListener('click', openChangeCoordinates, false); | |
append(newButton, gcTourFieldset); | |
// display changed coordinates (if they have been changed by GCTour) | |
if (GM_getValue('coords_' + cacheId, "null") != "null") { | |
var coords_cacheId = GM_getValue('coords_' + cacheId); | |
displayChangedCoordinates(new LatLon(coords_cacheId.split('#')[0], coords_cacheId.split('#')[1]).toString()); | |
} | |
} | |
} | |
// the tour list under main navigation | |
function initComponents() { | |
// gcTour Button +++++++++++++++++++++++++++++++++++ | |
$("<div>", { | |
id : "gctourButtonWrapper", | |
"class" : "header gctour-grand-default", | |
"html" : | |
$("<img>", { | |
"src" : $.gctour.img.gctourLogoSmall | |
}) | |
}) | |
.hover( | |
function () { | |
$(this).addClass('gctour-grand-hover'); | |
$("#gctourContainer").animate({ | |
left : 0 | |
}, 500); | |
}, | |
function () { | |
$(this).removeClass('gctour-grand-hover'); | |
}) | |
.appendTo("body"); | |
// gcTour Container +++++++++++++++++++++++++++++++++++ | |
$("<div>", { | |
id : "gctourContainer", | |
"css" : { | |
left : (STICKY) ? 0 : -210 | |
} | |
}) | |
.hover( | |
function () { | |
clearTimeout(TIMEOUT); | |
}, | |
function () { | |
if (!STICKY) { | |
TIMEOUT = setTimeout(function () { | |
$("#gctourContainer").animate({ | |
left : -210 | |
}, 500); | |
}, 1000); | |
} | |
}) | |
.appendTo("body"); | |
var $geocacheList = $('<div>', { | |
id : "gctour_geocacheList", | |
"css" : { | |
overflow : 'auto', | |
height : '80%', | |
width : '100%' | |
}, | |
"html" : | |
$('<ul>', { | |
id : "cacheList", | |
'class' : 'cachelist' | |
}) | |
.sortable({ | |
axis : 'y', | |
placeholder : 'ui-sortable-placeholder', | |
opacity : 0.8, | |
revert : true, | |
start : function (e, ui) { | |
// save old position | |
$(this).data('old-pos', ui.item.index()); | |
}, | |
stop : function (e, ui) { | |
// init | |
var newPos = ui.item.index(); | |
var oldPos = $(this).data('old-pos'); | |
$(this).removeData('old-pos'); | |
debug("Drag n Drop in progress:\n" + | |
"\tMove " + CURRENT_TOUR.geocaches[oldPos].name + " (" + ui.item.attr('id') + ") from '" + oldPos + "' to '" + newPos + "'"); | |
// ignore the same position | |
if (oldPos === newPos) { | |
return; | |
} | |
// determine positions | |
var insertPos = (oldPos > newPos) ? newPos : newPos + 1; | |
var removePos = (oldPos < newPos) ? oldPos : oldPos + 1; | |
// changing the position | |
CURRENT_TOUR.geocaches.splice(insertPos, 0, CURRENT_TOUR.geocaches[oldPos]); | |
CURRENT_TOUR.geocaches.splice(removePos, 1); | |
// ... and save the new tour object | |
setTimeout(function () { // hack to prevent "access violation" from Greasemonkey | |
saveCurrentTour(); | |
}, 0); | |
move(ui.item.attr('id'), 0); // force numbering update | |
return; | |
} | |
}) | |
.disableSelection() | |
}); | |
var webcodelink = GCTOUR_HOST + 'tour/' + $.trim(CURRENT_TOUR.webcode); | |
var $tourHeader = $("<div>", { | |
id : "gctour_tourHeader", | |
"css" : {}, | |
"html" : '<img id="inconsistentTour" src="' + $.gctour.img.danger + '" style="float:right;padding:3px;display:none"/>' + | |
'<u id="tourName">' + CURRENT_TOUR.name + '</u> <span style="font-size:66%" id="cachecount">(' + CURRENT_TOUR.geocaches.length + ')</span>' + | |
'<span id="webcode" style="display:' + ((!CURRENT_TOUR.webcode) ? "none" : "inline") + ';"><br/>' + | |
'Webcode: <b><a href="' + webcodelink + '" title="' + $.gctour.lang('container.tourHeader.makeMap.caption') + '" target="_blank">' + CURRENT_TOUR.webcode + '</a></b> </span><br/>' | |
}); | |
$tourHeader.append( | |
// rename | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.edit, | |
title : $.gctour.lang('general.rename'), | |
alt : $.gctour.lang('general.rename'), | |
click : function () { | |
var newTourName = prompt($.gctour.lang('tour.newDialog'), CURRENT_TOUR.name); | |
if (!newTourName) { | |
return; | |
} | |
CURRENT_TOUR.name = newTourName; | |
saveCurrentTour(); | |
updateTour(); | |
} | |
}), | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.printer, | |
title : $.gctour.lang('settings.printview.header'), | |
alt : $.gctour.lang('settings.printview.header'), | |
click : function () { | |
printPageFunction(CURRENT_TOUR); | |
} | |
}), | |
// sendToGPS | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.sendGPS, | |
title : $.gctour.lang('container.tourHeader.sendToGps'), | |
alt : $.gctour.lang('container.tourHeader.sendToGps'), | |
click : function () { | |
if (GM_getValue('sendToGPS', 'old') == 'new') { | |
send2Garmin(); | |
} else { | |
openSend2GpsDialog(); | |
} | |
} | |
}), | |
// downloadGPX | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.downloadGPX, | |
title : $.gctour.lang('container.tourHeader.downloadGpx'), | |
alt : $.gctour.lang('container.tourHeader.downloadGpx'), | |
click : function () { | |
downloadGPXFunction(); | |
} | |
}), | |
// send2cgeo | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.send2cgeo, | |
title : $.gctour.lang('send2cgeo.title'), | |
alt : $.gctour.lang('send2cgeo.title'), | |
'style' : (DEBUG_MODE) ? '' : 'display:none;', | |
click : function () { | |
openGcTour2cgeoDialog(); | |
} | |
}), | |
// saveAsBookmarklist (PMO) | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.saveAsBookmarklist, | |
title : $.gctour.lang('container.tourHeader.saveAsBookmarklist.title'), | |
alt : $.gctour.lang('container.tourHeader.saveAsBookmarklist.title'), | |
'style' : (isPremiumUser()) ? '' : 'display:none;', | |
click : function () { | |
saveAsBookmarklist(); | |
} | |
}), | |
// makeMap | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.map, | |
title : $.gctour.lang('container.tourHeader.makeMap.caption'), | |
alt : $.gctour.lang('container.tourHeader.makeMap.caption'), | |
click : function () { | |
makeMapFunction(); | |
} | |
}), | |
// uploadTour | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.upload, | |
title : $.gctour.lang('container.tourHeader.upload.caption'), | |
alt : $.gctour.lang('container.tourHeader.upload.caption'), | |
click : function () { | |
uploadTourFunction(CURRENT_TOUR.id); | |
} | |
}), | |
// addWaypoint | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.plus, | |
title : $.gctour.lang('container.tourHeader.addOwnWaypoint'), | |
alt : $.gctour.lang('container.tourHeader.addOwnWaypoint'), | |
click : function () { | |
showNewMarkerDialog(); | |
} | |
}), | |
// deleteTour | |
$('<img>', { | |
id : 'gctourDeleteButton', | |
'class' : 'tourImage', | |
src : $.gctour.img.del, | |
title : $.gctour.lang('tour.remove'), | |
alt : $.gctour.lang('tour.remove'), | |
css : { | |
'display' : (TOURS.length <= 1) ? 'none' : 'inline' | |
}, | |
click : function () { | |
deleteCurrentTour(); | |
} | |
})).find("img.tourImage").addShadowEffect().addOpacityEffect(); | |
var $toolbar = $("<div>", { | |
id : "gctour_toolbar", | |
"css" : { | |
height : 20, | |
'-moz-user-select' : "none" | |
} | |
}); | |
$toolbar.append( | |
// newTourButton | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.newTour, | |
title : $.gctour.lang('container.toolbar.newList'), | |
alt : $.gctour.lang('container.toolbar.newList'), | |
click : function () { | |
newTourFunction()(); | |
} | |
}), | |
// toggleTourListButton | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.openTour, | |
title : $.gctour.lang('container.toolbar.openTour'), | |
alt : $.gctour.lang('container.toolbar.openTour'), | |
click : function () { | |
openTourDialog(); | |
} | |
}), | |
// downloadButton | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.download, | |
title : $.gctour.lang('container.toolbar.downloadTour.caption'), | |
alt : $.gctour.lang('container.toolbar.downloadTour.caption'), | |
click : function () { | |
downloadTourDialog(); | |
} | |
}), | |
// autoTourButton | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.autoTour, | |
title : $.gctour.lang('autoTour.title'), | |
alt : $.gctour.lang('autoTour.title'), | |
click : function () { | |
var gooMap = getMapCenterAndRadius(); | |
showAutoTourDialog(gooMap.center, gooMap.radius); | |
} | |
}), | |
// toggleSettingsButton | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.settings, | |
title : $.gctour.lang('container.toolbar.showSettings'), | |
alt : $.gctour.lang('container.toolbar.showSettings'), | |
click : function () { | |
openSettingsDialog(); | |
} | |
}), | |
// GCTour Home | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.globe, | |
title : $.gctour.lang('container.toolbar.homepage'), | |
alt : $.gctour.lang('container.toolbar.homepage'), | |
style : "float: right; margin-right: 11px;", | |
click : function () { | |
GM_openInTab(GCTOUR_HOST, false); | |
} | |
}), | |
// save settings info | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.info, | |
title : $.gctour.lang('container.toolbar.saveSettings'), | |
alt : $.gctour.lang('container.toolbar.saveSettings'), | |
style : "float: right;", | |
click : function() { | |
openSettingsDialog(); | |
$("#tabs").tabs({ active: 6 }); | |
} | |
}) | |
); | |
// Greasemonkey info | |
if (IS_GREASEMONKEY) { | |
$toolbar.append( | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.danger, | |
title : 'Greasemonkey Info', | |
alt : 'Greasemonkey Info', | |
style : "float: right;", | |
click : function() { | |
gmNotice(); | |
} | |
}) | |
); | |
} | |
var $header = $("<div>", { | |
id : "gctour_header", | |
"class" : "header gctour-grand-default" + ((STICKY) ? " gctour-grand-hover" : ""), | |
"css" : { | |
height : 40, | |
'cursor' : "pointer", | |
'-moz-user-select' : "none" | |
}, | |
"html" : "<img src='" + $.gctour.img.gctourLogo + "' style='margin: 6px 0px 0px;'/><small style='font-size: 75%;color:gray'>v " + VERSION + "</small>" + | |
"<img id='gcTourPin' style='float:right;margin: 6px 2px 0 0;' src='" + ((STICKY) ? $.gctour.img.pinned : $.gctour.img.pin) + "'>", | |
click : function (e) { | |
STICKY = !STICKY; | |
GM_setValue('sticky', STICKY); | |
$("img#gcTourPin").attr("src", ((STICKY) ? $.gctour.img.pinned : $.gctour.img.pin)); | |
} | |
}) | |
.hover( | |
function() { | |
$(this).addClass('gctour-grand-hover'); | |
}, | |
function() { | |
if (!STICKY) { | |
$(this).removeClass('gctour-grand-hover'); | |
} | |
}); | |
$("#gctourContainer").append( | |
$header, | |
$toolbar, | |
$tourHeader, | |
$geocacheList | |
); | |
// if available, add link to bookmark list | |
if (CURRENT_TOUR.bml) { | |
let bml = new Bookmarklist(CURRENT_TOUR.bml); | |
bml.addLink(); | |
}; | |
/* | |
if(DEBUG_MODE) { | |
var $footer = $('<div>', { | |
id : "gctour_footer", | |
"css" : { | |
position : "absolute", | |
bottom : -10, | |
"font-size" : "75%", | |
width : "100%", | |
height : "30" | |
}, | |
"html" : | |
$("<div>", { | |
"css" : { | |
'width' : '100%' | |
} | |
}).append( | |
$("<div>", { | |
"css" : { | |
'float' : 'right', | |
'margin-right' : 5 | |
}, | |
"html" : "Debug mode" | |
})) | |
}); | |
$("#gctourContainer").append($footer); | |
} | |
*/ | |
// populate the current list on load | |
for (var i = 0; i < CURRENT_TOUR.geocaches.length; i++) { | |
addToCacheList(CURRENT_TOUR.geocaches[i], false); | |
} | |
if (CURRENT_TOUR.geocaches.length <= 0) { | |
var table = document.getElementById('cacheList'); | |
table.innerHTML = $.gctour.lang('tour.empty'); | |
} | |
// finally: set new heights and layout! | |
setTimeout(function () { // ensure that everything is loaded before resizing | |
handleResize(); | |
}, 500); | |
} | |
/* init gui utilities*/ | |
function getEntryFromBookmarkTd(bmLine) { | |
/* | |
own bookmark list - Tabellenstruktur | |
1. checkbox | |
2. Richtung und Entfernung | |
3. Found | |
4. GC Code | |
5. Cache Name | |
6. "extra Feld" | |
other bookmark list - Tabellenstruktur | |
1. checkbox | |
2. Richtung und Entfernung | |
3. GC Code | |
4. Cache Name | |
5. "extra Feld" | |
*/ | |
var entry = {}, | |
colID = 2, // if this column is GC Code then other bookmark list | |
nameSpan = $("span", bmLine.eq(colID)).eq(0); | |
if ($.trim(bmLine.eq(colID).text()).length == 0) { | |
colID++; // own bookmark list | |
} | |
entry.id = $.trim(bmLine.eq(colID).text()); | |
entry.name = (nameSpan.length > 0) ? nameSpan.parent().html().replace(/<img.*?>/, "") : $.trim(bmLine.eq(colID + 1).text()); | |
entry.guid = bmLine.eq(colID + 1).find('a:first').attr("href").split('guid=')[1]; | |
entry.image = bmLine.eq(colID + 1).find('img:first').attr('src').split("/")[4]; // index changed from 6 to 4 | |
entry.checked = bmLine.eq(0).find("input:checkbox:first").is(':checked'); | |
debug("Bookmarklist cache row" + | |
"\n id: '" + entry.id + "'" + | |
"\n Name: '" + entry.name + "'" + | |
"\n Guid: '" + entry.guid + "'" + | |
"\n image: '" + entry.image + "'" + | |
"\n checked: '" + entry.checked + "'"); | |
return entry; | |
} | |
// get entries from old search page: https://www.geocaching.com/seek/nearest.aspx | |
function getEntriesFromOldSearchpage() { | |
// Data Rows without header and without GCVote tr | |
// <tr class="SolidRow Data BorderTop"> and | |
// <tr class="AlternatingRow Data BorderTop"> | |
var q = $("table.SearchResultsTable tbody tr.Data"); | |
var entries = []; | |
entries = q.map(function () { | |
// ToDo: in 099... bei process autoTour ~ Zeile 172 fast gleich ~~ beide zusammenlegen ?! | |
var entryTds = $(this).find('td'); | |
var entry = {}; | |
var lnk, | |
checkbox, | |
dt; | |
// use waypoint type column as reference for other columns (GCLH may add an additional column for fav score) | |
if (entryTds.find(".SearchResultsWptType").closest("td")[0] == entryTds.eq(4)[0]) { | |
var tdWpttype = 4; | |
} | |
else if (entryTds.find(".SearchResultsWptType").closest("td")[0] == entryTds.eq(5)[0]) { | |
var tdWpttype = 5; | |
} | |
// RegEx gc-id | |
entryTds.eq(tdWpttype + 1).find("span").eq(1).text().search(/\|\s*GC(\S{2,9})\s*\|/); | |
entry.id = "GC" + RegExp.$1; | |
lnk = entryTds.eq(tdWpttype + 1).find("a.lnk:first"); | |
entry.name = $.trim(lnk.text()); | |
entry.available = (lnk.css('text-decoration') !== "line-through"); | |
entry.image = entryTds.eq(tdWpttype).find("img:first").attr("src").toLowerCase().replace(/wpttypes\//, "wpttypes/sm/"); | |
// remove image path | |
entry.image = entry.image.split('/').pop(); | |
entry.type = entry.image.split('.')[0]; | |
// type Korrektur | |
entry.type = (entry.type == "earthcache") ? 137 : entry.type; | |
entry.pm_only = (entryTds.eq(tdWpttype + 2).find("img[src$='premium_only.png']").length > 0); | |
dt = $.trim(entryTds.find('span.small').closest('td.AlignCenter').find('span.small').text()); | |
entry.difficulty = dt.split("/")[0]; | |
entry.terrain = dt.split("/")[1]; | |
entry.size = $.trim(entryTds.find('img[src*="/images/icons/container/"]:first').attr("src").split("/")[4].split(".")[0]); | |
//entry.addBtnPosition = entryTds.find('.IconButton:first').closest('td'); | |
// Groundspeak removed Send To GPS column --> add GCTour button to checkbox column instead | |
entry.addBtnPosition = entryTds.eq(0).find("input:checkbox:first").closest('td'); | |
entry.checked = entryTds.eq(0).find("input:checkbox:first").is(':checked'); | |
entry.favorites = entryTds.eq(2).find("span[id$='FavoritesValue']").text(); | |
/* | |
debug( | |
"getEntriesFromOldSearchpage cache row: " + "\n" + | |
"\tid:\t\t" + entry.id + "\n" + | |
"\tname:\t\t" + entry.name + "\n" + | |
"\tavailable:\t" + entry.available + "\n" + | |
"\timage:\t\t" + entry.image + "\n" + | |
"\tsize:\t\t" + entry.size + "\n" + | |
"\ttype:\t\t" + entry.type + "\n" + | |
"\tdifficulty:\t" + entry.difficulty + "\n" + | |
"\tterrain:\t" + entry.terrain + "\n" + | |
"\tfavorites:\t" + entry.favorites + "\n" + | |
"\tpm_only:\t" + entry.pm_only + "\n" + | |
"\tchecked:\t" + entry.checked + "\n"); | |
*/ | |
return entry; | |
}).get(); | |
return entries; | |
} | |
/* gui functions */ | |
function isLoggedIn() { | |
if (USERNAME) { | |
return true; | |
} else { | |
$('<div>' + $.gctour.lang('general.notLoggedIn') + '</div>').dialog($.gctour.dialog.info()); | |
return false; | |
} | |
} | |
function isEmptyTour(tour) { | |
if (tour.geocaches.length > 0) { | |
return false; | |
} else { | |
$('<div>' + $.gctour.lang('tour.empty') + '</div>').dialog($.gctour.dialog.info()); | |
return true; | |
} | |
} | |
function showGeocacheNotification(geocache, event) { | |
geocache.name = escapeHTML(geocache.name); | |
if (event.type == "success") { | |
$.gctour.notification.add({ | |
title : $.gctour.lang('notifications.addgeocache.success.caption').format(geocache.id), | |
text : $.gctour.lang('notifications.addgeocache.success.content').format(geocache.tourname, geocache.name), | |
icon : geocache.image, | |
style : "green" | |
}); | |
} else if (event.type == "contains") { | |
$.gctour.notification.add({ | |
title : $.gctour.lang('notifications.addgeocache.contains.caption').format(geocache.id), | |
text : $.gctour.lang('notifications.addgeocache.contains.content').format(geocache.tourname, geocache.name), | |
icon : geocache.image, | |
style : "yellow" | |
}); | |
} else { | |
$.gctour.notification.add({ | |
title : "ERROR", | |
text : "Event '" + event + "' is not supported!", | |
style : "red" | |
}); | |
} | |
return; | |
} | |
function handleResize(e) { | |
// Change the height of the container and Cache List | |
var container = $(window).height() - 30, | |
header = $("#gctourContainer #gctour_header").height(), // 40 | |
toolbar = $("#gctourContainer #gctour_toolbar").height(), // 20; | |
tourheader = $("#gctourContainer #gctour_tourHeader").height(), | |
//footer = $("#gctourContainer #gctour_footer").height(), // 14; | |
cachelist = container - (header + toolbar + tourheader /*+ footer*/); | |
// set the container height | |
$('#gctourContainer').css("height", container); | |
// set the cachelist height | |
$('#cacheList').parent().css("height", cachelist); | |
/*log( | |
"handleResize change height:\n" + | |
"\tcontainer: " + container + "\n" + | |
"\theader: " + header + "\n" + | |
"\ttoolbar: " + toolbar + "\n" + | |
"\ttourheader: " + tourheader + "\n" + | |
//"\tfooter: " + footer + "\n" + | |
"\t => cachelist: " + cachelist);*/ | |
} | |
function updateGUI() { | |
var cacheList, | |
i, | |
table; | |
// update the cache count | |
updateCacheCount(CURRENT_TOUR.geocaches.length); | |
// update tourName | |
$("#tourName").html(CURRENT_TOUR.name); | |
// update webcode | |
var $webcode = $("#webcode"); | |
if (CURRENT_TOUR.webcode) { | |
$webcode | |
.find("a:first") | |
.attr('href', GCTOUR_HOST + 'tour/' + $.trim(CURRENT_TOUR.webcode)) | |
.text(CURRENT_TOUR.webcode) | |
.end() | |
.show(); | |
} else { | |
$webcode.hide(); | |
} | |
// update bookmark list | |
$('span#gct_bml').remove(); | |
if (CURRENT_TOUR.bml) { | |
let bml = new Bookmarklist(CURRENT_TOUR.bml); | |
bml.addLink(); | |
}; | |
cacheList = $('#cacheList'); | |
cacheList.html(""); | |
// populate the current list on load | |
for (i = 0; i < CURRENT_TOUR.geocaches.length; i++) { | |
addToCacheList(CURRENT_TOUR.geocaches[i], false); | |
} | |
if (CURRENT_TOUR.geocaches.length <= 0) { | |
cacheList.html($.gctour.lang('tour.empty')); | |
} | |
handleResize(); | |
var deleteButton = $('#gctourDeleteButton'); | |
if (TOURS.length == 1 && deleteButton) { | |
deleteButton.hide(); | |
} else { | |
deleteButton.show(); | |
} | |
} | |
// ToDo: switch to $.fn.addOpacityEffects | |
var addOpacityEffects = function (elem) { | |
$(elem) | |
.css({ | |
opacity : "0.5" | |
}) | |
.bind({ | |
mouseenter : function () { | |
$(this).stop().animate({ | |
opacity : '1' | |
}, 200); | |
}, | |
mouseleave : function () { | |
$(this).stop().animate({ | |
opacity : '0.5' | |
}, 300); | |
} | |
}); | |
}; | |
function addClickEffect(element) { | |
return function () { | |
element.style.background = '#a9b2bf'; | |
}; | |
} | |
function removeClickEffect(element) { | |
return function () { | |
element.style.background = '#cdd8e8'; | |
}; | |
} | |
function addHoverEffect(element) { | |
return function () { | |
element.style.margin = '0px'; | |
element.style.border = '1px solid lightgray'; | |
element.style.background = '#cdd8e8'; | |
}; | |
} | |
function removeHoverEffect(element) { | |
return function () { | |
element.style.margin = '1px'; | |
element.style.border = '0px solid lightgray'; | |
element.style.background = ''; | |
}; | |
} | |
function addHoverEffects(element) { | |
element.addEventListener('mouseover', addHoverEffect(element), false); | |
element.addEventListener('mouseout', removeHoverEffect(element), false); | |
element.addEventListener('mousedown', addClickEffect(element), false); | |
element.addEventListener('mouseup', removeClickEffect(element), false); | |
element.style.margin = '1px'; | |
} | |
async function getMapGeocache(gcid) { | |
try { | |
var mapCache, | |
additional_waypoints, | |
waypoint_i, | |
geocache = await getGeocache(gcid, 0); | |
if (geocache === "pm only") { | |
return; | |
} | |
mapCache = {}; | |
mapCache.gcid = geocache.gcid; | |
mapCache.guid = geocache.guid; | |
mapCache.image = geocache.image; | |
mapCache.name = geocache.name; | |
mapCache.difficulty = geocache.difficulty; | |
mapCache.terrain = geocache.terrain; | |
mapCache.latitude = geocache.lat; | |
mapCache.longitude = geocache.lon; | |
// save additional waypoints | |
additional_waypoints = geocache.additional_waypoints; | |
for (waypoint_i = 0; waypoint_i < additional_waypoints.length; waypoint_i++) { | |
additional_waypoints[waypoint_i].note = ""; | |
} | |
mapCache.additional_waypoints = additional_waypoints; | |
return mapCache; | |
} catch(e) { | |
throw "fn getMapGeocache - " + e; | |
} | |
} | |
function getMapMarker(markerId) { | |
var position = getPositionOfId(markerId), | |
marker = CURRENT_TOUR.geocaches[position]; | |
marker.index = position; | |
return marker; | |
} | |
function uploadMap(markerObj) { | |
let jsonMap = JSON.stringify(markerObj).replace(/&/g, " and "); // IMPORTANT! prevents critical errors in webapplication | |
let headers = {'Content-type' : 'application/x-www-form-urlencoded'}; | |
promiseRequest('POST', GCTOUR_HOST + 'map/save', headers, encodeURI("map=" + jsonMap)); | |
} | |
async function makeMapFunction() { | |
try { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
var gcIds = [], | |
wptIds = [], | |
allIds = [], | |
i; | |
// cache and custom marker IDs | |
for (i = 0; i < CURRENT_TOUR.geocaches.length; ++i) { | |
var marker = CURRENT_TOUR.geocaches[i]; | |
if (marker.id) { | |
gcIds.push(marker.id); | |
allIds.push(marker.id); | |
} else if (marker.wptcode) { | |
wptIds.push(marker.wptcode); | |
allIds.push(marker.wptcode); | |
} | |
} | |
// add the overlay while loading | |
addProgressbar({ | |
caption : $.gctour.lang('container.tourHeader.makeMap.wait'), | |
_document : document, | |
closeCallback : function (_document) { | |
return function () { | |
if (confirm($.gctour.lang('general.cancel') + "?") == true) { | |
window.location.reload(); | |
} | |
}; | |
} | |
}); | |
// for progress bar update | |
PROGRESS_BAR.progress = 0; | |
PROGRESS_BAR.total = gcIds.length + wptIds.length; | |
// fetch all caches in parallel, not one by one | |
var promises = []; | |
for (i = 0; i < gcIds.length; i++) { | |
promises.push(getMapGeocache(gcIds[i])); | |
} | |
FAVSCORE = false; // fav score not needed for map preview | |
var cache_objects = await Promise.all(promises); | |
FAVSCORE = true; | |
// store map specific cache information in array | |
var geocaches = []; | |
for (i = 0; i < gcIds.length; i++) { | |
geocaches.push(cache_objects[i]); | |
} | |
// store custom markers in array | |
var costumMarkers = []; | |
for (i = 0; i < wptIds.length; i++) { | |
costumMarkers.push(getMapMarker(wptIds[i])); | |
updateProgressBar(); | |
} | |
// store caches and custom markers in object | |
var cacheObject = {}; | |
cacheObject.geocaches = geocaches; | |
cacheObject.costumMarkers = costumMarkers; | |
// upload map content to server | |
uploadMap(cacheObject); | |
// open map content from server in new tab (request hash value according to tour content) | |
var mapUrl = await getMapUrl(allIds.join(",")); | |
setTimeout( function () { // ensure that GCTour server finished all tasks before opening map page | |
GM_openInTab(mapUrl + '#gui', false); | |
},1000); | |
closeOverlay(); | |
} catch(e) { | |
addErrorDialog({ | |
caption : "makeMapFunction error", | |
_exception : e | |
}); | |
} | |
} | |
async function upload(tour) { | |
try { | |
if (!tour.password) { | |
tour.password = "not yet implemented"; | |
} | |
var jsonTour = JSON.stringify(tour).replace(/&/g, " and "); // IMPORTANT! prevents critical errors in web application | |
var headers = {'Content-type' : 'application/x-www-form-urlencoded'}; | |
var response = await promiseRequest('POST', GCTOUR_HOST + 'tour/save', headers, encodeURI("tour=" + jsonTour)); | |
var tourServer = JSON.parse(response.responseText); | |
// after an error you get this result, e.g. | |
// {"message":"wrong password","type":"error"} | |
// only if the result is a message | |
if (tourServer.message && tourServer.type == "error") { | |
var pw = prompt("falsches Passwort - bitte richtiges eingeben"); // TODO !!! LANGUAGES!! | |
//if pw is empty or dialog closed | |
if (!pw) { | |
closeOverlay(); | |
return; | |
} | |
tour.password = pw; | |
upload(tour); | |
} else if (tourServer.message && tourServer.type == "info") { | |
alert(tourServer.message); | |
closeOverlay(); | |
} else { // result is a tour | |
// save password and webcode to tour | |
CURRENT_TOUR.password = tour.password; | |
CURRENT_TOUR.webcode = tourServer.webcode; | |
// save and update tour | |
saveTour(CURRENT_TOUR); | |
updateTour(); | |
closeOverlay(); | |
var str = $.gctour.lang('container.tourHeader.upload.tourUploaded1') + CURRENT_TOUR.webcode; | |
// Basic Members cannot upload PMO caches | |
var nPMOcaches = CURRENT_TOUR.geocaches.length - (tour.geocaches.length + tour.costumMarkers.length); | |
if (nPMOcaches > 0) { | |
var pmoc = []; | |
for (var i=0; i<CURRENT_TOUR.geocaches.length; i++) { | |
var gc = $.grep(tourServer.geocaches, function (obj,ind) { return (obj.id == CURRENT_TOUR.geocaches[i].id) }); | |
if (gc.length === 0) { // cache is PMO | |
pmoc.push((i+1)+':'+CURRENT_TOUR.geocaches[i].id); | |
} | |
} | |
var pmo = nPMOcaches + $.gctour.lang('container.tourHeader.upload.tourUploadPMO') + ':<br>' + pmoc.join(); | |
str += '</b><br><br><small><i>' + pmo + '</i></small>'; | |
} | |
str += $.gctour.lang('container.tourHeader.upload.tourUploaded2').replace(/xWEBCODEx/g, CURRENT_TOUR.webcode); | |
$('<div>' + str + '</div>').dialog($.gctour.dialog.info()); | |
} | |
} catch(e) { | |
throw 'fn upload - ' + e; | |
} | |
} | |
async function uploadTourFunction(id) { | |
try { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
var i, | |
tour, | |
geocaches, | |
cache_i, | |
costumMarker, | |
geocache, | |
mapCache, | |
waypoint_i, | |
codeString, | |
costumMarkers; | |
i = TOURS.map(function (tour) { | |
return tour.id | |
}).indexOf(id); | |
if (i == -1) { | |
throw ('uploadTourFunction(), line ' + new Error().lineNumber + ' - tour for index "' + id + '" not found'); | |
} | |
tour = TOURS[i]; // tour object to upload | |
var nCaches = tour.geocaches.length; | |
// deep copy of tour to upload (otherwise tour changes unintentionally before saving the updated status) | |
CURRENT_TOUR = JSON.parse(JSON.stringify(TOURS[i])); | |
// add the overlay while loading | |
GM_setValue("stopTask", false); | |
addProgressbar({ | |
_document : document, | |
closeCallback : function (_document) { | |
return function () { | |
if (confirm($.gctour.lang('general.cancel') + "?") == true) { | |
window.location.reload(); | |
} | |
}; | |
} | |
}); | |
// for progress bar update | |
PROGRESS_BAR.progress = 0; | |
PROGRESS_BAR.total = nCaches; | |
//create the overview map | |
geocaches = []; | |
costumMarkers = []; | |
// fetch all caches in parallel, not one by one | |
var promises = []; | |
for (i = 0; i < nCaches; i++) { | |
costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (costumMarker) { | |
promises.push(tour.geocaches[i]); | |
updateProgressBar(); | |
} else { | |
promises.push(getMapGeocache(tour.geocaches[i].id)); | |
} | |
} | |
FAVSCORE = false; // fav score not needed for tour upload | |
var cache_objects = await Promise.all(promises); | |
FAVSCORE = true; | |
var ind = 0; // in case that PMO caches are skipped for Basic Members | |
for (i = 0; i < nCaches; ++i) { | |
costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (!costumMarker) { | |
mapCache = cache_objects[i]; | |
if (mapCache) { // otherwise cache is PMO and user is Basic Member | |
geocaches.push(mapCache); | |
ind++; | |
} | |
} else { | |
var cm = cache_objects[i]; | |
cm.index = ind; | |
ind++; | |
costumMarkers.push(cm); | |
} | |
} | |
// separate own waypoints and caches for tour upload | |
tour.costumMarkers = costumMarkers; | |
tour.geocaches = geocaches; | |
await upload(tour); | |
} catch (e) { | |
closeOverlay(); | |
addErrorDialog({ | |
caption : "uploadTourFunction error", | |
_exception : e | |
}); | |
} | |
} | |
function isPremiumUser() { | |
try { | |
if(window.eval('typeof dataLayer') !== "undefined") { | |
return (window.eval('dataLayer[0].membershipLevel') == 'Premium') ? true : false; | |
} else if(window.eval('typeof serverParameters') !== "undefined") { | |
return (window.eval('serverParameters["user:info"].userType') == 'Premium') ? true : false; | |
} else if(window.eval('typeof ListResources') !== "undefined") { // maps page | |
return (window.eval('ListResources.isPremium') == 'True') ? true : false; | |
} | |
} catch(e) { | |
throw 'fn isPremiumUser - ' + e; | |
} | |
} | |
function switchToMyLists() { | |
(document.URL.search("account/lists") >= 0) ? window.location.reload() : GM_openInTab(GS_HOST + 'account/lists', false); | |
} | |
// prototype for bookmark lists | |
function Bookmarklist(id, auth) { | |
this._id = id; | |
this._auth = auth; | |
} | |
Bookmarklist.prototype.getToken = async function() { | |
let url = GS_HOST + 'account/oauth/token'; | |
let response = await promiseRequest("GET", url); | |
response = JSON.parse(response.responseText); | |
this._auth = response.token_type + ' ' + response.access_token; | |
} | |
Bookmarklist.prototype.create = async function() { | |
let list = {}; | |
list.name = ('GCTour - ' + CURRENT_TOUR.name).replace(/%/g,'_'); // '%' in cache name causes error | |
list.description = 'GCTour'; | |
let d = new Date(); | |
list.lastUpdateUtc = d.toJSON(); | |
list.count = 0; | |
list.type = { | |
"code": "bm" | |
}; | |
list.isShared = true; | |
list.isPublic = false; | |
list.isNotify = false; | |
let url = GS_HOST + 'api/proxy/web/v1/lists'; | |
let headers = { | |
'Authorization': this._auth, | |
'Content-Type': 'application/json' | |
}; | |
let response = await promiseRequest("POST", url, headers, JSON.stringify(list)); | |
let obj = JSON.parse(response.responseText); | |
// list id | |
this._id = obj.referenceCode; | |
} | |
Bookmarklist.prototype.delete = function() { | |
let url = GS_HOST + 'api/proxy/web/v1/lists/' + this._id; | |
let headers = { | |
'Authorization': this._auth | |
}; | |
promiseRequest("DELETE", url, headers); | |
} | |
Bookmarklist.prototype.addGeocaches = async function() { | |
let cacheArray = []; | |
let geocaches = CURRENT_TOUR.geocaches; | |
let nCaches = Math.min(geocaches.length,1000); // max. 1000 caches per bookmark list | |
for (let i = 0; i < nCaches; i++) { | |
let cache = {}; | |
cache.name = geocaches[i].name; | |
cache.id = geocaches[i].id; | |
cache.rownumber = i; | |
cache.referenceCode = geocaches[i].id; | |
cache.listItem = {}; | |
cache.listItem.name = geocaches[i].name; | |
cache.listItem.description = ""; | |
cacheArray.push(cache); | |
} | |
let url = GS_HOST + 'api/proxy/web/v1/lists/' + this._id + '/geocaches'; | |
let headers = { | |
'Authorization': this._auth, | |
'Content-Type': 'application/json;charset=utf-8' | |
}; | |
await promiseRequest("PUT", url, headers, JSON.stringify(cacheArray)); | |
} | |
Bookmarklist.prototype.addLink = function () { | |
// add link to tour header | |
$('span#webcode').after('<span id="gct_bml"><br>Bookmark: <b><a href="https://coord.info/' + this._id + '" target="_blank">' + this._id + '</a></b></span>'); | |
// delete bookmark list and link to bookmark list on click | |
let deleteImage = document.createElement('img'); | |
deleteImage.alt = $.gctour.lang('general.remove'); | |
deleteImage.title = $.gctour.lang('general.remove'); | |
deleteImage.style.cursor = 'pointer'; | |
deleteImage.style.width = '14px'; | |
deleteImage.style.verticalAlign = 'text-bottom', | |
deleteImage.style.marginLeft = '5px', | |
deleteImage.src = $.gctour.img.del; | |
deleteImage.addEventListener('click', async function() { | |
await deleteBookmarklist(CURRENT_TOUR.bml, CURRENT_TOUR.id); | |
$('span#gct_bml').remove(); // delete link to bookmark list from tour header | |
}, true); | |
addOpacityEffects(deleteImage); | |
$('span#gct_bml').append(deleteImage); | |
} | |
async function saveAsBookmarklist() { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
// a bookmark list for this tour already exists | |
if (CURRENT_TOUR.bml) { | |
$('<div>'+$.gctour.lang('container.tourHeader.saveAsBookmarklist.duplicate')+'</div>').dialog($.gctour.dialog.info(),{title: ''}); | |
return; | |
} | |
// tour contains own waypoints only | |
if ($.grep(CURRENT_TOUR.geocaches, function(e){ return e.id; }).length === 0) { // number of caches | |
log('nothing to add to a bookmark list - tour contains own waypoints only'); | |
return; | |
} | |
try { | |
// new lists page is only available for Premium member (Groundspeak decision) | |
if (!isPremiumUser()) { | |
switchToMyLists(); | |
return; | |
} | |
addProgressbar({ | |
caption: $.gctour.lang('container.tourHeader.saveAsBookmarklist.caption'), | |
closeCallback: function() { | |
return function() { | |
closeOverlayRemote(document)(); | |
}; | |
} | |
}); | |
let bml = new Bookmarklist(); | |
// request token | |
await bml.getToken(); | |
// create empty bookmark list | |
await bml.create(); | |
// add caches from tour to bookmark list | |
await bml.addGeocaches(); | |
closeOverlay(); | |
// add link to bookmark list | |
bml.addLink(); | |
// save BM link in tour | |
CURRENT_TOUR.bml = bml._id; | |
saveCurrentTour(); | |
// show info dialog | |
/*$('<div>'+$.gctour.lang('container.tourHeader.saveAsBookmarklist.success')+':<br><a href="'+GS_HOST+'account/lists" target="_blank">'+GS_HOST+'account/lists</a><br><a href="https://coord.info/'+bml._id+'" target="_blank">https://coord.info/'+bml._id+'</a></div>').dialog($.gctour.dialog.info(),{title: ''}); | |
$(".ui-button span").text($.gctour.lang('general.close'));*/ | |
} catch (e) { | |
addErrorDialog({ | |
caption : "saveAsBookmarklist error", | |
_exception : e | |
}); | |
} | |
} | |
async function deleteBookmarklist(bml_id, tour_id) { | |
// delete bookmark list | |
let bml = new Bookmarklist(bml_id); | |
await bml.getToken(); | |
bml.delete(); | |
// delete bookmark list id from tour | |
delete CURRENT_TOUR.bml; | |
saveCurrentTour(); | |
} | |
function openGarminExpress(url) { | |
// if installed then open, otherwise return false | |
try { | |
var $iframe = $("<iframe />"); | |
$iframe.css({ | |
"display": "none" | |
}); | |
$iframe.appendTo("body"); | |
$iframe[0].contentWindow.location.href = url; | |
return true; | |
} catch (e) { | |
return false; | |
} | |
} | |
async function send2Garmin() { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
try { | |
// new lists page and send to Garmin feature are only available for Premium member (Groundspeak decision) | |
if (!isPremiumUser()) { | |
switchToMyLists(); | |
return; | |
} | |
addProgressbar(); | |
let bml = new Bookmarklist(); | |
// request token | |
await bml.getToken(); | |
// create empty bookmark list temporarily | |
await bml.create(); | |
// add caches from tour to bookmark list | |
await bml.addGeocaches(); | |
// call Garmin Express locally | |
let url = GS_HOST + 'api/proxy/web/v1/garminexpress/list/' + bml._id; | |
let headers = { | |
'Authorization' : bml._auth | |
}; | |
let response = await promiseRequest("POST", url, headers); | |
let hash = JSON.parse(response.responseText); | |
url = 'garminexpress://manifestupdate/?manifesturl=https://api.groundspeak.com/web/v1/garminexpress/public/manifest/' + hash; | |
if (!openGarminExpress(url)) { // if Garmin Express is not available show info dialog | |
let info = | |
'<div style="text-align:center;">' + | |
'<p style="text-align:left;">Groundspeak message:</p>' + | |
' <b><i>Garmin Express not detected</b>' + | |
' <p>Make sure you have the latest version of Garmin Express installed.</p>' + | |
' <p><a href="http://software.garmin.com/en-US/express.html" target="_blank">Get Garmin Express</a></p></i>' + | |
'</div>'; | |
$(info).dialog($.gctour.dialog.info(),{title: ''}); | |
$(".ui-button span").text($.gctour.lang('general.close')); | |
} | |
// delete bookmark list | |
bml.delete(); | |
closeOverlay(); | |
} catch (e) { | |
addErrorDialog({ | |
caption : "Send to Garmin error", | |
_exception : e | |
}); | |
} | |
} | |
async function sendToGPS() { | |
try { | |
var dataStringElement, | |
tourName, | |
d, | |
currentDateString; | |
// add the overlay while loading | |
addProgressbar(); | |
// fix width and height of the header | |
$("div#dialogBody").find("h1").css({ | |
width : 486, | |
height : 14 | |
}); | |
// first time send to GPS is clicked: Accept the License | |
var accept_input = document.getElementById('chkAccept'); | |
if (accept_input) { | |
accept_input.checked = "checked"; | |
document.getElementById('btnSubmit').click(); | |
return; | |
} | |
// change ALWAYS to Garmin | |
var garmin_tab = document.getElementById('uxGPSProviderTabs').getElementsByTagName('li')[2]; | |
if (garmin_tab.getElementsByTagName('a')[0].className.toLowerCase().indexOf('selected') === -1) { | |
window.eval("__doPostBack('uxGPSProviderTabs', '2')"); | |
return; | |
} | |
// hint to new Garmin Express functionality | |
$('#uxGPSProviderTabs').removeClass("Tabs").html('<p><i style="font-weight: initial;"><small><u>New method available:</u> Open GCTour settings menu, navigate to "Send to GPSr" tab and select method "New (Garmin Express)" (<a href="http://forums.groundspeak.com/GC/index.php?showtopic=343784&st=0&p=5647070&#entry5647070" target="_new">more details</a>).</small></i></p>'); | |
// remove PM nag screen for basic members | |
$('#premiumUpsellMessage').remove(); | |
// change obsolete Garmin communicator links to signed mozilla communicator add-on | |
$(document).ready(function() { | |
$('#uxSendToGps a[href^="http://www.garmin.com/products/communicator"]').each(function() { | |
this.href = "https://addons.mozilla.org/de/firefox/addon/garmin-communicator/"; | |
}) | |
}) | |
// Beginning in Firefox 52, support for Garmin Communicator Plugin in Firefox has ended | |
$(document).ready(function() { | |
if ($('.pluginElement > #statusText').text().indexOf('Garmin Communicator Plugin NOT detected') != -1) { | |
var unsupported = ""; | |
if (IS_FF) { | |
unsupported = "Beginning in Firefox version 52 (your version: " + $.browser.version + "), support for NPAPI plugins (especially Garmin Communicator Plugin) in Firefox has ended (<a href='https://support.mozilla.org/t5/Problems-with-add-ons-plugins-or/Why-do-Java-Silverlight-Adobe-Acrobat-and-other-plugins-no/ta-p/31069' target='_new'>more details</a>).<br>However, Firefox ESR (Extended Support Release) version will continue to support these plugins until early 2018 (<a href='https://support.mozilla.org/t5/Problems-with-add-ons-plugins-or/Why-do-Java-Silverlight-Adobe-Acrobat-and-other-plugins-no/ta-p/31069' target='_new'>more details</a>)."; | |
} else { // Chrome | |
unsupported = "Chrome does not support NPAPI plugins (especially Garmin Communicator Plugin) anymore."; | |
} | |
var note = "<small><i><u>NOTE:</u> " + unsupported + "</i></small>"; | |
$('.pluginElement>#statusText').html(note); | |
} | |
}) | |
dataStringElement = document.getElementById('dataString'); | |
dataStringElement.value = $.gctour.lang('general.pleaseWait'); | |
dataStringElement.value = await getGPX(); | |
tourName = CURRENT_TOUR.name.replace(/\s+/g, "_").replace(/[^A-Za-z0-9_]*/g, ""); | |
d = new Date(); | |
currentDateString = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + | |
"_" + d.getHours() + "-" + d.getMinutes() + "-" + d.getSeconds(); | |
$('#cacheID').val('GCTour.' + tourName + '.' + currentDateString + '.gpx'); | |
// all done - remove the overlay | |
closeOverlay(); | |
} catch(e){ | |
addErrorDialog({ | |
caption : "Send to GPSr error", | |
_exception : e, | |
_document : parent.document | |
}); | |
} | |
} | |
function openSend2GpsDialog() { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
var overlay = getOverlay({ | |
caption : "Send to GPS", | |
minimized : true | |
}); | |
overlay.innerHTML = "<iframe src='" + GS_HOST + "seek/sendtogps.aspx?guid=3f26d17b-5fde-40c7-bbfb-3539964d0d31&tour=1' width='450px' height='350' scrolling='no' marginheight='0' marginwidth='0' frameborder='0'><p>Your browser does not support iframes.</p></iframe>"; | |
// Groundspeak pages "/seek/nearest.aspx*" hide contents of iframes --> Send to GPS would not work | |
$("iframe").css("display","block"); | |
} | |
function openSettingsDialog() { | |
if (DEBUG_MODE && console && console.time) { | |
console.time('show settings menu'); | |
} | |
var settings = new Settings_jqUI(); | |
settings.show(); | |
if (DEBUG_MODE && console && console.time) { | |
console.timeEnd('show settings menu'); | |
} | |
} | |
function populateTours() { | |
var tourIt, | |
tour, | |
$tourListLi, | |
$tourLink, | |
$webImage, | |
$deleteButton; | |
var $tourList = $('#dialogListContainer'); | |
$tourList.html(""); | |
var $tourListUl = $('<ul>', { | |
"class" : "dialogList", | |
"id" : "sortable" | |
}); | |
$tourList.append($tourListUl); | |
// construct tour list | |
for (tourIt = 0; tourIt < TOURS.length; tourIt++) { | |
tour = TOURS[tourIt]; | |
$tourListLi = $('<li>', { | |
id : "tour" + tour.id | |
}); | |
$tourListUl.append($tourListLi); | |
$tourLink = $('<a>', { | |
"css" : { | |
"cursor" : "pointer", | |
"font-size" : 10, | |
"color" : "#003399" | |
}, | |
html : tour.name + " <small>(" + tour.geocaches.length + ")</small>" | |
}) | |
.bind('click', { | |
tour : tour | |
}, function (e) { | |
showCacheList(e.data.tour)(); | |
}); | |
if (tour.webcode) { | |
$webImage = $('<img>', { | |
src : $.gctour.img.globe, | |
"css" : { | |
"float": "left", | |
"margin-right" : 3 | |
} | |
}); | |
$tourLink.prepend($webImage); | |
} | |
if (tour.id == CURRENT_TOUR.id) { | |
$tourLink.css({ | |
'font-weight' : 'bolder' | |
}); | |
} else { | |
$deleteButton = $('<img>', { | |
title : $.gctour.lang('tour.remove'), | |
src : $.gctour.img.del, | |
"css" : { | |
"cursor" : 'pointer', | |
"float" : 'right' | |
} | |
}) | |
.bind('click', { | |
tour : tour | |
}, function (e) { | |
deleteTour(e.data.tour.id)(); | |
}); | |
$tourLink.append($deleteButton); | |
} | |
$tourListLi.prepend($tourLink); | |
} | |
// sorting tours by drag and drop | |
$tourListUl.sortable({ | |
axis : "y", | |
cursor: "move", | |
helper: "clone", // prevent to fire click events | |
items: "> li", | |
placeholder : "gct_sortable-placeholder", | |
revert: true, | |
start : function (e, ui) { | |
// save old position | |
$(this).data('old-pos', ui.item.index()); | |
}, | |
update: function(e, ui) { | |
var oldPos = $(this).data('old-pos'); | |
var newPos = ui.item.index(); | |
debug("Drag n Drop in progress:\n" + | |
"\tMove tour " + TOURS[oldPos].name + " (id: " + ui.item.attr('id') + ") from '" + oldPos + "' to '" + newPos + "'"); | |
// positions to insert/remove | |
var insertPos = (oldPos > newPos) ? newPos : newPos + 1; | |
var removePos = (oldPos < newPos) ? oldPos : oldPos + 1; | |
// insert tour to new position, then remove tour from old position | |
TOURS.splice(insertPos, 0, TOURS[oldPos]); | |
TOURS.splice(removePos, 1); | |
// save tour with new order | |
saveValue('tours', TOURS); | |
}, | |
stop : function (e, ui) { | |
// remove old position | |
$(this).removeData('old-pos'); | |
} | |
}); | |
} | |
function showCacheList(tour) { | |
return function () { | |
var cacheList = document.getElementById('dialogDetails'); | |
cacheList.scrollTop = 0; | |
cacheList.setAttribute("tourid", tour.id); | |
cacheList.innerHTML = "<u><b>" + tour.name + "</b>"; | |
if (tour.webcode) { | |
cacheList.innerHTML += " <i>Webcode: <a href='" + GCTOUR_HOST + "tour/" + $.trim(tour.webcode) + "' title='" + $.gctour.lang('container.tourHeader.makeMap.caption') + "' target='_blank'>" + tour.webcode + "</a></i>"; | |
} | |
cacheList.innerHTML += "</u><br/>"; | |
var copyButton = document.createElement('img'); | |
copyButton.title = $.gctour.lang('tour.copy'); | |
copyButton.src = $.gctour.img.copy; | |
copyButton.style.cursor = 'pointer'; | |
copyButton.style.marginRight = '5px'; | |
copyButton.style.cssFloat = 'right'; | |
copyButton.addEventListener('click', function () { | |
var newTour = JSON.parse(JSON.stringify(tour)); | |
newTour.id = getNewTourId(); | |
newTour.name = newTour.name + " - " + $.gctour.lang('general.copy'); | |
TOURS.push(newTour); | |
log("Creating copy tour: " + newTour.id + " ; " + newTour.name); | |
saveTour(newTour, true); | |
populateTours(); | |
showCacheList(newTour)(); | |
}, false); | |
var deleteButton = document.createElement('img'); | |
deleteButton.title = $.gctour.lang('tour.remove'); | |
deleteButton.src = $.gctour.img.del; | |
deleteButton.style.cursor = 'pointer'; | |
deleteButton.style.marginRight = '5px'; | |
deleteButton.style.cssFloat = 'right'; | |
deleteButton.addEventListener('click', deleteTour(tour.id), false); | |
var renameButton = document.createElement('img'); | |
renameButton.src = $.gctour.img.edit; | |
renameButton.title = $.gctour.lang('general.rename'); | |
renameButton.alt = $.gctour.lang('general.rename'); | |
renameButton.style.cursor = 'pointer'; | |
renameButton.style.marginRight = '5px'; | |
renameButton.style.cssFloat = 'right'; | |
renameButton.addEventListener('click', | |
function () { | |
var newTourName = prompt($.gctour.lang('tour.newDialog'), tour.name); | |
if (!newTourName) { | |
return; | |
} | |
tour.name = newTourName; | |
saveTour(tour, true); | |
populateTours(); | |
showCacheList(tour)(); | |
}, false); | |
if (tour.id != CURRENT_TOUR.id) { | |
cacheList.insertBefore(deleteButton, cacheList.firstChild); | |
} | |
cacheList.insertBefore(renameButton, cacheList.firstChild); | |
cacheList.insertBefore(copyButton, cacheList.firstChild); | |
var cacheListUl = createElement('ul'); | |
cacheListUl.setAttribute("class", "dialogList"); | |
for (var cacheIt = 0; cacheIt < tour.geocaches.length; cacheIt++) { | |
var geocache = tour.geocaches[cacheIt]; | |
var cacheListLi = createElement('li', { | |
style : "b" | |
}); | |
append(cacheListLi, cacheListUl); | |
cacheListLi.innerHTML = "<img src='" + geocache.image + "' style='margin-left=10px'> " + geocache.name + ' <small style="font-size: 90%;">' + ((geocache.id !== undefined) ? '('+geocache.id+')' : '') + "</small>"; | |
} | |
append(cacheListUl, cacheList); | |
// make loadButton available | |
var loadButton = document.getElementById('loadButton'); | |
loadButton.value = '"' + tour.name + '"'; | |
loadButton.removeAttribute('disabled'); | |
// first remove all active tour css classes | |
$("ul.dialogList > li").removeClass("activeTour"); | |
//and then set it to the clicked | |
$('#tour' + tour.id).addClass("activeTour"); | |
}; | |
} | |
function moveEntryToOtherTour(entryId,tourId) { | |
// get entry from current tour | |
var pos = getPositionOfId(entryId); | |
var entry = CURRENT_TOUR.geocaches[pos]; | |
// get other tour | |
var otherTour = getTourById(tourId); | |
// check if element is already in other tour | |
var isInTour = false; | |
$.each(otherTour.geocaches, function (i, obj) { | |
if (obj.id == entryId || obj.wptcode == entryId) { | |
isInTour = true; | |
return false; // break each | |
} | |
}); | |
if (isInTour) { | |
showGeocacheNotification({ | |
id : (entry.id || entry.name), | |
name : entry.name, | |
image : entry.image, | |
tourname : otherTour.name | |
}, { | |
type : "contains" | |
}); | |
return; | |
} | |
debug("moving '" + entryId + "' to '"+ otherTour.name + "'"); | |
// add entry to other tour | |
otherTour.geocaches.push(entry); | |
// save modified other tour without changing current tour | |
saveTour(otherTour, true); | |
// delete entry from current tour and update | |
deleteElement(entryId)(); | |
showGeocacheNotification({ | |
id : (entry.id || entry.name), | |
name : entry.name, | |
image : entry.image, | |
tourname : otherTour.name | |
}, { | |
type : "success" | |
}); | |
} | |
function openTourDialog(entryId) { | |
var overLay = getOverlay({ | |
caption : (entryId === undefined) ? $.gctour.lang('container.toolbar.openTour') : $.gctour.lang('container.cacheList.moveToList') | |
}); | |
// make dialog draggable | |
$('#dialogBody').draggable({ | |
cancel: '#dialogListContainer,#dialogDetails,input', | |
// cursor: "move", // does not work | |
start: function (e, ui) { | |
$(this).css('cursor', 'move'); | |
}, | |
stop: function (e, ui) { | |
$(this).css('cursor', 'default'); | |
} | |
}); | |
var tourList = createElement('div', { | |
id : "dialogListContainer" | |
}); | |
append(tourList, overLay); | |
var cacheList = createElement('div', { | |
id : "dialogDetails" | |
}); | |
append(cacheList, overLay); | |
populateTours(); | |
// load,close buttons | |
var buttonsDiv = createElement('div', { | |
style : "width:580px;position: absolute; bottom: 10px;" | |
}); | |
append(buttonsDiv, overLay); | |
buttonsDiv.setAttribute('class', 'dialogFooter'); | |
var closeButton = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.cancel'), | |
style : "background-image:url(" + $.gctour.img.closebutton + ")" | |
}); | |
append(closeButton, buttonsDiv); | |
closeButton.addEventListener('click', closeOverlay, false); | |
var loadButton = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.load'), | |
disabled : "", | |
id : "loadButton", | |
style : "background-image:url(" + $.gctour.img.openTour + ")" | |
}); | |
append(loadButton, buttonsDiv); | |
loadButton.addEventListener('click', function () { | |
var id = $("#dialogDetails").attr("tourid"); // ToDo: to $().data | |
if (entryId === undefined) { | |
loadTour(id)(); | |
} else { | |
moveEntryToOtherTour(entryId,id); | |
} | |
closeOverlay(); | |
}, false); | |
// load currentTour | |
showCacheList(CURRENT_TOUR)(); | |
loadButton.setAttribute("disabled", "disabled"); | |
} | |
async function downloadTour(webcode, _url) { | |
try { | |
var url, | |
onlineTour; | |
// add the overlay while loading | |
addProgressbar(); | |
url = GCTOUR_HOST + 'tour/' + $.trim(webcode) + '/json'; | |
if (typeof _url !== "undefined") { // url to old server | |
url = _url; | |
} | |
var response = await promiseRequest('GET', url), | |
booResponse = (response.status === 200), // only status 200 | |
booIsJson = isJSON(response.responseText); // is response json ? | |
if (!booResponse || !booIsJson) { | |
alert("Webcode '" + webcode + "' could not be loaded.\n" + | |
response.status + ", " + response.statusText + ((booIsJson) ? "" : ", format is not valid")); | |
closeOverlay(); | |
return false; | |
} | |
var responseObject = JSON.parse(response.responseText); | |
if (responseObject.type == "error" && responseObject.message == "no tour") { | |
// if webcode was not found on new server, try old server | |
if (response.finalUrl.indexOf(GCTOUR_HOST) >= 0) { | |
downloadTour(webcode, 'http://gctour.madd.in/tour/' + $.trim(webcode) + '/json'); | |
closeOverlay(); | |
return false; | |
} | |
// neither on new nor on old server | |
$('<div>' + $.gctour.lang('container.toolbar.downloadTour.webcodeerror') + '</div>').dialog($.gctour.dialog.info()); | |
} else if (responseObject.type == "oldtour") { | |
onlineTour = JSON.parse(responseObject.message); | |
onlineTour.id = getNewTourId(); | |
TOURS.push(onlineTour); | |
saveCurrentTour(); | |
log("Download of an old online tour successful: " + onlineTour.id + " ; " + onlineTour.name); | |
closeOverlay(); | |
alert("tour '" + onlineTour.name + "'\n" + $.gctour.lang('container.toolbar.downloadTour.webcodesuccess') + "\n" + $.gctour.lang('container.toolbar.downloadTour.webcodeOld')); | |
loadTour(onlineTour.id)(); | |
} else { | |
onlineTour = responseObject; | |
onlineTour.id = getNewTourId(); | |
for (var i=0; i<onlineTour.geocaches.length; i++) { | |
onlineTour.geocaches[i].name = escapeHTML(onlineTour.geocaches[i].name); | |
} | |
TOURS.push(onlineTour); | |
saveCurrentTour(); | |
closeOverlay(); | |
var str = "<br>Tour <u>" + onlineTour.name + "</u> " + $.gctour.lang('container.toolbar.downloadTour.webcodesuccess'); | |
$('<div>' + str + '</div>').dialog($.gctour.dialog.info()); | |
loadTour(onlineTour.id)(); | |
} | |
} catch (e) { | |
addErrorDialog({ | |
caption : "Download tour error", | |
_exception : e | |
}); | |
} | |
} | |
function downloadTourDialog() { | |
var overlay = getOverlay({ | |
caption : $.gctour.lang('container.toolbar.downloadTour.caption'), | |
minimized : true | |
}); | |
var divEbene = createElement('div'); | |
append(divEbene, overlay); | |
divEbene.innerHTML = '<b>Webcode:</b> <input type="text" id="webcodeInput" class="gctour-input-text" style="width:300px;"><br/>' + $.gctour.lang('container.toolbar.downloadTour.webcodeDownloadHelp'); | |
divEbene = createElement('div'); | |
append(divEbene, overlay); | |
divEbene.setAttribute('class', 'dialogFooter'); | |
var downloadButton = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('container.toolbar.downloadTour.caption'), | |
style : "background-image:url(" + $.gctour.img.download + ")" | |
}); | |
append(downloadButton, divEbene); | |
downloadButton.addEventListener('click', function () { | |
var webcode = $.trim($('#webcodeInput').val()); | |
if (webcode == "") { | |
return; | |
} | |
downloadTour(webcode); | |
}, false); | |
} | |
/* BETA begin GCTour send2cgeo */ | |
// TODO: move style definition to function "initStyle()" | |
GM_addStyle("" + | |
"#gctour_send2cgeo_progressbar {" + | |
" margin: 2px 0;" + | |
"}" + | |
"" + | |
".hide {" + | |
" display: none;" + | |
"}" + | |
".ui-progressbar {" + | |
" position: relative;" + | |
" width: 60%;" + | |
"}" + | |
"" + | |
".ui-progressbar-value {" + | |
"}" + | |
".progress-label {" + | |
" position: absolute;" + | |
" width: 100%;" + | |
" text-align: center;" + | |
" top: 4px;" + | |
" font-weight: bold;" + | |
"}" + | |
"div.gct_send2cgeo ol li {" + | |
" padding: 2px;" + | |
"}" + | |
"div.gct_send2cgeo ul {" + | |
" list-style-type: disc;" + | |
"}" + | |
"div.gct_send2cgeo ul, ol {" + | |
" padding-left: 1.5em;" + | |
" margin-bottom: 0.5em;" + | |
" margin-left: 1.5em;" + | |
"}" + | |
""); | |
function send2cgeo() { | |
var cacheIDs = [], | |
caches = CURRENT_TOUR.geocaches, | |
cacheIDsCount = 0, // number of caches | |
group = 1, // number of IDs to submit simultaneously | |
url = "https://send2.cgeo.org/add.html", | |
$pBar = $("#gctour_send2cgeo_progressbar"), | |
$btn = $("#btnSend2cgeo"), | |
txtReg = "Register first!", // response from Send2cgeo if browser is not registered | |
txtSuc = "Success!", // response from Send2cgeo if submission was successful | |
// cache IDs | |
cacheIDs = $.map(caches, function (n, i) { | |
return ((n.id !== undefined) ? n.id : null); | |
}); | |
cacheIDsCount = cacheIDs.length; | |
// set progress bar options | |
$pBar | |
.progressbar("option", { | |
"value" : 0, | |
"max" : cacheIDsCount | |
}) | |
.removeClass("hide") | |
.css({ // necessary for pages in new design (search, dashboard,...), otherwise the progress bar doesn't show up | |
opacity : "", | |
display : "", | |
position : "", | |
height : "", | |
width : "", | |
top : "", | |
left : "", | |
fontSize: "" | |
}); | |
// disable Send2cgeo button | |
$btn.button("disable"); | |
// send cacheIDs recursively | |
async function sendRequests(fromPos) { | |
group = cacheIDsCount; // instead one by one, send all cacheIDs by one call | |
var toPos = fromPos + group, | |
param = "", | |
res = "", | |
boo = true; | |
toPos = (toPos > cacheIDsCount) ? cacheIDsCount : toPos; | |
// cacheIDs to send | |
param = cacheIDs.slice(fromPos, toPos).join(","); | |
// submit and wait for response | |
res = await promiseRequest('GET', url + "?cache=" + param); // https://send2.cgeo.org/add.html?cache=GC123,GC345 | |
res = res.responseText; | |
$pBar.progressbar("option", "value", toPos); | |
if (res.indexOf(txtReg) !== -1) { // browser not registered | |
boo = false; | |
$('<div>' + $.gctour.lang('send2cgeo.register') + '</div>').dialog(); | |
$pBar.addClass("hide"); | |
$btn.button("enable"); | |
} else if (res.indexOf(txtSuc) === -1) { // response not ok (cache probably could not be added to the queue) | |
boo = false; | |
$('<div>' + $.gctour.lang('send2cgeo.senderror') + '</div>').dialog(); | |
$pBar.addClass("hide"); | |
$btn.button("enable"); | |
} | |
fromPos = toPos; | |
if (cacheIDsCount > fromPos && boo) { | |
sendRequests(fromPos); | |
} | |
}; | |
// start recursion by sending first cacheID | |
if (cacheIDsCount > 0) { | |
sendRequests(0); | |
} | |
} | |
var openGcTour2cgeoDialog = function () { | |
if (!DEBUG_MODE) { | |
return; | |
} | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
var cacheIDsCount = $.grep(CURRENT_TOUR.geocaches, function (n, i) { | |
return (n.id !== undefined); | |
}).length, | |
waypointCount = CURRENT_TOUR.geocaches.length - cacheIDsCount, | |
noWP = (waypointCount > 0 ? ' (' + $.gctour.lang('send2cgeo.noWP') + ')' : ''), | |
btnText = $.gctour.lang('send2cgeo.title') + noWP, | |
send = | |
'<div class="gct_send2cgeo">' + | |
'<br>' + | |
'<ol>' + | |
'<li>' + | |
'<div><button id="btnSend2cgeo">' + btnText + '</button></div>' + | |
'<div id="gctour_send2cgeo_progressbar" class="hide">' + // hide progress bar | |
'<div class="progress-label"></div>' + | |
'</div>'+ | |
'</li>' + | |
$.gctour.lang('send2cgeo.usage') + | |
'</ol>' + | |
'</div>', | |
setup = | |
'<div class="gct_send2cgeo">' + | |
'<strong>' + $.gctour.lang('send2cgeo.setup.header') + '</strong>' + | |
'<ol>' + | |
'<li><a href="https://send2.cgeo.org/api/browser.html" target="_blank" title="https://send2.cgeo.org/api/browser.html">' + $.gctour.lang('send2cgeo.setup.registerBrowser') + '</a></li>' + | |
$.gctour.lang('send2cgeo.setup.desc1') + | |
'<li>' + | |
'<form name="device" action="https://send2.cgeo.org/pin.html" target="_blank" method="post">' + | |
'<label for="pin" class="gctour-label">' + $.gctour.lang('send2cgeo.setup.desc2') + '</label> ' + | |
'<input name="pin" type="text" placeholder="12345" maxlength="5" class="gctour-input-text" style="width: 5em; text-align: center;"/>' + | |
'<input name="button" type="submit" value="' + $.gctour.lang('send2cgeo.setup.desc3') + '" class="ui-button" style="margin-left: 10px;"/>' + | |
'</form>' + | |
'</li>' + | |
'</ol>' + | |
'</div>' + | |
'<br>' + | |
'<hr>' + | |
'<div class="gct_send2cgeo">' + | |
'<strong>Send2cgeo</strong>' + | |
'<ul>' + | |
'<li><a target="_blank" href="https://send2.cgeo.org/home.html">' + $.gctour.lang('send2cgeo.overview') + '</a></li>' + | |
'<li><a target="_blank" href="http://www.cgeo.org/faq.html#send2cgeo">FAQ</a></li>' + | |
'</ul>' + | |
'</div>', | |
// dialog tabs structure | |
$tabs = $( | |
'<div id="tabs">' + | |
' <ul>' + | |
' <li><a href="#tabs-1">Send</a></li>' + | |
' <li><a href="#tabs-2">Setup</a></li>' + | |
' </ul>' + | |
' <div id="tabs-1">' + send + '</div>' + | |
' <div id="tabs-2">' + setup + '</div>' + | |
'</div>' | |
); | |
$tabs.on("dialogcreate", function () { | |
var $thisDlg = $(this).dialog("widget"), | |
$progressbar = $thisDlg.find("#gctour_send2cgeo_progressbar"), | |
$pl = $thisDlg.find(".progress-label"); | |
$thisDlg.find("input[type=submit], button").button(); | |
$progressbar.progressbar({ | |
value: false, | |
max: CURRENT_TOUR.geocaches.length, | |
change: function() { | |
var $pBar = $(this), | |
value = $pBar.progressbar("value"), | |
max = $pBar.progressbar("option", "max"); | |
$pl.text(value + " / " + max); | |
}, | |
complete: function () { | |
$pl.text($pl.text() + " Complete!"); | |
} | |
}); | |
$thisDlg.find("#btnSend2cgeo").on('click', {}, function () { | |
send2cgeo(); | |
}); | |
}); | |
// tabs menu | |
$tabs.dialog($.gctour.dialog.info(), { | |
title: $.gctour.lang('send2cgeo.title'), | |
width: '75%', | |
maxHeight: $(window).height() - 20, | |
resizable: false, | |
dialogClass: 'gct_dialog', | |
buttons: [{ | |
text: $.gctour.lang('general.close'), | |
icons: { | |
primary: "ui-icon-closethick" | |
}, | |
click: function () { | |
$(this).dialog("close"); | |
} | |
}] | |
}); | |
// different font size on new search page necessary | |
/*if (document.URL.search("\/play\/search") >= 0) { | |
var $elem = $("div.ui-widget"); | |
$elem.attr('style', $elem.attr('style') + ';font-size: 0.8em !important'); | |
}*/ | |
$("div#tabs").tabs({ | |
heightStyle: "content" | |
}); | |
}; | |
/* BETA end GcTour send2cgeo */ | |
/* overlays */ | |
/* usage: | |
var options = { | |
caption: "Test Beschriftung", | |
color: 'red', | |
_document: document, | |
minimized: true, | |
closeCallback : function(_document){alert('oioio');} | |
} | |
getOverlay(options); | |
*/ | |
function getOverlay(options) { | |
var bodyNew, | |
verLay, | |
overlayMarker, | |
title, | |
closeDiv, | |
closeButton, | |
caption, | |
localDocument, | |
background_color; | |
caption = options.caption; | |
localDocument = options._document || document; | |
background_color = options.color || "#B2D4F3"; | |
bodyNew = localDocument.getElementsByTagName('body')[0]; | |
// first - close all old overlays | |
closeOverlayRemote(localDocument)(); | |
var overLay = localDocument.createElement('div'); | |
overLay.align = 'center'; | |
overLay.className = 'dialogMask'; | |
overLay.id = "dialogMask"; | |
var dialogBody = localDocument.createElement('div'); | |
dialogBody.id = "dialogBody"; | |
dialogBody.className = "dialogBody header"; | |
if (options.minimized) { | |
dialogBody.className += " dialogMin"; | |
} | |
var dialogHead = localDocument.createElement('h1'); | |
append(dialogHead, dialogBody); | |
dialogHead.style.backgroundColor = background_color; | |
var icon = "<img style='float:left;position:relative;top:-3px;' src='" + $.gctour.img.gctourLogo + "'>"; | |
dialogHead.innerHTML = icon + caption; | |
closeButton = createElement('img', { | |
style : "cursor:pointer;" | |
}); | |
append(closeButton, dialogHead); | |
closeButton.style.cssFloat = "right"; | |
closeButton.src = $.gctour.img.closebutton; | |
var closeFunction = options.closeCallback || closeOverlayRemote; | |
closeButton.addEventListener('click', closeFunction(localDocument), false); | |
//addOpacityEffects(closeButton); | |
var dialogContent = localDocument.createElement('div'); | |
append(dialogContent, dialogBody); | |
dialogContent.className = "dialogContent"; | |
bodyNew.appendChild(overLay); | |
bodyNew.appendChild(dialogBody); | |
return dialogContent; | |
} | |
function closeOverlayRemote(theDocument) { | |
return function () { | |
$(theDocument) | |
.find("#dialogMask").remove().end() | |
.find("#dialogBody").remove().end() | |
.find("#progressOverlay").remove(); | |
}; | |
} | |
function closeOverlay() { | |
closeOverlayRemote(document)(); | |
} | |
function getListOverlay(options) { | |
var overlay = getOverlay(options); | |
var list = createElement('div', { | |
id : "dialogListContainer" | |
}); | |
append(list, overlay); | |
var listUl = createElement('ul'); | |
listUl.setAttribute("class", "dialogList"); | |
append(listUl, list); | |
var details = createElement('div', { | |
id : "dialogDetails" | |
}); | |
append(details, overlay); | |
var dialogFooter = createElement('div', { | |
style : "width:580px;position: absolute; bottom: 10px;" | |
}); | |
append(dialogFooter, overlay); | |
dialogFooter.setAttribute('class', 'dialogFooter'); | |
var close = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.close'), | |
style : "background-image:url(" + $.gctour.img.save + ")" | |
}); | |
append(close, dialogFooter); | |
close.addEventListener('click', closeOverlay, false); | |
return [listUl, details]; | |
} | |
function addErrorDialog(options) { | |
var localDocument, | |
post_data; | |
localDocument = options._document || document; | |
closeOverlay(); | |
options.minimized = true; | |
options.color = "#f00"; | |
options.caption = options.caption || 'Error'; | |
//log the exception: | |
log_exception(options._exception); | |
var overlay = getOverlay(options); | |
$(overlay).append( | |
$('<div/>') | |
.css('border', '1px dashed red') | |
.css('clear', 'both') | |
.css('margin', '3px').css('padding', '5px') | |
.html('<b>' + options._exception + '</b>'), | |
$('<div/>') | |
.html($.gctour.lang('dlg.error.content')), | |
$('<div/>') | |
.addClass('dialogFooter') | |
.append( | |
$('<input/>') | |
.attr('onclick', 'return false;') | |
.attr('type', 'button') | |
.attr('value', $.gctour.lang('general.close')) | |
.css('background-image', 'url(' + $.gctour.img.closebutton + ')') | |
.bind('click', function () { | |
if (localDocument == document) { | |
closeOverlayRemote(localDocument)(); | |
} else { // if we are on the printview - close the whole window | |
localDocument.defaultView.close(); | |
} | |
}) | |
)).find("#gctour_update_error_dialog").bind('click', function () { | |
update(true); | |
}); | |
} | |
function addProgressbar(options) { | |
var overlay; | |
if (options) { | |
var theDocument = options._document || document; | |
var theCaption = options.caption || $.gctour.lang('general.pleaseWait'); | |
if (options.closeCallback) { | |
overlay = getOverlay({ | |
caption : theCaption, | |
minimized : true, | |
_document : theDocument, | |
closeCallback : options.closeCallback | |
}); | |
} else { | |
overlay = getOverlay({ | |
caption : theCaption, | |
minimized : true, | |
_document : theDocument | |
}); | |
} | |
} else { | |
overlay = getOverlay({ | |
caption : $.gctour.lang('general.pleaseWait'), | |
minimized : true, | |
_document : document | |
}); | |
} | |
var progressBarContainer = document.createElement('div'); | |
append(progressBarContainer, overlay); | |
progressBarContainer.style.marginLeft = "135px"; | |
var progressBar = document.createElement('div'); | |
append(progressBar, progressBarContainer); | |
progressBar.style.border = '1px solid lightgray'; | |
progressBar.style.height = '13px'; | |
progressBar.style.width = '208px'; | |
progressBar.style.cssFloat = 'left'; | |
progressBar.style.margin = '10px'; | |
progressBar.style.align = 'center'; | |
progressBar.style.lineHeight = '13px'; | |
progressBar.style.verticalAlign = 'middle'; | |
progressBar.style.background = "url(" + $.gctour.img.loader2 + ")"; | |
progressBar.style.setProperty("-moz-border-radius", "4px", ""); | |
progressBar.style.setProperty("border-radius", "4px", ""); | |
var progressBarElement = document.createElement('div'); | |
append(progressBarElement, progressBarContainer); | |
progressBarElement.id = 'progressbar'; | |
progressBarElement.style.opacity = '0.6'; | |
progressBarElement.style.width = '0px'; | |
progressBarElement.style.height = '13px'; | |
progressBarElement.style.fontSize = '10px'; | |
progressBarElement.style.backgroundColor = '#E78F08'; | |
progressBarElement.style.position = 'absolute'; | |
progressBarElement.style.margin = '11px'; | |
progressBarElement.align = 'center'; | |
progressBarElement.style.setProperty("-moz-border-radius", "4px", ""); | |
progressBarElement.style.setProperty("border-radius", "4px", ""); | |
} | |
function setProgress(i, count, theDocument) { | |
var width = ((208 * (i + 1)) / count); | |
$("#progressbar", theDocument) | |
.css('width', width) | |
.html("<b>" + (i + 1) + "/" + count + "</b>"); | |
} | |
function updateProgressBar() { | |
//setProgress(Math.round(PROGRESS_BAR.progress/PROGRESS_BAR.total*100),100, document); // percentage | |
setProgress(PROGRESS_BAR.progress, PROGRESS_BAR.total, document); | |
PROGRESS_BAR.progress += 1; | |
} | |
/* gui notifications */ | |
$.gctour.notification = $.gctour.notification || {}; | |
$.gctour.notification.init = function () { | |
var $noteBlock = $('<ul>', { | |
id : "gctour-notification-box" | |
}).appendTo('body'); | |
}; | |
$.gctour.notification.add = function (options) { | |
var content = (options.icon) ? "<img style='float:left;padding-right:6px;'src='" + options.icon + "'/>" : ""; | |
content += (options.title) ? "<span style='font-size:18px'><b>" + options.title + "</b></span><br/>" : ""; | |
content += (options.text) ? options.text : ""; | |
var $note = $('<li>', { | |
"class" : "gctour-notification-" + ((options.style) ? options.style : "green"), | |
click : function () { | |
$(this).animate({ | |
height : 0 | |
}, 300, "linear", function () { | |
$(this).remove(); | |
}); | |
} | |
}) | |
.disableSelection() | |
.append( | |
$('<div>', { | |
html : content, | |
css : { | |
'font-size' : '13px', | |
'line-height' : '16px', | |
'padding' : '8px 10px 9px', | |
'position' : 'relative', | |
'text-align' : 'left', | |
'width' : 'auto' | |
} | |
})) | |
//~ .prependTo( $('#gctour-notification-box') ).show('fast'); | |
.prependTo($('#gctour-notification-box')); | |
setTimeout(function () { | |
$note.animate({ | |
height : 0 | |
}, 600, "linear", function () { | |
$note.remove(); | |
}); | |
}, 6000); | |
}; | |
$.gctour.notification.init(); | |
$.gctour.notification.test = function () { | |
if (DEBUG_MODE) { | |
var dummyNote = [{ | |
title: "test 1", | |
icon: GS_HOST + GS_WPT_IMAGE_PATH + "2.gif", | |
text: "test notification", | |
style: "yellow" | |
}, { | |
title: "test 2", | |
icon: GS_HOST + GS_WPT_IMAGE_PATH + "3.gif", | |
text: "test notification, longer text", | |
style: "red" | |
}, { | |
title: "test 3", | |
icon: GS_HOST + GS_WPT_IMAGE_PATH + "4.gif", | |
text: "test notification, longer text, even longer text", | |
style: "blue" | |
}, { | |
title: "test 4", | |
icon: GS_HOST + GS_WPT_IMAGE_PATH + "5.gif", | |
text: "test notification" | |
} | |
], | |
dummyNoteZaehler = 0, | |
dummyNoteLength = dummyNote.length, | |
dummyNoteInterval, | |
foo = function () { | |
if ((0 <= dummyNoteZaehler) && (dummyNoteZaehler <= dummyNote.length)) { | |
$.gctour.notification.add(dummyNote[dummyNoteZaehler]); | |
} | |
dummyNoteZaehler++; | |
if (dummyNoteZaehler >= dummyNoteLength) { | |
clearInterval(dummyNoteInterval); | |
dummyNoteZaehler = 0; | |
} | |
}; | |
$('#ctl00_uxLoginStatus_hlHeaderAvatar').hover(function () { | |
clearInterval(dummyNoteInterval); | |
dummyNoteZaehler = 0; | |
dummyNoteInterval = window.setInterval(foo, 500); | |
}); | |
} | |
} | |
//$.gctour.notification.test(); | |
/* Leaflet maps for autoTour, change coordinates and own waypoints */ | |
function LeafletMap(options) { | |
if (typeof L !== "object") { // leaflet not available | |
addErrorDialog({ | |
caption : "Map error", | |
_document : document, | |
_exception : 'Leaflet not available' | |
}); | |
} | |
this._options = options; | |
this._id = options.id; | |
this._marker = ''; | |
this._circle = ''; | |
this._features = []; | |
this.init(); | |
} | |
LeafletMap.prototype.init = function() { | |
// add leaflet css | |
if ($("head link#gct-leaflet-css").length === 0) { // has to be added only once | |
$("head").append('<link id="gct-leaflet-css" href="https://unpkg.com/[email protected]/dist/leaflet.css" rel="stylesheet" type="text/css">'); | |
} | |
// add map | |
$('<div/>', { | |
id: this._id, | |
height: (this._options.height) ? this._options.height : '280px' | |
}).appendTo(this._options.anchor); | |
this._lm = L.map(this._id, { | |
maxZoom: 15, | |
boxZoom: false, | |
doubleClickZoom: false, | |
dragging: false, | |
keyboard: false, | |
prefix: false, | |
scrollWheelZoom: false, | |
tap: false, | |
touchZoom: false, | |
zoomControl: false, | |
zoomSnap: 0.1 | |
}); | |
L.control.scale().addTo(this._lm); | |
switch (this._options.map) { | |
case 'osm': | |
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', | |
subdomains: 'abc' | |
}).addTo(this._lm); | |
break; | |
case 'gm': | |
default: // 'gm' | |
L.tileLayer('https://mt.google.com/vt?&x={x}&y={y}&z={z}', { | |
attribution: '© <a href="https://maps.google.com/">Google Maps</a>', | |
maxZoom: 22, | |
subdomains: '1234' | |
}).addTo(this._lm); | |
break; | |
} | |
this._lm.setView(this._options.center,15); | |
} | |
LeafletMap.prototype.addMarker = function(marker) { | |
let size = 20, // px | |
ico; | |
switch(marker.type) { | |
case 'gs': // GS marker | |
let GSIcon = L.Icon.extend({ | |
options: { | |
iconSize: [size, size+3], | |
iconAnchor: [size/2, size] | |
} | |
}); | |
ico = new GSIcon({iconUrl: '/images/wpttypes/pins/'+marker.icon+'.png'}); | |
this._marker = L.marker(marker.center, {icon: ico}); | |
break; | |
case 'gct': // GCTour marker | |
let GCTIcon = L.Icon.extend({ | |
options: { | |
iconSize: [size, size], | |
iconAnchor: [size/2, size] | |
} | |
}); | |
ico = new GCTIcon({iconUrl: GCTOUR_HOST+'i/'+marker.icon+'.png'}); | |
this._marker = L.marker(marker.center, {icon: ico}); | |
break; | |
default: | |
this._marker = L.marker(marker.center); | |
} | |
this._features.push(this._marker); | |
let group = new L.featureGroup(this._features); | |
group.addTo(this._lm); | |
this._lm.fitBounds(group.getBounds().pad(0.1)); | |
} | |
LeafletMap.prototype.addCircle = function(circle) { | |
this._circle = L.circle(circle.center, circle.radius/*[m]*/); | |
this._features.push(this._circle); | |
let group = new L.featureGroup(this._features); | |
group.addTo(this._lm); | |
this._lm.fitBounds(group.getBounds().pad(0.1)); | |
} | |
LeafletMap.prototype.removeLayer = function() { | |
if (this._features.length > 0) { | |
this._lm.removeLayer(this._features.pop()); | |
} | |
} | |
/* own marker */ | |
async function showNewMarkerDialog(marker) { | |
// create overlay | |
let overlayMarker = getOverlay({ | |
caption : '<b>' + $.gctour.lang('printview.marker') + '</b>', | |
minimized : true | |
}); | |
// hidden error field | |
let dangerDanger = document.createElement('div'); | |
dangerDanger.id = "dangerdanger"; | |
dangerDanger.style.visibility = "hidden"; | |
dangerDanger.style.cssFloat = "right"; | |
dangerDanger.innerHTML = "<img src='" + $.gctour.img.danger + "'>"; | |
overlayMarker.appendChild(dangerDanger); | |
// content table | |
let anTable = document.createElement('table'); | |
anTable.style.width = '100%'; | |
anTable.style.clear = 'both'; | |
anTable.align = 'center'; | |
overlayMarker.appendChild(anTable); | |
// row name | |
let tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
let td = document.createElement('td'); | |
td.style.width = '20%'; | |
td.textContent = 'Name'; | |
tr.appendChild(td); | |
// input field for name of marker | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
let nameInput = document.createElement('input'); | |
nameInput.type = 'text'; | |
nameInput.id = 'markerName'; | |
nameInput.className = "gctour-input-text"; | |
nameInput.style.width = '450px'; | |
td.appendChild(nameInput); | |
// row name | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
td.textContent = $.gctour.lang('marker.coord'); | |
// input field for marker coords | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
// lat/lon input field | |
let cordsInput = document.createElement('input'); | |
cordsInput.type = 'text'; | |
cordsInput.id = 'markerCoords'; | |
cordsInput.className = "gctour-input-text"; | |
cordsInput.style.width = '450px'; | |
cordsInput.style.marginRight = '5px'; | |
cordsInput['placeholder'] = 'N49° 26.082 E7° 46.587'; | |
td.appendChild(cordsInput); | |
// example coords for lat/lon input field | |
let exampleCoords = document.createElement('div'); | |
exampleCoords.innerHTML = '<div style="font-size:xx-small"><i>' + $.gctour.lang('general.exampleCoords') + '</i></div>'; | |
td.appendChild(exampleCoords); | |
let defaultMarker = {}; | |
defaultMarker.center = [0,0]; | |
defaultMarker.type = 'gct'; | |
defaultMarker.icon = 'RedFlag'; | |
// check marker coords as you type | |
let checkMarkerCoord = function (input) { | |
return async function () { | |
let coords = await parseCoordinates(input.value); | |
if (coords === false) { | |
cordsInput.style.backgroundColor = "#FF8888"; | |
} else { | |
cordsInput.style.backgroundColor = "#88DC3B"; | |
// add marker | |
defaultMarker.center = [coords._lat, coords._lon]; | |
lm.removeLayer(); // delete previous marker | |
lm.addMarker(defaultMarker); | |
} | |
}; | |
}; | |
cordsInput.addEventListener('keyup', checkMarkerCoord(cordsInput), false); | |
cordsInput.addEventListener('paste', checkMarkerCoord(cordsInput), false); | |
// add map | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
td = document.createElement('td'); | |
td.align = 'left'; | |
tr.appendChild(td); | |
let map = document.createElement('div'); | |
td.appendChild(map); | |
let options = {}; | |
options.id = 'gct-marker-map', | |
options.center = [0,0]; | |
options.height = '250px'; | |
options.map = 'gm'; | |
options.anchor = $(map); | |
let lm = new LeafletMap(options); | |
// row name | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
td.innerHTML = $.gctour.lang('marker.content') + '<br/><div style="font-size:xx-small">(' + $.gctour.lang('marker.contentHint') + ')</div>'; | |
tr.appendChild(td); | |
// text content of marker | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
let contentTextarea = document.createElement('textarea'); | |
contentTextarea.style.width = '450px'; | |
contentTextarea.style['border'] = '1px solid #ccc'; | |
contentTextarea.style['border-radius'] = '3px'; | |
contentTextarea.id = 'markerContent'; | |
contentTextarea.rows = '2'; | |
td.appendChild(contentTextarea); | |
// row name | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
td.style.width = '20%'; | |
td.textContent = $.gctour.lang('marker.type'); | |
tr.appendChild(td); | |
// marker icons | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
let markerTypeTable = createElement('table', { | |
style : "width:auto;" | |
}); | |
td.appendChild(markerTypeTable); | |
markerTypeTable.id = 'markerType'; | |
let typeArray = [ | |
[GCTOUR_HOST + 'i/RedFlag.png', 'Red Flag'], | |
[GCTOUR_HOST + 'i/BlueFlag.png', 'Blue Flag'], | |
[GCTOUR_HOST + 'i/GreenFlag.png', 'Green Flag'], | |
[GCTOUR_HOST + 'i/Geocache.png', 'Geocache'], | |
[GCTOUR_HOST + 'i/GeocacheFound.png', 'Geocache Found'], | |
[GCTOUR_HOST + 'i/Information.png', 'Information'], | |
[GCTOUR_HOST + 'i/Park.png', 'Park'], | |
[GCTOUR_HOST + 'i/ParkingArea.png', 'Parking'], | |
[GCTOUR_HOST + 'i/SkullAndBones.png', 'Skull And Crossbones'] | |
]; | |
let trElement = createElement('tr', { | |
style : "height:27px;" | |
}); | |
markerTypeTable.appendChild(trElement); | |
for (let i = 0; i < typeArray.length; i++) { | |
let tdElement = createElement('td', { | |
style : "width:25px;" | |
}); | |
tdElement.style.background = "url(" + typeArray[i][0] + ") center center no-repeat"; | |
if (!marker) { | |
if (i === 0) { | |
tdElement.style.backgroundColor = '#B2D4F3'; | |
} | |
} else { | |
if (typeArray[i][0] == marker.image) { | |
tdElement.style.backgroundColor = '#B2D4F3'; | |
} | |
} | |
tdElement.style.cursor = 'pointer'; | |
tdElement.style.padding = '0px'; | |
tdElement.style.border = '1px solid silver'; | |
tdElement.addEventListener('click', function(){ | |
defaultMarker.icon = typeArray[i][0].split("/").pop().split(".")[0]; | |
// emphasize selected icon | |
let $icons = $("table#markerType td"); | |
$icons.css("background-color", ""); | |
$($icons[i]).css("background-color", "#B2D4F3"); | |
// update marker | |
lm.removeLayer(); | |
lm.addMarker(defaultMarker); | |
}, false); | |
trElement.appendChild(tdElement); | |
} | |
// add save and cancel buttons | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
td.colSpan = '2'; | |
td.align = 'right'; | |
tr.appendChild(td); | |
// vars for saving marker to tour | |
let latitude = ''; | |
let longitude = ''; | |
let wptCode = ''; | |
// button container | |
let buttonsDiv = createElement('div'); | |
buttonsDiv.setAttribute('class', 'dialogFooter'); | |
append(buttonsDiv, overlayMarker); | |
// cancel button | |
let cancel = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.cancel'), | |
style : "background-image:url(" + $.gctour.img.closebutton + ")" | |
}); | |
append(cancel, buttonsDiv); | |
cancel.addEventListener('click', closeOverlay, false); | |
// save button | |
let save = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.save'), | |
style : "background-image:url(" + $.gctour.img.save + ")" | |
}); | |
append(save, buttonsDiv); | |
save.addEventListener('click', function() { | |
let errors = 0; | |
let markerName = document.getElementById('markerName'); | |
if (markerName.value != "") { | |
markerName.style.backgroundColor = "#FFFFFF"; | |
} else { | |
markerName.style.backgroundColor = "#FF8888"; | |
errors++; | |
} | |
let markerCoords = document.getElementById('markerCoords'); | |
if (markerCoords.style.backgroundColor != "rgb(136, 220, 59)") { | |
markerCoords.style.backgroundColor = "#FF8888"; | |
errors++; | |
} | |
let markerContent = document.getElementById('markerContent'); | |
let markerType = GCTOUR_HOST + 'i/' + defaultMarker.icon + '.png'; | |
let markerTypeSym = $.map(typeArray, function(value, key) { | |
if (value[0] === markerType) { | |
return value[1]; | |
} | |
}); | |
if (errors !== 0) { | |
document.getElementById('dangerdanger').style.visibility = "visible"; | |
return; | |
} | |
latitude = defaultMarker.center[0]; | |
longitude = defaultMarker.center[1]; | |
let markerPositionDelta = ''; | |
if (marker) { | |
let markerPosition = getPositionOfId(marker.wptcode); | |
markerPositionDelta = markerPosition - CURRENT_TOUR.geocaches.length + 1; | |
deleteElement((marker.id) ? marker.id : marker.wptcode)(); | |
} else { | |
markerPositionDelta = 0; | |
} | |
let entry = addCustomMarker(markerName.value, latitude, longitude, markerContent.value, markerType, markerTypeSym, wptCode); | |
move(entry.wptcode, markerPositionDelta); | |
updateGUI(); | |
closeOverlay(); | |
}, false); | |
// if we edit a marker then set all previous values | |
if (marker) { | |
nameInput.value = marker.name; | |
latitude = marker.latitude; | |
longitude = marker.longitude; | |
wptCode = marker.wptcode; | |
let latLon = new LatLon(marker.latitude, marker.longitude); | |
cordsInput.value = latLon.toString("dm"); | |
cordsInput.style.backgroundColor = "#88DC3B"; | |
contentTextarea.innerHTML = marker.content; | |
defaultMarker.icon = marker.image.split('/').pop().split('.')[0]; | |
} else { | |
let latlon; | |
// use listing coords when on a cache page and home coords otherwise | |
if (!(latlon = $('span#uxLatLon').text())) { | |
latlon = await getHoomeCoords(); | |
} | |
nameInput.value = 'WP'; | |
cordsInput.value = latlon; | |
} | |
// set initial marker | |
checkMarkerCoord(cordsInput)(); | |
// set the focus to coords input | |
cordsInput.focus(); | |
} | |
/* change coordinates */ | |
function displayChangedCoordinates(coordinates) { | |
let coordinates_org, | |
coordinates_ele = $('#uxLatLon'); | |
try { // if coordinates were already changed by GCTour, extract original coordinates | |
coordinates_org = coordinates_ele.text().split("(")[1].split(")")[0]; | |
} catch (e) { // no previous changes by GCTour | |
coordinates_org = coordinates_ele.text(); | |
} | |
if (!coordinates) { // display original coords | |
coordinates_ele.html(coordinates_org); | |
} else { // display new coords | |
coordinates_ele.html( | |
"<small><div style='font-weight:bold;'>" + coordinates + | |
" - changed by GCTour</div> (" + coordinates_org + ")</small>"); | |
} | |
} | |
async function openChangeCoordinates() { | |
// content table | |
let anTable = createElement('table', { | |
style : "clear:both;" | |
}); | |
anTable.style.width = '100%'; | |
anTable.align = 'center'; | |
// create overlay | |
let overlayMarker = getOverlay({ | |
caption : $.gctour.lang('cache.moveCoords'), | |
minimized : true | |
}); | |
overlayMarker.appendChild(anTable); | |
// help section | |
let tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
let td = document.createElement('td'); | |
td.colSpan = 2; | |
td.innerHTML = $.gctour.lang('cache.moveCoordsHelp'); | |
tr.appendChild(td); | |
// original coords name | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
td.style.width = '20%'; | |
td.textContent = $.gctour.lang('cache.originalCoords'); | |
tr.appendChild(td); | |
// get original coordinates | |
let coordinates = $('#uxLatLon').text(); | |
try { | |
// if coordinates were already changed by GCTour, extract original coordinates | |
coordinates = coordinates.split("(")[1].split(")")[0]; | |
} catch (e) { | |
// no previous changes by GCTour | |
coordinates = coordinates; | |
} | |
// cache details | |
let minimal_geocache = getMinimalGeocacheDetails(document.getElementsByTagName('html')[0]); | |
let gc_type = minimal_geocache.type; | |
let coords = await parseCoordinates(coordinates); | |
let cacheId = minimal_geocache.gccode; | |
// original coords value | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
let nameInput = document.createElement('input'); | |
nameInput.type = 'text'; | |
nameInput.id = 'markerName'; | |
nameInput.className = "gctour-input-text"; | |
nameInput.value = coords; | |
nameInput.style.width = '350px'; | |
nameInput.style.marginRight = '5px'; | |
nameInput.disabled = 'disabled'; | |
td.appendChild(nameInput); | |
// new coords name | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
td.textContent = $.gctour.lang('cache.newCoords'); | |
tr.appendChild(td); | |
// new coords value | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
// hidden lat value (decimal) | |
let cordsInputLat = document.createElement('input'); | |
cordsInputLat.type = "hidden"; | |
cordsInputLat.id = 'cordsInputLat'; | |
td.appendChild(cordsInputLat); | |
// hidden lon value (decimal) | |
let cordsInputLon = document.createElement('input'); | |
cordsInputLon.type = "hidden"; | |
cordsInputLon.id = 'cordsInputLon'; | |
td.appendChild(cordsInputLon); | |
// visible lat/lon value | |
let cordsInput = document.createElement('input'); | |
cordsInput.type = 'text'; | |
cordsInput.id = 'markerCoords'; | |
cordsInput.className = "gctour-input-text"; | |
cordsInput.style.width = '350px'; | |
cordsInput.style.marginRight = '5px'; | |
td.appendChild(cordsInput); | |
// add example coords text to new coords input | |
let exampleCoords = document.createElement('div'); | |
exampleCoords.innerHTML = '<div style="font-size:x-small"><i>' + $.gctour.lang('general.exampleCoords') + '</i></div>'; | |
td.appendChild(exampleCoords); | |
// process new coords as you type | |
let checkMarkerCoord = function(input) { | |
return async function() { | |
let coords = await parseCoordinates(input.value); | |
if (coords === false) { | |
cordsInput.style.backgroundColor = "#FF8888"; | |
} else { | |
cordsInput.style.backgroundColor = "#88DC3B"; | |
cordsInputLat.value = coords._lat; | |
cordsInputLon.value = coords._lon; | |
// update marker on map | |
let marker = {}; | |
marker.center = [cordsInputLat.value, cordsInputLon.value]; | |
marker.type = 'gs'; | |
marker.icon = gc_type.split(".")[0]; | |
lm.removeLayer(); // remove previous marker first | |
lm.addMarker(marker); | |
} | |
}; | |
}; | |
// check new coords on key input or paste | |
cordsInput.addEventListener('keyup', checkMarkerCoord(cordsInput), false); | |
cordsInput.addEventListener('paste', checkMarkerCoord(cordsInput), false); | |
// map section | |
let mapTd = document.createElement('td'); | |
mapTd.align = 'left'; | |
// add map to table | |
tr = document.createElement('tr'); | |
anTable.appendChild(tr); | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
tr.appendChild(mapTd); | |
let options = {}; | |
options.id = 'gct-changeCoords-map', | |
options.center = [coords._lat, coords._lon]; | |
options.height = '250px'; | |
options.map = 'gm'; | |
options.anchor = $(mapTd); | |
let lm = new LeafletMap(options); | |
// save/delete/cancel buttons | |
// container for buttons | |
let buttonsDiv = createElement('div'); | |
append(buttonsDiv, overlayMarker); | |
buttonsDiv.setAttribute('class', 'dialogFooter'); | |
// cancel button | |
let cancel = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.cancel'), | |
style : "background-image:url(" + $.gctour.img.closebutton + ")" | |
}); | |
append(cancel, buttonsDiv); | |
cancel.addEventListener('click', closeOverlay, false); | |
// delete button | |
let delete_btn = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('cache.deleteCoords'), | |
style : "background-image:url(" + $.gctour.img.closebutton + ")" | |
}); | |
append(delete_btn, buttonsDiv); | |
delete_btn.addEventListener('click', function () { | |
GM_deleteValue('coords_' + cacheId); | |
displayChangedCoordinates(); | |
updateGUI(); | |
closeOverlay(); | |
}, false); | |
// save button | |
let save = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('general.save'), | |
style : "background-image:url(" + $.gctour.img.save + ")" | |
}); | |
append(save, buttonsDiv); | |
save.addEventListener('click', function () { | |
GM_setValue('coords_' + cacheId, cordsInputLat.value + '#' + cordsInputLon.value); | |
displayChangedCoordinates(new LatLon(cordsInputLat.value, cordsInputLon.value).toString()); | |
updateGUI(); | |
closeOverlay(); | |
}, false); | |
// initialize | |
let latlng = ''; | |
if (GM_getValue('coords_' + cacheId, "null") != "null") { // coords have been changed before | |
var coords_cacheId = GM_getValue('coords_' + cacheId); | |
latlng = new LatLon(coords_cacheId.split('#')[0], coords_cacheId.split('#')[1]); | |
} else { // original coords | |
latlng = await parseCoordinates(coordinates); | |
} | |
cordsInputLat.value = latlng._lat; | |
cordsInputLon.value = latlng._lon; | |
cordsInput.value = latlng.toString(); | |
cordsInput.style.backgroundColor = "#88DC3B"; | |
let marker = {}; | |
marker.center = [cordsInputLat.value, cordsInputLon.value]; | |
marker.type = 'gs'; | |
marker.icon = gc_type.split(".")[0]; | |
lm.addMarker(marker); | |
} | |
/* tour functions */ | |
function getTourById(id) { | |
for (var i = 0; i < TOURS.length; i++) { | |
if (TOURS[i].id == id) { | |
return TOURS[i]; | |
} | |
} | |
return; | |
} | |
function getNewTourId() { | |
var tourId = 0; | |
for (var i = 0; i < TOURS.length; i++) { | |
if (TOURS[i].id >= tourId) { | |
tourId = TOURS[i].id + 1; | |
} | |
} | |
return tourId; | |
} | |
function isGcIdInTable(gcId) { | |
for (var i = 0; i < CURRENT_TOUR.geocaches.length; i++) { | |
if (CURRENT_TOUR.geocaches[i].id == gcId) { | |
return true; | |
} | |
} | |
return false; | |
} | |
function getPositionOfId(theId) { | |
var id = -1; | |
$.each(CURRENT_TOUR.geocaches, function (i, obj) { | |
if (obj.id == theId || obj.wptcode == theId) { | |
id = i; | |
return false; // break each | |
} | |
}); | |
return id; | |
} | |
function saveTour(tour, notLoad) { | |
var i; | |
for (i = 0; i < TOURS.length; ++i) { | |
if (TOURS[i].id == tour.id) { | |
TOURS[i] = tour; | |
} | |
} | |
GM_setValue('tours', JSON.stringify(TOURS)); | |
if (notLoad === undefined) { | |
GM_setValue('currentTour', tour.id); | |
log("updating " + tour.name); | |
} | |
} | |
function saveCurrentTour() { | |
saveTour(CURRENT_TOUR); | |
} | |
// move a cache to a given position in the list | |
function move(id, positionDelta) { | |
var i; | |
// locate the selected cache in the list | |
var position = getPositionOfId(id); | |
// return if we are at the end or at top of the list! | |
if ((position === 0 && positionDelta < 0) || (position == CURRENT_TOUR.geocaches.length - 1 && positionDelta > 0)) { | |
return; | |
} | |
// save clicked cache | |
var geoCache = CURRENT_TOUR.geocaches[position]; | |
// remove it from the current geocaches | |
CURRENT_TOUR.geocaches.splice(position, 1); | |
var tempCaches = []; | |
// first push all caches in front of the selected in the new array | |
for (i = 0; i < position + positionDelta; i++) { | |
tempCaches.push(CURRENT_TOUR.geocaches[i]); | |
} | |
// then the selected | |
tempCaches.push(geoCache); | |
// and now the rest | |
for (i = position + positionDelta; i < CURRENT_TOUR.geocaches.length; i++) { | |
tempCaches.push(CURRENT_TOUR.geocaches[i]); | |
} | |
// ... and make it persistent | |
CURRENT_TOUR.geocaches = tempCaches; | |
saveCurrentTour(); | |
updateTourNumbering(); | |
} | |
function moveUp(id) { | |
return function () { | |
move(id, -1); | |
}; | |
} | |
function moveDown(id) { | |
return function () { | |
move(id, 1); | |
}; | |
} | |
function moveTop(id) { | |
return function () { | |
var position = getPositionOfId(id); | |
move(id, -position); | |
}; | |
} | |
function moveBottom(id) { | |
return function () { | |
var position = getPositionOfId(id); | |
move(id, CURRENT_TOUR.geocaches.length - position - 1); | |
}; | |
} | |
function updateCacheCount(count) { | |
$("#cachecount") | |
.html('(' + count + ')') | |
.stop(true, true) | |
.animate({ | |
backgroundColor : '#ffe000' | |
}, 800) | |
.animate({ | |
backgroundColor : '#ffffff' | |
}, 700); | |
if (!STICKY) { // nur wenn sichtbar | |
$("#gctourButtonWrapper") | |
.stop(true, true) | |
.toggleClass("gctour-grand-highlight", 300) | |
.toggleClass("gctour-grand-highlight", 1200); | |
} | |
} | |
function updateTourNumbering() { | |
$('ul#cacheList div.counter').each(function(i) { | |
$(this).text(i+1); | |
}); | |
} | |
function saveCurrentTourRefreshGUI() { | |
saveCurrentTour(); | |
updateTourNumbering(); | |
updateCacheCount(CURRENT_TOUR.geocaches.length); | |
} | |
function addToCacheList(theEntry, effects) { | |
var costumMarker = (typeof(theEntry.latitude) !== "undefined"); | |
// if this is a custom marker user other id | |
var theId = (!costumMarker) ? theEntry.id : theEntry.wptcode; | |
var entryLi = createElement('li', { | |
id : theId, | |
style : "position:relative;opacity:0;width:90%;list-style-image='url('" + theEntry.image + "');background-color:pink;" | |
}); | |
//set the type | |
entryLi.style.listStyleImage = "url('" + theEntry.image + "')"; | |
// make the gcid link | |
var nameCite = createElement('span', { | |
style : "vertical-align:top" | |
}); | |
if (!costumMarker) { | |
var coordinates = GM_getValue('coords_' + theId, "null"); // changed by GCTour | |
if (coordinates != "null") { | |
var moveCoords = createElement('img', { | |
src : $.gctour.img.coord_update, | |
height : "12", | |
style : "float:right;margin-right:5px;margin-top:2px", | |
alt : $.gctour.lang('cache.movedCoords'), | |
title : $.gctour.lang('cache.movedCoords') | |
}); | |
nameCite.appendChild(moveCoords); | |
} | |
var linkElement = document.createElement('a'); | |
//linkElement.style.fontSize = '9px'; to small! | |
linkElement.style.fontFamily = 'arial,sans-serif'; | |
linkElement.href = 'http://coord.info/' + theId; | |
linkElement.target = '_blank'; | |
linkElement.textContent = theId; | |
nameCite.appendChild(linkElement); | |
} else { | |
nameCite.innerHTML += theEntry.name; | |
nameCite.style.textDecoration = "underline"; | |
} | |
// the log/edit, move and delete button | |
var functionButtonsDiv = document.createElement('div'); | |
functionButtonsDiv.style.cssFloat = 'right'; | |
functionButtonsDiv.setAttribute("class", "controls"); | |
if (!costumMarker) { | |
var logVisitImage = document.createElement('img'); | |
logVisitImage.alt = $.gctour.lang('container.cacheList.logYourVisit'); | |
logVisitImage.title = $.gctour.lang('container.cacheList.logYourVisit'); | |
logVisitImage.style.cursor = 'pointer'; | |
logVisitImage.src = $.gctour.img.add_comment; | |
logVisitImage.addEventListener('click', function () { | |
GM_openInTab(GS_HOST + 'seek/log.aspx?wp=' + theId, false); | |
}, true); | |
addOpacityEffects(logVisitImage); | |
functionButtonsDiv.appendChild(logVisitImage); | |
} else { | |
var editMarkerButton = document.createElement('img'); | |
editMarkerButton.alt = $.gctour.lang('general.edit'); | |
editMarkerButton.title = $.gctour.lang('general.edit'); | |
editMarkerButton.style.cursor = 'pointer'; | |
editMarkerButton.src = $.gctour.img.edit; | |
editMarkerButton.addEventListener('click', function () { | |
showNewMarkerDialog(theEntry); | |
}, false); | |
addOpacityEffects(editMarkerButton); | |
functionButtonsDiv.appendChild(editMarkerButton); | |
} | |
// button to move an element to a different tour | |
var moveImage = document.createElement('img'); | |
moveImage.alt = $.gctour.lang('container.cacheList.moveToList'); | |
moveImage.title = $.gctour.lang('container.cacheList.moveToList'); | |
moveImage.style.cursor = 'pointer'; | |
moveImage.style.marginLeft = '1px'; | |
moveImage.style.marginRight = '1px'; | |
moveImage.src = $.gctour.img.move; | |
moveImage.addEventListener('click', function() { | |
openTourDialog(theId); | |
}); | |
addOpacityEffects(moveImage); | |
functionButtonsDiv.appendChild(moveImage); | |
// button to remove an element from a tour | |
var deleteImage = document.createElement('img'); | |
deleteImage.alt = $.gctour.lang('container.cacheList.removeFromList'); | |
deleteImage.title = $.gctour.lang('container.cacheList.removeFromList'); | |
deleteImage.style.cursor = 'pointer'; | |
deleteImage.src = $.gctour.img.del; | |
deleteImage.addEventListener('click', deleteElement(theId), true); | |
addOpacityEffects(deleteImage); | |
functionButtonsDiv.appendChild(deleteImage); | |
entryLi.appendChild(functionButtonsDiv); | |
entryLi.appendChild(nameCite); | |
var nameDiv = document.createElement('div'); | |
nameDiv.style.clear = 'left'; | |
nameDiv.style.position = 'relative'; | |
nameDiv.style.zIndex = 2; | |
// truncate single words that are too long | |
nameDiv.style.overflow = 'hidden'; | |
nameDiv.style.textOverflow = 'ellipsis'; | |
if (!costumMarker) { | |
nameDiv.innerHTML += theEntry.name; | |
} else { | |
nameDiv.innerHTML += new LatLon(theEntry.latitude, theEntry.longitude).toString() + " " + theEntry.content; | |
} | |
entryLi.appendChild(nameDiv); | |
var counterDiv = document.createElement('div'); | |
counterDiv.className = 'counter unselectable'; | |
counterDiv.innerHTML = (getPositionOfId(theEntry.id || theEntry.wptcode) + 1); | |
entryLi.appendChild(counterDiv); | |
$('#cacheList').append(entryLi); | |
if (unsafeWindow.draglist) { | |
unsafeWindow.draglist.sync(); // needed to function properly | |
} | |
if (effects) { // when adding more than one cache this gets quite slow ... | |
$("#" + theId).fadeTo(1000, 1); | |
} else { | |
$("#" + theId).css({ | |
opacity : 1 | |
}); | |
} | |
} | |
function addToCurrentTour(entry) { | |
var currentTourId = GM_getValue('currentTour', -1); | |
CURRENT_TOUR = getTourById(currentTourId); | |
CURRENT_TOUR.geocaches.push(entry); | |
log("saving " + (entry.id ? entry.id : entry.wptcode) + " to " + CURRENT_TOUR.name); | |
} | |
function addCustomMarker(name, lat, lon, content, typeImage, typeSymbol, wptcode) { | |
// customMarker: | |
// name -> cachename parking area | |
// lat -> latitude 51.12342 | |
// lon -> longitude -12.33456 | |
// content -> content "Test\nLINEBREAK" | |
// image -> typeimage https://gctour.geocaching.cx/i/ParkingArea.png | |
// symbol -> GPX symbol name "Red Flag" | |
// wptcode -> waypoint id 1664d58479d | |
if (CURRENT_TOUR.geocaches.length === 0) { | |
$('ul#cacheList').html(''); | |
} | |
var entry = {}; | |
entry.wptcode = (wptcode) ? wptcode : (new Date().getTime() - Math.round(lat + lon * 1000)).toString(16); | |
entry.name = name; | |
entry.latitude = lat; | |
entry.longitude = lon; | |
entry.image = typeImage; | |
entry.content = content; | |
entry.symbol = typeSymbol; | |
log("New custom marker: " + entry.name + " lat:" + entry.latitude + " lon:" + entry.longitude + " Type:" + entry.symbol + " content:" + entry.content); | |
// add the newbie | |
addToCacheList(entry, true); | |
addToCurrentTour(entry); | |
return entry; | |
} | |
function addGeocache(theId, theGuId, theName, theTypeImage) { | |
return function (event) { | |
if (CURRENT_TOUR.geocaches.length === 0) { | |
$('ul#cacheList').html(''); | |
} | |
if (!isGcIdInTable(theId)) { | |
// entry: | |
// id -> the gc.com id GC00815 | |
// guid -> the guid 6e974919-2b47-46e2-8661-3fc62a5a9650 | |
// name -> the cachename Echo the tomcat | |
// image -> the typeimage 2.gif | |
var entry = {}; | |
entry.id = theId; | |
entry.name = escapeHTML(theName); | |
entry.guid = theGuId; | |
entry.image = GS_HOST + GS_WPT_IMAGE_PATH + theTypeImage; | |
// add the newbie | |
addToCacheList(entry, false); | |
addToCurrentTour(entry); | |
showGeocacheNotification({ | |
id : theId, | |
name : theName, | |
image : GS_HOST + GS_WPT_IMAGE_PATH + theTypeImage, | |
tourname : CURRENT_TOUR.name | |
}, { | |
type : "success" | |
}); | |
} else { | |
showGeocacheNotification({ | |
id : theId, | |
name : theName, | |
image : GS_HOST + GS_WPT_IMAGE_PATH + theTypeImage, | |
tourname : CURRENT_TOUR.name | |
}, { | |
type : "contains" | |
}); | |
} | |
}; | |
} | |
function deleteElement(theId) { | |
return function () { | |
let delay = 500; | |
// effect | |
$("#" + theId) | |
.fadeOut(delay, function () { | |
$(this).remove(); | |
}); | |
// locate the element to delete | |
for (var i = 0; i < CURRENT_TOUR.geocaches.length; i++) { | |
if (CURRENT_TOUR.geocaches[i].id == theId || CURRENT_TOUR.geocaches[i].wptcode == theId) { | |
// array in js are dumb - where is removeAt ?? | |
CURRENT_TOUR.geocaches.splice(i, 1); | |
log("removing '" + theId + "' from '" + CURRENT_TOUR.name + "'"); | |
break; | |
} | |
} | |
saveCurrentTour(); | |
// update the cache count | |
updateCacheCount(CURRENT_TOUR.geocaches.length); | |
// update numbering | |
setTimeout(function() { | |
updateTourNumbering(); | |
}, delay); | |
// if tour is empty display hint | |
if (CURRENT_TOUR.geocaches.length === 0) { | |
$('#cacheList').html($.gctour.lang('tour.empty')); | |
} | |
}; | |
} | |
function removeElements(descriptionElement, id, tagName) { // currently not used | |
return function () { | |
var elements = descriptionElement.getElementsByTagName(tagName); | |
for (var x = 0; x < elements.length; x++) { | |
if (elements[x].id == id) { | |
elements[x].style.display = "none"; | |
} | |
} | |
}; | |
} | |
function updateTour() { | |
initCore(); | |
updateGUI(); | |
} | |
function loadTour(id) { | |
return function () { | |
GM_setValue('currentTour', id); | |
if (document.getElementById("inconsistentTour")) { | |
document.getElementById("inconsistentTour").style.display = "none"; | |
} | |
if (document.URL.search("webcode") >= 0) { | |
window.location = GS_HOST; | |
} else { | |
updateTour(); | |
} | |
}; | |
} | |
function newTourFunction(preset) { | |
return function () { | |
var newTour = {}; | |
newTour.id = getNewTourId(); | |
var tourName = (preset) ? preset : "Tour " + newTour.id; | |
newTour.name = prompt($.gctour.lang('tour.newDialog'), tourName); | |
newTour.geocaches = []; | |
if (!newTour.name) { | |
return false; | |
} | |
TOURS.push(newTour); | |
log("Creating new tour: " + newTour.id + " ; " + newTour.name); | |
saveTour(newTour); | |
updateTour(); | |
return true; | |
}; | |
} | |
function deleteTour(id, force) { | |
return function () { | |
if (force || confirm($.gctour.lang('tour.removeDialog'))) { | |
for (var i = 0; i < TOURS.length; i++) { | |
if (TOURS[i].id == id) { | |
log("removing '" + TOURS[i].name + "'"); | |
// array in js are dumb - where is removeAt ?? | |
var cachelist = $('#dialogDetails'); | |
if (cachelist.length > 0 && cachelist.attr("tourid") == TOURS[i].id) { | |
showCacheList(CURRENT_TOUR)(); | |
$('#loadButton').attr("disabled", "disabled"); | |
} | |
$("#tour" + id).remove(); | |
if (TOURS[i].bml) { | |
deleteBookmarklist(TOURS[i].bml,TOURS[i].id); | |
} | |
TOURS.splice(i, 1); | |
saveCurrentTour(); | |
break; | |
} | |
} | |
} | |
}; | |
} | |
function deleteCurrentTour() { | |
if (confirm($.gctour.lang('tour.removeDialog'))) { | |
var tableId; | |
for (tableId = 0; tableId < TOURS.length; tableId++) { | |
if (TOURS[tableId].id == CURRENT_TOUR.id) { | |
break; | |
} | |
} | |
var nextTourId = TOURS[(tableId + 1) % TOURS.length].id; | |
var currentTourId = CURRENT_TOUR.id; | |
loadTour(nextTourId)(); | |
deleteTour(currentTourId, true)(); | |
} | |
} | |
/* printpage functions */ | |
async function printPageFunction(tour) { | |
if (isEmptyTour(tour) || !isLoggedIn()) { | |
return; | |
} | |
var i, | |
waypoint_i, | |
tr, | |
td, | |
nCaches = tour.geocaches.length, | |
minimal = GM_getValue('printMinimal', false); | |
var cacheDetailTemplate = | |
'<div class="cacheDetail ###HIDDENSTYLE###" id="###GUID###">' + | |
' <div class="geocache_count ###HIDDENSTYLE###"><span>###CACHECOUNT###</span></div>' + | |
' <div class="geocache_id">###GCID###</div>' + | |
' <div>' + | |
' <img src="' + $.gctour.img.wpt_type + '">' + | |
' <span style="font-weight: bold;">###CACHENAME###</span>' + | |
' <span style="margin-right: 3px;"> (###OWNER### - ###HIDDEN###)</span>' + | |
' </div>' + | |
' <div class="details">' + | |
' <span><img src="' + $.gctour.img.coord_update + '" heigth="12px" class="###COORDINATESISEDIT###"/> ###COORDINATES###</span>' + | |
' <span><img src="' + $.gctour.img.bearing + '"/>###DISTANCE### </span>' + | |
' <span>D:<img src="' + $.gctour.img.stars_d + '"/></span>' + | |
' <span>T:<img src="' + $.gctour.img.stars_t + '"/></span>' + | |
' <span>S:<img src="' + $.gctour.img.cache_size + '"/></span>' + | |
' </div>' + | |
' <div>' + | |
' <span>###ATTRIBUTES###</span>' + | |
' <span><img alt="Inventory" style="padding-left: 10px;" src="' + $.gctour.img.tb_coin + '"/>Inventory:</span>' + | |
' <span>###INVENTORY###</span>' + | |
' <span><img src="' + $.gctour.img.fav + '" style="padding-left: 10px;"/>Favorites: ###FAV### ###FAVSCORE###</span>' + | |
' </div>' + | |
' <div class="content">' + | |
' <div class="short ###HIDDENSTYLE###">###SHORT_DESCRIPTION###</div>' + | |
' <div class="long ###HIDDENSTYLE###">###LONG_DESCRIPTION###</div>' + | |
' <div>###GCCOMMENT###</div>' + | |
' <div class="removable">###CACHENOTE###</div>' + | |
' <div contenteditable="true"><b><u>Hint:</u></b>###HINT###</div>' + | |
' <div class="waypoints ###HIDDENSTYLE###">###ADDITIONAL_WAYPOINTS###</div>' + | |
' <div class="images">###IMAGES###</div>' + | |
' <div id = "###MAPID###" class="map ###HIDDENSTYLE###">###MAP###</div>' + | |
' <div class="removable ###HIDDENSTYLE###">###LOGCOUNTER###</div>' + | |
' <div class="logs ###HIDDENSTYLE###">###LOGS###</div>' + | |
' <div style="clear:both"> </span>' + | |
' </div>' + | |
'</div>'; | |
var ownMarkerTemplate = | |
'<div class="cacheDetail ###HIDDENSTYLE###">' + | |
' <div class="geocache_count ###HIDDENSTYLE###" style="padding:5px !important"><span>###CACHECOUNT###</span></div>' + | |
' <div class="wpt_id">###GCID###</div>' + | |
' <div>' + | |
' <img src="###TYPE###">' + | |
' <span style="font-weight: bold;">###NAME###</span><br/>' + | |
' <span>###COORDINATES###</span>' + | |
' </div>' + | |
' <div>' + | |
' <div class="long">###CONTENT###</div>' + | |
' </div>' + | |
'</div>'; | |
// show/hide cache and own marker details (but only if title page is present and minimal printview is not set; otherwise print preview is completely empty) | |
if (GM_getValue('showCacheDetails', true)===false && GM_getValue('printFrontpage', true) && !minimal) { | |
cacheDetailTemplate = cacheDetailTemplate.replace("###HIDDENSTYLE###", "hidden"); | |
ownMarkerTemplate = ownMarkerTemplate.replace("###HIDDENSTYLE###", "hidden"); | |
} else { | |
cacheDetailTemplate = cacheDetailTemplate.replace("###HIDDENSTYLE###", ""); | |
ownMarkerTemplate = ownMarkerTemplate.replace("###HIDDENSTYLE###", ""); | |
} | |
// clear content | |
$('html').html(""); // result: <html><head></head><body></body></html> | |
// title of print preview page | |
$('html').append('<title>' + $.gctour.lang('settings.printview.header') + '</title>'); | |
var bodyTag = document.getElementsByTagName('body')[0]; | |
bodyTag.style.background = 'none'; | |
bodyTag.style.backgroundColor = "white"; | |
bodyTag.innerHTML = ''; | |
// add styles to body tag | |
$('head').remove(); // presence of head tag causes problems when printing in Firefox --> add styles to body tag | |
var jqCss = $('<link/>').attr("href", "https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css").attr("rel", "stylesheet").appendTo($(bodyTag)); | |
var style = document.createElement('style'); | |
style.type = 'text/css'; | |
style.innerHTML = '*{ font-size:' + GM_getValue("printFontSize", "x-small") + ' } .cacheDetail{ border: 1px solid lightgray; width: 100%; text-align: left;padding:5px; -moz-box-sizing: border-box; } .wpt_id{ position:relative; padding:5px !important; float:right; font-weight:bold; } .geocache_id{ position:relative; padding:20px !important; padding-right: 5px !important; float:right; font-weight:bold; } .content{ clear:both; border-top:2px dashed lightgray; margin-top:10px; padding-top:10px; } img{ vertical-align:middle; } #details span{ margin-left: 10px } .images{clear:both;height:auto}' + | |
'.map{clear:both} .logs{clear:both} .hidden{display:none} .highlight{background-color:pink}' + | |
'.geocache_count{ position:relative; padding:20px !important; padding-left: 5px !important; padding-right: 5px !important; float:right; font-weight:bold; } .geocache_count span{padding: 5px; font-weight: bold; -moz-border-radius: 5px; border-radius: 5px; border:2px dotted black;}' + | |
'sup {vertical-align:baseline;font-size:77%;position:relative;top:-5px;}' + | |
'.dialogMask {background-image:url(' + $.gctour.img.dialogMask + ');height:100%;left:0;opacity:0.7;position:fixed;top:0;width:100%;z-index:1100;}' + | |
'.dialogBody{-moz-border-radius:5px; border-radius:5px; background:none repeat scroll 0 0 #fff;border:1px solid #333333;color:#333333;cursor:default;font-family:Arial;font-size:12px;left:50%;margin-left:-250px;margin-top:20px;padding:0 0 1em;position:fixed;text-align:left;top:0;width:500px;z-index:1101;max-height:85%;min-height:370px;overflow:auto;}' + | |
'.dialogBody p {font-size:12px;font-weight:normal;margin:1em 0em;}' + | |
'.dialogBody h1{background-color:#B2D4F3;font-size:110%;font-family:Helvetica Neue,Arial,Helvetica,sans-serif;margin-bottom:0.2em;padding:0.5em;-moz-border-radius:5px 5px 0px 0px;border-radius:5px 5px 0px 0px;color:#333333;background-image:url("' + $.gctour.img.tabBg + '");margin:0px;}' + | |
'.dialogHistory {border:1px inset #999999;margin:0 1em 1em;height:200px;overflow-y:auto;width:448px;padding-left:1em;}' + | |
'.dialogHistory ul{margin-left:2em;}' + | |
'.dialogHistory li{list-style-type:circle;}' + | |
'.dialogFooter input{-moz-border-radius:3px;border-radius:3px;background:none no-repeat scroll 4px center #EEEEEE;border:1px outset #666666;cursor:pointer;float:right;margin-left:0.5em;padding:3px 5px 5px 20px;min-width:100px;}' + | |
'.dialogFooter input:hover { background-color:#f9f9f9; }' + | |
'.dialogContent {padding:0px 10px 0px 10px;}' + | |
'.dialogMin {min-height:0px !important}' + | |
'.noprint {padding:2px;border: 1px solid #c0cee3;z-index: 10000;background-color: #eff4f9; text-align: left;margin-top:10px} .noprint>div {margin-top:2px} ' + | |
'.noprint>input {border: 1px outset #666666;cursor: pointer;margin:5px;padding: 3px 5px 5px 25px;background: none no-repeat scroll 4px center #eeeeee;float:left;clear:both;} ' + | |
'.noprint>input:hover {background-color:#f9f9f9}'; | |
// limit the font size of the cache table to "small"; for bigger sizes the table most likely gets too wide | |
var fs = GM_getValue("printFontSize", "x-small"); | |
if ((fs != "xx-small") && (fs != "x-small") && (fs != "small")) { | |
fs = "small"; | |
} | |
style.innerHTML += 'div#printTitle>table * {font-size:' + fs + ';}' + | |
'.noprint * {font-size:' + fs + ';}'; | |
bodyTag.appendChild(style); | |
style = document.createElement('style'); | |
style.media = 'print'; | |
style.type = 'text/css'; | |
//hide the map control in print | |
style.innerHTML = '.noprint { display: none; } body {margin: 0;padding: 0;color: black;background: transparent;width:99%}'; | |
bodyTag.appendChild(style); | |
var body = document.createElement('div'); | |
var printviewWidthDefault = 648; | |
var printviewWidth = GM_getValue("printviewWidth", printviewWidthDefault); | |
$(body).width(printviewWidth+"px"); | |
$(body).css("margin", "30px auto"); | |
bodyTag.appendChild(body); | |
var $printInfo = $('<div/>', { | |
'class': 'noprint', | |
'html': $.gctour.lang('printview.dontPrintHint'), | |
'css': { | |
'font-size': fs | |
} | |
}); | |
$(body).append($printInfo); | |
////////////////////////////////////////////// | |
// slider for changing width of print preview | |
var $div_width = $('<div/>', { | |
'class': 'noprint', | |
'html': $.gctour.lang('printview.printWidth'), | |
'css': { | |
'font-size': fs | |
} | |
}), | |
$slider = $('<div/>', { | |
'id': 'slider', | |
'css': { | |
//'width': '75%', | |
'display': 'inline-block', | |
'margin-left': '10px', | |
'margin-right': '40px', | |
'top': '2px' | |
} | |
}), | |
$slider_handle = $('<div/>', { | |
'id': 'slider_handle', | |
'class': 'ui-slider-handle', | |
'css': { | |
'width': '3.5em', | |
'text-align': 'center', | |
'font-size': 'smaller', | |
'top': '-2.25px' | |
} | |
}); | |
$(body).append( | |
$div_width.append( | |
$slider.append($slider_handle))); | |
var offset = 150; | |
$(function () { | |
var handle = $("#slider_handle"); | |
$("#slider").slider({ | |
value: printviewWidth, | |
min: 600, | |
max: $(document).width()-24, | |
create: function () { | |
handle.text($(this).slider("value") + "px"); | |
$(this).width($("#slider").parent().width()-offset); | |
}, | |
slide: function (event, ui) { | |
handle.text(ui.value + "px"); | |
$("#slider").parent().parent().width(ui.value); | |
$(this).width($("#slider").parent().width()-offset); | |
}, | |
stop: function (event, ui) { // store current width as new default value | |
GM_setValue("printviewWidth", $(this).slider("value")); | |
} | |
}); | |
}); | |
// reset button | |
$("#slider").parent().append('<div id="reset" style="display: inline-block;"></div>'); | |
$("#reset").button({ | |
label: "Reset" | |
}).click(function (event) { | |
$("#slider").slider("value", printviewWidthDefault); | |
$("#slider_handle").text(printviewWidthDefault + "px"); | |
$("#slider").parent().parent().width(printviewWidthDefault); | |
$("#slider").width($("#slider").parent().width()-offset); | |
GM_setValue("printviewWidth", printviewWidthDefault); | |
}); | |
$("div#reset > span.ui-button-text").css("font-size","smaller"); | |
////////////////////////////////////////////// | |
addProgressbar({ | |
_document : document, | |
closeCallback : function (_document) { | |
return function () { | |
if (confirm($.gctour.lang('general.cancel') + "?") == true) { | |
window.location.reload(); | |
} | |
}; | |
} | |
}); | |
// for progress bar update | |
PROGRESS_BAR.progress = 0; | |
PROGRESS_BAR.total = nCaches; | |
$("<fieldset/>", { | |
'class' : 'noprint' | |
}) | |
.css('right', '50px') | |
.css('position', 'fixed') | |
.append( | |
$("<legend/>").html($.gctour.lang('settings.printview.header')) | |
.css('background', "url(\"" + $.gctour.img.gctourLogoSmall + "\") no-repeat scroll 0 0 transparent") | |
.css('padding-left', '20px'), | |
$("<input/>").attr("type", "input").attr("value", $.gctour.lang('printview.print')).css("background-image", "url(" + $.gctour.img.printer + ")").click(function () { | |
self.print() | |
}), | |
$("<input/>").attr("type", "input").attr("value", $.gctour.lang('general.close')).css("background-image", "url(" + $.gctour.img.closebutton + ")").click(function () { | |
window.location.reload(); | |
})).appendTo($(body)); | |
// front page | |
if (GM_getValue('printFrontpage', true) && !minimal) { | |
var title = $('<div>', { | |
id : 'printTitle', | |
css : { | |
width : "100%", | |
textAlign : 'center', | |
"page-break-after" : ((GM_getValue('printPageBreakAfterMap', true)) ? 'always' : 'never') | |
}, | |
html : "<h1>" + tour.name + "</h1>" | |
}); | |
$(body).append(title); | |
var coverTable = document.createElement('table'); | |
coverTable.style.width = "100%"; | |
coverTable.style.border = '1px solid lightgray'; | |
coverTable.innerHTML = | |
'<thead><tr> ' + | |
' <th colspan="2" style="border-bottom:1px solid lightgray;"><b>Geocache</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;"> </th> ' + | |
' <th style="border-bottom:1px solid lightgray;"> </th> ' + | |
' <th style="border-bottom:1px solid lightgray;" align="center"><b>D</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;" align="center"><b>T</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;" align="center"><b>S</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;" align="center"><b>L4L</b> </th> ' + | |
' <th colspan="2" style="border-bottom:1px solid lightgray;" align="center"><b>Fav</b> </th> ' + | |
' <th style="border-bottom:1px solid lightgray;"><b>' + $.gctour.lang('marker.coord') + '</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;"><b>' + $.gctour.lang('printview.found') + '</b></th> ' + | |
' <th style="border-bottom:1px solid lightgray;"> <b>' + $.gctour.lang('printview.note') + '</b></th> ' + | |
'</tr><thead>'; | |
var tbody = createElement('tbody'); | |
append(tbody, coverTable); | |
// table of caches | |
var isCostumMarker = false, | |
id, | |
coords; | |
for (i = 0; i < nCaches; ++i) { | |
var costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (costumMarker) { | |
id = "WP"; | |
coords = "'coords_WP" + (i + 1) + "'>" + new LatLon(tour.geocaches[i].latitude, tour.geocaches[i].longitude).toString(); | |
} else { | |
id = tour.geocaches[i].id; | |
coords = "'coords_" + tour.geocaches[i].id + "'>"; | |
} | |
if (GM_getValue('addCustomMarkerToCacheTable', true) === true) { | |
costumMarker = false; // add custom marker to cache table | |
} | |
if (!costumMarker) { | |
tr = createElement('tr'); | |
tbody.appendChild(tr); | |
// numbering | |
td = createElement('td'); | |
tr.appendChild(td); | |
td.innerHTML = "<b style='margin:0 6px'>" + (i + 1) + "</b>"; | |
// image | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<img src='" + tour.geocaches[i].image + "'>"; | |
// name | |
td = createElement('td', { | |
style : "text-align:left;border-bottom:1px solid lightgray;white-space:nowrap;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<a style='color:#000000;text-decoration: none' target='_blank' href='http://coord.info/" + tour.geocaches[i].id + "'>" + tour.geocaches[i].name + "</a>"; | |
// id | |
td = createElement('td', { | |
style : "text-align:left;border-bottom:1px solid lightgray;border-right:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span style='margin:0 2px'>" + id + "</span>"; | |
// difficulty | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;border-right:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span style='margin:0 2px' id='d_" + tour.geocaches[i].id + "'></span>"; | |
// terrain | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;border-right:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span style='margin:0 2px' id='t_" + tour.geocaches[i].id + "'></span>"; | |
// size | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;border-right:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span style='margin:0 2px' id='s_" + tour.geocaches[i].id + "'></span>"; | |
// last 4 logs | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;white-space:nowrap;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<canvas id='l4l_" + tour.geocaches[i].id + "' width='17' height='17' style='margin-left: 2px;position: relative;top: 2px;'/>"; | |
// favorite points | |
td = createElement('td', { | |
style : "text-align:left;border-bottom:1px solid lightgray;border-left:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span id='fp_" + tour.geocaches[i].id + "'></span>"; | |
// favorite score | |
td = createElement('td', { | |
style : "text-align:right;border-bottom:1px solid lightgray;border-right:1px dashed lightgray;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span id='fs_" + tour.geocaches[i].id + "'></span>"; | |
// coords | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;white-space:nowrap;" | |
}); | |
tr.appendChild(td); | |
td.innerHTML = "<span style='margin:0 2px' id=" + coords + "</span>"; | |
// found checkbox | |
td = createElement('td'); | |
tr.appendChild(td); | |
td.style.verticalAlign = "middle"; | |
td.innerHTML = "<div style='margin-left:auto;margin-right:auto;width:10px;height:10px;border:1px solid lightgray;'> </div>"; | |
// note | |
td = createElement('td', { | |
style : "border-bottom:1px solid lightgray;" | |
}); | |
tr.appendChild(td); | |
td.style.verticalAlign = "middle"; | |
td.style.width = "100%"; | |
td.innerHTML = " "; | |
} else { | |
if (GM_getValue('addCustomMarkerToCacheTable', false) === false) { // custom marker in separate table | |
isCostumMarker = costumMarker; | |
continue; | |
} | |
} | |
} | |
// table of custom marker | |
if (isCostumMarker) { | |
tbody.innerHTML += | |
'<tr> ' + | |
' <td colspan="11" style="border-bottom:1px solid lightgray;"><b>' + $.gctour.lang('printview.marker') + '</b></td> ' + | |
'</tr>'; | |
for (i = 0; i < nCaches; ++i) { | |
var costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (costumMarker) { | |
tr = document.createElement('tr'); | |
tbody.appendChild(tr); | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
td.innerHTML = "<b style='margin:0 10px'>" + (i + 1) + "</b>"; | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
td.innerHTML = "<img src='" + tour.geocaches[i].image + "'>"; | |
td = document.createElement('td'); | |
tr.appendChild(td); | |
td.style.verticalAlign = "middle"; | |
td.style.width = "30%"; | |
td.colSpan = "9"; | |
td.style.borderBottom = '1px solid lightgray'; | |
td.innerHTML = tour.geocaches[i].name; | |
td.innerHTML += " - " + new LatLon(tour.geocaches[i].latitude, tour.geocaches[i].longitude).toString(); | |
} | |
} | |
} | |
$(title).append($(coverTable)); | |
var overview_map = createElement('div', { | |
id : "overview_map" | |
}); | |
$(title).append($(overview_map)); | |
} | |
var geocaches = []; | |
var costumMarkers = []; | |
var maxPrintLogs = parseInt(GM_getValue('maxPrintLogs', 3), 10); | |
// fetch all caches in parallel, not one by one | |
var promises = []; | |
for (i = 0; i < nCaches; i++) { | |
costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (costumMarker) { | |
promises.push(tour.geocaches[i]); | |
updateProgressBar(); | |
} else { | |
// retrieve at least 4 logs (if available) in order to display Last4Logs status, independent of maxPrintLogs parameter | |
promises.push(getGeocache(tour.geocaches[i].id, Math.max(4,maxPrintLogs))); | |
} | |
} | |
try { | |
var cache_objects = await Promise.all(promises); | |
for (i = 0; i < cache_objects.length; ++i) { | |
var costumMarker = (typeof(tour.geocaches[i].latitude) != "undefined"); | |
if (!costumMarker) { | |
var geocache = cache_objects[i]; | |
if (geocache == "pm only") { | |
var pmOnlyDiv = createElement('div'); | |
pmOnlyDiv.setAttribute('class', 'cacheDetail'); | |
pmOnlyDiv.innerHTML = "<b><img src='" + tour.geocaches[i].image + "'>" + tour.geocaches[i].name + " (" + tour.geocaches[i].id + ") is PM ONLY</b>"; | |
body.appendChild(pmOnlyDiv); | |
body.appendChild(document.createElement('br')); | |
$(document).find("span#coords_" + tour.geocaches[i].id) | |
.html("PM ONLY"); | |
} else { | |
//logs | |
var logs_div = createElement('div'); | |
var logs = geocache.logs; | |
// if maxprintlogs <= -1, export all logs to the print overview | |
if (maxPrintLogs <= -1) { | |
maxPrintLogs = logs.length; | |
} | |
maxPrintLogs = maxPrintLogs; | |
for (var log_i = 0; (log_i < logs.length && (log_i < maxPrintLogs)); log_i++) { | |
var log_div = createElement('div', { | |
style : "width:100%;page-break-inside:avoid;" | |
}); | |
log_div.setAttribute("class", "removable"); | |
var log_type_img = createElement('img', { | |
src : GS_HOST + 'images/logtypes/' + logs[log_i].LogTypeImage | |
}); | |
log_div.appendChild(log_type_img); | |
log_div.innerHTML += " " + logs[log_i].Visited + " - " + logs[log_i].UserName + " (" + logs[log_i].GeocacheFindCount + ")<br/>"; | |
log_div.innerHTML += logs[log_i].LogText; | |
log_div.style.borderBottom = "1px dashed lightgray"; | |
append(log_div, logs_div); | |
} | |
var dummy_additional_waypoints = createElement('div'); | |
if (GM_getValue('printAdditionalWaypoints', true)) { | |
var wpts_table = createElement('table', { | |
style : "width:100%;border-collapse:separate;" | |
}); | |
append(wpts_table, dummy_additional_waypoints); | |
wpts_table.setAttribute("class", "removable"); | |
var content = ""; | |
for (var waypoints_i = 0; waypoints_i < geocache.additional_waypoints.length; waypoints_i++) { | |
if (waypoints_i % 2 === 0) { | |
content += "<tr>"; | |
} | |
content += "<td style='width:50%;'>"; | |
content += "<img src='" + geocache.additional_waypoints[waypoints_i].symbol + "'> "; | |
content += "<b>" + geocache.additional_waypoints[waypoints_i].prefix + "·</b>"; | |
content += "<b>" + geocache.additional_waypoints[waypoints_i].name + "</b>"; | |
content += " | " + geocache.additional_waypoints[waypoints_i].coordinates + "<br/>"; | |
content += "<i>" + geocache.additional_waypoints[waypoints_i].note + "</i><br/>"; | |
content += "</td>"; | |
if (waypoints_i % 2 === 1 || waypoints_i === geocache.additional_waypoints.length-1) { | |
content += "</tr>"; | |
} | |
} | |
wpts_table.innerHTML = content; | |
} | |
//images | |
var dummy_images = createElement('div'); | |
if (GM_getValue('printSpoilerImages', true)) { | |
var image_table = createElement('table', { | |
style : "border-collapse:separate;border-spacing:2px;width:100%" | |
}); | |
append(image_table, dummy_images); | |
var content = ""; | |
for (var images_i = 0; images_i < geocache.images.length; images_i++) { | |
if (images_i % 2 === 0) { | |
content += "<tr>"; | |
} | |
content += "<td class='removable'>"; | |
content += "<img style='max-width:8cm;' src='" + geocache.images[images_i].href + "'><br/>"; | |
content += "<b>" + geocache.images[images_i].textContent + "</b>"; | |
content += "</td>"; | |
if (images_i % 2 === 1 || images_i === geocache.images.length-1) { | |
content += "</tr>"; | |
} | |
} | |
image_table.innerHTML = content; | |
} | |
//inventory | |
var inventory = createElement('span'); | |
for (var inventory_i = 0; inventory_i < geocache.$inventory.length; inventory_i++) { | |
var image = createElement('img'); | |
image.src = geocache.$inventory[inventory_i].src; | |
append(image, inventory); | |
} | |
if (geocache.$inventory.length === 0) { | |
var empty_inventory = createElement('span'); | |
empty_inventory.innerHTML = "empty"; | |
append(empty_inventory, inventory); | |
} | |
//attributes | |
var attributes = createElement('span'); | |
for (var attributes_i = 0; attributes_i < geocache.$attributes.length; attributes_i++) { | |
var attribute = geocache.$attributes[attributes_i]; | |
attribute.style.width = "16px"; | |
attribute.style.height = "16px"; | |
attribute.style.marginRight = "3px"; | |
if (attribute.src != $.gctour.img.attribute_blank) { | |
append(attribute, attributes); | |
} | |
} | |
var map_element_dummy = createElement('div'); | |
var map_element = createElement('div'); | |
append(map_element, map_element_dummy); | |
// map the geocache to uploadable version | |
var mapCache = {}; | |
mapCache.gcid = geocache.gcid; | |
mapCache.guid = geocache.guid; | |
mapCache.image = geocache.image; | |
mapCache.name = geocache.name; | |
mapCache.difficulty = geocache.difficulty; | |
mapCache.terrain = geocache.terrain; | |
mapCache.latitude = geocache.lat; | |
mapCache.longitude = geocache.lon; | |
// add additional waypoints | |
var additional_waypoints = geocache.additional_waypoints; | |
for (waypoint_i = 0; waypoint_i < additional_waypoints.length; waypoint_i++) { | |
additional_waypoints[waypoint_i].note = ""; | |
} | |
mapCache.additional_waypoints = additional_waypoints; | |
geocaches.push(mapCache); | |
// export from GCComment script | |
var gcComment = ""; | |
if (geocache.comment) { | |
gcComment = "<b><u>GCComment:</u></b><br/>"; | |
if (geocache.comment.lat) { | |
var parsedCoords = new LatLon(geocache.comment.lat, geocache.comment.lng).toString(); | |
gcComment += "<b>Final Coordinates:</b> " + parsedCoords + "<br/>"; | |
} | |
gcComment += "<b>Comment:</b> (" + geocache.comment.state + ") " + geocache.comment.commentValue; | |
} | |
// cache note from Groundspeak | |
var cache_note = ""; | |
if (geocache.cache_note) { | |
cache_note = "<b><u>Cache Note:</u></b><br/>"; | |
cache_note += '<span style="word-wrap:break-word;">' + geocache.cache_note + '</span>'; | |
} | |
if (GM_getValue('printFrontpage', true) && !minimal) { | |
$(document) | |
// setting real coordinates on front page | |
.find("span#coords_" + geocache.gcid) | |
.html(geocache.coordinates) | |
.css({ | |
'border-bottom' : (geocache.coordinatesisedit === true ? '2px solid gray' : 'none') | |
}) | |
.end() | |
// setting D, T, size and favorite points on front page | |
.find("span#d_" + geocache.gcid).html(geocache.difficulty).end() | |
.find("span#t_" + geocache.gcid).html(geocache.terrain).end() | |
.find("span#s_" + geocache.gcid).html(geocache.size.substring(0, 1)).end() | |
.find("span#fp_" + geocache.gcid).html(geocache.fav).end() | |
.find("span#fs_" + geocache.gcid).html(geocache.favScore).end(); | |
// set the last 4 logs icon: | |
getLast4Logs(geocache.logs, $("canvas#l4l_" + geocache.gcid, document)); | |
} | |
geocache.name = escapeHTML(geocache.name); | |
var geocacheMapping = [ | |
['GCID', geocache.gcid], | |
['CACHECOUNT', i + 1], | |
['GUID', geocache.guid], | |
['TYPE', geocache.type], | |
['CACHENAME', (geocache.available) ? geocache.name : "<span style='text-decoration: line-through !important;'>" + geocache.name + "</span>"], | |
['CACHESYM', geocache.cacheSym], | |
['OWNER', geocache.owner], | |
['HIDDEN', await formatDate(geocache.hidden)], | |
['ATTRIBUTES', attributes.innerHTML], | |
['BEARING', geocache.bearing], | |
['DISTANCE', geocache.distance], | |
['INVENTORY', inventory.innerHTML], | |
['COORDINATESISEDIT', (geocache.coordinatesisedit === true) ? '' : 'hidden'], | |
['COORDINATES', geocache.coordinates], | |
['DIFFICULTY', geocache.difficulty.replace(/\./, "_")], | |
['TERRAIN', geocache.terrain.replace(/\./, "_")], | |
['SIZE', geocache.size.toLowerCase().replace(/ /, "_")], | |
['SHORT_DESCRIPTION', (geocache.$short_description.length === 1) ? geocache.$short_description.html() : ""], | |
['LONG_DESCRIPTION', (geocache.$long_description.length === 1) ? geocache.$long_description.html() : ""], | |
['GCCOMMENT', gcComment], | |
['CACHENOTE', cache_note], | |
['HINT', (GM_getValue('decryptPrintHints', true)) ? geocache.hint : convertROTStringWithBrackets(geocache.hint)], | |
['ADDITIONAL_WAYPOINTS', dummy_additional_waypoints.innerHTML], | |
['IMAGES', dummy_images.innerHTML], | |
['MAP', map_element_dummy.innerHTML], | |
['MAPID', "MAP_" + geocache.gcid], | |
['LOGCOUNTER', (GM_getValue('printLoggedVisits', false) && geocache.find_count) ? geocache.find_count : ""], // empty for non-published caches | |
['LOGS', logs_div.innerHTML], | |
['FAV', geocache.fav ? geocache.fav : 'none'], | |
['FAVSCORE', geocache.favScore], | |
['HIDDENSTYLE', minimal ? 'hidden' : ''] | |
]; | |
var cacheDetailTemp = fillTemplate(geocacheMapping, cacheDetailTemplate); | |
// class "removable" elements and removable images in cache description | |
$(".removable, div.short img, div.long img", cacheDetailTemp) | |
.click(function (e) { | |
e.stopPropagation(); | |
$(this).remove(); | |
}) | |
.hover( | |
function () { | |
$(this).css({ | |
"opacity" : "0.5", | |
"cursor" : "url('" + $.gctour.img.del + "'),pointer" | |
}); | |
}, | |
function () { | |
$(this).css({ | |
"opacity" : 1 | |
}); | |
}); | |
// remove href attribute from links in cache description | |
$("div.short a, div.long a", cacheDetailTemp).removeAttr("href"); | |
// add edit mode | |
if (GM_getValue('printEditMode', true)) { | |
$("div.short, div.long", cacheDetailTemp).attr('contenteditable', 'true'); | |
} | |
if (GM_getValue('printPageBreak', false)) { | |
if (i < nCaches - 1) { | |
cacheDetailTemp.style.pageBreakAfter = 'always'; | |
} | |
} | |
body.appendChild(cacheDetailTemp); | |
body.appendChild(document.createElement('br')); | |
} | |
} else { | |
// map custom marker to uploadable version | |
var cm = cache_objects[i]; | |
cm.index = i; | |
costumMarkers.push(cm); | |
var markerMapping = [ | |
['GCID', $.gctour.lang('printview.marker')], | |
['CACHECOUNT', (i + 1)], | |
['TYPE', tour.geocaches[i].image], | |
['NAME', tour.geocaches[i].name], | |
['COORDINATES', new LatLon(tour.geocaches[i].latitude, tour.geocaches[i].longitude).toString()], | |
['CONTENT', tour.geocaches[i].content.replace(/\n/g, "<br />")], | |
['HIDDENSTYLE', minimal ? 'hidden' : ''] | |
]; | |
var cacheDetailTemp = fillTemplate(markerMapping, ownMarkerTemplate); | |
body.appendChild(cacheDetailTemp); | |
body.appendChild(document.createElement('br')); | |
} | |
} | |
closeOverlayRemote(document)(); // close old overlay (scraping data) | |
// maps | |
addProgressbar({ | |
caption : $.gctour.lang('container.tourHeader.makeMap.wait'), | |
_document : document, | |
closeCallback : function (_document) { | |
return function () { | |
if (confirm($.gctour.lang('general.cancel') + "?") == true) { | |
window.location.reload(); | |
} | |
}; | |
} | |
}); | |
// upload map content to server | |
var cacheObject = {}; | |
cacheObject.geocaches = geocaches; | |
cacheObject.costumMarkers = costumMarkers; | |
uploadMap(cacheObject); | |
// show maps | |
try { | |
var overviewMapQuery = ""; | |
var geocacheCodes = []; | |
for (var i = 0; i < nCaches; ++i) { | |
var marker = tour.geocaches[i]; | |
if (marker.wptcode) { | |
overviewMapQuery += marker.wptcode; | |
} else { | |
overviewMapQuery += (marker.id) ? marker.id : marker.gcid; | |
geocacheCodes.push((marker.id) ? marker.id : marker.gcid); | |
} | |
if (i < nCaches - 1) { | |
overviewMapQuery += ","; | |
} | |
} | |
// overview map | |
var printOverviewMap = ( | |
GM_getValue('printOutlineMap', true) && | |
GM_getValue('printFrontpage', true) && | |
!minimal); | |
var mapCount = (printOverviewMap) ? 1 : 0; | |
mapCount += (GM_getValue('printOutlineMapSingle', false)) ? geocacheCodes.length : 0; | |
if (printOverviewMap) { | |
$("div#overview_map", document).first().append(await getMapElement(overviewMapQuery, document)); | |
setProgress(0, mapCount, document); | |
} | |
// map for each geocache | |
var printMapForEachCache = ( | |
GM_getValue('showCacheDetails', true) && | |
GM_getValue('printOutlineMapSingle', false)); | |
if (printMapForEachCache) { | |
for (var i = 0; i < geocacheCodes.length; ++i) { | |
var geocacheCode = geocacheCodes[i]; | |
var mapElement = $("div#MAP_" + geocacheCode, document).first(); | |
if (mapElement) { | |
mapElement.append(await getMapElement(geocacheCode, document)); | |
} | |
setProgress(i + 1, mapCount, document); | |
} | |
} | |
closeOverlayRemote(document)(); | |
} catch (e) { | |
throw "show maps - " + e; | |
} | |
} | |
catch(e) { | |
addErrorDialog({ | |
caption : "printPageFunction error", | |
_document : document, | |
_exception : e | |
}); | |
} | |
// scale listing images to fit print preview | |
$('div.short img, div.long img').removeAttr('width').removeAttr('height').removeAttr('style').css({'max-width':'100%','max-height':'100%','object-fit':'contain'}); | |
} | |
// funktion ähnlich http://www.gsak.net/help/hs11980.htm | |
function getLast4Logs(logs, canvas_element) { | |
var getColor = function (log4Logs) { | |
if ((typeof(log4Logs)) === 'undefined') { | |
return "LightGray"; | |
} | |
switch (log4Logs.LogType) { | |
case "Found it": | |
return "green"; | |
case "Didn't find it": | |
return "red"; | |
case "Needs Maintenance": | |
return "blue"; | |
case "Temporarily Disable Listing": | |
return "black"; | |
case "Needs Archived": | |
return "yellow"; | |
default: | |
return "LightGray"; | |
} | |
}; | |
var ctx = canvas_element.get(0).getContext('2d'); | |
ctx.fillStyle = "black"; | |
//~ ctx.fillRect(0,0,17,17); | |
ctx.clearRect(1, 1, 15, 15); | |
var pos = [[2, 2], [9, 2], [2, 9], [9, 9]]; | |
var dim = [6, 6]; | |
for (var i = 0; i < pos.length; i++) { | |
ctx.fillStyle = getColor(logs[i]); | |
ctx.fillRect(pos[i][0], pos[i][1], dim[0], dim[1]); | |
} | |
} | |
/* printpage maps */ | |
function updateMapSize(newDocument, mapId, factor) { | |
return function () { | |
var map = newDocument.getElementById(mapId).getElementsByTagName('iframe')[0]; | |
map.style.width = (factor * 20) + "cm"; | |
map.style.height = (1 * 500) + "px"; | |
}; | |
} | |
function getMapType() { | |
return GM_getValue('printOutlineMapType', 'roadmap'); | |
} | |
function getMapSettings() { | |
var settings = []; | |
// settings String: | |
// 1 - Geocache GCID | |
// 2 - Geocache Name | |
// 3 - Waypoint Hide all | |
// 4 - Waypoint Name | |
// 5 - Waypoint Lookup | |
// 6 - Own Waypoint show | |
// 7 - Own Waypoints name | |
// 8 - Show gc.de maps overlay | |
// 9 - Show Geocache Index | |
settings.push(GM_getValue('settings_map_geocacheid', true)); | |
settings.push(GM_getValue('settings_map_geocachename', true)); | |
settings.push(GM_getValue('settings_map_awpts', true)); | |
settings.push(GM_getValue('settings_map_awpt_name', true)); | |
settings.push(GM_getValue('settings_map_awpt_lookup', true)); | |
settings.push(GM_getValue('settings_map_owpts', true)); | |
settings.push(GM_getValue('settings_map_owpt_name', true)); | |
settings.push(false); // gc.de maps does not exist anymore: do not skip here, but set to false! | |
settings.push(GM_getValue('settings_map_geocacheindex', true)); | |
return settings.join("").replace(/true/g, "1").replace(/false/g, "0"); | |
} | |
async function getMapUrl(mapQuery) { | |
try { | |
var headers = {'Content-type' : 'application/x-www-form-urlencoded'}, | |
response = await promiseRequest('POST', GCTOUR_HOST + "map/make", headers, encodeURI("ids=" + mapQuery)), | |
hash_value = response.responseText; | |
debug("Hash '" + hash_value + "' for this query '" + mapQuery + "'"); | |
return GCTOUR_HOST + "map/show/h/" + hash_value + "/" + getMapSettings() + "/" + getMapType(); | |
} catch(e) { | |
throw 'fn getMapUrl - ' + e; | |
} | |
} | |
async function getMap(mapQuery) { | |
var map_size_px, | |
mapId = mapQuery.replace(/,/g, ""), | |
map_frame = document.createElement('iframe'); | |
switch (GM_getValue('defaultMapSize', 'large')) { | |
case "medium": | |
map_size_px = 375; | |
break; | |
case "small": | |
map_size_px = 250; | |
break; | |
default: | |
map_size_px = 500; | |
break; | |
} | |
map_frame.className = 'cacheMap'; | |
map_frame.id = mapId; | |
map_frame.style.width = "100%"; | |
map_frame.style.height = map_size_px + 'px'; | |
$(map_frame).css("border", '1px solid lightgray'); | |
$(map_frame).css("box-sizing", "border-box"); | |
map_frame.src = await getMapUrl(mapQuery); | |
return map_frame; | |
} | |
async function getMapControl(mapQuery, map_frame, newDocument) { | |
var mapId = mapQuery.replace(/,/g, ""), | |
control_container = createElement('div'), | |
map_size_px; | |
control_container.className = 'noprint'; | |
switch (GM_getValue('defaultMapSize', 'large')) { | |
case "small": | |
map_size_px = 250; | |
break; | |
case "medium": | |
map_size_px = 375; | |
break; | |
default: | |
map_size_px = 500; | |
break; | |
} | |
$(control_container).append( | |
$('<div>'+$.gctour.lang('printview.mapHeight')+'</div>') | |
.css('float', 'left') | |
.css('margin-right', '5px'), | |
$("<div/>").gct_slider({ | |
min : 100, | |
max : 1000, | |
value : map_size_px, | |
document : newDocument, | |
slide : function (values) { | |
map_frame.style.height = values.value + "px"; | |
} | |
}) | |
.css('float', 'left') | |
.css('width', '250px'), | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.del, | |
title : $.gctour.lang('printview.removeMap'), | |
alt : $.gctour.lang('printview.removeMap'), | |
click : function () { | |
map_frame.parentNode.style.display = "none"; | |
} | |
}) | |
.css('float', 'right'), | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.refresh, | |
title : $.gctour.lang('printview.reloadMap'), | |
alt : $.gctour.lang('printview.reloadMap'), | |
click : function () { | |
map_frame.src = map_frame.src; | |
} | |
}) | |
.css('float', 'right'), | |
$('<img>', { | |
'class' : 'tourImage', | |
src : $.gctour.img.map, | |
title : $.gctour.lang('printview.zoomMap'), | |
alt : $.gctour.lang('printview.zoomMap'), | |
click : async function () { | |
GM_openInTab(await getMapUrl(mapQuery), false); | |
} | |
}) | |
.css('float', 'right'), | |
$('<div/>') | |
.css('clear', 'both')).find("img.tourImage").addShadowEffect().addOpacityEffect().css('margin-left', '5px'); | |
return control_container; | |
} | |
// add gct_slider method to jquery (e.g. height slider in print preview) | |
(function ($) { | |
var methods = { | |
init : function (options) { | |
var settings = $.extend({ | |
'min' : '0', | |
'max' : '100', | |
'document' : document, | |
'value' : 0 | |
}, options), | |
scroller_element = $("<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>") | |
.appendTo(this), | |
dragged = false, | |
slider_width = 0, | |
slider_offset = 0, | |
percentage = 0, | |
self = this; | |
// set start value | |
percentage = (100 * settings.value) / settings.max; | |
scroller_element | |
.css("left", (percentage) + "%") | |
.click(function (event) { | |
event.preventDefault(); | |
}) | |
.hover( | |
function () { | |
$(this).addClass("ui-state-hover"); | |
}, | |
function () { | |
$(this).removeClass("ui-state-hover"); | |
}) | |
.focus(function () { | |
$(".ui-slider .ui-state-focus").removeClass("ui-state-focus"); | |
$(this).addClass("ui-state-focus"); | |
}) | |
.blur(function () { | |
$(this).removeClass("ui-state-focus"); | |
}) | |
.mousedown(function (e) { | |
e.preventDefault(); | |
dragged = true; | |
slider_width = parseInt(self.css("width"), 10); | |
slider_offset = parseInt(self.offset().left, 10); | |
scroller_element.addClass("ui-state-active"); | |
methods["trigger"].apply(self, ["start", methods["calculate"].apply(self, [percentage])]); | |
}); | |
this.addClass('ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all') | |
.append(scroller_element); | |
$('*', settings.document).mousemove(function (e) { | |
if (dragged) { | |
e.preventDefault(); | |
percentage = (100 * (e.pageX - slider_offset)) / (slider_width); | |
percentage = (percentage < 0) ? 0 : percentage; | |
percentage = (percentage > 100) ? 100 : percentage; | |
// debug("MousePos:"+e.pageX+"\tSliderWidth:"+slider_width+"\tSliderOffset:"+slider_offset+"\tMove to:"+percentage); | |
scroller_element.css("left", (percentage) + "%"); | |
methods["trigger"].apply(self, ["slide", methods["calculate"].apply(self, [percentage])]); | |
} | |
}); | |
$('*', settings.document).mouseup(function () { | |
if (dragged) { | |
dragged = false; | |
scroller_element.removeClass("ui-state-active"); | |
methods["trigger"].apply(self, ["stop", methods["calculate"].apply(self, [percentage])]); | |
// methods["trigger"].apply( self, {value:percentage}); | |
} | |
}); | |
this.data('gct_slider', { | |
target : $(this), | |
settings : settings | |
}); | |
return this; | |
}, | |
calculate : function (percentage) { | |
var $data = $(this).data('gct_slider'), | |
max = $data.settings.max, | |
min = $data.settings.min, | |
relative_value = (percentage * (max - min)) / 100, | |
value = min + relative_value; | |
// log("relative_value"+ relative_value+ "\tvalue:"+value); | |
return { | |
percentage : percentage, | |
value : value | |
}; | |
}, | |
trigger : function (type, data) { | |
var $data = $(this).data('gct_slider'), | |
callback = $data.settings[type], | |
data = data || {}; | |
return !($.isFunction(callback) && | |
callback.apply(this, [data]) === false); | |
} | |
}; | |
$.fn.gct_slider = function (method) { | |
if (methods[method]) { | |
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); | |
} else if (typeof method === 'object' || !method) { | |
return methods.init.apply(this, arguments); | |
} else { | |
$.error('Method ' + method + ' does not exist on jQuery.tooltip'); | |
} | |
}; | |
})($); | |
async function getMapElement(mapQuery, newDocument) { | |
var map_container = createElement('div', { | |
style : "text-align: center; margin-left: auto; margin-right: auto;" | |
}); | |
var map_frame = await getMap(mapQuery); | |
map_container.appendChild(await getMapControl(mapQuery, map_frame, newDocument)); | |
map_container.appendChild(map_frame); | |
return map_container; | |
} | |
/* cache scraper */ | |
// source of all evil asking groundspeak | |
async function getGeocacheFromElement(element, maxLogsCount) { | |
var coordinates, | |
logLink, | |
minimal_geocache, | |
$divCacheDetails, | |
latlonhref; | |
var geocache = {}; | |
/* | |
geocache | |
.gcid | |
.cacheid | |
.guid | |
.name | |
.type | |
.image | |
.sym | |
.owner | |
.comment (optional) | |
.cache_note (optional) | |
.archived | |
.available | |
.hidden | |
.difficulty | |
.terrain | |
.size | |
.coordinates | |
.coordinatesisedit (custom edit boolean) | |
.lat | |
.lon | |
.location | |
.state | |
.country | |
.bearing | |
.distance | |
.$inventory | |
.$attributes | |
.$short_description | |
.$long_description | |
.images | |
.additional_waypoints | |
.hint | |
.find_count | |
.logs | |
.fav | |
.favScore | |
*/ | |
if ($("ul.premium-features-list", element).length > 0) { | |
return "pm only"; | |
} | |
minimal_geocache = getMinimalGeocacheDetails(element); | |
geocache.gcid = minimal_geocache.gccode; | |
geocache.cacheid = minimal_geocache.cacheid; | |
geocache.guid = minimal_geocache.guid; | |
geocache.name = minimal_geocache.name; | |
geocache.type = minimal_geocache.type.split(".")[0]; | |
geocache.image = GS_HOST + "images/wpttypes/" + geocache.type + ".gif"; | |
geocache.sym = "Geocache"; | |
if (($('a#ctl00_ContentBody_hlFoundItLog', element).length >= 1) || ($('strong#ctl00_ContentBody_GeoNav_logText', element).length >= 1)) { | |
geocache.sym = "Geocache Found"; | |
} | |
geocache.owner = $.trim($('a[href*="' + GS_HOST + 'profile/?guid="]', element).first().text()); | |
if (unsafeWindow.getGCComment) { | |
var comment = unsafeWindow.getGCComment(geocache.guid); | |
if (comment) { | |
geocache.comment = comment; | |
} | |
} | |
var usernote = $("span#viewCacheNote", element); | |
if (usernote.length > 0) { | |
geocache.cache_note = usernote.html(); | |
} | |
// check availability | |
var warning_element = $("ul.OldWarning", element).first(); // contains text like | |
//This cache is temporarily unavailable. Read the logs below to read the status for this cache. | |
//This cache has been archived, but is available for viewing for archival purposes. | |
if (warning_element.length > 0) { | |
geocache.archived = (warning_element.text().indexOf("archived") != -1); | |
geocache.available = false; | |
} else { | |
geocache.archived = false; | |
geocache.available = true; | |
} | |
$divCacheDetails = $('#ctl00_ContentBody_mcd2', element).first(); | |
geocache.hidden = await parseDate($.trim($divCacheDetails.text().split(':').pop())); | |
geocache.difficulty = $.trim($("span#ctl00_ContentBody_uxLegendScale > img", element).first().attr("alt").split(" out of ")[0]); | |
geocache.terrain = $.trim($("span#ctl00_ContentBody_Localize12 > img", element).first().attr("alt").split(" out of ")[0]); | |
geocache.size = $.trim($('img[src*="/images/icons/container/"]', element).first().attr("src").split("/")[4].split(".")[0]); | |
geocache.coordinates = $('span#uxLatLon', element).first().text(); | |
// get userDefinedCoords from GS Javascript | |
// example string: var userDefinedCoords = {"status":"success","data":{"isUserDefined":false,"oldLatLngDisplay":"N 52° 31.268' E 013° 21.255'"}}; | |
var patt = /var userDefinedCoords = {*([\s\S]*?)}[;]+/; // search for "var userDefinedCoords = {" until "};" | |
var r; | |
var userDefinedCoordsString = ((r = patt.exec($(element).text())) != null) ? r[1] : ""; | |
var userDefinedCoords = jQuery.parseJSON('{' + userDefinedCoordsString + '}'); | |
geocache.coordinatesisedit = (userDefinedCoords && userDefinedCoords.status == "success" && userDefinedCoords.data.isUserDefined == true); // false = original | |
// get cache coordinates | |
latlonhref = $("span#ctl00_ContentBody_MapLinks_MapLinks a", element).map(function(i,el) { | |
return $(el).attr('href'); | |
}).get(); | |
geocache.lat = 0.0; | |
geocache.lon = 0.0; | |
for (let i = 0; i < latlonhref.length; ++i) { | |
if (latlonhref[i].includes("geocaching")) { | |
geocache.lat = latlonhref[i].split("lat=")[1].split("&")[0]; | |
geocache.lon = latlonhref[i].split("lng=")[1]; | |
break; | |
} else if (latlonhref[i].includes("mapquest")) { | |
geocache.lat = latlonhref[i].split("latitude=")[1].split("&")[0]; | |
geocache.lon = latlonhref[i].split("longitude=")[1].split("&")[0]; | |
break; | |
} else if (latlonhref[i].includes("bing")) { | |
geocache.lat = latlonhref[i].split("point")[1].split("_")[0]; | |
geocache.lon = latlonhref[i].split("point")[1].split("_")[1]; | |
break; | |
} else if (latlonhref[i].includes("opencyclemap")) { | |
geocache.lat = latlonhref[i].split("lat=")[1].split("&")[0]; | |
geocache.lon = latlonhref[i].split("lon=")[1]; | |
break; | |
} else if (latlonhref[i].includes("openstreetmap")) { | |
geocache.lat = latlonhref[i].split("mlat=")[1].split("&")[0]; | |
geocache.lon = latlonhref[i].split("mlon=")[1].split("&")[0]; | |
break; | |
} | |
} | |
// if the user moved the coordinates of this geocache by GCTour | |
if (GM_getValue('coords_' + geocache.gcid, "null") != "null") { // use it | |
coordinates = GM_getValue('coords_' + geocache.gcid, "null").split("#"); | |
geocache.lat = coordinates[0]; | |
geocache.lon = coordinates[1]; | |
geocache.coordinates = new LatLon(geocache.lat, geocache.lon).toString(); | |
geocache.coordinatesisedit = true; | |
} | |
geocache.location = $("span#ctl00_ContentBody_Location", element).first().text(); | |
try { | |
// get the country and (if exists) the state! | |
if (geocache.location.indexOf(",") < 0) { // if the index of "," < 0 then the state is not given! | |
geocache.state = ""; | |
geocache.country = $.trim(geocache.location.split("In ")[1]); | |
} else { | |
geocache.state = $.trim(geocache.location.split("In ")[1].split(',')[0]); | |
geocache.country = $.trim(geocache.location.split("In ")[1].split(',')[1]); | |
} | |
} catch (e) { // something went wrong - write the whole location to country | |
geocache.state = ""; | |
geocache.country = $.trim(geocache.location); | |
} | |
try { | |
// ToDo check distance | |
geocache.bearing = $('span#lblDistFromHome > img', element).first().attr("alt"); | |
var distanceTemp = $('span#lblDistFromHome', element).first().text().split(" "); | |
geocache.distance = distanceTemp[0] + " " + distanceTemp[1]; | |
} catch (e) { | |
// if homecoordinates are not set | |
geocache.bearing = ""; | |
geocache.distance = ""; | |
} | |
geocache.$inventory = $('span#ctl00_ContentBody_uxTravelBugList_uxInventoryLabel', element).parent().parent().find('img'); | |
geocache.$attributes = $('div#ctl00_ContentBody_detailWidget > div.WidgetBody > img', element); | |
geocache.attributes_array = []; | |
geocache.$attributes.each(function (index, Element) { | |
// remove garbage from source address and split at "-" | |
// (special care for "Special Tool Required" since the image name is "s-tool") | |
var attribute_array = this.src.replace(GS_HOST + "images/attributes/", "").replace(".png", "").replace("-y", "_y").replace("-n", "_n").split("_"); | |
// iterate over every attribute defined in the global attributes array | |
for (var attributesDef_i = 0; attributesDef_i < ATTRIBUTES_ARRAY.length; attributesDef_i++) { | |
// ... and check whether the image is equal to the definition | |
if (attribute_array[0] == ATTRIBUTES_ARRAY[attributesDef_i][1]) { | |
// add this attribute as array with id-0, image-1, name-2 and yes/no-4 | |
geocache.attributes_array.push([ATTRIBUTES_ARRAY[attributesDef_i][0], ATTRIBUTES_ARRAY[attributesDef_i][1], ATTRIBUTES_ARRAY[attributesDef_i][2], ((attribute_array[1] == "yes") ? 1 : 0)]); | |
} | |
} | |
}); | |
geocache.$short_description = $('span#ctl00_ContentBody_ShortDescription', element).first(); | |
geocache.$long_description = $('span#ctl00_ContentBody_LongDescription', element).first(); | |
geocache.images = $('a[rel="lightbox"]', element); | |
geocache.additional_waypoints = []; | |
var additional_waypoints = $('table.Table > tbody > tr', element); | |
for (var i = 0; i < additional_waypoints.length; i = i + 2) { | |
var row1 = additional_waypoints[i]; | |
var row2 = additional_waypoints[i + 1]; | |
var row1_tds = row1.getElementsByTagName('td'); | |
var row2_tds = row2.getElementsByTagName('td'); | |
var waypoint = {}; | |
waypoint.symbol = row1_tds[1].childNodes[1].src; | |
waypoint.prefix = $.trim(row1_tds[2].textContent); | |
waypoint.lookup = $.trim(row1_tds[3].textContent); | |
waypoint.name = row1_tds[4].childNodes[1].textContent; | |
//waypoint.url = row1_tds[4].childNodes[1].href.split('&')[0]; // just in case... | |
waypoint.coordinates = $.trim(row1_tds[5].textContent); | |
coordinates = await parseCoordinates(row1_tds[5].textContent); | |
waypoint.latitude = coordinates._lat; | |
waypoint.longitude = coordinates._lon; | |
waypoint.note = $.trim(row2_tds[2].innerHTML); // HTML in waypoint description | |
// waypoint.note = $.trim(row2_tds[2].textContent); // pure text only, no line breaks etc | |
// Final Location https://www.geocaching.com/images/WptTypes/sm/flag.jpg | |
// Parking Area https://www.geocaching.com/images/WptTypes/sm/pkg.jpg | |
// Question to Answer https://www.geocaching.com/images/WptTypes/sm/puzzle.jpg | |
// Stages of a Multicache https://www.geocaching.com/images/WptTypes/sm/stage.jpg | |
// Trailhead https://www.geocaching.com/images/WptTypes/sm/trailhead.jpg | |
// Reference Point https://www.geocaching.com/images/WptTypes/sm/waypoint.jpg | |
var sym = waypoint.symbol.toLowerCase().split(GS_HOST + GS_WPT_IMAGE_PATH)[1]; | |
switch (sym) { | |
case "flag.jpg": | |
waypoint.symbol_groundspeak = "Final Location"; | |
waypoint.type_groundspeak = "Waypoint|Final Location"; | |
break; | |
case "pkg.jpg": | |
waypoint.symbol_groundspeak = "Parking Area"; | |
waypoint.type_groundspeak = "Waypoint|Parking Area"; | |
break; | |
case "puzzle.jpg": | |
waypoint.symbol_groundspeak = "Question to Answer"; | |
waypoint.type_groundspeak = "Waypoint|Question to Answer"; | |
break; | |
case "stage.jpg": | |
waypoint.symbol_groundspeak = "Stages of a Multicache"; | |
waypoint.type_groundspeak = "Waypoint|Stages of a Multicache"; | |
break; | |
case "trailhead.jpg": | |
waypoint.symbol_groundspeak = "Trailhead"; | |
waypoint.type_groundspeak = "Waypoint|Trailhead"; | |
break; | |
case "waypoint.jpg": | |
waypoint.symbol_groundspeak = "Reference Point"; | |
waypoint.type_groundspeak = "Waypoint|Reference Point"; | |
break; | |
default: | |
waypoint.symbol_groundspeak = "Unknown Type"; | |
waypoint.type_groundspeak = "Waypoint|Unknown Type"; | |
break; | |
} | |
geocache.additional_waypoints.push(waypoint); | |
} | |
var hints_element = $('div#div_hint', element).first(); | |
geocache.hint = (hints_element.length > 0) ? convertROTStringWithBrackets($.trim(hints_element.text())) : ""; | |
// numbers of finds, DNFs, notes etc. | |
geocache.find_count = $('span#ctl00_ContentBody_lblFindCounts > p.LogTotals', element).html(); | |
// total number of logged visits (e.g. "8,507 Logged Visits"; order can vary for different languages) | |
var nLoggedVisits = parseInt( $('div.InformationWidget.Clear > h3', element).text().replace(/[^0-9]/g,'') ); | |
// UserToken for favorite score and fetching logs | |
var userToken = element.innerHTML.split("userToken = '")[1].split("'")[0]; | |
// favorite points | |
geocache.fav = $('span.favorite-value', element).text().trim(); | |
// fetch logs and favorite score in parallel | |
var promises = []; | |
promises.push( getLogs(userToken, maxLogsCount, nLoggedVisits, element) ); | |
// fav score only if favorite points are necessary and available (e.g. not for events) | |
if (FAVSCORE && geocache.fav) { | |
promises.push( promiseRequest('POST', GS_HOST + 'datastore/favorites.svc/score?u=' + userToken) ); | |
} | |
try { | |
var response = await Promise.all(promises); | |
geocache.logs = response[0]; | |
// favorite points available; check for a string "between" 0 and 100, thereby exclude that content is a web page | |
if (response.length==2 && response[1].responseText.length<4) { | |
var favScore = response[1].responseText; | |
if (favScore>100) { | |
favScore = '(100%)'; | |
} else if (favScore<1) { | |
favScore = '(<1%)'; | |
} else { | |
favScore = '('+favScore+'%)'; | |
} | |
geocache.favScore = favScore; | |
} else { | |
geocache.favScore = ''; | |
} | |
//debug('getGeocacheFromElement -\n' + JSON.stringify(geocache)); | |
return geocache; | |
} | |
catch(e) { | |
throw "fn getGeocacheFromElement - " + e; | |
} | |
} | |
async function getGeocache(gcid, maxLogsCount) { | |
try { | |
var response = await promiseRequest('GET', GS_HOST + 'seek/cache_details.aspx?log=y&wp=' + gcid); | |
// after execution parse the result | |
var response_div = createElement('div'); | |
response_div.innerHTML = response.responseText; | |
updateProgressBar(); | |
return await getGeocacheFromElement(response_div, maxLogsCount); | |
} catch(e) { | |
throw "fn getGeocache - " + e; | |
} | |
} | |
/* cache scraper utilities */ | |
// return an object with these attributes: gccode, cacheid, name, guid, type | |
function getMinimalGeocacheDetails(detailsPage) { | |
/* gccode, cacheid, name, guid, type */ | |
var geocache_details = {}; | |
var $obj = {}; // temp jquery container | |
/* GCCode | |
* <span id="ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode" class="CoordInfoCode">GC2HFRB</span> | |
* <title>GC2HFRB 3, 2, 1 ... Lift-Off (Traditional Cache) in Thüringen, Germany created by Astronaut Hoffi1986</title> | |
*/ | |
$obj.gcc = [ | |
$('.CoordInfoCode', detailsPage).first().text(), | |
$('title', detailsPage).first().text() | |
]; | |
geocache_details.gccode = | |
(findGCCodeFromString($obj.gcc[0])) || | |
(findGCCodeFromString($obj.gcc[1])) || | |
null; | |
if (!geocache_details.gccode) { | |
throw "fn getMinimalGeocacheDetails - Error getting GCCode!"; | |
} else { | |
debug( | |
"getMinimalGeocacheDetails - GCCode: " + geocache_details.gccode + "\n" + | |
"\t1: " + findGCCodeFromString($obj.gcc[0]) + "\n" + | |
"\t2: " + findGCCodeFromString($obj.gcc[1])); | |
} | |
/* CacheId: | |
* HTML REGEXP Quelle | |
* ccid=1957539" ccid=(\d+) "View all Trackables" Link | |
* "CacheID":1957539 \"CacheID\":(\d+) teil der vorgeladenen Logs | |
* w=1957539" \Ww=(\d+) "Watch Listing" link | |
* log.aspx?id=1957539&LogType= log\.aspx\?id=\d+ "Archive Listing" link (owned listings) | |
*/ | |
try { | |
var cacheid_regex = /ccid=\d+|\"CacheID\":\d+|\Ww=\d+|log\.aspx\?id=\d+/; | |
var cacheid_arr = cacheid_regex.exec(detailsPage.innerHTML); | |
geocache_details.cacheid = cacheid_arr[0].split(/:|=/)[1]; | |
debug("getMinimalGeocacheDetails - CacheID: " + geocache_details.cacheid); | |
} catch (e) { | |
throw "fn getMinimalGeocacheDetails - Error getting 'cacheid' from " + geocache_details.gccode; | |
} | |
/* Cachename: | |
* <span id="ctl00_ContentBody_CacheName">3, 2, 1 ... Lift-Off</span></h2> | |
* <meta name="og:title" content="3, 2, 1 ... Lift-Off" property="og:title" /> | |
*/ | |
$obj.name = [ | |
$('span#ctl00_ContentBody_CacheName', detailsPage).first().text(), | |
$('meta[name="og:title"]', detailsPage).first().attr('content') // Fallback #1 | |
]; | |
geocache_details.name = | |
($obj.name[0] && $.trim($obj.name[0])) || | |
($obj.name[1] && $.trim($obj.name[1])) || | |
null; | |
if (!geocache_details.name) { | |
throw "fn getMinimalGeocacheDetails - Error getting 'cacheName' from " + geocache_details.gccode; | |
} else { | |
debug( | |
"getMinimalGeocacheDetails - Name: " + geocache_details.name + "\n" + | |
"\t1: " + (($obj.name[0]) ? $obj.name[0] : "null") + "\n" + | |
"\t2: " + (($obj.name[1]) ? $obj.name[1] : "null")); | |
} | |
/* guid | |
* <form method="post" action="/geocache/GC2HFRB_3-2-1-lift-off?guid=712fed16-77ab-48f4-a269-18cc27bb2a14" id="aspnetForm"> | |
* <a id="ctl00_ContentBody_lnkPrintFriendly5Logs" href="cdpf.aspx?guid=712fed16-77ab-48f4-a269-18cc27bb2a14&lc=5" target="_blank">5 Logs</a> | |
* <a id="ctl00_ContentBody_uxTravelBugList_uxTrackableItemsHistory" href="../track/search.aspx?wid=712fed16-77ab-48f4-a269-18cc27bb2a14">View past Trackables</a> | |
* <a id="ctl00_ContentBody_uxLogbookLink" href="cache_logbook.aspx?guid=712fed16-77ab-48f4-a269-18cc27bb2a14">View Logbook</a> | |
* <a href="/seek/gallery.aspx?guid=712fed16-77ab-48f4-a269-18cc27bb2a14">View Gallery</a> | |
*/ | |
$obj.guid = [ | |
$("form[id='aspnetForm'][action*='guid=']", detailsPage).first().attr("action"), | |
$("a#ctl00_ContentBody_lnkPrintFriendly[href*='guid=']", detailsPage).first().attr("href"), | |
$("a#ctl00_ContentBody_uxTravelBugList_uxTrackableItemsHistory[href*='wid=']", detailsPage).first().attr("href"), | |
$("a#ctl00_ContentBody_uxLogbookLink[href*='guid=']", detailsPage).first().attr("href"), | |
$("div.CacheDetailNavigation a[href*='guid=']", detailsPage).first().attr("href") | |
]; | |
geocache_details.guid = | |
($obj.guid[0] && $.trim($obj.guid[0].split("guid=")[1])) || | |
($obj.guid[1] && $.trim($obj.guid[1].split("guid=")[1])) || | |
($obj.guid[2] && $.trim($obj.guid[2].split("wid=")[1])) || | |
($obj.guid[3] && $.trim($obj.guid[3].split("guid=")[1])) || | |
($obj.guid[4] && $.trim($obj.guid[4].split("guid=")[1])) | |
null; | |
if (!geocache_details.guid) { | |
throw "fn getMinimalGeocacheDetails - Error getting 'guid' from " + geocache_details.gccode; | |
} else { | |
debug( | |
"getMinimalGeocacheDetails - Guid: " + geocache_details.guid + "\n" + | |
"\t1: " + (($obj.guid[0]) ? $obj.guid[0].split("guid=")[1].split("&")[0] : "null") + "\n" + | |
"\t2: " + (($obj.guid[1]) ? $obj.guid[1].split("guid=")[1].split("&")[0] : "null") + "\n" + | |
"\t3: " + (($obj.guid[2]) ? $obj.guid[2].split("wid=")[1].split("&")[0] : "null") + "\n" + | |
"\t4: " + (($obj.guid[3]) ? $obj.guid[3].split("guid=")[1].split("&")[0] : "null") + "\n" + | |
"\t5: " + (($obj.guid[4]) ? $obj.guid[4].split("guid=")[1] : "null")); | |
} | |
/* type | |
* <use xlink:href="/app/ui-icons/sprites/cache-types.svg#icon-137-disabled"></use> | |
* <a class="btn-add-to-list" data-gcrefcode="GC3Y9WC" href="/bookmarks/mark.aspx?guid=e36a3706-8336-4071-b14e-d04537a4bfa0&WptTypeID=137">Add to list</a> | |
* <a href="/bookmarks/ignore.aspx?guid=e36a3706-8336-4071-b14e-d04537a4bfa0&WptTypeID=137">Ignore</a> | |
*/ | |
$obj.type = [ | |
$('svg.cache-icon > use', detailsPage)[0].href.baseVal, // starting at 2018-08-18 | |
$('li#ctl00_ContentBody_GeoNav_uxAddToListBtn > a', detailsPage).attr("href"), | |
$('li#ctl00_ContentBody_GeoNav_uxIgnoreBtn > a', detailsPage).attr("href") | |
]; | |
geocache_details.type = | |
($obj.type[0] && $obj.type[0].split("#")[1].split("-")[1] + ".gif") || | |
($obj.type[1] && $obj.type[1].split("=")[2] + ".gif") || | |
($obj.type[2] && $obj.type[2].split("=")[2] + ".gif") | |
null; | |
if (!geocache_details.type) { | |
throw "fn getMinimalGeocacheDetails - Error getting 'type' from " + geocache_details.gccode; | |
} else { | |
debug( | |
"getMinimalGeocacheDetails - Type: " + geocache_details.type + "\n" + | |
"\t1: " + (($obj.type[0]) ? $obj.type[0].split("#")[1].split("-")[1] + ".gif" : "null") + "\n" + | |
"\t2: " + (($obj.type[1]) ? $obj.type[1].split("=")[2] + ".gif" : "null") + "\n" + | |
"\t3: " + (($obj.type[2]) ? $obj.type[2].split("=")[2] + ".gif" : "null")); | |
} | |
return geocache_details; | |
} | |
async function getLogs(userToken, maxLogsCount, nLoggedVisits, element) { | |
//~ LogID 273160821 | |
//~ CacheID 2436701 | |
//~ LogGuid "8fd33a36-bb44-40ed-9b8b-41737e2d0c6a" | |
//~ Latitude null | |
//~ Longitude null | |
//~ LatLonString "" | |
//~ LogType "Found it" | |
//~ LogTypeImage "2.png" | |
//~ LogText "Schönes Versteck, süße ...>Lisa, Yvonne und Frank" | |
//~ Created "10/25/2012" | |
//~ Visited "10/14/2012" | |
//~ UserName "sweet cats" | |
//~ MembershipLevel "1" | |
//~ AccountID 6385212 | |
//~ AccountGuid "0260fb1b-7cf1-4ef5-a3b6-6257276e3962" | |
//~ Email "" | |
//~ AvatarImage "99ff8cf2-7b7a-49a9-bb90-a38448158223.jpg" | |
//~ GeocacheFindCount 33 | |
//~ GeocacheHideCount 0 | |
//~ ChallengesCompleted 0 | |
//~ IsEncoded false | |
//~ creator Object { GroupTitle="Member", GroupImageUrl="/images/icons/reg_user.gif"} | |
//~ GroupTitle "Member" | |
//~ GroupImageUrl "/images/icons/reg_user.gif" | |
//~ Images [] | |
try { | |
maxLogsCount = $.isNumeric(maxLogsCount) ? maxLogsCount : 0; | |
nLoggedVisits = $.isNumeric(nLoggedVisits) ? nLoggedVisits : 0; | |
if (maxLogsCount == 0 || nLoggedVisits == 0) { // no logs | |
return []; | |
} | |
var nLogs = Math.min(maxLogsCount,nLoggedVisits), // number of required logs | |
logs = [], | |
fetch = true; | |
// up to 25 logs are already inside fetched listing, no need to fetch again | |
if (nLogs < 26) { | |
try { | |
var initialLogs = '{"' + element.innerHTML.split('initialLogs = {"')[1].split('};')[0] + '}'; | |
logs = JSON.parse(initialLogs).data; | |
fetch = false; | |
} catch(e) { // if something went wrong give it a 2nd try and fetch the logs | |
error(e); | |
} | |
} | |
// fetch logs | |
if (fetch) { | |
var i, | |
// max possible number of logs by a single request: 100 | |
nMax = 100, | |
nLogsByRequest = Math.min(nLogs,nMax), | |
// number of pages to be fetched | |
nPages = Math.ceil(nLogs/nLogsByRequest), | |
// idx: page index, num: number of logs by page (max:100) | |
// num=100,nLogs=200: --> idx=[1,2]: [1,100],[101,200] | |
// num=50, nLogs=200: --> idx=[1,2,3,4] [1,50],[51,100],[101,150],[151,200] | |
urlTemplate = GS_HOST + 'seek/geocache.logbook?tkn=' + userToken + '&idx=#PAGE#&num=' + nLogsByRequest + '&decrypt=false', | |
url, | |
log_obj = {}, | |
log_objects, | |
promises = []; | |
// fetch all logs in parallel | |
for (i=1; i<=nPages; i++) { | |
url = urlTemplate.replace("#PAGE#", i); | |
promises.push(promiseRequest('GET', url)); | |
} | |
log_objects = await Promise.all(promises); | |
for (i=0; i<log_objects.length; i++) { | |
// parse the result | |
log_obj = JSON.parse(log_objects[i].responseText); | |
// append new logs | |
logs = logs.concat(log_obj.data); | |
} | |
} | |
// truncate log array if necessary | |
if (logs.length > nLogs) { | |
logs = logs.slice(0, nLogs-logs.length); | |
} | |
return logs; | |
} catch(e) { | |
throw 'fn getLogs - ' + e; | |
} | |
} | |
/* gpx geocache */ | |
function getAttributeXML(attribute_a) { | |
return ' <groundspeak:attribute id="' + attribute_a[0] + '" inc="' + attribute_a[3] + '">' + attribute_a[2] + '</groundspeak:attribute>\n'; | |
} | |
function getGPXfromMarker(marker) { | |
var gpx = ''; | |
gpx += ' <wpt lat="' + marker.latitude + '" lon="' + marker.longitude + '">\n'; | |
gpx += ' <time>' + xsdDateTime(new Date()) + '</time>\n'; | |
gpx += ' <name>' + escapeHTML(marker.name) + '</name>\n'; | |
gpx += ' <cmt>' + escapeHTML(marker.content) + '</cmt>\n'; | |
gpx += ' <sym>' + marker.symbol + '</sym>\n'; | |
gpx += ' </wpt>'; | |
return gpx; | |
} | |
function getWaypointsGPXFromGeocache(waypoint, geocache) { | |
var waypointName = waypoint.prefix + geocache.gcid.replace(/GC/, ''); | |
var gpx = ''; | |
gpx += ' <wpt lat="' + waypoint.latitude + '" lon="' + waypoint.longitude + '">\n'; | |
gpx += ' <time>' + xsdDateTime(geocache.dateHidden) + '</time>\n'; | |
gpx += ' <name>' + escapeHTML(waypointName) + '</name>\n'; | |
gpx += ' <cmt>' + escapeHTML(waypoint.note) + '</cmt>\n'; | |
gpx += ' <desc>' + escapeHTML(waypoint.name) + '</desc>\n'; | |
gpx += ' <sym>' + waypoint.symbol_groundspeak + '</sym>\n'; | |
gpx += ' <type>' + waypoint.type_groundspeak + '</type>\n'; | |
gpx += ' </wpt>'; | |
return gpx; | |
} | |
async function getGPXGeoCache(gcid) { | |
/* | |
geocache | |
.gcid | |
.guid | |
.cacheid | |
.name | |
.type | |
.owner | |
.hidden | |
.coordinates | |
.lat | |
.lon | |
.location | |
.state | |
.country | |
.bearing | |
.distance | |
.$inventory | |
.size | |
.difficulty | |
.terrain | |
.$attributes | |
.$short_description | |
.$long_description | |
.hint | |
.images | |
.additional_waypoints | |
.find_count | |
.logs | |
.favscore | |
*/ | |
try { | |
var i, // for () | |
geocache = {}, | |
maxGPXLogs = parseInt(GM_getValue('maxGPXLogs', 10), 10), | |
geocache_obj = await getGeocache(gcid, maxGPXLogs); | |
if (geocache_obj === "pm only") { // basic member and pm only cache | |
return geocache_obj; | |
} | |
geocache.gcid = geocache_obj.gcid; | |
if (GM_getValue('gpxstripgc', false)) { | |
geocache.gcid = geocache.gcid.replace(/GC/, ''); | |
} | |
geocache.guid = geocache_obj.guid; | |
geocache.cacheid = geocache_obj.cacheid; | |
geocache.archived = (geocache_obj.archived) ? "True" : "False"; | |
geocache.available = (geocache_obj.available) ? "True" : "False"; | |
geocache.cacheName = geocache_obj.name; | |
geocache.cacheOwner = geocache_obj.owner; | |
geocache.cacheSym = geocache_obj.sym; | |
switch (geocache_obj.size) { | |
case "micro": | |
geocache.cacheSize = "Micro"; | |
break; | |
case "small": | |
geocache.cacheSize = "Small"; | |
break; | |
case "regular": | |
geocache.cacheSize = "Regular"; | |
break; | |
case "large": | |
geocache.cacheSize = "Large"; | |
break; | |
case "other": | |
geocache.cacheSize = "Other"; | |
break; | |
case "not_chosen": | |
geocache.cacheSize = "Not chosen"; | |
break; | |
case "virtual": | |
geocache.cacheSize = "Virtual"; | |
break; | |
default: | |
geocache.cacheSize = ""; | |
break; | |
} | |
for (i = 0; i < WPT_ARRAY.length; i++) { | |
if (WPT_ARRAY[i].wptTypeId == geocache_obj.type) { | |
geocache.cacheType = WPT_ARRAY[i].name; | |
} | |
} | |
geocache.attributes_array = geocache_obj.attributes_array; | |
geocache.difficulty = geocache_obj.difficulty; | |
geocache.terrain = geocache_obj.terrain; | |
var summary = geocache_obj.$short_description, | |
description = geocache_obj.$long_description; | |
if (GM_getValue('gpxhtml', true)) { | |
geocache.shortDescription = (summary.length === 1) ? summary.html() : ""; | |
geocache.longDescription = (description.length === 1) ? description.html() : ""; | |
} else { | |
geocache.shortDescription = (summary.length === 1) ? summary.text() : ""; | |
geocache.longDescription = (description.length === 1) ? description.text() : ""; | |
} | |
geocache.hint = geocache_obj.hint; | |
geocache.state = geocache_obj.state; | |
geocache.country = geocache_obj.country; | |
geocache.dateHidden = geocache_obj.hidden; | |
// logs | |
geocache.logs = []; | |
for (i = 0; i < geocache_obj.logs.length; i++) { | |
var logObj = {}; | |
// cacherName: "user" | |
// type: "Found It", "Didn't find it", "Temporarily Disable Listing", "Write note", "Enable Listing",... | |
// foundDate: "August 18" oder "February 17, 2007" | |
// id: 12345679 | |
// content: "Netter Log eintrag." | |
var gc_log = geocache_obj.logs[i]; | |
logObj.cacherName = gc_log.UserName; | |
logObj.type = gc_log.LogType; | |
logObj.foundDate = await parseDate(gc_log.Visited); | |
logObj.id = gc_log.LogID; | |
// handling of HTML code in logs (since GS change to Markdown logs), e.g. | |
// <p> One, two & three</p> | |
// in a log becomes | |
// <p> One, two &amp; three</p> | |
// to parse | |
var textarea = document.createElement("textarea"); | |
// gc_log.LogText = <p> One, two &amp; three</p> | |
// unescaped = <p> One, two & three</p> | |
var unescaped = $('<textarea>').html(gc_log.LogText).val(); // unescape HTML | |
// logObj.content = One, two & three | |
logObj.content = $(unescaped).text(); // no HTML in logs | |
geocache.logs.push(logObj); | |
} | |
geocache.additionalWaypoints = geocache_obj.additional_waypoints; | |
geocache.latitude = geocache_obj.lat; | |
geocache.longitude = geocache_obj.lon; | |
geocache.favScore = geocache_obj.favScore; | |
return geocache; | |
} catch(e) { | |
throw 'fn getGPXGeoCache - ' + e; | |
} | |
} | |
async function getGPX() { | |
try { | |
var i, | |
ii, | |
iii; // for () | |
var gpxHeader = | |
'<?xml version="1.0" encoding="utf-8"?>\n' + | |
'<gpx xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" creator="GCTour" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">\n' + | |
' <name>' + escapeHTML(CURRENT_TOUR.name) + '</name>\n' + | |
// do not change <desc> content, otherwise GSAK does not handle additional cache waypoints as child waypoints during GPX import | |
' <desc>This is an individual cache generated from Geocaching.com</desc>\n' + | |
' <author>GCTour ' + VERSION + '</author>\n' + | |
' <url>' + GS_HOST + '</url>\n' + | |
' <urlname>Geocaching - High Tech Treasure Hunting</urlname>\n' + | |
' <time>' + (new Date()).toISOString() + '</time>\n' + | |
' <bounds minlat="##MINLAT##" minlon="##MINLON##" maxlat="##MAXLAT##" maxlon="##MAXLON##" />\n' + | |
'##GEOCACHES##\n' + | |
'##WAYPOINTS##\n' + | |
'</gpx>'; | |
var geocacheTemplate = | |
' <wpt lat="##LAT##" lon="##LON##">\n' + | |
' <time>##TIME##</time>\n' + | |
' <name>##GCID##</name>\n' + | |
' <desc>##CACHENAME## by ##OWNER##, ##TYPE## (##DIFFICULTY##/##TERRAIN##)</desc>\n' + | |
' <url>http://coord.info/##GCID##</url>\n' + | |
' <urlname>##CACHENAME##</urlname>\n' + | |
' <sym>##CACHESYM##</sym>\n' + | |
' <type>Geocache|##TYPE##</type>\n' + | |
' <groundspeak:cache id="##CACHEID##" available="##AVAILABLE##" archived="##ARCHIVED##" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">\n' + | |
' <groundspeak:name>##CACHENAME##</groundspeak:name>\n' + | |
' <groundspeak:placed_by>##OWNER##</groundspeak:placed_by>\n' + | |
' <groundspeak:owner>##OWNER##</groundspeak:owner>\n' + | |
' <groundspeak:type>##TYPE##</groundspeak:type>\n' + | |
' <groundspeak:container>##CONTAINER##</groundspeak:container>\n' + | |
' <groundspeak:attributes>\n##ATTRIBUTES## </groundspeak:attributes>\n' + | |
' <groundspeak:difficulty>##DIFFICULTY##</groundspeak:difficulty>\n' + | |
' <groundspeak:terrain>##TERRAIN##</groundspeak:terrain>\n' + | |
' <groundspeak:country>##COUNTRY##</groundspeak:country>\n' + | |
' <groundspeak:state>##STATE##</groundspeak:state>\n' + | |
' <groundspeak:short_description html="True">##SUMMARY## </groundspeak:short_description>\n' + | |
' <groundspeak:long_description html="True">##DESCRIPTION## </groundspeak:long_description>\n' + | |
' <groundspeak:encoded_hints>##HINT##</groundspeak:encoded_hints>\n' + | |
' <groundspeak:logs>\n##LOGS##\n </groundspeak:logs>\n' + | |
' </groundspeak:cache>\n' + | |
' </wpt>'; | |
var geocacheLogTemplate = | |
' <groundspeak:log id="##LOGID##">\n' + | |
' <groundspeak:date>##TIME##</groundspeak:date>\n' + | |
' <groundspeak:type>##LOGTYPE##</groundspeak:type>\n' + | |
' <groundspeak:finder>##CACHERNAME##</groundspeak:finder>\n' + | |
' <groundspeak:text encoded="False">##LOGTEXT##</groundspeak:text>\n' + | |
' </groundspeak:log>'; | |
var gcStrArray = [], | |
wptStrArray = [], | |
minLat, | |
minLon, | |
maxLat, | |
maxLon, | |
nCaches = CURRENT_TOUR.geocaches.length; | |
// for progress bar update | |
PROGRESS_BAR.progress = 0; | |
PROGRESS_BAR.total = nCaches; | |
// fetch all caches in parallel, not one by one | |
var promises = []; | |
for (i = 0; i < nCaches; i++) { | |
var costumMarker = (typeof(CURRENT_TOUR.geocaches[i].latitude) != "undefined"); | |
if (costumMarker) { | |
wptStrArray.push(getGPXfromMarker(CURRENT_TOUR.geocaches[i])); | |
updateProgressBar(); | |
} else { | |
promises.push(getGPXGeoCache(CURRENT_TOUR.geocaches[i].id)); | |
} | |
} | |
// fav score only needed if prefix option in GPX settings is active | |
if (!GM_getValue('gpxprefixfavscore', false)) { | |
FAVSCORE = false; | |
} | |
var cache_objects = await Promise.all(promises); | |
FAVSCORE = true; | |
var pmo = ""; | |
for (i = 0; i < cache_objects.length; i++) { | |
// if the cancel button is pressed... | |
if (GM_getValue("stopTask", false)) { | |
GM_setValue("stopTask", false); | |
return "canceled"; // ...then return! | |
} | |
var geocache = cache_objects[i]; | |
if (geocache !== "pm only") { | |
var logs = geocache.logs, | |
logsStringArray = [], | |
attributeLog, | |
attributeLogtext; | |
// create log with attributes! | |
if (GM_getValue('gpxattributestolog', false)) { | |
attributeLogtext = $.map(geocache.attributes_array, function (row, i) { | |
return row[2] + ": " + ((row[3] === 1) ? "yes" : "no"); | |
}).join("\n"); | |
attributeLog = geocacheLogTemplate | |
.replace('##LOGID##', geocache.cacheid) | |
.replace('##TIME##', xsdDateTime(new Date())) | |
.replace('##CACHERNAME##', "GCTour") | |
.replace('##LOGTYPE##', "Write note") | |
.replace('##LOGTEXT##', attributeLogtext); | |
logsStringArray.push(attributeLog); | |
} | |
// for removing all emoji codes in logs | |
var emoji_ranges = [ | |
'\ud83c[\udf00-\udfff]', // U+1F300 to U+1F3FF | |
'\ud83d[\udc00-\ude4f]', // U+1F400 to U+1F64F | |
'\ud83d[\ude80-\udeff]' // U+1F680 to U+1F6FF | |
]; | |
for (ii = 0; ii < logs.length; ii++) { | |
var geocacheLogMapping = [ | |
['LOGID', logs[ii].id], | |
['TIME', xsdDateTime(logs[ii].foundDate)], | |
['CACHERNAME', escapeHTML(logs[ii].cacherName)], | |
['LOGTYPE', logs[ii].type], | |
// remove ASCII control codes and escape HTML entities | |
['LOGTEXT', escapeHTML(stripASCIIcodes(logs[ii].content))] | |
// for removing all emoji codes in logs | |
//['LOGTEXT', escapeHTML( stripASCIIcodes(logs[ii].content).replaceAll(emoji_ranges.join('|'),'') )] | |
]; | |
var cacheWaypointLog = geocacheLogTemplate; | |
for (iii = 0; iii < geocacheLogMapping.length; iii++) { | |
cacheWaypointLog = cacheWaypointLog.replaceAll("##" + geocacheLogMapping[iii][0] + "##", geocacheLogMapping[iii][1]); | |
} | |
logsStringArray.push(cacheWaypointLog); | |
} | |
var attributesString = ""; | |
for (ii = 0; (ii < geocache.attributes_array.length); ii++) { | |
attributesString += getAttributeXML(geocache.attributes_array[ii]); | |
} | |
var geocacheMapping = [ | |
['LAT', geocache.latitude], | |
['LON', geocache.longitude], | |
['TIME', xsdDateTime(geocache.dateHidden)], | |
['GCID', geocache.gcid], | |
['CACHEID', geocache.cacheid], | |
['GUID', geocache.guid], | |
['AVAILABLE', geocache.available], | |
['ARCHIVED', geocache.archived], | |
['CACHENAME', escapeHTML(geocache.cacheName)], | |
['CACHESYM', geocache.cacheSym], | |
['OWNER', escapeHTML(geocache.cacheOwner)], | |
['STATE', escapeHTML(geocache.state)], | |
['COUNTRY', escapeHTML(geocache.country)], | |
['TYPE', geocache.cacheType], | |
['CONTAINER', geocache.cacheSize], | |
['ATTRIBUTES', attributesString], | |
['DIFFICULTY', geocache.difficulty], | |
['TERRAIN', geocache.terrain], | |
['SUMMARY', escapeHTML(stripASCIIcodes(geocache.shortDescription))], | |
['DESCRIPTION', escapeHTML(stripASCIIcodes(geocache.longDescription))], | |
['HINT', escapeHTML(geocache.hint)], | |
['LOGS', logsStringArray.join("\n")] | |
]; | |
// add favorite score in front of cache name (visible only in Geocaching menu of GPSr) | |
if (GM_getValue('gpxprefixfavscore', false)) { | |
// e.g. favscore = (<1%) --> remove "(", ")" and escape "<" to "<" | |
var favScore = geocache.favScore ? geocache.favScore.replace(/[()]/g,'').replace(/</g,'<') : ''; | |
geocacheMapping.push(['FAVSCORE', favScore]); | |
geocacheTemplate = geocacheTemplate.replace('<groundspeak:name>##CACHENAME##</groundspeak:name>','<groundspeak:name>##FAVSCORE####CACHENAME##<\/groundspeak:name>'); | |
} | |
// bounds for caches | |
minLat = (!minLat) ? geocache.latitude : Math.min(geocache.latitude, minLat); | |
maxLat = (!maxLat) ? geocache.latitude : Math.max(geocache.latitude, maxLat); | |
minLon = (!minLon) ? geocache.longitude : Math.min(geocache.longitude, minLon); | |
maxLon = (!maxLon) ? geocache.longitude : Math.max(geocache.longitude, maxLon); | |
var cacheWaypoint = geocacheTemplate; | |
for (ii = 0; ii < geocacheMapping.length; ii++) { | |
cacheWaypoint = cacheWaypoint.replaceAll('##' + geocacheMapping[ii][0] + '##', geocacheMapping[ii][1]); | |
} | |
gcStrArray.push(cacheWaypoint); | |
if (GM_getValue('gpxwpts', true)) { | |
for (iii = 0; iii < geocache.additionalWaypoints.length; iii++) { | |
if (geocache.additionalWaypoints[iii].coordinates != "???") { | |
wptStrArray.push(getWaypointsGPXFromGeocache(geocache.additionalWaypoints[iii], geocache)); | |
} | |
} | |
} | |
} | |
else { // pm only: not available for basic members | |
pmo += "- " + CURRENT_TOUR.geocaches[i].name + " (" + CURRENT_TOUR.geocaches[i].id + ")<br>"; | |
} | |
} // iteration end | |
// info of skipped PM only caches for BM (if any) | |
if (pmo.length > 0) { | |
pmo = '<u>Skipped PM only cache(s):</u><br>' + pmo; | |
$('<div>' + pmo + '</div>').dialog($.gctour.dialog.info()); | |
} | |
// bounds for cache waypoints + custom waypoints | |
var lat, lon; | |
for (i = 0; i < wptStrArray.length; ++i) { | |
lat = wptStrArray[i].split('lat="')[1].split('"')[0]; | |
lon = wptStrArray[i].split('lon="')[1].split('"')[0]; | |
minLat = (!minLat) ? lat : Math.min(lat, minLat); | |
maxLat = (!maxLat) ? lat : Math.max(lat, maxLat); | |
minLon = (!minLon) ? lon : Math.min(lon, minLon); | |
maxLon = (!maxLon) ? lon : Math.max(lon, maxLon); | |
} | |
var str = gpxHeader | |
.replaceAll('##GEOCACHES##', gcStrArray.join("\n")) | |
.replaceAll('##WAYPOINTS##', wptStrArray.join("\n")) | |
.replaceAll('##MINLAT##', minLat) | |
.replaceAll('##MINLON##', minLon) | |
.replaceAll('##MAXLAT##', maxLat) | |
.replaceAll('##MAXLON##', maxLon); | |
return str; | |
} catch (e) { | |
throw 'fn getGPX - ' + e; | |
} | |
} | |
async function downloadGPXFunction() { | |
try { | |
if (isEmptyTour(CURRENT_TOUR) || !isLoggedIn()) { | |
return; | |
} | |
var tourName, | |
currentDate, | |
currentDateString, | |
gpxString, | |
filename, | |
blob; | |
// add progressbar while loading | |
GM_setValue("stopTask", false); | |
addProgressbar({ | |
closeCallback: function () { | |
return function () { | |
if (confirm($.gctour.lang('general.cancel') + "?") == true) { | |
//GM_setValue("stopTask", true); | |
window.location.reload(); | |
} | |
}; | |
} | |
}); | |
tourName = CURRENT_TOUR.name.replace(/\s+/g, "_").replace(/[^A-Za-z0-9_ÄäÖöÜüß-]*/g, ""); | |
currentDate = new Date(); | |
currentDateString = currentDate.getFullYear() + "-" + (currentDate.getMonth() + 1) + "-" + currentDate.getDate() + "_" + currentDate.getHours() + "-" + currentDate.getMinutes() + "-" + currentDate.getSeconds(); | |
filename = 'GCTour.' + tourName + '.' + currentDateString + '.gpx'; | |
gpxString = await getGPX(); | |
// if the cancel button is pressed the gpxString just contains canceled | |
if (gpxString == "canceled") { | |
closeOverlay(); | |
return; | |
} | |
// open save file dialog | |
var file = new File([gpxString], filename, { | |
type: "application/gpx;charset=utf-8" | |
}); | |
saveAs(file); | |
// all done - remove the overlay | |
closeOverlay(); | |
} catch (e) { | |
addErrorDialog({ | |
caption: "downloadGPXFunction error", | |
_exception: e | |
}); | |
} | |
} | |
/* setting utilities */ | |
function setLanguage(l) { | |
return function () { | |
GM_setValue('language', l); | |
window.location.reload(); | |
}; | |
} | |
function toggleBoolValue(valueName, defaultValue) { | |
return function () { | |
GM_setValue(valueName, !GM_getValue(valueName, defaultValue)); | |
}; | |
} | |
function setPrintFontSize(fontSize) { | |
return function () { | |
GM_setValue('printFontSize', fontSize); | |
}; | |
} | |
function setPrintMapType(mapType) { | |
return function () { | |
GM_setValue('printOutlineMapType', mapType); | |
}; | |
} | |
function setPrintMapSize(mapSize) { | |
return function () { | |
GM_setValue('defaultMapSize', mapSize); | |
}; | |
} | |
/* settings jqUI prototype: properties and methods */ | |
function Settings_jqUI() { | |
// checkbox settings | |
this.settings_printview_cb = [ | |
['settings.printview.printMinimal', 'printMinimal', false], | |
['settings.printview.decryptHints', 'decryptPrintHints', true], | |
['settings.printview.editDescription', 'printEditMode', true], | |
['settings.printview.showSpoiler', 'printSpoilerImages', true], | |
['settings.printview.additionalWaypoints', 'printAdditionalWaypoints', true], | |
['settings.printview.additionalWaypoints2', 'addCustomMarkerToCacheTable', true], | |
['settings.printview.loggedVisits', 'printLoggedVisits', false], | |
['settings.printview.pageBreak', 'printPageBreak', false], | |
['settings.printview.pageBreakAfterMap', 'printPageBreakAfterMap', true], | |
['settings.printview.frontPage', 'printFrontpage', true], | |
['settings.printview.outlineMap', 'printOutlineMap', true], | |
['settings.printview.outlineMapSingle', 'printOutlineMapSingle', false], | |
['settings.printview.showCacheDetails', 'showCacheDetails', true] | |
]; | |
this.settings_map_cb = [ | |
['settings.map.geocacheid', 'settings_map_geocacheid', true], | |
['settings.map.geocachename', 'settings_map_geocachename', true], | |
['settings.map.geocacheindex', 'settings_map_geocacheindex', true], | |
['settings.map.awpts', 'settings_map_awpts', true], | |
['settings.map.awpt_name', 'settings_map_awpt_name', true], | |
['settings.map.awpt_lookup', 'settings_map_awpt_lookup', true], | |
['settings.map.owpts', 'settings_map_owpts', true], | |
['settings.map.owpt_name', 'settings_map_owpt_name', true] | |
]; | |
this.settings_gpx_cb = [ | |
['settings.gpx.html', 'gpxhtml', true], | |
['settings.gpx.wpts', 'gpxwpts', true], | |
['settings.gpx.attributesToLog', 'gpxattributestolog', false], | |
['settings.gpx.stripGC', 'gpxstripgc', false], | |
['settings.gpx.prefixFavScore', 'gpxprefixfavscore', false] | |
]; | |
// menu structure | |
this.tabs = | |
'<div id="tabs">' + | |
' <ul>' + | |
' <li><a href="#tabs-1">' + $.gctour.lang('settings.language.header') + '</a></li>' + | |
' <li><a href="#tabs-2">' + $.gctour.lang('settings.printview.header') + '</a></li>' + | |
' <li><a href="#tabs-3">' + $.gctour.lang('settings.map.header') + '</a></li>' + | |
' <li><a href="#tabs-4">' + $.gctour.lang('settings.gpx.header') + '</a></li>' + | |
' <li><a href="#tabs-5">' + $.gctour.lang('settings.gps.header') + '</a></li>' + | |
' <li><a href="#tabs-6">' + $.gctour.lang('settings.theme.header') + '</a></li>' + | |
' <li><a href="#tabs-7">' + $.gctour.lang('settings.exportimport.header') + '</a></li>' + | |
' </ul>' + | |
' <div id="tabs-1">' + this.getLanguage() + '</div>' + | |
' <div id="tabs-2">' + this.getPrintview() + '</div>' + | |
' <div id="tabs-3">' + this.getMap() + '</div>' + | |
' <div id="tabs-4">' + this.getGpx() + '</div>' + | |
' <div id="tabs-5">' + this.getSendToGPS() + '</div>' + | |
' <div id="tabs-6">' + this.getThemes() + '</div>' + | |
' <div id="tabs-7">' + this.getExportImport() + '</div>' + | |
'</div>'; | |
} | |
Settings_jqUI.prototype.getLanguage = function () { | |
var language = | |
'<div id="lang">' + | |
' <label for="selLang" class="gctour-label ui-widget-header ui-corner-all" style="padding: .1em .5em;">' + $.gctour.lang('settings.language.select') + '</label>' + | |
' <select name="selLang" id="selLang" class="ui-widget ui-corner-all">'; | |
$.each($.gctour.i18n, function (l, o) { | |
language += ' <option value="' + l + '">' + o.name + '</option>'; | |
}); | |
language += | |
' </select>' + | |
'</div>'; | |
return language; | |
}; | |
Settings_jqUI.prototype.getPrintview = function () { | |
var printview = | |
this.cbLayout(this.settings_printview_cb[0][0]) + | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <b>' + $.gctour.lang('settings.printview.logCount') + '</b><br>' + | |
' <div id="settingsLogCount">' + | |
' <input type="radio" name="radio-1" id="radio-1" value="0">' + | |
' <label for="radio-1" class="ui-button ui-widget-header ui-corner-all" style="margin: 2px; padding: .1em .5em;">' + $.gctour.lang('settings.printview.logCounts')[0] + '</label><br>' + | |
' <input type="radio" name="radio-1" id="radio-2" value="3">' + | |
' <input type="text" style="width: 2em;" class="gctour-input-text" maxlength="3">' + | |
' <label for="radio-2" class="ui-button ui-widget-header ui-corner-all" style="margin: 2px; padding: .1em .5em;">' + $.gctour.lang('settings.printview.logCounts')[2] + '</label><br>' + | |
' </div>' + | |
'</div>' + | |
'<div id="selectmenu" style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <b>' + $.gctour.lang('settings.printview.fontSize') + '</b><br>' + | |
' <select name="settingsFontSize" id="settingsFontSize" class="ui-widget ui-corner-all">'; | |
$.each($.gctour.lang('settings.printview.fontSizes'), function (i, val) { | |
printview += ' <option value="' + val + '">' + val + '</option>'; | |
}); | |
printview += | |
' </select>' + | |
'</div>'; | |
var i; | |
for (i = 1; i < this.settings_printview_cb.length; i++) { // checkboxes | |
printview += this.cbLayout(this.settings_printview_cb[i][0]); | |
} | |
return printview; | |
}; | |
Settings_jqUI.prototype.getMap = function () { | |
var map = | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <b>' + $.gctour.lang('settings.map.type') + '</b><br>' + | |
' <select name="settingsMapType" id="settingsMapType" class="ui-widget ui-corner-all">'; | |
$.each($.gctour.lang('settings.map.types'), function (key,val) { | |
map += ' <option value="' + val + '">' + key + '</option>'; | |
}); | |
map += | |
' </select>' + | |
'</div>' + | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <b>' + $.gctour.lang('settings.map.size') + '</b><br>' + | |
' <select name="settingsMapSize" id="settingsMapSize" class="ui-widget ui-corner-all">'; | |
$.each($.gctour.lang('settings.map.sizes'), function (i,val) { | |
map += ' <option value="' + val + '">' + val + '</option>'; | |
}); | |
map += | |
' </select>' + | |
'</div>'; | |
var i; | |
for (i = 0; i < this.settings_map_cb.length; i++) { // checkboxes | |
map += this.cbLayout(this.settings_map_cb[i][0]); | |
} | |
return map; | |
}; | |
Settings_jqUI.prototype.getGpx = function () { | |
var gpx = ''; | |
var i; | |
for (i = 0; i < this.settings_gpx_cb.length - 2; i++) { // checkboxes | |
gpx += this.cbLayout(this.settings_gpx_cb[i][0]); | |
} | |
gpx += | |
'<div id="maxLogCount" style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <b>' + $.gctour.lang('settings.gpx.maxLogCount') + '</b><br>' + | |
' <input type="text" style="width: 2em;" class="gctour-input-text" maxlength="3">' + | |
'</div>'; | |
gpx += this.cbLayout(this.settings_gpx_cb[this.settings_gpx_cb.length - 2][0]); | |
gpx += this.cbLayout(this.settings_gpx_cb[this.settings_gpx_cb.length - 1][0]); | |
return gpx; | |
}; | |
Settings_jqUI.prototype.getSendToGPS = function () { | |
var send2gps = ''; | |
send2gps += | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <label for="sendToGPS" class="gctour-label ui-widget-header ui-corner-all" style="padding: .1em .5em;">' + $.gctour.lang('settings.gps.selectSend2GPS') + '</label>' + | |
' <select name="sendToGPS" id="sendToGPS" class="ui-widget ui-corner-all">' + | |
' <option value="old">Old (Browser Plugin)</option>' + | |
' <option value="new">New (Garmin Express)</option>' + | |
' </select>' + | |
'</div>'; | |
return send2gps; | |
}; | |
Settings_jqUI.prototype.getThemes = function () { | |
var themes = | |
'<div id="ThemeSwitcher">' + | |
' <label for="selTheme" class="gctour-label ui-widget-header ui-corner-all" style="padding: .1em .5em;">' + $.gctour.lang('settings.theme.select') + '</label>' + | |
' <select id="selTheme" name="selTheme" class="ui-widget ui-corner-all">'; | |
var themeArray = ["black-tie", "blitzer", "cupertino", "dark-hive", "dot-luv", "eggplant", | |
"excite-bike", "flick", "hot-sneaks", "humanity", "le-frog", "mint-choc", "overcast", | |
"pepper-grinder", "redmond", "smoothness", "south-street", "start", "sunny", "swanky-purse", | |
"trontastic", "ui-darkness", "ui-lightness", "vader"]; | |
$.each(themeArray, function (i, theme) { | |
themes += ' <option value="' + theme + '">' + theme + '</option>'; | |
}); | |
themes += | |
' </select>' + | |
'</div>'; | |
return themes; | |
}; | |
Settings_jqUI.prototype.getExportImport = function () { | |
var exp_imp = | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
'<b>' + $.gctour.lang('settings.exportimport.export') + '</b><br>' + | |
'<button id="ExportButton">Export</button>' + | |
'</div>' + | |
'<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
'<b>' + $.gctour.lang('settings.exportimport.import') + '</b><br>' + | |
'<input id="ImportButton" type="file" accept=".json" style="display:none;">' + | |
'<button onclick="document.getElementById(\'ImportButton\').click();">Import</button>' + | |
'</div>'; | |
return exp_imp; | |
}; | |
Settings_jqUI.prototype.show = function () { | |
// jQuery UI new settings menu | |
var thiz = this; | |
$(this.tabs).dialog($.gctour.dialog.info(), { | |
title : $.gctour.lang('settings.caption'), | |
width : '75%', | |
maxHeight : $(window).height() - 20, | |
resizable : false, | |
dialogClass : 'gct_dialog', | |
buttons : [{ | |
text : $.gctour.lang('general.close'), | |
icons : { | |
primary : "ui-icon-closethick" | |
}, | |
click : function () { | |
$(this).dialog("close"); | |
} | |
} | |
], | |
beforeClose: function(event, ui) { | |
// remove dialog leftovers | |
$("div.gct_dialog").remove(); | |
} | |
}); | |
// different font size on new search page necessary; as of 2018 not necessary anymore ... | |
/*if (document.URL.search("\/play\/search") >= 0) { | |
var $elem = $("div.gct_dialog"); | |
$elem.attr('style', $elem.attr('style') + ';' + 'font-size: 0.8em !important'); | |
}*/ | |
// tabs menu | |
$("div#tabs").tabs({ | |
heightStyle : "content" | |
}); | |
// pre-selections | |
this.getCurrentSettings(); | |
// import/export settings | |
$("button").button(); | |
$('#ImportButton').on("change", importGCTourSettings); | |
$('#ExportButton').on("click", exportGCTourSettings); | |
}; | |
// pre-selection of current settings | |
Settings_jqUI.prototype.getCurrentSettings = function () { | |
var thiz = this; | |
// language | |
$("select#selLang").change(function (e) { | |
GM_setValue('language', $(this).val()); | |
window.location.reload(); | |
}).children("[value=" + GM_getValue('language', $.gctour.defaultLang) + "]").prop("selected", true); | |
// printview | |
var $radio = $('div#settingsLogCount input[type="radio"]'), | |
$text = $('div#settingsLogCount input[type="text"]'), | |
nLogs = GM_getValue('maxPrintLogs', 3); | |
if (nLogs === 0) { // no logs | |
$radio.eq(0).prop("checked", true); | |
} else { // fixed number of logs | |
$radio.eq(1).prop("checked", true); | |
$text.prop("value", nLogs); | |
} | |
$radio.eq(0).click(function (e) { | |
GM_setValue('maxPrintLogs', 0); | |
}); | |
$radio.eq(1).click(function (e) { | |
GM_setValue('maxPrintLogs', $text.prop("value")); | |
}); | |
$text.click(function (e) { | |
$radio.eq(1).prop("checked", true); | |
}); | |
$text.keyup(function (e) { | |
thiz.checkInput($(this), 'maxPrintLogs'); | |
}); | |
$("select#settingsFontSize").change(function (e) { | |
GM_setValue('printFontSize', $(this).val()); | |
}).children("[value=" + GM_getValue('printFontSize', 'x-small') + "]").prop("selected", true); | |
// maps | |
$("select#settingsMapType").change(function (e) { | |
GM_setValue('printOutlineMapType', $(this).val()); | |
}).children("[value=" + GM_getValue('printOutlineMapType', 'roadmap') + "]").prop("selected", true); | |
$("select#settingsMapSize").change(function (e) { | |
GM_setValue('defaultMapSize', $(this).val()); | |
}).children("[value=" + GM_getValue('defaultMapSize', 'large') + "]").prop("selected", true); | |
// GPSr | |
$("select#sendToGPS").change(function (e) { | |
GM_setValue('sendToGPS', $(this).val()); | |
}).children("[value=" + GM_getValue('sendToGPS', 'old') + "]").prop("selected", true); | |
// gpx | |
var $text1 = $('div#maxLogCount input[type="text"]'); | |
$text1.prop("value", GM_getValue('maxGPXLogs', 10)); | |
$text1.keyup(function (e) { | |
thiz.checkInput($(this), 'maxGPXLogs'); | |
}); | |
// themes | |
$("select#selTheme").change(function (e) { | |
addJqUiTheme($(this).val()); | |
GM_setValue('theme', $(this).val()); | |
}).children("[value=" + GM_getValue('theme', 'smoothness') + "]").prop("selected", true); | |
// checkboxes | |
var settings_array = this.settings_printview_cb.concat(this.settings_map_cb).concat(this.settings_gpx_cb); | |
var thiz = this; | |
$("input.gct-ui-checkbox").each(function (i) { | |
var item = settings_array[i]; | |
thiz.createCheckBox($(this), item[0], item[1], item[2]); | |
// pre-selection | |
if (GM_getValue(item[1], item[2])) { // is checked | |
$(this).prop('checked', true) | |
.button("option", { | |
icons : { | |
primary : "ui-icon-check" | |
} | |
}).button("refresh"); | |
} | |
}); | |
$("input.gct-ui-checkbox+label").css({ | |
'float' : 'right', | |
'border-radius' : '3px', | |
'width' : '1em', | |
'height' : '1em', | |
'vertical-align' : 'middle' | |
}); | |
}; | |
// create checkboxes in jQuery UI style | |
Settings_jqUI.prototype.createCheckBox = function (elem, id, gmValue, dValue) { | |
elem.attr({ | |
"id" : id | |
}) | |
.prop({ | |
"type" : "checkbox", | |
"checked" : false | |
}) | |
.after($("<label>").attr({ | |
for : id | |
})) | |
.button({ | |
text : false | |
}) | |
.click(function () { | |
var isChecked = GM_getValue(gmValue, dValue); | |
GM_setValue(gmValue, !isChecked); // toggle value | |
$(this).button("option", { | |
icons : { | |
primary : !isChecked ? "ui-icon-check" : "" | |
} | |
}) | |
}); | |
}; | |
// layout template for checkboxes | |
Settings_jqUI.prototype.cbLayout = function (setting) { | |
return '<div style="border-bottom:1px solid;padding-bottom:10px;padding-top:10px">' + | |
' <input class="gct-ui-checkbox">' + | |
' <b>' + $.gctour.lang(setting) + '</b><br>' + | |
$.gctour.lang(setting + "Desc") + | |
'</div>' | |
}; | |
// check for int values in input fields | |
Settings_jqUI.prototype.checkInput = function (elem, ident) { | |
var value = elem.prop("value"), | |
intOnly = new RegExp(/^\d+$/); | |
if (intOnly.test(value)) { | |
elem.css("backgroundColor", ''); | |
GM_setValue(ident, value); | |
} else { | |
elem.css("backgroundColor", '#ff7f7f'); | |
} | |
}; | |
// adding a jQuery UI theme to the end of document's head section | |
function addJqUiTheme(theme) { | |
var thmURL = "https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/" + theme + "/jquery-ui.css", | |
thmLink = $("<link>", { | |
id : "gct-ui-theme-link", | |
href : thmURL, | |
rel : "stylesheet", | |
type : "text/css" | |
}); | |
$("head link#gct-ui-theme-link").remove(); // remove other theme(s) first | |
$("head").append(thmLink); | |
} | |
// export GCTour settings (including all tours) | |
function exportGCTourSettings() { | |
let settings = {}; | |
for (let val of GM_listValues()) { | |
settings[val] = GM_getValue(val); | |
} | |
let file = new File([JSON.stringify(settings)], 'GCTour_Settings.json', { | |
type: "text/plain;charset=utf-8" | |
}); | |
saveAs(file); | |
} | |
// import GCTour settings (including all tours) | |
function importGCTourSettings(evt) { | |
// check for the various File API support | |
if (window.File && window.FileReader && window.FileList && window.Blob) { | |
// Great success! All the File APIs are supported. | |
} else { | |
alert('Sorry, the File APIs are not fully supported in your browser. Please update your browser.'); | |
return; | |
} | |
let f = evt.target.files[0], | |
reader = new FileReader(); | |
// closure to capture the file information | |
reader.onload = (function (theFile) { | |
return function (e) { | |
// here comes the file content! | |
let content = e.target.result; | |
try { | |
let parsed = JSON.parse(content); | |
$.each(parsed, function(key, value) { | |
if (parsed[key]) { | |
GM_setValue(key, value); | |
} | |
}); | |
if (console && console.table) { console.table(parsed); } | |
window.location.reload(); | |
} catch (e) { | |
alert('File content not valid:\n' + e); | |
} | |
}; | |
})(f); | |
reader.readAsText(f, "UTF-8"); | |
} | |
/* autoTour */ | |
// autoTour gui | |
async function updateAutoTourMap(lat, lon) { | |
// make the container visible | |
$('#autoTourContainer').show(); | |
// this is necessary if Leaflet map was hidden first and got visible later | |
LM._lm.invalidateSize(); | |
var radiusOrg = $.trim($("input#markerRadius").val()); | |
if (isNaN(radiusOrg) || radiusOrg == "") { // please break if radius is no number | |
return; | |
} | |
var kmMiles = $("select#markerRadiusUnit").prop("selectedIndex"); | |
// 0: km, 1: miles | |
var radiusMiles = parseFloat(radiusOrg) * ((kmMiles == 1) ? 1 : 0.621371); | |
if (radiusMiles == "") { | |
return; | |
} | |
// add circle | |
let radiusMeter = parseFloat(radiusOrg) / ((kmMiles == 0) ? 1 : 0.621371)*1000; | |
let circle = {}; | |
circle.center = [lat,lon]; | |
circle.radius = radiusMeter; | |
LM.removeLayer(); | |
LM.addCircle(circle); | |
var url = GS_HOST + "seek/nearest.aspx?lat=" + lat + "&lng=" + lon + "&dist=" + radiusMiles; | |
log("url: " + url); | |
$('b#markerCoordsPreview').empty().append( | |
$("<a>", { | |
href : url, | |
title : url, | |
text : new LatLon(lat, lon).toString() | |
}) | |
.click(function () { | |
window.open(this.href); | |
return false; | |
})); | |
$('b#markerRadiusPreview').html(radiusOrg + " " + ((kmMiles == 1) ? "mi" : "km")); | |
$("b#markerCoordsPreview, b#markerRadiusPreview") | |
.css("background-color", "#FFE000") | |
.animate({ | |
"background-color" : "transparent" | |
}, 2000); | |
// get how many caches are in this area | |
$('b#markerCountPreview, b#markerDurationMin, b#markerDurationSec').html("<img src='" + $.gctour.img.loader3 + "'>"); | |
var loadingTime1 = new Date(); | |
var response = await promiseRequest('GET', url); | |
var dummyDiv = $(response.responseText), | |
color, | |
pagesSpan = $("td.PageBuilderWidget", dummyDiv).first(); | |
if (pagesSpan.length > 0) { | |
var cacheCount = $("b", pagesSpan).first().text(), | |
pageCount = $("b", pagesSpan).last().text(); | |
var miliseconds = new Date() - loadingTime1; | |
var seconds = Math.floor((miliseconds * parseFloat(pageCount)) / 1000); | |
seconds = seconds + parseFloat(pageCount) * 2; | |
var secondsMod = seconds % 60; | |
var minutes = (seconds - secondsMod) / 60; | |
$("b#markerCountPreview").html(cacheCount); | |
$("b#markerDurationMin").html(minutes); | |
$("b#markerDurationSec").html(secondsMod); | |
color = (cacheCount<500) ? "#FFE000" : "#FF0000"; | |
} else { | |
$("b#markerCountPreview, b#markerDurationMin, b#markerDurationSec").html("0"); | |
color = "#FF0000"; | |
} | |
$("b#markerCountPreview") | |
.css("background-color", color) | |
.animate({ | |
"background-color" : "transparent" | |
}, 2000); | |
// last, save the values | |
$('input#coordsDivLat').val(lat); | |
$('input#coordsDivLon').val(lon); | |
$('input#coordsDivRadius').val(radiusMiles); | |
// enable the startQuery button | |
$('button#startQuery').removeAttr('disabled').css({ | |
"opacity" : 1, | |
"cursor" : "pointer" | |
}); | |
} | |
async function updateAutoTourMapNewSearch(lat, lon) { | |
// make the container visible | |
$('#autoTourContainer').show(); | |
// this is necessary if Leaflet map was hidden first and got visible later | |
LM._lm.invalidateSize(); | |
var radiusOrg = $.trim($("input#markerRadius").val()); | |
if (isNaN(radiusOrg) || radiusOrg == "") { // break if radius is no number | |
return; | |
} | |
var kmMiles = $("select#markerRadiusUnit").prop("selectedIndex"); | |
// 0: km, 1: miles | |
var radiusMiles = parseFloat(radiusOrg) * ((kmMiles == 1) ? 1 : 0.621371); | |
if (radiusMiles == "") { | |
return; | |
} | |
// add circle | |
let radiusMeter = parseFloat(radiusOrg) / ((kmMiles == 0) ? 1 : 0.621371)*1000; | |
let circle = {}; | |
circle.center = [lat,lon]; | |
circle.radius = radiusMeter; | |
LM.removeLayer(); | |
LM.addCircle(circle); | |
var url = GS_HOST + 'play/search/@'+lat+','+lon+'?origin='+lat+','+lon+'&radius='+radiusMiles+'mi'; | |
$('b#markerCoordsPreview').empty().append( | |
$("<a>", { | |
href : url, | |
title : url, | |
text : new LatLon(lat, lon).toString() | |
}) | |
.click(function () { | |
window.open(this.href); | |
return false; | |
})); | |
$('b#markerRadiusPreview').html(radiusOrg + " " + ((kmMiles == 1) ? "mi" : "km")); | |
$("b#markerCoordsPreview, b#markerRadiusPreview") | |
.css("background-color", "#FFE000") | |
.animate({ | |
"background-color" : "transparent" | |
}, 2000); | |
// get how many caches are in this area | |
$('b#markerCountPreview, b#markerDurationMin, b#markerDurationSec').html("<img src='" + $.gctour.img.loader3 + "'>"); | |
var loadingTime1 = new Date(); | |
var response = await promiseRequest('GET', url); | |
var color; | |
var cacheCount = $('.controls-header',response.responseText).text().split(' ')[0].replace(/\D/g,''); | |
if (cacheCount > 0) { | |
var miliseconds = new Date() - loadingTime1; | |
var seconds = Math.floor((miliseconds * 3) / 1000); | |
var secondsMod = seconds % 60; | |
var minutes = (seconds - secondsMod) / 60; | |
$("b#markerCountPreview").html(cacheCount); | |
$("b#markerDurationMin").html(minutes); | |
$("b#markerDurationSec").html(secondsMod); | |
color = (cacheCount<500) ? "#FFE000" : "#FF0000"; | |
} else { | |
$("b#markerCountPreview, b#markerDurationMin, b#markerDurationSec").html("0"); | |
color = "#FF0000"; | |
} | |
$("b#markerCountPreview") | |
.css("background-color", color) | |
.animate({ | |
"background-color" : "transparent" | |
}, 5000); | |
// last, save the values | |
$('input#coordsDivLat').val(lat); | |
$('input#coordsDivLon').val(lon); | |
$('input#coordsDivRadius').val(radiusMiles); | |
// enable the startQuery button | |
$('button#startQuery').removeAttr('disabled').css({ | |
"opacity" : 1, | |
"cursor" : "pointer" | |
}); | |
} | |
function startAutoTour() { | |
var i, | |
typeFilter = {}, | |
sizeFilter = {}, | |
difficultyFilter = {}, | |
terrainFilter = {}, | |
specialFilter = {}, | |
ele = $("#autoTourContainer"), | |
lat, | |
lon, | |
radius, | |
url; | |
ele.find("input[name='type']").each(function (index) { | |
typeFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='size']").each(function (index) { | |
sizeFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='Difficulty']").each(function (index) { | |
difficultyFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='Terrain']").each(function (index) { | |
terrainFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='special']").each(function (index) { | |
specialFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("select[id^='special_']").each(function (index) { | |
var p = $(this).attr('id').replace("special_", ""); | |
specialFilter[p] = $(this).val(); | |
}); | |
specialFilter['minFavorites'] = ele.find("input[id='special_favorites']").val(); | |
lat = ele.find("input#coordsDivLat").val(); | |
lon = ele.find("input#coordsDivLon").val(); | |
radius = ele.find("input#coordsDivRadius").val(); | |
url = GS_HOST + "seek/nearest.aspx?lat=" + lat + "&lon=" + lon + "&dist=" + radius; | |
if (specialFilter["I haven't found "]) { | |
url += "&f=1"; | |
} | |
specialFilter["minFavorites"] = specialFilter["minFavorites"] || 0; | |
GM_setValue('tq_url', url); | |
GM_setValue('tq_typeFilter', JSON.stringify(typeFilter)); | |
GM_setValue('tq_sizeFilter', JSON.stringify(sizeFilter)); | |
GM_setValue('tq_dFilter', JSON.stringify(difficultyFilter)); | |
GM_setValue('tq_tFilter', JSON.stringify(terrainFilter)); | |
GM_setValue('tq_specialFilter', JSON.stringify(specialFilter)); | |
GM_setValue('tq_StartUrl', document.location.href); | |
debug("fn startAutoTour GM_setValue: " + | |
"\n\tq_url:" + url + | |
"\n\tq_typeFilter:" + JSON.stringify(typeFilter) + | |
"\n\tq_sizeFilter:" + JSON.stringify(sizeFilter) + | |
"\n\tq_dFilter:" + JSON.stringify(difficultyFilter) + | |
"\n\tq_tFilter:" + JSON.stringify(terrainFilter) + | |
"\n\tq_specialFilter:" + JSON.stringify(specialFilter) + | |
"\n\tq_StartUrl:" + document.location.href); | |
document.location.href = url; | |
} | |
async function startAutoTourNewSearch() { | |
var i, | |
typeFilter = {}, | |
sizeFilter = {}, | |
difficultyFilter = {}, | |
terrainFilter = {}, | |
specialFilter = {}, | |
ele = $("#autoTourContainer"), | |
lat, | |
lon, | |
radius, | |
url, | |
index; | |
// get current filter settings | |
ele.find("input[name='type']").each(function (index) { | |
typeFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='size']").each(function (index) { | |
sizeFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='Difficulty']").each(function (index) { | |
difficultyFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='Terrain']").each(function (index) { | |
terrainFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("input[name='special']").each(function (index) { | |
specialFilter[$(this).val()] = $(this).is(':checked'); | |
}); | |
ele.find("select[id^='special_']").each(function (index) { | |
var p = $(this).attr('id').replace("special_", ""); | |
specialFilter[p] = $(this).val(); | |
}); | |
specialFilter['minFavorites'] = ele.find("input[id='special_favorites']").val(); | |
// store current filter settings for re-use | |
GM_setValue('tq_typeFilter', JSON.stringify(typeFilter)); | |
GM_setValue('tq_sizeFilter', JSON.stringify(sizeFilter)); | |
GM_setValue('tq_dFilter', JSON.stringify(difficultyFilter)); | |
GM_setValue('tq_tFilter', JSON.stringify(terrainFilter)); | |
GM_setValue('tq_specialFilter', JSON.stringify(specialFilter)); | |
// map objects to arrays | |
typeFilter = $.map(typeFilter, function(value, key) { | |
return (value ? key : null); | |
}); | |
sizeFilter = $.map(sizeFilter, function(value, key) { | |
index = SIZES_ARRAY.findIndex(obj => obj.sizeTypeId==key); | |
return (value && key !== 'not_chosen' ? SIZES_ARRAY[index].newSearchId : null); // ignore size 'not_chosen' (contained in 'other') | |
}); | |
difficultyFilter = $.map(difficultyFilter, function(value, key) { | |
return (value ? key : null); | |
}); | |
terrainFilter = $.map(terrainFilter, function(value, key) { | |
return (value ? key : null); | |
}); | |
lat = ele.find("input#coordsDivLat").val(); | |
lon = ele.find("input#coordsDivLon").val(); | |
radius = ele.find("input#coordsDivRadius").val(); // miles | |
radius = Math.round(radius*1.609344*1000)/1000; // km | |
var isPMO = isPremiumUser(); | |
var url_args = ''; | |
url_args += '?origin=' + lat + ',' + lon + '&radius=' + radius + 'km'; | |
url_args += typeFilter.length==12 ? '' : '&types=' + typeFilter.join(','); | |
if (isPMO) { // except type filtering all filter options are for PM only :( | |
url_args += sizeFilter.length==6 ? '' : '&sizes=' + sizeFilter.join(','); | |
// for difficulty and terrain only a single value or a range (2-3.5) are possible | |
url_args += difficultyFilter.length==9 ? '' : '&d=' + Math.min(...difficultyFilter) + '-' + Math.max(...difficultyFilter); | |
url_args += terrainFilter.length==9 ? '' : '&t=' + Math.min(...terrainFilter) + '-' + Math.max(...terrainFilter); | |
if (specialFilter["I haven't found "] === true) { | |
url_args += '&f=2'; | |
} | |
if (specialFilter["is Active"] === true) { | |
url_args += '&e=1'; | |
} | |
if (specialFilter["pm"] === 'only') { | |
url_args += '&p=1'; | |
} | |
else if (specialFilter["pm"] === 'not') { | |
url_args += '&p=2'; | |
} | |
if ($.isNumeric(specialFilter["minFavorites"]) && Number(specialFilter["minFavorites"]) > 0) { | |
url_args += '&fav=' + Number(specialFilter["minFavorites"]); | |
} | |
} | |
addProgressbar({ | |
caption : $.gctour.lang('autoTour.wait'), | |
closeCallback : function () { | |
return function () { | |
closeOverlayRemote(document)(); | |
}; | |
} | |
}); | |
// number of hits | |
var url_nHits = GS_HOST + 'play/search/@' + lat + ',' + lon + url_args; | |
var response = await promiseRequest('GET', url_nHits); | |
var nHits = $('.controls-header',response.responseText).text().split(' ')[0]; | |
nHits = nHits.replace(/\D/g,''); // if nHits >=1000, e.g. 1,234 or 1.234 hits | |
// fetch hits (500 max.) | |
url = GS_HOST + 'play/search/more-results' + url_args + '&selectAll=false&startIndex='; | |
var nCalls = Math.ceil(nHits/50); | |
nCalls = Math.min(nCalls,10); // max. 500 caches = max. 10 calls | |
var promises = []; | |
var startIndex; | |
var url_fetchHits; | |
for (i=0; i<nCalls; i++) { | |
startIndex = i*50; | |
url_fetchHits = url + startIndex; | |
promises.push(promiseRequest('GET', url_fetchHits)); | |
} | |
response = await Promise.all(promises); | |
difficultyFilter = difficultyFilter.map(Number); | |
terrainFilter = terrainFilter.map(Number); | |
var caches = []; | |
for (var i=0; i<response.length; i++) { | |
var parsedResponse = JSON.parse(response[i].responseText); | |
var $HtmlString = $(parsedResponse.HtmlString); | |
// find all <tr> in HtmlString (just in case): | |
//$('<div/>').append(parsedResponse.HtmlString).find('tr'); | |
var $name = $HtmlString.find('.cache-name'); | |
var $type_gccode = $HtmlString.find('.cache-details'); | |
var $type_image = $HtmlString.find('.cache-type-img'); | |
var $diff = $HtmlString.find('[data-column="Difficulty"]'); | |
var $terr = $HtmlString.find('[data-column="Terrain"]'); | |
var nCaches = $name.length; | |
for (var j=0; j<nCaches; j++) { | |
// if D/T of cache is not covered by filter then ignore this cache (filter not available for BM) | |
// (necessary since the new search accepts either single values or ranges) | |
if (isPMO && | |
(difficultyFilter.indexOf(Number($($diff[j]).text().trim())) === -1 || | |
terrainFilter.indexOf(Number($($terr[j]).text().trim())) === -1)) { | |
continue; | |
} | |
var cache = {}; | |
cache.name = $($name[j]).text(); | |
cache.id = $($type_gccode[j]).text().split('|')[1].trim(); | |
cache.image = $($type_image[j]).html().split('icon-')[1].split('-')[0].split('"')[0]; | |
cache.image = GS_HOST + GS_WPT_IMAGE_PATH + cache.image + '.gif'; | |
caches.push(cache); | |
} | |
} | |
CURRENT_TOUR = {}; | |
CURRENT_TOUR.id = getNewTourId(); | |
CURRENT_TOUR.name = "autoTour " + CURRENT_TOUR.id; | |
CURRENT_TOUR.geocaches = caches; | |
TOURS.push(CURRENT_TOUR); | |
log("autoTour done - create new Tour: " + CURRENT_TOUR.id + " ; " + CURRENT_TOUR.name); | |
saveCurrentTour(); | |
updateTour(); | |
closeOverlay(); | |
debug("fn startAutoTourNewSearch: " + | |
"\n\turl hits: " + url_nHits + | |
"\n\turl lazy load: " + url + 0 + | |
"\n\ttypeFilter: " + typeFilter.join(',') + | |
"\n\tsizeFilter: " + sizeFilter.join(',') + | |
"\n\tdFilter: " + difficultyFilter.join(',') + | |
"\n\ttFilter: " + terrainFilter.join(',') + | |
"\n\tspecialFilter: " + JSON.stringify(specialFilter) + | |
"\n\tnHits: " + nHits | |
); | |
} | |
async function getMarkerCoord() { | |
var markerCoords = $("input#markerCoords").val(); | |
var coords = await parseCoordinates(markerCoords, true); | |
if (coords) { | |
if (AUTOTOUR_NEW) { | |
await updateAutoTourMapNewSearch(coords._lat, coords._lon); | |
} else { | |
await updateAutoTourMap(coords._lat, coords._lon); | |
} | |
} else { // even a geocoding service cannot determine the coordinates | |
alert("'" + markerCoords + "' cannot be recognized as address."); | |
} | |
} | |
function addCheckUncheckAllLinks($div) { | |
var checkboxes = $div.find('input[type=checkbox]'), | |
$all_none = $('<span>') | |
.append( | |
$('<a style="cursor:pointer;">').html('<i>' + $.gctour.lang('settings.printview.logCounts')[1] + '</i>').click(function () { | |
checkboxes.prop('checked', true); | |
})) | |
.append(' / ') | |
.append( | |
$('<a style="cursor:pointer;">').html('<i>' + $.gctour.lang('settings.printview.logCounts')[0] + '</i>').click(function () { | |
checkboxes.prop('checked', false); | |
})) | |
.append($('<br>')); | |
$all_none.insertBefore($div.find('span:first')); | |
$div.find('a') | |
.css({ | |
'color' : '#00447c', | |
'text-decoration' : 'underline' | |
}) | |
.hover(function () { | |
$(this).css("color", "#6c8e10"); | |
}, function () { | |
$(this).css("color", "#00447c"); | |
}); | |
} | |
function getSpecialFilter() { | |
var $div, | |
$checkbox, | |
$selectbox, | |
$favorites, | |
opt, | |
attributs, | |
select_specials = $.gctour.lang('autoTour.filter.special.pm'), | |
checkbox_specials = { | |
'I haven\'t found ' : $.gctour.lang('autoTour.filter.special.notfound'), | |
'is Active' : $.gctour.lang('autoTour.filter.special.isActive') | |
}, | |
initial = '{"I haven\'t found ":false,"is Active":false,"pm":"ignore","minFavorites":"0"}', | |
tq_filter = JSON.parse(GM_getValue('tq_specialFilter', initial)); | |
// Beginn für Umstellung des Filters | |
// => Kann bei übernächster Version wieder entfernt werden | |
if (tq_filter["is not a PM cache"]) { | |
tq_filter["pm"] = "not"; | |
} | |
// End | |
$div = $('<div>') | |
.html("<b>" + $.gctour.lang('autoTour.filter.special.caption') + "</b><br/>") | |
.css({ | |
"text-align" : "left", | |
"padding-left" : "10px", | |
"padding-right" : "10px", | |
"float" : "left", | |
"background-color" : "#ffe" | |
}); | |
//begin PM | |
$selectbox = $('<select/>', { | |
id : "special_pm" | |
}) | |
.css({ | |
"margin" : "0 0 6px 0", | |
"width" : "190px" | |
}); | |
$.each(select_specials, function (key, value) { | |
opt = $('<option value="' + key + '">' + value + '</option>'); | |
if (tq_filter["pm"] == key) { | |
opt.prop('selected', true); | |
} | |
$selectbox.append(opt); | |
}); | |
$div.append( | |
$selectbox, | |
$('<br>')); | |
//end PM | |
$.each(checkbox_specials, function (key, value) { | |
attributs = { | |
type : 'checkbox', | |
name : "special", | |
class : "gctour-input-checkbox", | |
id : "special" + key, | |
value : key, | |
checked : tq_filter[key] ? 'checked' : false | |
}; | |
$checkbox = $('<span>') | |
.css({ | |
"margin" : "2px", | |
"vertical-align" : "middle" | |
}) | |
.append( | |
$('<input/>', attributs).css({ | |
"margin" : "0 4px 0 0" | |
}), | |
$('<label>') | |
.attr({ | |
"for" : "special" + key, | |
"class" : "gctour-label" | |
}) | |
.text(value)); | |
$div.append( | |
$checkbox, | |
$('<br>')); | |
}); | |
$favorites = $('<input>', { | |
type : 'text', | |
id : 'special_favorites', | |
class : 'gctour-input-text', | |
value : tq_filter['minFavorites'] | |
}).css({ | |
'margin' : '4px 0 0 4px', | |
'width' : '40px' | |
}); | |
$div.append( | |
$('<span>').text($.gctour.lang('autoTour.filter.special.minFavorites')), | |
$favorites, | |
$('<br>')); | |
return $div; | |
} | |
function getDtFiler(boxName) { | |
var $div, | |
$checkbox, | |
attributs, | |
tq_filter, | |
initial = '{"1":true,"2":true,"3":true,"4":true,"5":true,"1.5":true,"2.5":true,"3.5":true,"4.5":true}', | |
title; | |
if (boxName == 'Difficulty') { | |
tq_filter = JSON.parse(GM_getValue('tq_dFilter', initial)); | |
title = $.gctour.lang('autoTour.filter.difficulty'); | |
} else { // terrain | |
tq_filter = JSON.parse(GM_getValue('tq_tFilter', initial)); | |
title = $.gctour.lang('autoTour.filter.terrain'); | |
} | |
$div = $('<div>') | |
.html("<b>" + title + "</b><br/>") | |
.css({ | |
"text-align" : "left", | |
"padding-left" : "10px", | |
"padding-right" : "10px", | |
"float" : "left", | |
"background-color" : "#ffe" | |
}); | |
for (var i = 1; i <= 5; i = i + 0.5) { | |
attributs = { | |
type : 'checkbox', | |
name : boxName, | |
class : "gctour-input-checkbox", | |
id : boxName + "" + i, | |
value : i, | |
checked : tq_filter["" + i] ? 'checked' : false | |
}; | |
$checkbox = $('<span>') | |
.css({ | |
"margin" : "2px", | |
"vertical-align" : "middle" | |
}) | |
.append( | |
$('<input/>', attributs).css({ | |
"margin" : "0 2px 0 0" | |
}), | |
$('<label>').attr({ | |
"for" : boxName + "" + i, | |
"class" : "gctour-label" | |
}) | |
.append( | |
$('<img>').attr("src", GS_HOST + "images/stars/stars" + ("" + i).replace(/\./g, "_") + ".gif").css({ | |
"vertical-align" : "unset" | |
}))); | |
$div.append( | |
$checkbox, | |
$('<br>')); | |
} | |
addCheckUncheckAllLinks($div); | |
return $div; | |
} | |
function getSizeFilter() { | |
var $div, | |
$checkbox, | |
attributs, | |
initial = '{"micro":true,"small":true,"regular":true,"large":true,"other":true,"not_chosen":true,"virtual":true}', | |
tq_filter = JSON.parse(GM_getValue('tq_sizeFilter', initial)); | |
$div = $('<div>') | |
.html("<b>" + $.gctour.lang('autoTour.filter.size') + "</b><br/>") | |
.css({ | |
"text-align" : "left", | |
"padding-left" : "10px", | |
"padding-right" : "10px", | |
"float" : "left", | |
"background-color" : "#ffe" | |
}); | |
$.each(SIZES_ARRAY, function (index, size) { | |
attributs = { | |
type : 'checkbox', | |
name : "size", | |
class : "gctour-input-checkbox", | |
id : "size" + size.sizeTypeId, | |
value : size.sizeTypeId, | |
checked : tq_filter[size.sizeTypeId] ? 'checked' : false | |
}; | |
$checkbox = $('<span>') | |
.css({ | |
"margin" : "2px", | |
"vertical-align" : "middle" | |
}) | |
.append( | |
$('<input/>', attributs).css({ | |
"margin" : "0 2px 0 0" | |
}), | |
$('<label>').attr({ | |
"for" : "size" + size.sizeTypeId, | |
"class" : "gctour-label" | |
}) | |
.append( | |
$('<img>').attr("src", GS_HOST + 'images/icons/container/' + size.sizeTypeId + '.gif').css({ | |
"vertical-align" : "unset" | |
}))); | |
$div.append( | |
$checkbox, | |
$('<br>')); | |
}); | |
addCheckUncheckAllLinks($div); | |
return $div; | |
} | |
function getTypeFilter() { | |
var $div, | |
$checkbox, | |
attributs, | |
boo, | |
initial = '{"2":true,"3":true,"4":true,"5":true,"6":true,"8":true,"11":true,"13":true,"1858":true,"137":true,"453":true,"7005":true}', | |
tq_filter = JSON.parse(GM_getValue('tq_typeFilter', initial)); | |
$div = $('<div>') | |
.html("<b>" + $.gctour.lang('autoTour.filter.type') + "</b><br/>") | |
.css({ | |
"text-align" : "left", | |
"padding-left" : "10px", | |
"padding-right" : "10px", | |
"float" : "left", | |
"background-color" : "#ffe" | |
}); | |
var wptArray_autoTour = WPT_ARRAY.slice(0, -1); // omit Lost and Found Events (last entry) | |
$.each(wptArray_autoTour, function (index, wpt) { | |
attributs = { | |
type : 'checkbox', | |
name : "type", | |
class : "gctour-input-checkbox", | |
id : "type" + wpt.wptTypeId, | |
value : wpt.wptTypeId, | |
checked : tq_filter[wpt.wptTypeId] ? 'checked' : false | |
}; | |
boo = ((index + 1) % 2 === 0); // letzter in seiner Spalte ? | |
$checkbox = $('<span>') | |
.css("padding-left", boo ? "10px" : "0px") | |
.append( | |
$('<input/>', attributs).css({ | |
"margin" : "0 2px 0 0" | |
}), | |
$('<label>').attr({ | |
"for" : "type" + wpt.wptTypeId, | |
"class" : "gctour-label" | |
}) | |
.append( | |
$('<img>').attr("src", GS_HOST + GS_WPT_IMAGE_PATH + wpt.wptTypeId + '.gif').css({ | |
"vertical-align" : "unset" | |
}))); | |
$div.append( | |
$checkbox, | |
(boo ? $('<br>') : "")); | |
}); | |
addCheckUncheckAllLinks($div); | |
return $div; | |
} | |
function getLocateMeButton() { | |
var button = $("<button>", { | |
css : { | |
"margin-left" : 10, | |
"font-size" : 12, | |
"cursor" : "pointer" | |
}, | |
html : "<img id='locateImage' src='" + $.gctour.img.locateMe + "'><span style='vertical-align:top;margin-left:3px;'>" + $.gctour.lang('general.findMe') + "</span>" | |
}) | |
.click(function () { | |
if (navigator.geolocation) { | |
$('locateImage').attr("src", $.gctour.img.loader3); | |
navigator.geolocation.getCurrentPosition( | |
function (position) { | |
$('locateImage').attr("src", $.gctour.img.locateMe); | |
var latitude = position.coords.latitude; | |
var longitude = position.coords.longitude; | |
$("input#markerCoords").val(new LatLon(latitude, longitude).toString()); | |
getMarkerCoord(); | |
}, | |
function (error) { | |
$('locateImage').attr("src", $.gctour.img.locateMe); | |
log('Unable to get current location: ' + error); | |
}, { | |
TIMEOUT : 10000 | |
}); | |
} else { | |
alert("Firefox 3.5? Please update to use this!"); | |
} | |
}); | |
return button; | |
} | |
function getCoordinatesTab() { | |
var coordsDiv = $("<div>", { | |
id : "coordsDiv", | |
css : { | |
"clear" : "both", | |
"align" : "left" | |
} | |
}); | |
var findMeButton = getLocateMeButton(); | |
findMeButton.css("cssFloat", "right"); | |
coordsDiv.append(findMeButton); | |
var divEbene = createElement('div', { | |
className : 'ebene' | |
}); | |
var placeholder = 'N49° 26.082 E7° 46.587'; | |
divEbene.innerHTML = '<b>' + $.gctour.lang('autoTour.center') + '</b> ' + | |
'<input type="text" id="markerCoords" class="gctour-input-text" style="width:350px;" placeholder="' + placeholder + '"><br/>' + | |
'<small class="gctour-small">' + $.gctour.lang('autoTour.help') + '</small>'; | |
coordsDiv.append(divEbene); | |
$("body").css("line-height", "1.5"); | |
divEbene = createElement('div', { | |
className : 'ebene' | |
}); | |
divEbene.innerHTML = '<b>' + | |
$.gctour.lang('autoTour.radius') + | |
'</b> ' + | |
'<input type="text" id="markerRadius" class="gctour-input-text" maxlength="4" value="2" style="width:40px;margin-right:5px;">' + | |
'<select id="markerRadiusUnit">' + | |
'<option value="km" selected="selected">' + $.gctour.lang('units.km') + '</option>' + | |
'<option value="sm">' + $.gctour.lang('units.mi') + '</option>' + | |
'</select>'; | |
coordsDiv.append(divEbene); | |
divEbene = createElement('div'); | |
divEbene.setAttribute('class', 'dialogFooter'); | |
var useButton = createElement('input', { | |
type : "button", | |
value : $.gctour.lang('autoTour.refresh'), | |
style : "background-image:url(" + $.gctour.img.autoTour + ");margin-top:-24px;" | |
}); | |
append(useButton, divEbene); | |
useButton.addEventListener('click', getMarkerCoord, false); | |
coordsDiv.append(divEbene); | |
return coordsDiv; | |
} | |
function getMapPreviewTab() { | |
var coordsDiv = createElement('div'); | |
coordsDiv.align = "left"; | |
coordsDiv.style.clear = "both"; | |
var cordsInputLat = createElement('input', { | |
type : 'hidden', | |
id : "coordsDivLat" | |
}); | |
coordsDiv.appendChild(cordsInputLat); | |
var cordsInputLon = createElement('input', { | |
type : 'hidden', | |
id : "coordsDivLon" | |
}); | |
coordsDiv.appendChild(cordsInputLon); | |
var cordsInputRadius = createElement('input', { | |
type : 'hidden', | |
id : "coordsDivRadius" | |
}); | |
coordsDiv.appendChild(cordsInputRadius); | |
var coordsLabel = createElement('div'); | |
coordsLabel.innerHTML = $.gctour.lang('marker.coord') + ": <b id='markerCoordsPreview'>???</b> " + $.gctour.lang('autoTour.radius') + ": <b id='markerRadiusPreview'>???km</b>"; | |
append(coordsLabel, coordsDiv); | |
// previewMap | |
var leafletMap = createElement('div'); | |
leafletMap.id = 'gct-leafletMap'; | |
coordsDiv.appendChild(leafletMap); | |
var cacheCountLabel = createElement('div'); | |
cacheCountLabel.innerHTML = $.gctour.lang('autoTour.cacheCounts') + " <b id='markerCountPreview'>???</b>"; | |
append(cacheCountLabel, coordsDiv); | |
var tourDurationLabel = createElement('div'); | |
tourDurationLabel.innerHTML = $.gctour.lang('autoTour.duration') + " <b id='markerDurationMin'>???</b> min <b id='markerDurationSec'>???</b> sec"; | |
append(tourDurationLabel, coordsDiv); | |
return coordsDiv; | |
} | |
function getAutoTourSubmit() { | |
var $submit = $("<div>").append( | |
$("<button>", { | |
id: "startQuery", | |
css: { | |
"margin": "15px 0 0 15px", | |
"opacity": "0.4" | |
}, | |
"disabled": "disabled", | |
html: "<img src ='" + $.gctour.img.startAutoTour + "'>" | |
}) | |
.on('click', (AUTOTOUR_NEW ? startAutoTourNewSearch : startAutoTour))); | |
return $submit; | |
} | |
async function showAutoTourDialog(center, radius) { | |
var overLay = getOverlay({ | |
caption : '<b>' + $.gctour.lang('autoTour.title') + '</b>', | |
minimized : true | |
}); | |
$(overLay).append( | |
getCoordinatesTab(), | |
$("<div>", { | |
id : "autoTourContainer", | |
css : { | |
"display" : "none", | |
"clear" : "both", | |
"border-top" : "2px dashed #B2D4F3", | |
"margin-top" : 12 | |
} | |
}).append( | |
getMapPreviewTab(), | |
$('<div>').append( | |
getTypeFilter(), | |
getSizeFilter(), | |
getDtFiler('Difficulty'), | |
getDtFiler('Terrain'), | |
getSpecialFilter()), | |
getAutoTourSubmit())); | |
if (center && radius) { | |
$("input#markerCoords").val(new LatLon(center.lat, center.lng).toString()); | |
$("input#markerRadius").val(radius); | |
} else { | |
$("input#markerRadius").val(2); | |
// on cache page get center point from cache coordinates, else from profile settings | |
var latlon; | |
if (!(latlon = $('span#uxLatLon').text())) | |
latlon = await getHoomeCoords(); | |
$('input#markerCoords') | |
.val(latlon) | |
.focus() | |
.select(); | |
} | |
// create map | |
let $map = $('div#gct-leafletMap'); | |
let options = {}; | |
options.id = 'gct-autoTour-map', | |
options.center = [0,0]; | |
options.height = '350px'; | |
options.map = 'gm'; | |
options.anchor = $map; | |
LM = new LeafletMap(options); | |
getMarkerCoord(); | |
} | |
// waypoint projection, earth approx. as sphere (now working in northern and southern hemisphere) | |
function CalcPrjWP(lat, lon, dist, angle) { | |
var lat1 = parseFloat(lat), // degree | |
lon1 = parseFloat(lon), // degree | |
Dist = parseFloat(dist), // miles | |
Angle = parseFloat(angle), // degree | |
d, | |
R, | |
mile, | |
lat2, | |
lon2; | |
while (Angle > 360) { | |
Angle = Angle - 360; | |
} | |
while (Angle < 0) { | |
Angle = Angle + 360; | |
} | |
// calculations in rad | |
lat1 = lat1 / 180 * Math.PI; | |
lon1 = lon1 / 180 * Math.PI; | |
Angle = Angle / 180 * Math.PI; | |
R = 6371.0; // mean earth radius in km | |
mile = 1.609344; | |
d = Dist * mile / R; // distance in km | |
lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1) * Math.sin(d) * Math.cos(-Angle)); | |
if (Math.cos(lat1) == 0) { | |
lon2 = lon1; | |
} else { | |
lon2 = (lon1 - Math.asin(Math.sin(-Angle) * Math.sin(d) / Math.cos(lat1)) + Math.PI) % (2 * Math.PI) - Math.PI; | |
} | |
// results in deg | |
lat2 = lat2 / Math.PI * 180; | |
lon2 = lon2 / Math.PI * 180; | |
return [Math.round(lat2 * 100000) / 100000, Math.round(lon2 * 100000) / 100000]; | |
} | |
// get home coordinates from profile settings | |
async function getHoomeCoords() { | |
var myUrl = GS_HOST + 'account/settings/homelocation', | |
response_div; | |
// get home coords | |
var response = await promiseRequest('GET', myUrl); | |
response_div = createElement('div'); | |
response_div.innerHTML = response.responseText; | |
//var homeCoords = $('input#Query', response_div).val(); | |
// first get script content, then extract coords (GS change, Aug 2017: coords wrapped in script) | |
var script_cont = $('script#tplSearchCoords', response_div).html(); | |
var homeCoords = $('input#Query', script_cont).val(); | |
return homeCoords; | |
} | |
// compare script version strings: return true if a > b else return false | |
function isNewVersion(a, b) { | |
if (a === b) { | |
return false; | |
} | |
var a_components = a.split("."); | |
var b_components = b.split("."); | |
var len = Math.min(a_components.length, b_components.length); | |
// loop while the components are equal | |
for (var i = 0; i < len; i++) { | |
// A bigger than B | |
if (parseInt(a_components[i]) > parseInt(b_components[i])) { | |
return true; | |
} | |
// B bigger than A | |
if (parseInt(a_components[i]) < parseInt(b_components[i])) { | |
return false; | |
} | |
} | |
// If one's a prefix of the other, the longer one is greater. | |
if (a_components.length > b_components.length) { | |
return true; | |
} | |
if (a_components.length < b_components.length) { | |
return false; | |
} | |
} | |
// Changelog | |
function changelog() { | |
let div = '<div id="gct_changelog" style="width:100vw;background-color:#e0b70a;vertical-align:middle;text-align:center;display:table-cell;font-size:0.8rem;">' | |
+ $.gctour.lang('dlg.newVersion.changelog') | |
+ '<a href="https://gist.github.com/DieBatzen/5814dc7368c1034470c8/raw/gctour.zChangelog.txt" target="_blank">Changelog</a>' | |
+ '<img id="gct_close_changelog" title="' + $.gctour.lang('general.close') + '" style="cursor: pointer;float: right;margin-right: 10px;margin-top: 5px;" src="' + $.gctour.img.closebutton + '">' | |
+ '</div>'; | |
$('body').prepend(div); | |
$('nav#gcNavigation').attr('style', 'position:static !important;font-size: 0.8rem;'); | |
$('img#gct_close_changelog').click(function () { | |
$('div#gct_changelog').remove(); | |
}); | |
} | |
// installation counter and Changelog (idea from GC little helper II: https://github.com/2Abendsegler/GClh) | |
function instCount() { | |
let ver = GM_getValue("version","0"); | |
if (isNewVersion(VERSION, ver)) { // script has been updated | |
GM_setValue("version",VERSION); | |
// show Changelog hint | |
changelog(); | |
// counter | |
//$(document.body).append('<div id="gct_counter1"><img src="https://www.worldflagcounter.com/dVE" style="visibility:hidden;"></div>'); | |
//$("#gct_counter1").remove(); | |
$(document.body).append('<div id="gct_counter2"><img src="https://s01.flagcounter.com/count2/doMh/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_250/viewers_4.11/labels_0/pageviews_0/flags_0/percent_0/" style="visibility:hidden;"></div>'); | |
$("#gct_counter2").remove(); | |
} | |
} | |
// update notifier for Gist repository | |
async function update(force) { | |
var updateURL = GM_info.scriptMetaStr.split('updateURL')[1].split('// @')[0].trim(); | |
var downloadURL = GM_info.scriptMetaStr.split('downloadURL')[1].split('// @')[0].trim(); | |
var updateDate = new Date(GM_getValue('updateDate')); | |
if (!updateDate || updateDate == "Invalid Date") { | |
updateDate = new Date(); | |
GM_setValue('updateDate', updateDate.toString()); | |
} | |
instCount(); | |
var currentDate = new Date(); | |
// if the last update check is more than 86 400 000 msec (1 day) ago - check for updates | |
if ((currentDate.getTime() - updateDate.getTime() > 86400000) || (force === true)) { | |
// set the new updateDate | |
GM_setValue('updateDate', currentDate.toString()); | |
var response = await promiseRequest('GET', updateURL); | |
var text = response.responseText; | |
var ver_gist = text.split("version")[1].split("//")[0].trim(); | |
if (!isNewVersion(ver_gist,VERSION)) { // no update available | |
log("update check: version " + VERSION + " is up to date"); | |
if (force === true) { | |
alert($.gctour.lang('update.upToDate')); | |
} | |
return; | |
} | |
var overlayBody = getOverlay({ | |
caption : $.gctour.lang('dlg.newVersion.caption'), | |
minimized : true | |
}); | |
var updateMapping = [ | |
['VERSION_OLD', VERSION], | |
['VERSION_NEW', ver_gist] | |
]; | |
var confirmString = $.gctour.lang('update.dialog'); | |
var update_dom = fillTemplate(updateMapping, confirmString); | |
var footer = update_dom.getElementsByTagName('div')[update_dom.getElementsByTagName('div').length - 1]; | |
// if install is pressed set the document.location to the update url | |
var install_button = document.createElement('input'); | |
install_button.type = "button"; | |
install_button.value = $.gctour.lang('general.install'); | |
install_button.style.backgroundImage = "url(" + $.gctour.img.userscript + ")"; | |
install_button.addEventListener('click', function () { | |
setTimeout(closeOverlay, 500); | |
document.location = downloadURL; | |
}, true); | |
var close_button = document.createElement('input'); | |
close_button.type = "button"; | |
close_button.value = $.gctour.lang('general.cancel'); | |
close_button.style.backgroundImage = "url(" + $.gctour.img.closebutton + ")"; | |
close_button.addEventListener('click', closeOverlay, false); | |
footer.appendChild(close_button); | |
footer.appendChild(install_button); | |
overlayBody.appendChild(update_dom); | |
} | |
} | |
/* helper */ | |
// Funktion, die in einem String die Wildcard {0},{1},{2}... mit den Paramtern von String.format ersetzt! | |
String.prototype.format = function () { | |
var s = this; | |
for (var i = 0; i < arguments.length; i++) { | |
var reg = new RegExp("\\{" + i + "\\}", "gm"); | |
s = s.replace(reg, arguments[i]); | |
} | |
return s; | |
} | |
// Convert HTML breaks to spaces | |
String.prototype.br2space = function () { | |
return this.replace(/<br\s*\/?>/mg, " "); | |
} | |
// Return a new string without leading and trailing whitespace | |
// Double spaces within the string are removed as well | |
String.prototype.trimAll = function () { | |
return this.replace(/^\s+|(\s+(?!\S))/mg, ""); | |
} | |
// replace all occurrences of str1 by str2 inside a string; optionally ignore case | |
// (http://dumpsite.com/forum/index.php?topic=4.msg29#msg29) | |
String.prototype.replaceAll = function(str1, str2, ignoreCase) { | |
return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignoreCase?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2); | |
}; | |
function gmNotice() { | |
let str_DE = | |
'<span>' + | |
'Ab Firefox Version 57, die Mitte November 2017 ansteht, wird GCTour mit Greasemonkey nicht mehr funktionieren. Den Grund dafür kann man hier nachlesen: ' + | |
'<a href="http://www.greasespot.net/2017/09/greasemonkey-4-announcement.html" target="_blank">Link.</a><br><br>' + | |
'Einfache Lösung: in Firefox eine andere Erweiterung für Userskripte verwenden, z.B. <a href="https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/" target="_blank">Tampermonkey</a>. ' + | |
'Damit läuft GCTour weiterhin einwandfrei.<br>' + | |
'<ol><li>Zuerst alle GCTour-Einstellungen, inklusive aller Touren sichern (NEU): "Einstellungen - Export/Import - Export"' + | |
'<li>Greasemonkey deinstallieren oder deaktivieren ("about:addons")' + | |
'<li>Tampermonkey installieren: <a href="https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/" target="_blank">Tampermonkey</a>' + | |
'<li>GCTour neu installieren: <a href="https://gctour.geocaching.cx/files/gctour.user.js" target="_blank">GCTour</a>' + | |
'<li>Alle GCTour-Einstellungen, inklusive aller Touren wiederherstellen (NEU): "Einstellungen - Export/Import - Import"' + | |
'</ol>' + | |
'</span>'; | |
let str_EN = | |
'<span>' + | |
'As of Firefox version 57 in mid-November 2017, GCTour will no longer work with Greasemonkey. The reason for this can be read here: ' + | |
'<a href="http://www.greasespot.net/2017/09/greasemonkey-4-announcement.html" target="_blank">Link.</a><br><br>' + | |
'Simple solution: in Firefox use another extension for user scripts, for example <a href="https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/" target="_blank">Tampermonkey</a>. ' + | |
'Thus GCTour continues to run flawlessly.<br>' + | |
'<ol><li>First save all GCTour settings, including all tours (NEW): "Settings - Export/Import - Export".' + | |
'<li>Uninstall or deactivate Greasemonkey ("about:addons")' + | |
'<li>Install Tampermonkey: <a href="https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/" target="_blank">Tampermonkey</a>' + | |
'<li>Reinstall GCTour: <a href="https://gctour.geocaching.cx/files/gctour.user.js" target="_blank">GCTour</a>' + | |
'<li>Restore all GCTour settings, including all tours (NEW): "Settings - Export/Import - Import"' + | |
'</ol>' + | |
'</span>'; | |
let str = str_DE + '<hr>' + str_EN; | |
$('<div>'+str+'</div>').dialog($.gctour.dialog.info(),{title: 'Hinweis / Notice',width: '75%',maxHeight: $(window).height() - 50}); | |
$(".ui-button span").text($.gctour.lang('general.close')); | |
} | |
/* start */ | |
// main | |
// don't run on frames or iframes, except on "send to GPS" page | |
if (window.top !== window.self && window.location.href.indexOf("/seek/sendtogps.aspx") <= 0) { | |
return; | |
} | |
try { | |
// load time | |
if (DEBUG_MODE && console && console.time) { | |
console.time('GCTour load time'); | |
} | |
// still necessary to check for Opera??? | |
if (IS_OPERA) { | |
// wait until document is loaded and init the core components (first tour, current tour) | |
window.addEventListener('DOMContentLoaded', function () { | |
initCore(); | |
init(); | |
}, true); | |
} else { | |
// init the core components (first tour, current tour) and check for script update | |
initCore(); | |
init(); | |
} | |
// load time | |
if (DEBUG_MODE && console && console.timeEnd) { | |
console.timeEnd('GCTour load time'); | |
} | |
update(); | |
// clear outdated data from GCTour database (temporary, to be removed in later versions) | |
var toBeDeleted = ['debug_lastcachesite', 'debug_lastgcid', 'gpxschema', 'hideCacheDetails', 'progress', 'settings_map_gcde', 'uploadMap', 'date_format_update']; | |
$.each(toBeDeleted, function (key, val) { | |
if (GM_getValue(val)) { | |
GM_deleteValue(val); | |
} | |
}); | |
if (IS_GREASEMONKEY && GM_getValue('gm_notice', 'null') === 'null') { // not set | |
GM_setValue('gm_notice', false); | |
gmNotice(); | |
}; | |
} catch (e) { | |
addErrorDialog({ | |
caption: "error in main", | |
_exception: e | |
}); | |
} | |
})(); // end of of immediately-invoked function expression |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @version 4.11 | |
// ==/UserScript== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4.11 | |
- FIX: GPX download and tour print didn't work anymore after Groundspeak retired the old search page | |
- FIX: Firefox update broke autoTour | |
- FIX: in GPX download PMO caches caused an error for BM | |
- CHANGE: improved buttons to add all/marked caches to current/new tour on bookmark and old search lists | |
4.10 | |
- NEW: GCTour now supports the new search map: https://www.geocaching.com/play/map | |
(Note: Groundspeak is still working on the new search map, therefore changes may occur at any time) | |
- autoTour | |
- add all search results to new or current tour | |
- add cache to current tour from cache details view in sidebar | |
- FIX: unpublished own cache listings: print preview didn't work properly | |
- CHANGE: code cleaning and minor improvements throughout many functions | |
4.9.1 | |
- FIX: timeout issue for some requests (e.g. GPX download) | |
4.9 | |
- CHANGE: Google changed their license model for several services (e.g. maps and geocoding). Therefore it was necessary to replace them: | |
- static maps: now Leaflet (open-source JavaScript library for interactive maps) | |
- affected functions: autoTour, change coordinates in cache listings, create own waypoints in tours | |
- Geocoding: now OSM based | |
- affected function: autoTour | |
- CHANGE: bookmark list: "add to tour" button now in 1st column; thus the same as in old search page | |
- FIX: PRINTVIEW: personal cache note was missing (reason: GS changes is cache listings) | |
- FIX: old search page: "add to tour" button now in 1st column (GS removed the "Send To GPS column") | |
- MISC: improved error handling | |
4.8.2 | |
- FIX: GS changed cache type images in listings to svg (previously: gif) | |
- CHANGE: Improved handling of special HTML chars (<,&) in cache names | |
4.8.1 | |
Due to GS changes on the website, confirmation dialogs were partly ill formatted | |
4.8 | |
PRINTVIEW: | |
- NEW: for cache waypoints the waypoint code is now shown in front of the name | |
- NEW: page width can now be changed with a slider interactively | |
- FIX: font size of noprint parts wasn't always appropriate | |
- CHANGE: minor layout optimizations | |
GPX: | |
- FIX: no logs when website language was set to Czech; now more robust and should work for all languages | |
MAP: | |
- FIX: add to tour did not work anymore when GCLH2 option "Enhanced Map Popup" was active | |
LISTING: | |
- FIX: add to tour didn't work anymore in unpublished cache listings | |
4.7 | |
- NEW: tours can now be saved as bookmark list (https://www.geocaching.com/account/lists) from the GCTour main window | |
- by that, all apps that support bookmark lists (e.g. Groundspeak app, Geocaching4Locus) can transfer tours directly as lists | |
- links to bookmark lists (and thus tours) can be shared among users | |
- lists feature is sadly PMO (Groundspeak decision) | |
- NEW: after script update a notification and link to the Changelog is shown at the top of each page once | |
- CHANGE: Changelog removed from script; now available in Gist repository | |
- CHANGE: GPX download: fav score now only gets downloaded if really necessary (i.e. if the prefix option in GPX settings is active) | |
- CHANGE: printPreview | |
- listing waypoints now aligned properly in table of cache listing | |
- print preview could have been completely empty if caches and own waypoints were suppressed at the same time - not anymore | |
- now it's ensured that images and cache notes always fit in preview page | |
- in print settings, improved explanation for option to suppress caches and own waypoints | |
- MISC: some code refactoring | |
4.6.4 | |
- FIX: GPX download stopped working due to changes in required external script "FileSaver.min.js" (only newer GCTour installations are affected) | |
4.6.3 | |
- CHANGE: results from old search (seek/nearest.aspx) are now handled more robust - preparation for future changes (credits to 2Abendsegler) | |
- FIX: GPX: waypoint types were not correct anymore due to a change by GS (wpttypes is now WptTypes) | |
- MISC: some small code changes | |
4.6.2 | |
- CHANGE: unneeded login-check removed | |
- FIX: if third-party cookies are not accepted by Firefox, GCTour does not work as expected | |
--> the error message now gives the user a hint | |
4.6.1 | |
- FIX: a Groundspeak update changed the table structure of additional waypoints in listings slightly | |
--> GPX download and print didn't work anymore | |
4.6 | |
- NEW: export/import of settings and tours in tab Preferences - Export/Import | |
- UPDATED: save settings info now redirects to export/import section in preferences | |
- FIX: autoTour: did not work properly for Tampermonkey in Firefox | |
- MISC: GCTour will not work anymore for the combination Firefox >= 57 and Greasemonkey >= 4 | |
(http://www.greasespot.net/2017/09/greasemonkey-4-announcement.html) | |
- if you continue to run earlier versions of Firefox ensure that Greasemonkey version is less than 4.0 | |
- however, GCTour is working flawlessly in Tampermonkey for both, Firefox and Chrome | |
- GCTour 4.6 shows a notice once | |
- new exclamation mark icon in GCTour main window to open notice again, only visible when running Greasemonkey | |
- GCTour icon changed to exclamation mark, only visible when running Greasemonkey | |
4.5.2 | |
- FIX: autoTour: GS changed the header layout back ... now both, new and old layout should work | |
4.5.1 | |
- FIX: autoTour: GS changed the way how home coordinates are stored in the user profile. Therefore autoTour didn't work any more as expected on sites other than the map site. | |
- FIX: autoTour: on maps page the autoTour button was missing (cause: GS changed the header of all pages) | |
4.5 | |
- NEW: caches and own waypoints can now be moved to another tour | |
- NEW: GPX: option to show the favorite score in front of the cache name (when in Geocaching menu of GPSr) | |
- UPDATE: new tabs opened by GCTour will now be opened in foreground (FF+Chrome) | |
- FIX: tour upload: PMO caches were deleted from tour when user is basic member; now they stay in tour (still don't get uploaded) and user gets notification | |
- FIX: sometimes GCTour main window not resized correctly | |
- FIX: GPX: ASCII control codes in short and long description could result in invalid GPX files; they are now removed from descriptions | |
- FIX: GPX and printview: log dates now show visited date (before: created date): | |
a log can be created today but the cache has been visited 2 weeks ago | |
- FIX: GPX: in header, time is now correct UTC time (before: UTC was stated but local time was used) | |
4.4.1 | |
- FIX: exception "Permission denied to access property Symbol.toPrimitive" (reason: simultaneous calls of loadValue/saveValue; credits to 2Abendsegler for figuring out) | |
4.4 | |
- NEW: GCTour now supports Chrome | |
- UPDATED: new async/await feature replaces all spawn/function generator functions; now we really can write asynchronous code as it were synchronous! | |
- UPDATED: enhanced error handling | |
- FIX: printview: favorite scores were not displayed completely | |
4.3.1 | |
- FIX: after bulk deleting caches from a bookmark list the add to tour buttons were missing (credits to 2Abendsegler for the fix) | |
- FIX: cancel of a tour upload did not always close the progress bar (especially if something went wrong) | |
4.3 | |
- NEW: sending a tour to GPS receiver is now possible in 2 ways (can be configured in GCTour settings): | |
1) using Garmin Communicator Plugin (old) | |
2) using Garmin Express (new) | |
- FIX: GPX: attribute "Special Tool Required" was missing | |
4.2 | |
- NEW: tours can now be sorted by drag and drop | |
- NEW: tour list window can now be moved | |
- UPDATED: improved handling for cache logs: fetching in parallel and fetching only if more than 25 logs are requested | |
- UPDATED: GPX: "new Blob([gpxString]" replaced by "new File([gpxString]" | |
- UPDATED: Send2GPS: Beginning in Firefox version 52, support for Garmin Communicator Plugin in Firefox has ended | |
- FIX: in stored tours, own waypoint icons could still point to madd.in's original GCTour web page; | |
meanwhile the pages are no longer accessible and therefore the icons were not shown any more | |
- MISC: some code polishing | |
4.1.4 | |
- FIX: GPX: HTML code in cache logs (leftover from GS change to Markdown logs) caused an error | |
4.1.3 | |
- FIX: GPX: GSAK did not handle additional cache waypoints as child waypoints during import of GPX files | |
- FIX: GPX: dollar sign in cache descriptions could cause ill formatted GPX files | |
4.1.2 | |
- FIX: preview tour on map: changed cache coordinates were not always updated in map preview | |
- FIX: GPX: ASCII control codes in logs resulted in invalid GPX files; they are now removed from logs | |
4.1.1 | |
- FIX: Map: adding caches from the map to a tour didn't work any more due to the new cache icons | |
4.1 | |
- NEW: printview: favorite points available as both, absolute and relative value | |
- NEW: printview settings: option to enable/disable printing for all cache listings and own waypoints | |
- FIX: sendToGPS: GS layout change | |
4.0.2 | |
- FIXED: tour upload: did not work due to changes in 4.0.1 | |
4.0.1 | |
- FIXED: printview: did not work for tours with (approx.) more than 40 caches | |
4.0 | |
- NEW: printview: favorite points available | |
- NEW: most data now fetched in parallel (as opposed to one by one) --> much faster | |
print preview, GPX download, send to GPS, upload tour, map preview | |
- FIXED: printview: prevent cache table getting too wide for large font sizes | |
- MISC: exchanged positions of GCTour Home and Save Settings Info buttons | |
3.2 | |
- FIXED: Main menu: GCTour settings now work on new search page | |
- FIXED: Main menu: immediate numbering update when deleting a cache from a tour | |
- FIXED: info dialogs were not displayed properly on map and new search page (stylesheet was missing) | |
- FIXED: GPX: German umlauts, 'ß' and '-' now allowed in file names | |
- FIXED: autoTour: now works on new search page | |
- NEW: autoTour: check/uncheck all switch for filters | |
- NEW: Main menu: new info button on how to backup the complete GCTour settings, all tours and moved coordinates | |
- NEW: Main settings menu: layout change to jQuery UI dialog | |
- NEW: Main settings menu: theme roller (individual layout for all dialogs) | |
3.1 | |
- FIXED: autoTour: map preview with circle now works on southern hemisphere, too | |
- FIXED: Main menu: immediate numbering update when adding new cache(s) | |
- FIXED: GPX: coord.info links reset to http from https | |
- FIXED: GPX: "<sym>Geocache Found</sym>" for Geocaches already found (thanks to Vasek) | |
- FIXED: printview: closing the progress bar now opens a confirmation dialog to cancel the print process | |
- UPDATED: autoTour: all filters are now enabled on first use | |
- UPDATED: Upload/Download Tour: new confirmation dialogs | |
- NEW: autoTour: filter option for Giga events | |
- NEW: GPX: new attribute "Geotour" | |
3.0.1 | |
- FIXED: icons of own waypoints not displayed on downloaded tour | |
- FIXED: when editing own waypoints they lost their position inside the tour | |
- FIXED: when sorting a tour by drag and drop numbering did not update automatically | |
- NEW: check and notification for Chrome browser which is currently not supported | |
3.0 | |
- FIXED: in printview, description formatting (line breaks etc) is preserved for additional cache waypoints | |
- FIXED: pm only caches for non-pm member are now detected properly | |
- FIXED: missing translations for "reload map" in printview | |
- UPDATED: switch of external Web server (preservation of main GCTour functionality); credits to Mark | |
- UPDATED: size of GCTour main window increased slightly | |
- UPDATED: update of get/post methods | |
- NEW: in printview, own waypoints can be added to cache table as opposed to a separate table (user option in main printview menu) | |
- MISC: new main version | |
- MISC: some code review | |
2.3.14271, revision 9 | |
- FIXED: GPX file download was broken (missing file on external Web server); now independent of an external Web server | |
- NEW: update notifier for Gist repository; update check once a day | |
- MISC: some code review | |
2.3.14271, revision 8 | |
- FIXED: display of last 4 logs in print preview is now independent of max. number of logs | |
- MISC: option "all" in Settings - Printview - Number of logs... disabled (didn't work anyway) | |
- MISC: some code review | |
2.3.14271, revision 7 | |
- FIXED: autoTour didn't work from map when called from http (as opposed to https) | |
- NEW: automatic updates from Gist repository (probably checked once a week) | |
- MISC: improved code readability by applying a code beautifier | |
2.3.14271, revision 6 | |
- FIXED: print issue in Firefox | |
- FIXED: number of logs in print preview was dependent of max. number of logs in GPX files | |
- NEW: GCTour now supports unpublished listings | |
- NEW: revision number in GPX files | |
2.3.14271, revision 5 | |
- FIXED: adding caches to tour from bookmark and search lists: single, marked, all | |
- FIXED: completion of autoTour re-design part: German translations in dialog were missing | |
- FIXED: on GS public profile page boxes with owned caches/trackables were shown at the bottom of the page | |
- FIXED: route menu from "show caches on map" page removed (not working as expected) | |
- UPDATED: most links now use https instead of http | |
- UPDATED: improved visibility of buttons for adding all or marked caches from search/bookmark lists | |
- UPDATED: autoTour dialog now shows a center point on all pages (cache coordinates on cache pages and home coordinates from GS profile settings else) | |
- NEW: GitHub link to GCTour footer added | |
- NEW: revision to GCTour identifier added | |
- NEW: changelog for revisions added | |
2.3.14271, revision 4 | |
- FIXED: GS layout changes | |
2.3.14271, revision 3 | |
- FIXED: GS layout changes | |
- FIXED: send to GPS | |
- FIXED: change coordinates didn't work due to a conflict with script "Geocaching.com + Project-GC 1.4.9" | |
- FIXED: now all GS date formats work | |
2.3.14271, revision 2 | |
- FIXED: GS layout changes | |
2.3.14271, revision 1 | |
- MISC: initial import to https://gist.github.com/DieBatzen/5814dc7368c1034470c8 | |
2.3.14271 | |
- FIXED: "Add to tour" is now working from the map | |
- FIXED: Setting the default width of the print view | |
- FIXED: Printview is now working again if you generate it from the gc.com map | |
- UPDATED: autoTour dialog -> Coordinates are taken from geocache detail page | |
- UPDATED: autoTour dialog -> special filter extended with "Only PM cache" | |
2.3.14249 | |
- FIXED: Printview is now working _AGAIN_ | |
- FIXED: Printview now contains travelbugs again | |
- NEW: "send message to the author" now contains a response email address | |
2.3.14198 | |
- FIXED: Printview is now working again | |
2.3.13263 | |
- FIXED: gc.com update | |
2.3.13241 | |
- NEW: Notifications with proper localisations and look | |
- FIXED: Issue 50 (Send to GPS always sends GC14PCD) | |
2.3.13239 | |
- FIXED: Issue 45, 47 and 49 | |
2.3.13018 | |
- FIXED: Tour upload is working again | |
2.3.12356 | |
- FIXED: Issue 31 | |
- FIXED: wrong geocaches size in languages other than english | |
- FIXED: wrong geocache location in languages other than english/german | |
- FIXED: Bug on map that you need to log in | |
- FIXED: Issue 42 "Add to tour" button on map | |
- FIXED: Some minor CSS glitches | |
2.3.12147 | |
- FIXED: Issue 37 and 39 | |
- UPDATED: buttons of searchpage and bookmarkpage adjusted | |
- UPDATED: jquery to 1.7.2 and jquery-ui to 1.8.18 | |
- UPDATED: GPX -> cache-attributes to log settings, default = false | |
- NEW: printview -> icon to add and underline if user has changed the coordinates | |
2.2.12059 | |
- FIXED: autoTour menu button | |
- NEW: maps show now details if you click on a marker | |
2.2.12058 | |
- FIXED: new geocaching.com maps are now supported again | |
2.2.12043 | |
- FIXED: autoTour - but still issues with GCVote, please disable this to use autoTour! | |
- FIXED: OwnWaypoints and moveCoordinates | |
- REMOVED: annoying alert on search page | |
2.2.12042 | |
- FIXED: printview -> Bug with GCComment version | |
- FIXED: searchpage in-use with Userscript GCVote | |
- FIXED: Issue 22, 32 and 33 | |
- REMOVED: dojo completely removed | |
2.2.12003 | |
- FIXED: GPX -> ALL caches were either not found or found | |
- FIXED: printview -> Unsupported type for GM_setValue (Your Account Details -> Date Format) | |
2.2.12002 | |
- FIXED: Map issues | |
- FIXED: Upload Tour | |
- FIXED: exception SyntaxError JSON.parse unexpected character by download tour | |
- FIXED: exception TypeError progressBar is undefined | |
- FIXED: function getlogs | |
- FIXED: GPX found Caches from "<sym>Geocache</sym>" to "<sym>Geocache Found</sym>" (big thanks to Vasek) | |
- UPDATED: French translation - thanks pascal | |
- UPDATED: css adjustments | |
- NEW: Map height is now variable | |
- REMOVED: geocaching.com.au Type -> Groundspeak is now the only GPX Type | |
2.1.11313 | |
- FIXED: GPX Download bug "...ctl00_hlSignOut... is undefined" | |
- FIXED: Issue 18 | |
- FIXED: Update bug | |
- NEW: Update added link in the error-Dialog | |
- NEW: User can write a message in the error-Dialog | |
2.1.11293 | |
- FIXED: <=3 Logs in printout -> "Last4Logs" (L4L) in the printout | |
- FIXED: Logs in GPX (Unicode hexadez.) | |
- UPDATED: dutch translation | |
- Add jQuery (1.6.4) and jQuery-ui (1.8.16) | |
2.1.11285 | |
- FIXED: autoTour | |
- FIXED: GCTour on the search page | |
- FIXED: Logs in printout | |
- FIXED: Logs in GPX | |
- UPDATED: french translation | |
- GPX: New Groundspeak implementation to prevent XML errors | |
- NEW: Titlepage in the printview now contains coordinates and basic informations | |
- NEW: printview contains now the PM cache note! | |
- NEW: delete button for current tour | |
- NEW: "Last4Logs" (L4L) has been added to the printout - similar to http://www.gsak.net/help/hs11980.htm | |
2.0.11280 | |
- FIXED: silent update changes from gc.com | |
2.0.11239 | |
- FIXED: GPX bug | |
2.0.11206 | |
- FIXED: GPX bug after gc.com update | |
- FIXED: Printview after gc.com update | |
2.0.11158 | |
- FIXED: scrollbar bug Firefox 3.6 | |
- FIXED: "Search For Geocaches" page in Firefox 3.6 | |
- FIXED: Bug with new GCComment version | |
- FIXED: bug in popup after uploading an tour | |
- UPDATED: french translation | |
2.0.11158 | |
- FIXED: Event-Cache bug | |
- FIXED: Printout need some work | |
- FIXED: Update dialog bug | |
- FIXED: autoTour dialog | |
- FIXED: Layout modifications from gc.com | |
- FIXED: autoTour find now earthcaches | |
- FIXED: own waypoints coordinates were sometimes wrong rounded | |
- GPX: Logs does now have an unique id | |
- GPX: Archived/Unavailable geocaches are marked so | |
- MAP: Tweak code on the map site. The use of the map will now be much faster. | |
- NEW: Coordinates of geocaches can now be moved. | |
- NEW: Added a dialog to send me a message. | |
- NEW: Geocaches can now printed directly from their detailspage | |
- NEW: Tour upload has been completly redesigned | |
- NEW: Support for the new beta Maps | |
- NEW: Dutch translation (thanks to searchjaunt) | |
- NEW: Portuguese translation (thanks to Ruben) | |
- NEW: French translation (thanks to flashmoon) | |
- NEW: Added support for all GC.com date formats | |
- NEW: GCComment print view implementation | |
- ... and much more i already forgot | |
1.97.11033 | |
- FIXED: gccom layout change. | |
1.97.10361 | |
- FIXED: autotour with new OCR program | |
- FIXED: GPX/Print now contains correct hidden date | |
- FIXED: geocaches lists now are shown correctly again | |
- NEW: Google-Appengine program to decode D/T/Size images | |
1.97.10356 | |
- FIXED: GCTour is now working after gc.com update #2 | |
1.97.10313 | |
- FIXED: GCTour is now working after gc.com update | |
1.97 | |
- GPX: add <groundspeak:name> to GPX | |
- GPX: Additional Waypoints now named - Waypoint.Prefix + (GCID without leading GC) | |
- GPX: changed Groundspeak "Multi-Cache" to "Multi-cache" | |
- GPX: fixed earthcache type | |
- GPX: changed log id to a usable value - Issue3 | |
- GPX: added attributes to Groundspeak GPX | |
- FIXED: caches can remain in watchlist without error | |
- FIXED: that a tour remains in list after deleting | |
- FIXED: autoTour is working after update 7/28/10 | |
- FIXED: superscript text is now shown correct in printview | |
- NEW: Bookmark Lists now have "add to tour" buttons | |
- NEW: Tour can now sorted via drag n' drop | |
- NEW: Add check on Firefox >= 3.5 | |
- NEW: Minimal-printview containing cacheheader, hint and spoiler images | |
- NEW: Recode the complete update routine | |
- NEW: Add check whether the script is still logged on when scraping data | |
- CHANGED: Renew the buttons | |
- MISC: Code Review | |
- MISC: Create repository at http://code.google.com/p/gctour/ | |
- MISC: Start implementing http://gctour-spot.appspot.com/ | |
1.96 | |
- gc.com layout update 6/29/10 fixed | |
- new groundspeak GPX implementation | |
- close-window-button get a function in printview | |
- removing annoying debug messages on maps | |
- add an check after 20sec if gctour is loaded - important for no script users | |
- caches on printview are now numbered | |
- own waypoints are now uploaded again | |
- tour uploads had now a map on gctour.madd.in | |
- autoTour gets an option to filter PM-Only caches | |
- update to dojo 1.4 | |
1.95 | |
- gc.com layout fixes | |
- repair the "add selected caches"-to-tour button | |
1.94 | |
- hints are now in the printout again | |
1.93 | |
- fixed major functions after layout update | |
- new code for the printview | |
- remove the download-complete-map-button from maps page - please use autotour instead | |
- some minor bugfixes | |
1.92 | |
- add gpx option - old groundspeak schema or new geocaching.com.au schema | |
- autoTour now part of GcTour | |
- GUI improvements - now every tab is up-to-date | |
- strip 'GC'-Option for GPX-Files | |
- add OSM-Maps to the overview maps | |
- append OSM and Topo Germany to default Maptype-Option | |
1.91 | |
- Fast GPX-File bugfix! Type of caches is now correctly set! | |
1.9 | |
- New-GcTour-GPX with geocaching.com.au/opencaching.de schema! Contains now logs and description for _ALL_ users. | |
- Add dojo to make some DOM operations MUCH faster. Printview e.g. is now MUCH faster. | |
- GUI improvments | |
- Attributes are now shown in the printview | |
1.85 | |
- fixed bug that own marker have wrong coordinates in printview | |
- redesign of the cache list | |
- redesign of "create new marker"-dialog | |
- adding preview map to "create new marker"-dialog | |
- adding "move to top/bottom" button to cache list - thanks to adam r | |
- adding map size control in printview maps | |
1.8 | |
- adding overview page to printpage | |
- creating map with all caches on it | |
- outline map for every cache + additional waypoints | |
- adding costum waypoints | |
- the GPX contains now the current date | |
- adding information button to show which cache is in tour before loading | |
1.7 | |
- adding upload feature | |
- removed bug, that gctour is not able to handle multiple tabs | |
- implement sorting | |
- adding text size option for the printview | |
1.6 | |
- fixed downloaded gpxfile - html-/ no-html-mode | |
- add some fancy sliding effects | |
- add multiple tour function | |
- add trackables to printview | |
- some minor bugfix (e.g. extended table on gc.com map) | |
1.5 | |
- add download GPX-button | |
- add additional waypoints to printview | |
- add an add all button to the map. thx atornedging | |
- fixed some mutated vowel bugs in GPX | |
- tweak update function | |
- adding changelog to updatedialog | |
1.4 | |
- fixing bug, that premiummembers dont have coordinates in the printview | |
- adding logcounter to printview | |
1.3 | |
- adding buttons to the search tables | |
- progress is now displayed in the print view and GPS Export | |
- adding language support | |
1.2 | |
- optimizing printview | |
- add the possibility to export the spoiler images to the printview | |
- add an add-to-tour-button in the GC-Table on the right side of the map view | |
- fixed minor bug in the settings | |
1.1 | |
- extended printview - it is now possible export logs and remove images/logs | |
- update function is now working ... | |
1.0 | |
- initial release |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment