Saturday, October 29, 2011

GCComment


// ==UserScript==
// @name            GCComment
// @namespace       http://www.birnbaum2001.com/gccomment
// @description     Add comments to your geocaches on geocaching.com.
// @include   http://*geocaching.com/*
// @require   http://crypto.stanford.edu/sjcl/sjcl.js
// @version   60
// @author   Birnbaum2001
// ==/UserScript==

/*
 History
 - 2010-04-02 22:00 started hacking a bit
 - 2010-04-02 23:30 worked :)
 - 2010-04-03 0:25 changed saving by GCCode to GUID
 - 2010-04-03 0:58 included icon to show on overview pages (copied some code from gcvote for
 branching depending on URL)
 - 2010-04-03 1:15 hotfix. changed GUID parser from substring to substr because full detail
 URLs contain more than just the GUID after guid=
 - 2010-04-05 0:44 kind of tooltips are created by mouseover
 - 2010-04-05 0:47 weniger Zeilen, wenn kommentar vorhanden, dann gleich auftoggeln
 - 2010-04-05 0:50 Notizblock in Suchseite
 - 2010-04-05 12:11 comment-list & delete function
 - 2010-04-06 hotfix for nullpointer in detailpage without existing comment
 - 2010-04-29 added some icons and changed detailpage to readonly and editmode
 - 2010-04-30 integrated real tooltips
 - 2010-05-02 content for tooltips is loaded when tooltips are shown
 - 2010-05-02 added timestamp to new comments
 - 2010-05-02 added check for updates
 - 2010-05-04 added import/export, cancel editing, copy from gcnote
 - 2010-05-17 small improvements by Schatzjäger2 ('hand' mousepointer and action on mouseout instead of mouseover
 - 2010-05-19 exchanged save and delete buttons and inserted javascript popup to confirm deletion
 - 2010-05-24 import/export handles XML characters
 - 2010-06-16 fixed gc layout update on cache detail page
 - 2010-06-20 implemented first version of server sync
 - 2010-07-31 cleaner code style (comment as object), waiting for gctour to finish before inserting comments
 - 2010-08-05 comments can be categorized and filtered on overview table
 - 2010-08-13 stats on gccomment-icon, server storage available, delete all button
 - further comments and changelog on http://userscripts.org/scripts/show/75959
 */

// version information
var version = "60";
var updatechangesurl = 'https://gccomment.svn.sourceforge.net/svnroot/gccomment/trunk/gccomment/src/version.xml';
var updateurl = 'http://userscripts.org/scripts/source/75959.meta.js';

// UI Elements - Profile page
var configDiv;
var commentTable;
var importDiv;
var patchDiv;
var importText;
var importresult;
var gccRoot;
var displayFilters;
var waitingTag;
var filter;
var serverImportLink;
var serverExportLink;
var listener;

// UI Elements - Detail page
var detailCommentDiv;
var detailCommentTextArea;
var detailCommentTextPane;
var detailCommentInputLatLng;
var detailCommentLastSaveTime;
var detailCommentCacheState;
var detailFinalInputLatLng;
var detailFinalCacheState;

// Buttons
var AddComment;
var SaveComment;
var EditComment;
var DeleteComment;
var CopyComment;
var EditCancelComment;
var SaveFinalCoords;
var DeleteFinalCoords;

// Detail page comment details
var currentComment = null;
var currentCacheGUID;
var currentCacheCode;
var currentCacheName;
var currentCommentOrigLat;
var currentCommentOrigLng;

// general script variables
var DELIM = "#gccom#";
var COMPREFIX = "gccomment";
var COMGCPREFIX = "gccode-";
var DEG = String.fromCharCode(176);
var DEFAULTCOORDS = "<N dd" + DEG + " mm.mmm E dd" + DEG + " mm.mmm>";
var stateOptions = new Array("-", "not solved", "solved", "found");
var LAST_IMPORT = "lastimport";
var LAST_EXPORT = "lastexport";
var INDEXBUILT = "indexbuilt";

// preferences
var AUTOMOVEMYSTERIES = "autoMoveMysteries";
var AUTOMOVEMYSTERIESBETA = "autoMoveMysteriesbeta";
var AUTOMOVEMYSTERIESBETAFOUND = "autoMoveMysteriesbetafound";
var AUTOMOVEMYSTERIESBETASOLVED = "autoMoveMysteriesbetasolved";
var AUTOMOVEMYSTERIESBETAHOME = "autoMoveMysteriesbetahome";
var ADDCOMMENTSETTING = "addCommentSetting";
var CHANGEORIGINALSETTING = "changeOriginalSetting";
var ADDWAYPOINTSETTING = "addWaypointSetting";
var PATCHGPX_CHANGEORIGINAL = "patchGPXChangeOriginal";
var PATCHGPX_ADDFINALWPT = "patchGPXAddFinalWpt";
var ENABLE_EXPORT = "enableExport";
var PATCHGPX_REMOVE_SOLVED = "PATCHGPX_REMOVE_SOLVED";
var PATCHGPX_REMOVE_UNSOLVED = "PATCHGPX_REMOVE_UNSOLVED";
var PATCHGPX_REMOVE_FOUND = "PATCHGPX_REMOVE_FOUND";
var PATCHGPX_REMOVE_OTHERS = "PATCHGPX_REMOVE_OTHERS";

// icons
var gccIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAwUExURdPer+b9v0mis4rElNjQMVyuXfvzR+O+c0BOO+egPfT93X2FbL/Z3qaxkODo4J2EMhLWxjYAAAB9SURBVHjaVMwJDkMhCATQQawgLtz/tl/kt0mHjMtLFK22Wmuz/blhNHfXP2iqZ7Gl+gVXIyJbQxOqwt4gAUZnXjkQtzVgWOcERrwPMYz7FWYARjQAKBzbypIISgiQlR5QGHTD0hOK6gDEvQdwyrTeE0pm/2BmtmHH7EeAAQAb9gXg4KzWZAAAAABJRU5ErkJggg==';
var commentIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAARFJREFUeNqkU03OREAQbXwRseAYnMy3sJO4BJYsuJQlFm4h/unp10kLZiY6mUqeblX9XlWXolBKyS/2JzZZluVs8SAoRM+rgK7rhe/7/4cCnGma0rquqYzhHM4fidhLLksWVlUVRHIIqOzhOY4jdV8QhmEgruuSrus8+FTZJq7rSvq+5wIfm3jPtG3bhTzPM8eyLFeBewX7vpNpmjhJiGEPInD2v1WA4DiOh4DoNPYAqjIM44jxHmiaVjRNw4m4I8AadAF8iJumSWzbJm3bEsuyisc5KMvycQ4UUQomkZXuiesEQcDXOI55XwQBmd8m8Y4kSXi2KIrop/gZ6rfPiMxhGCpP8/FVQIYMU379nV8CDADQEaUK/jLo9wAAAABJRU5ErkJggg==';
var commentIconEdit = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAYJJREFUeNqUU89LAlEQnn27BMKyNzsmnvYP6FJ3b0XgPei2Ed4M6yheJFaDiPWgB5GIrkHU/9Cha+YmQkpQ2SVEZV3E15uBt2j+SAeGj5l533zzfimcc1jC1oXvCt+w9vfSmChd32UEtBTZoFAoFAVYGMscYigUgmg0CrquQ9nJwnncp9rx7Ro1oQaCzGOxGJimOXcEoRyQnz8ZVD8YPL4xUMPhcFGQN1cho313FXj/UYCJCaxVyVIdt8AWHeIi8sHRKYYttoicsXegux2fpQydTgdT91MTjEYjGA6HQexWv8AztwKy7VxRvl6vI7QnJkBiv9+HwWBAcfrkgfD1pU3ks8sKXS2u6/V6VNNUVS25rmtFIhHwfR88zyOUdlN5IsxelIExBpqmQaPRAMMwSsFjcRyH12o1/teazeZUDtfhevngJl6iGN2SyslkkjCXy9G5SAIqJxKJw2BEWRj3fD5ParZt81n1cZ95jVhA5VQqpfz3y+Y2WIaMpiz5nefarwADACQFMs6fhMd+AAAAAElFTkSuQmCC';
var commentIconDelete = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXpJREFUeNqUUr9Lw1AQvpd2qFFaRBwFHaQ46x8g0jooQqGjexy6BfpPtB3TweziYkX8tQiOrhkcTIbi4CgilKRJIc3z3YN7pLU19eC4e/fuu/vu3mOcc8iSj9M6+EHIV5aXGMXonKdAt9s9F8bAglSUbDUIFei5emwfPD0Yn1EEQjnDJAHmlUoFyuXyXBZvtSPlIxhla22Vadg5C4yyc/Oo/PVCAV5P6jb6mmBgZIGJAXVGwTGowL/Am5c9Ncb71zfXZgGwaBzHUsfjMWxf3cr43vU9hGGoxpE7mGaQJAlEojomogZBIO1u7w6GwyEMBgOZ97J/CBsXPcinwdgRwaPRSPr0pGk2BbFAupM7yOVytud5EogdUH3fn1CM4b2u61AqlaDf70OxWLTVvJZlcdd1+bQ4jvMrhnmYT+wYUcH/IKgbNI5pmtK22225FwJg50ajcTax8WntdDqyW6vV4rPu0zr3GbFzs9lkWX9kboFFwChskZ/4l/wIMADyMlZUy0YWOAAAAABJRU5ErkJggg==';
var commentIconDeleteAll = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURe6trfLy8tHR0Y+Pj7GxsQAAAIjuhv///20imzoAAAAIdFJOU/////////8A3oO9WQAAAGtJREFUeNpcjwEKwDAIA9Xo/P+Pl9iugwaq5KpgrC9ZV+KoS6CCekZFkDlke7QhQmT5ZwGR5QcYVeWu5x8goY/4AUl4zESeCfogaOx/7UCXNlBlroo5vXkrDNMXYAcmmIhNxY6qLHf8V4ABAESSBHQ3l0TpAAAAAElFTkSuQmCC';
var commentIconSave = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAZBJREFUeNqckz1LxEAQhmeTNGIjWliJIKKltWCjWAgWWihW1hYHgthb2Fmo1aE2dld5wtlZCFoINv4C/8EVnk0u2a8k7jvJHmejOQeGbDLvM7s7MxFFUdD5Taegf9jxwbYQZ812sbyyTr3PLm2tLtQCH54/aHJqmt5enyjIsoyMsWSNqQVDDy0YrKPMWveinZs/QWi0LrVgwEbIhI/wYcvznIW8oxPCsYZ7PdgImZSCK0JBEcC63MUwiGRwb4iDARtBxB8cmCQJpWlKUkpO5HdFYlgQBBSGIWv9JpHmBJKUg65bL7VbCEZzApdNSkVj4xMjzQAYsJHR5Qm8fbl5+M3iuM/Pmdk5Ajs4AcO9LjX210gIwQ7D/X0NUMgrd81+HA9OEKCSWit2FAZ2enlHt/fvg+rDfft8B6Avu+Aq7UFdtbIUKQbxbnnYypbqKsZdwCDZaro4gXsC8oNiq+R+oIaHiOPoQqd1ITb3Dov5xSVuC6CTo10Wx3xX+WMWdDVg7E4rfGBjpzHyL/3YbopvAQYALTKvvIqUmbwAAAAASUVORK5CYII=';
var commentIconAdd = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXxJREFUeNqMU7uKwlAQnRgLsYitsB+QZn/BQggo+RC3CKQQUqW1UhuDIvohmr+w2cIUlrtNEE0UH/gY78x6ZeP7wDDDZE5mTmYCiAivrFQqsa/Vaj8iRvIyr1BA6HQ6PeEqkkQgr2kaRFHEse/7oHufENjfFCtUkz6T0TAM0HUd7sHzPBgOh4lcuVzGQqHwq7Tb7Z4gVx6Rz8Xc+Ro0SVqM9pRMME0TBvaAYymBQBOkpN5nsG37RkKxWATXdT9S9wj00v1+f7HNZgO73Y6lUHeaSEqDVquF/3E4HHC1WmEcx2xiAzidTjEMQ1wsFrher7mu2+2S+9uChOy23W45liuVk8znc8hkMpDP52E2mzEnpapqPwgCJorObMvlMmGUo+fZbBZyuRxMJhO6j/5Fr1gljsdjvMZoNLrJUR3Vy+kSlyhGr0g51WqVfaPRgOPxeJFDnS3L+kp88WtrNpvcrV6v46v/5OEaqbPjOMqrG3n4gnfIBOWdS3yGkwADADDQiUjr02VlAAAAAElFTkSuQmCC';
var commentIconCopy = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUJJREFUeNqckj2Kg1AQxyebrQNWHsBSLCQgiJaiZzEH8A56gBXvYCtoLfZ2KUwsPEM+/HYzj/h2JWogAw/GefN+/5lxNrZtmxzH/cCKnc/ng2VZ7uyl7/vDO3vmwNz5XlI9nU7Uv16vi9VRQJIkNMiyLKRpCnme05jjOMPMe3exAnz86HttNAg1v+BDw/4nLSiKQi+PxyP1oyiivmEY9FtV1dcZILXrOmAYZlFZ13W43+9wu92mAFmWoa5rqKoKsixbLDsIAiKy3+//ABiI4xjatiX+breblD3a5XIBSZKoEAWUZQmCIJAgXhZF8TIDhDdNQwT6vif5BIBrGobhZJX/L46mabRnjKMIQhBIAM8dd2f+8YBJDzhJHg+qo/E8Px3inKGiKIpEHavAVhGw3W4paA3gep5nvtkndzNu1Kf2K8AAAxf9KklDG6EAAAAASUVORK5CYII=';
var commentIconEditCancel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAACB0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVi7kSokAAAAFnRFWHRDcmVhdGlvbiBUaW1lADExLzA1LzA33bqJ2wAAAx9JREFUeJxVk09om3UYxz/v722ydEmb2HYiS50dWDdT5sS1uoOitTo7LSMFFRHRwnbaSUFBpzgsDHGX1YvgofUg7CIutd2GTIR2A1vcULN2rTYwti7tivRP0vRPkvf9PY+HFmm/1+9feHgcVWUrbr76+BNOMPgFxm1W49aLWKRcykq5dEPLpdMtQ/dubtU7WwPGO59MYdxk8f40Xn4Ja+0GYVzccAQnWgO+3394aLpzW8D02Q9DhevDGW9pvn41e4fA7gZqXkoS3n8QVWFl8i8Wfh3Am72LidXCjlB2ra6+8ciF0SKqyljyYOrPtga9tg+d/LhLvfySirUqXlltqah2fVXX57I6O3heR57fo0OHYjr8TF1KVXHGX29uUZHf87f+oLazi/1ffoeKMNZ7juzoMOXlHAfePUlD61FUhL+//4b7X3+GidXiqD5dIaXimdL8HE5VjEc/OYeK8MNrTzE/kabSQLg6Smz3w6gIiGVvx5vcPv8tVfl/kUDwjHFClQkvv8Su5Hu4kWrG+nqYn0gTdSFSHeXFvktEGxMsTqb57atPQZQHnj1C2SvjqZMwIhq31rIj/giI5faVn6g0EKyK0tp3iVhjgoXJNAPHk+SmxgnsDFPTmGDFKr5I3IhsnkpkY6Yqkert5sHjSfyVPGGj/+uKAiqWCvH9GYwbL87cAbE0tHVQ1fn2hnkizeCJJH4hT8SF+HOvoGJZmLq10WntjHO9be8VL7/4si9Ky+UJAuEIKsLiRJqBExvNEQN1jzXR2nsRbznHha4OQguzhF3zi1E3cMqJ1qAry2TOfoRaAWtZnpnmwX1NJFrbaX7/NK29F0GEkZ5u1uZmqDAGK3LKUVVGX9iT8tfXkn5ugZ3tb9H0QTfBzSWIRUXwlnOM9HST+TlFXcAh5NB/LCOdjqpy9Z22kJn+J2PXVuu1kKMQqibW/gbhh+KgSmH2HpnLP+KvFqgJOAQdsrNlbTx5V4vbnunq4V0pTzRp1lawXpm8VcqbtOs4BFyDK9J/LCPbn2krhg9FD/hKty/a7InWq1iwNuuIveGqfH50Ssa26v8D7vnE690mEL0AAAAASUVORK5CYII=';
var waitingGif = 'data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==';
var errorIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtZJREFUeNpUU7tLI2EQn3y72TWJutnERCRHtBEL8URIUCy0sTsQ7a6xsbG8IsWBl0qut4hgd839Baaw0ubA4k7kCtEQuEAS0DMPjXnt43a/zc3sZcX7YPgeM/Ob3zw+n2ma4K1fx8fzlmlmdV1f+2OacdMwRFEQbL8s11G+iaL4eSGTufHsJUkCnwdQzOU+af3+B2l0NKaEwxBkDPz4bg4G0LMseGo0wOh2uwFFOVrKZPb/A3CdNe1jZGpqTNV1sB8fYYA7t20AQQAIBEBQVWjiuV6t2koy+fXt3t4uAQjvo9H5bqdzHE0k1PDTE1j398A1DRzOQd3Zgd7VFTgE2ulAQBQBolHWLJcXOGN3sdnZnwwZZIl2GJ2seh0cjOogPWVrC0JLS6BubwPHNIiNiXrVcUCUZbFVKBxUKpUYMzRtjXLmGJ2MyNhBGQwLRTvdPRAL7SKTk9CqVBKc802m9/vxABbMJtpDxwEZ452W3e8DfwVk4XtoZAQ6lCrnG8zUNFFCAEIfDKNTNKvd/geAOzl7zDh2RPL7QcOaOI6TxjYLtsG5OMAKk9KL1Lq4cIXOzpAV6XxopxsG+JEFMphmgiTVuzQL+OBFd4u4ugpzuZy7O8PoJD5sabvXg+DEBAFUmIQT1nx4ABaJgIPoHgM2Pu6mICjKizOxFNHuoVwGZXaWUrgUBRzPdqv1rqEoY2o8Dkat5raydnoKWrUK7etr15kGSkZ9DYuqdbvwZnmZGJyxdDZ7E1LVo9+lkt3E4kjJJAjYVh9OWfv2FkCWwY/3wMwMNHEG7opFmFpfB6YoJ8gg//IXvh8efmmWSjtyMChOJBIwirnSqBqo72DEGtLWMHdyVlKpH1jU/VQqde57/Ruv8/nd52Lx4BmHhPqso6MUDEIoFgN1bg7UlRWqyQk65xYXF8/dz0Tteb0KhUIMqW2ibKAujfs0SgXPlyhnKPl0Ot3w7P8KMAB6SM2aovTkagAAAABJRU5ErkJggg==';
var successIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAACB0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVi7kSokAAAAFnRFWHRDcmVhdGlvbiBUaW1lADExLzA1LzA33bqJ2wAAAmFJREFUeJyNk89L1FEUxT/vfcfRkdG0yRZqIYiCgmVorloUhCAkKLQxguwvSKiVUJYgFLSwZW3Kje7S3AgRiNQiTDQVhyhE0RkzTPwx4zjfmXnvtpgaZyCss3vvnXPPvedxlYiQjbql6+e8Ku+RI7rZQVcaa3BtIuTa5IxrE33rTRML2XyVXaAxeGPUUbpjzd1kx0QwGAAcNH58BKSYpE2NrbVMdOYUuBcaLJiKzH77mdqtXE1scBwCpgif8YYqDk7WfLw6EtcA7/anR/5HDLDtRIiqw8rlgs0RANUcvHnRItOzsS//FHcH2llJhJmKzHLqwI+1tkXHbWJgzd08Vni5qImVhnEEYerHJ3AtUW+cpDID2qfy63dMJEOu8pbTWFibOQ+euctk7XMGw8MMLb1OX+ZrXI9BJaVei0jFn7QBXlb10V3aTon4Ga1+yp3TXYxtTfJsYQj8DhQ6AIgSrLEV6sJCl8wlvgLQWFjLXN0wADupfUo9xeymIlS9bWXPE4NAXs5ovi2NTlkTdtAA3ApcyzyWeooB6Fl4wp6JQmmuWAkYa8I6amNBPz4AHm684NX38QxpNbbB0PobKPHw2+OoQByMxwZ1nnV6A5J22zNRbof66V66z24yQs/iY/CozNzZ0BGDTZpeJSKcnW4bjRHv2HaOfuO8qmY+HEy37su11/sWiZsx2zbfqQFq3PIun/GGSpKFGdK8LEOZ9+/imAnJymFXOousZSr7cGUUKx1RbxzXYxAlmcBUPN22wY7ZtvncZcrGifeXGjDSL0aaJWUrjVgMJmSUnbFKHtjWz4vZ/F9iIi867oQHZwAAAABJRU5ErkJggg==';
var state_default = commentIcon;
var state_unsolved = 'data:imag/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAEoSURBVDhPrVPHSgNRFM3XJ8P0RpJJ75AGKT/hTlFRUWyoCwu6EHV5nHPHZ2KiJAwOnN1p9747mcx/fWEYRjEQBAF83xd4nidwXReO48C2bZC3lknhXqGAj/l8I8gj/9uEjtuKVcBuPr9owsrbJJPzPpvheTQSvqZpSQvOuo3B62SCp+EQd73eZgMmUaDwMh7jvt/HTaeDi2bzpwG3vNzgbTqVmg+xgKCQqVetFs7qdRxXKsLP5XLJCMsGTHwcDHDb7YrgMgYTT2s1HJXLOIgiMSEvm80mBuoVVM3rdhsn1SoOSyUR7BeL8sTc/HmjIa2+nnJxD3/dwc7KeKy+dgfqINjEsiwoqL3oui5PxplZ+9dLXD1N0zRlURSn+lUMw0gvZmLq5DR1PwE9E+oxQiT4SQAAAABJRU5ErkJggg==';
var state_solved = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAEqSURBVDhPrVPJToRAEJ0fNmZkERgIiEIj+3bxezypUaNG4+7BJXow6heUXdX2zCiaIUSSd3tbdRWj0X99bdtucUDTNFDXNaGqKkJZllAUBeR5DsjrZKJQ3VuB+IMtBPKQPzVBx75iGaDujmdNsHKfZORsvocQPPvEj6JItMBZ+xiw1w1Yf1oD785ZbIBJKJAIXnzw711wb2ywL8zvBvjK8w2it4Bq+g+eABdiqnNlgXVmgHGsEZ8xJkaYN6Cajx64tzYJ7EsOnmidroJxpIF+oJAJ8sIwFAZyC7Kmcz0B80QH/VAlgbav0IqVnTFMzk1q9bXK2T38dQfL20udB+7cgTwIbJJlGUhM3yWOaWU4M9b+9RJ/nmaapiKZiwf9KkmSDBdj4uDkIXU/Ae1xwo0cXQQMAAAAAElFTkSuQmCC';
var state_found = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAESSURBVDhPrVNJaoRQEO3TqzhPmxzAjYrihAMqqCiIeqZKV9k/3YkJLRLh7d5Uv8rb7b8+27Y/7gDLssA0TYJhGARd10HTNFBVFZB3yESh7/uwbdtbIA/5XyboeFbMAjzPezbBymeSkbOuK4zjSHxBEPYWOOsZg3meYRgGaNv2vQEmoYBhmiboug7quoaiKL4b4Cu/NliWhWr2fU9AIaaWZQlZlkEcx8TneX4f4dWA1WyahgQITEzTFKIogjAMyQR5HMftBmwLrGZVVZAkCZERQRDQil3XhTzPqdVjlc97+OsOHMc5PPDhDthBYBNFUYCBvYsoirQynBlr/3qJP09TlmVKRvGlX0WSpOtiTLycfKXuJ+0c7jtCU1KuAAAAAElFTkSuQmCC';
var state_clear = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAFkSURBVDhPrZNLa8JQFIT9yy1uC30mNr4fIBXcKC6UCD7+RYvYRQlBwbRaY2pIbSxtKC6mOcdGY7RQQi/M4obMN3PPTSKR/1qFQuHGFfL5PHK5HCubzbIymQzS6TRSqRTcdxZ7mWSUZRm9Xm9Hki0iqOjdMUGwgVDyITPBDgHoWfT2aNuEKgeTvX0QcP0m4Mo4Z3AsFlu3oLP+BSBal7jQz3CqnewDnG4Xfn12OnhvtbBarViO48C2bZimCV3XQWvTgKbsN3+023h1Bzqv17FcLtloWRYMw8BkMoGmaQwQRXF9BD+AUs1GA8+1Gh4rFcxmM04cj8cYjUYYDocMoVaCIKwB7i0o98UiFs0mXtzUp2oVarmMh1KJDYPBAKqqQlEUTKdTbkV71/flv0oQJDiLfr/Pdf3rx7z9DjwKNUkmk/BEMFqSJPHA6MxUeyf5t98gkUhwGzKH+lXi8Xh4MyWGTg5T9xt4yvfg78PulQAAAABJRU5ErkJggg==';
var fadedMysteryIcon = 'data:image/gif;base64,R0lGODlhEAAQAJEAAOfq+JSfy4ODg/7+/iH5BAEAAAMALAAAAAAQABAAAAIznC2pxwgPRUOh2gAkE1bZvFXawGEjWYGo2ZRSqbZvek5obN+1ze18kpsAgwcOLmf0CX0FADs=';
var movedMysteryIcon = 'data:image/gif;base64,R0lGODlhCQAZAOYAAA/tDw/sDw/oDw/mDw7lDg7kDg7bDg7ZDgzFDAy/DAy+DAuyCw7jDg7iDg7hDg3TDQ3RDQzDDAu1CwqlCgqjCg/rDw/nDw7eDg7dDg7aDg7YDg7XDg7WDg3PDQ3ODQ3NDQ3MDQ3IDQ3HDQzADAy8DAy7DAy3DAuvCwuqCwumCwqbCgqYChHtERPtExTtFBfuFxruGhzuHCHuISbvJifvJynvKSzvLDfwNzjwOD3wPUTxRGDzYHb1dnf1d3j1eHr1en31fX71foz2jJ34naP4o6v5q7f6t7z6vML6wv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEkALAAAAAAJABkAAAeVgEmCSUSDg0NHRToEhj1GRTIHgwE5QDsDHwmCDBU4LxgREoIGBDABGQkLgw0sAQcKhgwurrCDBTEAB5qDAzO5u4ICNrm1SQ4CNQEcJIMXBC0CECaDGgYFGAgnhiAeIgsphiEIJSiGggcd5uqGQkhBA+Y8Rz8FD4MWND43BwiDBwYONoxQJQhEhFQTKBhaMEHFinXmAgEAOw==';
var moveMysteriesIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC4SURBVHjaYvz//z8DDDAyMiI4SACohpEBB2BB1nzh+hesikByMEPQLQHJgAVVbKbjsoRhzexYBgNNHqwuAQmgaL5zJBPORhbHZQgLMgekGVkBLpchewPFAFAYIPsXF0CRh8YCyCYwhgihigENhoujYwQDyCSkGaYGBWM1FWoAPpsxXECOZhBmwRVQyFGGL4UyIidldMWEYgMEmEhJ97jilGAYYA19qBwLkZbgdBVGGCCHAzHeAQgwAAYJB8lhWYArAAAAAElFTkSuQmCC';
var deleteMysteryIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAACB0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVi7kSokAAAAFnRFWHRDcmVhdGlvbiBUaW1lADExLzA1LzA33bqJ2wAAAp9JREFUeJxVk8tr1FcUxz/3/n55VFMT8gCtQ6uLUBqqCCbiSgqFgpa2mVIEQUo2QnFZioj0QQVduOhf0FXBnTQDpVJ3RkTETqXkYTudjRknhj6m6TiTYfL73XNOF7+ZMHM253Lvh/M9j3ucmdFry2feOOoGB7/GR7Pmo5yqoMlOVZOdoiU7X83dfbbcy7veAKv5Y4v4aL69WSGtbyEi2YOPiPaO4EbHIYTCybuVfF+Ayo3Phhs/L5XTrX9y29WniMHUhwtMX/4GQylf/5Q/C98RAX5sAoaGq63J3PQ73z9sOzNjNX9sMTTq883qU4JBMHjrUY2fzhyhFuDs7cfcOrGfAzHEDtzLY7g4Lpx6+HferX40O2eqj+prj0kNpvILzFz/FtTAFFMFU1Bl5YtP+OuHmww4kNEJnNkJrzvta+3NCtJRPnzxcxDFVDAR6HhT5bULl9hMM863mlhIr8Vu+KWZtL6FAAK8WPqRRhRlHeo2uOM1BJqacT4kpPHQjFe1gyKCkWUdHXqdqfwCmDH5wcdMvncegIl3z5G+cpghl3GYEVQPetVsVN1h1n/7tVO3ZWWo7J5rv6/gHLu8qeA1hA18ROee1sY6dOcvWQDDQJXGxjqDXRCHimx4bTWfRHtHcIB30Cgt96miCgYmQq20RuwyLjhHrPLEWzRwxY2OEwER0Cqt9KmaSJawCrXyGkMu49rmENUrfu5OqUgIBT82QeyA7Rf8W7zPyJtzu2McPPAqz395QNJssMdD4jxOtfB+WYvOzLh3/u1hXymVpbWds8Z/BIPNAA3p2zP2RTA+4EnUqs8Tm764bu2+Zbp3cmoxVZvPPkmS9aHTsOAcbXNd5f5l6rWl46NHgnE1qM2majlTAZGqUylGpl+e/kNXevn/AT0JpV86x3yxAAAAAElFTkSuQmCC';
var finalIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAILSURBVHjanFVBSONAFP0bJaIggbU3FcSDeKkXl4LSXrwGhF5786SHgguCdG+CRVlBKFiiFy305nEXT4UUhNKDWoRAURZaFva4Zrd1QWgp/P0zNmPaJk3ig9c/zUze/Hkz+QOICBYJEWKOaBDRJ6vEPHGlR6srOELMhMNhzOVyaBgG+kW1WsV8Po+RSIQJnRAVu7CWTCax1Wrhe9HpdDCVSjExrasJajQaFQO+6be4vX/OI8fFQaAJVFVlqokP9HNFoP8qn+V78Q6KZYO3j/7tgHz2AhbaWxM8you74hlsfAE7SqUSxGKxkkTtZQK4wRLjgt1J2o9HnPB5jxwdo+0+hKd6nfeR1zww4XGCeHl17iMEBk0Qur58nVyWQVEUWeofE5qfF+3dyeMBDbs1Pavqs0RySmBmdtpXosLzr38H+hyFF2anXH3uyZ428en+wbFv1Onh+toncTLc8LxZ4baFXPoltxctO/p9Zhmypdv3IpBwvx2Q2eOiXoJDrbCOXbHsb9mBMrZnVv75J/DRloZ1rq0u8ei1kW7CbYLnQOuT9TzbpNVsNttM+IYAbscuqB2VSoUHJnxKAK9j9+OX6Us4m82ycCoKfTqddqyvv2s1XptFfR4CTdPeCn1XmKWlxeNxLBQKaJqm78LeaDRQ13VMJBJclBgWwrbLNE4sEM0Al2mDqLNbw671X4ABANNJB/Q2gPgTAAAAAElFTkSuQmCC';
var finalIconLink = 'http://gccomment.svn.sourceforge.net/svnroot/gccomment/trunk/gccomment/res/finalcoord.png';
var cm = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURUrnIjT8ATj5CDb+BP///zP/ANLS0v///zHaLKsAAAAIdFJOU/////////8A3oO9WQAAAFFJREFUeNrk0VEOwCAIA1CwdNz/xqvRLEbxBOsfD76oZSa3iKxjY3zRoIV4xblIg8cR0thOhpj1dcHxC76/CgU7ew27GkdpWEuD8xGXFb8CDAD8WAgNrkSa2QAAAABJRU5ErkJggg==';
var cm_hvr = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURd+3t1rvKUvzGT74C+PAwDP/ADj8Bf///4LPUpoAAAAIdFJOU/////////8A3oO9WQAAAE5JREFUeNrc0dsNACAIA0AQlP03ViG+gAns5zUh0YKIVJdBEFAL48I7xfjFVUxml6YMnjFn/pExf3zzTPaDGG5UnYGuAuisk4yWTtwFGAAPCwgiHEofAAAAAABJRU5ErkJggg==';
var cm_dis = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURczMzDP/AD/+DzP9ADT2AzP9ATT8Av////A+tykAAAAIdFJOU/////////8A3oO9WQAAAEdJREFUeNpiYGdnZ2RjYWZEAkAhBnYwiwEOQDwmiDADCgCpZ0AXhEhQQZhhRAiTFiasjKBowFSMPdJAwsAoZmFkRItigAADABeaARPvgIzyAAAAAElFTkSuQmCC';

GM_registerMenuCommand("Enter a GCComment UUID", function() {
 var newUUID = window.prompt("Enter a new GCComment UUID. Previous one is "
   + GM_getValue("gccUUID") + ".");
 if ((newUUID != null) && (newUUID != "")) {
  GM_setValue("gccUUID", newUUID);
 }
});
GM_registerMenuCommand("Enter a GCComment Server", function() {
 var newServer = window
   .prompt("Enter a new GCComment Server. Previous one is "
     + GM_getValue("gccServer") + ".");
 if ((newServer != null) && (newServer != "")) {
  GM_setValue("gccServer", newServer);
 }
});

var indexbuilt = GM_getValue(INDEXBUILT);
if (indexbuilt != 'done') {
 log(
   'info',
   'Building index for GCCode-GUID assignment. This is done only once after update on version 46');
 var keys = GM_listValues();
 for ( var i = 0; i < keys.length; i++) {
  if (keys[i].indexOf(COMPREFIX) >= 0) {
   // we got a comment
   var guid = keys[i].split(COMPREFIX)[1];
   var comment = doLoadCommentFromGUID(guid);
   var indexKey = COMGCPREFIX + comment.gccode;
   GM_setValue(indexKey, guid);
   log("info", indexKey + "=" + guid);
  }
 }
 log('info', 'Finished building index.');
 GM_setValue(INDEXBUILT, 'done');
}

if (GM_getValue(ENABLE_EXPORT)) {
 log('info', 'Enabling export to other scripts');
 unsafeWindow.getGCComment = function(guid) {
  return doLoadCommentFromGUID(guid);
 };
}

// starting the GCC
log('debug', 'found URL: ' + document.URL);
if (document.URL.search("cache_details\.aspx") >= 0) {
 log('debug', 'matched gccommentOnDetailpage');
 gccommentOnDetailpage();
} else if (document.URL.search("cdpf\.aspx") >= 0) {
 log('debug', 'matched gccommentOnPrintPage');
 gccommentOnPrintPage();
} else if ((document.URL.search("\/my\/default\.aspx") >= 0)
  || (document.URL.search("\/my\/$") >= 0)
  || (document.URL.search("\/my\/#") >= 0)) {
 log('debug', 'matched gccommentOnProfilePage');
 gccommentOnProfilePage();
} else if ((document.URL.search("\/my\/logs\.aspx") >= 0)
  || (document.URL.search("\/seek\/nearest\.aspx") >= 0)
  || (document.URL.search("\/watchlist\.aspx") >= 0)
  || (document.URL.search("\/bookmarks\/view\.aspx") >= 0)) {
 log('debug', 'matched addCommentBubblesToPage');
 addCommentBubblesToPage();
} else if (document.URL.search("geocaching.com/map/beta/") >= 0) {
 log('debug', 'matched mysteryMoverOnBetaMap');
 mysteryMoverOnBetaMap();
} else if (document.URL.search("www.geocaching.com\/map") >= 0) {
 log('debug', 'matched mysteryMoverOnMapPage');
 mysteryMoverOnMapPage();
} else if (document.URL.search("sendtogps\.aspx") >= 0) {
 log('debug', 'matched sendToGPS');
 sendToGPS();
} else if (document.URL.search("\/account\/ManageLocations\.aspx") >= 0) {
 log('debug', 'matched gccommentOnManageLocations');
 gccommentOnManageLocations();
} else if (document.URL.search("\/seek\/log\.aspx") >= 0) {
 log('debug', 'matched gccommentOnLogPage');
 gccommentOnLogPage();
}

// GCComment auf der Profilseite
function gccommentOnProfilePage() {
 checkforupdates();

 // add links to each entry on that page
 addCommentBubblesToPage();

 // add overview of all comments on top of page
 var h2list = document.getElementsByTagName('h2');
 if (h2list.length > 0) {
  var root = h2list[0];

  gccRoot = document.createElement('div');
  gccRoot.setAttribute('style',
    'outline:1px solid #D7D7D7;margin-bottom:10px;padding:3px;');
  root.parentNode.insertBefore(gccRoot, root.nextSibling);

  var gcclink = document.createElement('a');
  // gcclink.setAttribute('href',
  // 'http://userscripts.org/scripts/show/75959');
  gcclink.setAttribute('target', 'blank');
  gcclink.setAttribute('title', 'Show options');
  var icon = document.createElement('img');
  icon.setAttribute('src', gccIcon);
  icon.setAttribute('style', 'vertical-align:middle;');
  gcclink.appendChild(icon);
  gccRoot.appendChild(gcclink);

  gcclink.addEventListener('mouseover', function(evt) {
   var stats = "<u><b>GCComment v" + version
     + "</b></u><br><b>Number comments: </b>"
     + getNumberOfComments() + " (" + GM_getValue('countWhite')
     + " default, " + GM_getValue('countRed') + " unsolved, "
     + GM_getValue('countGreen') + " solved, and "
     + GM_getValue('countGray') + " found)";
   stats = stats + "<br/><b>Last import: </b>";
   var lastim = GM_getValue(LAST_IMPORT);
   if (lastim)
    stats = stats + createTimeString(lastim);
   else
    stats = stats + " never";
   stats = stats + "<br/><b>Last export: </b>";
   var lastex = GM_getValue(LAST_EXPORT);
   if (lastex)
    stats = stats + createTimeString(lastex);
   else
    stats = stats + " never";

   stats = stats + "<br/><b>Last check for updates: </b>";
   stats = stats + createTimeString(eval(GM_getValue('updateDate')));
   unsafeWindow.tooltip.show(stats, 500);
  }, false);
  gcclink.addEventListener('mouseup', function(evt) {
   toggleTabOnProfile('configDiv');
  }, false);
  gcclink.setAttribute('onmouseout', 'tooltip.hide();');
  gcclink.setAttribute('style', 'cursor:pointer;');

  gccRoot.appendChild(document.createTextNode(' | '));

  var showCommentsLink = document.createElement('a');
  showCommentsLink.appendChild(document
    .createTextNode('Show my comments'));
  showCommentsLink.addEventListener('mouseup', function() {
   toggleTabOnProfile('gccommentoverviewtable');
  }, false);
  showCommentsLink.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(showCommentsLink);

  // -----
  displayFilters = document.createElement("div");
  displayFilters.style.display = "none";
  displayFilters.setAttribute('id', 'displayFilters');

  var filterclear = document.createElement('img');
  filterclear.setAttribute('src', state_clear);
  filterclear.setAttribute('style', 'cursor:pointer');
  filterclear.setAttribute('title', 'Show all');
  filterclear.addEventListener('mouseup', function() {
   filter = null;
   refreshTable(true);
  }, false);
  displayFilters.appendChild(document.createTextNode(' '));
  displayFilters.appendChild(filterclear);

  var filterall = document.createElement('img');
  filterall.setAttribute('src', state_default);
  filterall.setAttribute('style', 'cursor:pointer');
  filterall.setAttribute('title', 'Show all untyped');
  filterall.addEventListener('mouseup', function() {
   filter = stateOptions[0];
   refreshTable(true);
  }, false);
  displayFilters.appendChild(document.createTextNode(' '));
  displayFilters.appendChild(filterall);

  var filterunsolved = document.createElement('img');
  filterunsolved.setAttribute('src', state_unsolved);
  filterunsolved.setAttribute('style', 'cursor:pointer');
  filterunsolved.setAttribute('title', 'Show unsolved');
  filterunsolved.addEventListener('mouseup', function() {
   filter = stateOptions[1];
   refreshTable(true);
  }, false);
  displayFilters.appendChild(document.createTextNode(' '));
  displayFilters.appendChild(filterunsolved);

  var filtersolved = document.createElement('img');
  filtersolved.setAttribute('src', state_solved);
  filtersolved.setAttribute('style', 'cursor:pointer');
  filtersolved.setAttribute('title', 'Show solved');
  filtersolved.addEventListener('mouseup', function() {
   filter = stateOptions[2];
   refreshTable(true);
  }, false);
  displayFilters.appendChild(document.createTextNode(' '));
  displayFilters.appendChild(filtersolved);

  var filterFound = document.createElement('img');
  filterFound.setAttribute('src', state_found);
  filterFound.setAttribute('style', 'cursor:pointer');
  filterFound.setAttribute('title', 'Show found');
  filterFound.addEventListener('mouseup', function() {
   filter = stateOptions[3];
   refreshTable(true);
  }, false);
  displayFilters.appendChild(document.createTextNode(' '));
  displayFilters.appendChild(filterFound);

  gccRoot.appendChild(displayFilters);
  // ------

  gccRoot.appendChild(document.createTextNode(' | Export to '));

  var exportLink = document.createElement('a');
  exportLink.appendChild(document.createTextNode('GCC'));
  exportLink.addEventListener('mouseup', function() {
   var data = "<?xml version='1.0' encoding='UTF-8'?>"
     + buildGCCExportString();
   openDownloadWindow(data, "Export data", "application/gccomment");
  }, false);
  exportLink.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(exportLink);

  gccRoot.appendChild(document.createTextNode(' '));

  var exportGPX = document.createElement('a');
  exportGPX.appendChild(document.createTextNode('GPX'));
  exportGPX.addEventListener('mouseup', exportToGPX, false);
  exportGPX.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(exportGPX);

  gccRoot.appendChild(document.createTextNode(' '));

  var exportCSV = document.createElement('a');
  exportCSV.appendChild(document.createTextNode('CSV'));
  exportCSV.addEventListener('mouseup', exportToCSV, false);
  exportCSV.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(exportCSV);

  gccRoot.appendChild(document.createTextNode(' '));

  var exportHTML = document.createElement('a');
  exportHTML.appendChild(document.createTextNode('HTML'));
  exportHTML.addEventListener('mouseup', exportToHTML, false);
  exportHTML.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(exportHTML);

  if ((GM_getValue("gccServer") != undefined)
    && (GM_getValue("gccServer") != "")) {
   gccRoot.appendChild(document.createTextNode(' '));
   serverExportLink = document.createElement('a');
   serverExportLink.appendChild(document.createTextNode('Server'));
   serverExportLink.addEventListener('mouseup', storeToServer, false);
   serverExportLink.setAttribute('style',
     'cursor:pointer;text-decoration:underline;');
   gccRoot.appendChild(serverExportLink);
  }

  gccRoot.appendChild(document.createTextNode(' | Import from '));

  var importLink = document.createElement('a');
  importLink.appendChild(document.createTextNode('GCC'));
  importLink.addEventListener('mouseup', function() {
   toggleTabOnProfile('importDiv');
  }, false);
  importLink.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(importLink);

  if ((GM_getValue("gccServer") != undefined)
    && (GM_getValue("gccServer") != "")) {
   gccRoot.appendChild(document.createTextNode(' '));
   serverImportLink = document.createElement('a');
   serverImportLink.appendChild(document.createTextNode('Server'));
   serverImportLink.addEventListener('mouseup', loadFromServer, false);
   serverImportLink.setAttribute('style',
     'cursor:pointer;text-decoration:underline;');
   gccRoot.appendChild(serverImportLink);
  }

  gccRoot.appendChild(document.createTextNode(' | '));

  var deleteAllLink = document.createElement('a');
  deleteAllLink.appendChild(document.createTextNode('Delete all'));
  deleteAllLink
    .addEventListener(
      'mouseup',
      function() {
       var check = confirm('Do you really want to delete all comments?\n\nIf you press ok, all comments will be lost!!!');
       if (check) {
        var keys = GM_listValues();
        log("info", "all keys: " + keys);
        for ( var i = 0; i < keys.length; i++) {
         var key = keys[i];
         if (key.indexOf(COMPREFIX) > -1) {
          log("info", "deleted: " + key + "("
            + GM_getValue(key) + ")");
          GM_deleteValue(key);
         }
        }
       }
      }, false);
  deleteAllLink.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  gccRoot.appendChild(deleteAllLink);

  if (unsafeWindow.File && unsafeWindow.FileReader
    && unsafeWindow.FileList && unsafeWindow.Blob) {
   gccRoot.appendChild(document.createTextNode(' | '));
   var patchGPXLink = document.createElement('a');
   patchGPXLink.appendChild(document.createTextNode('Patch GPX'));
   patchGPXLink.addEventListener('mouseup', function() {
    toggleTabOnProfile('patchdiv');
   }, false);
   patchGPXLink.setAttribute('style',
     'cursor:pointer;text-decoration:underline;');
   gccRoot.appendChild(patchGPXLink);

   patchDiv = document.createElement('div');
   patchDiv.setAttribute('id', 'patchdiv');
   patchDiv
     .setAttribute('style',
       'margin:5px;padding:10px;outline:1px solid #D7D7D7;position:relative');
   patchDiv.style.display = 'none';
   gccRoot.appendChild(patchDiv);

   var removeUnusedDiv = document.createElement('div');
   removeUnusedDiv.setAttribute('id', 'removeUnusedDiv');
   removeUnusedDiv.setAttribute('style', 'margin-left:20px');
   appendCheckBox(removeUnusedDiv, PATCHGPX_REMOVE_OTHERS,
     "have no GCC entry");
   appendCheckBox(removeUnusedDiv, PATCHGPX_REMOVE_UNSOLVED,
     "you marked as not solved");
   appendCheckBox(removeUnusedDiv, PATCHGPX_REMOVE_SOLVED,
     "you marked as solved");
   appendCheckBox(removeUnusedDiv, PATCHGPX_REMOVE_FOUND,
     "you marked as found");

   var removeUnused = document.createElement('p');
   removeUnused.appendChild(document
     .createTextNode("Remove caches from GPX that ..."));
   removeUnused.appendChild(removeUnusedDiv);
   patchDiv.appendChild(removeUnused);

   appendCheckBox(removeUnused, PATCHGPX_CHANGEORIGINAL,
     "Change the original waypoint's coordinates to your final coordinates");

   appendCheckBox(removeUnused, PATCHGPX_ADDFINALWPT,
     "Add additional waypoints for final coordinates");

   var input = document.createElement('input');
   input.setAttribute('id', 'patchgpxinput');
   input.setAttribute('name', 'files[]');
   input.setAttribute('type', 'file');
   input.setAttribute('style', 'margin:3px');
   input.addEventListener('change', function(evt) {
    var files = evt.target.files;
    var file = files[0];
    var reader = new FileReader();
    reader.onload = (function(theFile) {
     return function(e) {
      handleGPXFileSelected(file.name, e.target.result);
     };
    })(file);
    if (file.name.indexOf('.gpx') > 0) {
     reader.readAsText(file);
    }
   }, false);
   patchDiv.appendChild(input);
   download = document.createElement('input');
   download.setAttribute('type', 'button');
   download.setAttribute('id', 'patchndownload');
   download.setAttribute('style', 'margin:3px');
   download.setAttribute('value', 'Patch and Download');
   download.setAttribute('disabled', '');
   patchDiv.appendChild(download);
   var patchResultDiv = document.createElement('div');
   patchResultDiv.setAttribute('id', 'patchResultDiv');
   patchDiv.appendChild(patchResultDiv);
  }

  configDiv = document.createElement('div');
  configDiv.setAttribute('id', 'configDiv');
  configDiv
    .setAttribute('style',
      'margin:5px;padding:10px;outline:1px solid #D7D7D7;position:relative');
  configDiv.style.display = 'none';

  var gccintro = document.createElement('p');
  gccintro.setAttribute('style', 'width:600px');
  gccintro.innerHTML = "Thanks for using GCComment. Visit <a href='http://userscripts.org/scripts/show/75959' target='blank'>userscripts.org</a> for general information and documentation or <a href='http://www.geoclub.de/viewtopic.php?f=117&t=44631' target='blank'>geoclub.de</a> for discussions & feedback. If you have direct feedback or questions, contact me at <a href='mailto:birnbaum2001@gmx.de'>birnbaum2001@gmx.de</a>.";
  configDiv.appendChild(gccintro);

  var paypallink = document.createElement('a');
  paypallink
    .setAttribute('style',
      'position:absolute;left:650px;top:10px;text-align:center;text-decoration:none;');
  paypallink
    .setAttribute(
      'href',
      'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3RG7N2ELTYRX4');
  paypallink.setAttribute('target', 'blank');
  paypallink.appendChild(document
    .createTextNode('Feel free to show your appreciation :)'));
  paypallink.appendChild(document.createElement('br'));
  var paypalImg = document.createElement('img');
  paypalImg.setAttribute('src',
    'https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif');
  paypallink.appendChild(paypalImg);
  paypallink.appendChild(document.createElement('br'));
  paypallink.appendChild(document.createTextNode('Thank you.'));
  configDiv.appendChild(paypallink);

  var configTable = document.createElement('table');
  var tr = document.createElement('tr');
  var td = document.createElement('td');

  var uuidText = document.createElement('input');
  uuidText.setAttribute('id', 'uuidText');
  uuidText.value = GM_getValue("gccUUID");
  uuidText.size = '40';
  var uuidLabel = document.createElement('label');
  uuidLabel.setAttribute('for', 'uuidText');
  uuidLabel.appendChild(document
    .createTextNode('UUID for server synchronisation'));
  td.appendChild(uuidLabel);
  tr.appendChild(td);
  td = document.createElement('td');
  td.appendChild(uuidText);
  tr.appendChild(td);
  configTable.appendChild(tr);

  var serverText = document.createElement('input');
  serverText.setAttribute('id', 'serverText');
  serverText.value = GM_getValue("gccServer");
  serverText.size = '40';
  var serverLabel = document.createElement('label');
  serverLabel.setAttribute('for', 'serverText');
  serverLabel.appendChild(document
    .createTextNode('Server for server synchronisation'));
  tr = document.createElement('tr');
  td = document.createElement('td');
  td.appendChild(serverLabel);
  tr.appendChild(td);
  td = document.createElement('td');
  td.appendChild(serverText);
  tr.appendChild(td);
  configTable.appendChild(tr);

  var label = document.createElement('label');
  label
    .appendChild(document
      .createTextNode('Allow export of comment data to other scripts'));
  tr = document.createElement('tr');
  td = document.createElement('td');
  td.appendChild(label);
  tr.appendChild(td);
  td = document.createElement('td');
  appendCheckBox(td, ENABLE_EXPORT, null);
  tr.appendChild(td);
  configTable.appendChild(tr);

  configDiv.appendChild(configTable);
  var saveButton = document.createElement('a');
  saveButton.appendChild(document.createTextNode('Save preferences'));
  saveButton.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  saveButton.addEventListener('mouseup', function() {
   GM_setValue('gccUUID', uuidText.value);
   GM_setValue('gccServer', serverText.value);
   saveButton.parentNode.appendChild(waitingTag);
   waitingTag.setAttribute('style', 'display:inline');
   waitingTag.setAttribute("src", successIcon);
   setTimeout(function() {
    unsafeWindow.$("#waiting").fadeOut('slow', function() {
    });
   }, 5000);

  }, false);
  configDiv.appendChild(saveButton);
  gccRoot.appendChild(configDiv);

  importDiv = document.createElement('div');
  importDiv.setAttribute('id', 'importDiv');
  importDiv
    .setAttribute('style',
      'margin:5px;padding:10px;outline:1px solid #D7D7D7;position:relative');
  importDiv.style.display = 'none';
  gccRoot.appendChild(importDiv);
  if (unsafeWindow.File && unsafeWindow.FileReader
    && unsafeWindow.FileList && unsafeWindow.Blob) {
   var input = document.createElement('input');
   input.setAttribute('id', 'fileinput');
   input.setAttribute('name', 'files[]');
   input.setAttribute('type', 'file');
   importDiv.appendChild(document
     .createTextNode('Choose GCC file to import from: '));
   importDiv.appendChild(input);
   importDiv.appendChild(document.createElement('br'));
   document.getElementById('fileinput').addEventListener('change',
     function(evt) {
      var files = evt.target.files;
      var file = files[0];
      var reader = new FileReader();
      reader.onload = (function(theFile) {
       return function(e) {
        importText.value = e.target.result;
       };
      })(file);
      if (file.name.indexOf('.gcc') > 0)
       reader.readAsText(file);
     }, false);
  }

  importText = document.createElement('textarea');
  importText.setAttribute('id', 'gccommentimporttextarea');
  importText.cols = 100;
  importText.rows = 10;
  importDiv.appendChild(importText);

  var submitImport = document.createElement('a');
  submitImport.appendChild(document.createTextNode('Execute import'));
  submitImport.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  submitImport.addEventListener('mouseup', parseXMLImport, false);
  importDiv.appendChild(document.createElement('br'));
  importDiv.appendChild(submitImport);

  var cancelImport = document.createElement('a');
  cancelImport
    .appendChild(document.createTextNode('Close import window'));
  cancelImport.addEventListener('mouseup', function() {
   importresult.innerHTML = "";
   unsafeWindow.$('#importDiv').slideToggle('slow');
  }, false);
  cancelImport.setAttribute('style',
    'cursor:pointer;text-decoration:underline;');
  importDiv.appendChild(document.createTextNode('\t'));
  importDiv.appendChild(cancelImport);

  importresult = document.createElement('p');
  submitImport.parentNode.appendChild(importresult);

  waitingTag = document.createElement('img');
  waitingTag.setAttribute('src', waitingGif);
  waitingTag.setAttribute('id', 'waiting');
  waitingTag.setAttribute('style', 'padding-right:5px');
 }
}

function patchNDownloadGPX(gccString) {
 unsafeWindow.$('#patchResultDiv').empty();
 var parser = new DOMParser();
 var xmlDoc = parser.parseFromString(gccString, "text/xml");
 var urls = xmlDoc.getElementsByTagName('url');
 var toRemove = new Array();
 var toAdd = new Array();
 var countCoordChanged = 0;
 var countWPTAdded = 0;
 var countWPTRemoved = 0;

 for ( var i = 0; i < urls.length; i++) {
  var url = urls[i];
  var guid = url.childNodes[0].nodeValue.split('guid=')[1];
  var comment = doLoadCommentFromGUID(guid);

  var wpt = url.parentNode;
  if (comment) {
   if ((comment.state == stateOptions[1])
     && GM_getValue(PATCHGPX_REMOVE_UNSOLVED)) {
    countWPTRemoved++;
    toRemove.push(wpt);
    continue;
   } else if ((comment.state == stateOptions[2])
     && GM_getValue(PATCHGPX_REMOVE_SOLVED)) {
    toRemove.push(wpt);
    countWPTRemoved++;
    continue;
   } else if ((comment.state == stateOptions[3])
     && GM_getValue(PATCHGPX_REMOVE_FOUND)) {
    toRemove.push(wpt);
    countWPTRemoved++;
    continue;
   }
   // weave comment into existing WPT
   // br - br - gccomment - br content
   var long = wpt.getElementsByTagName('groundspeak:long_description')[0];
   if (long)
    long
      .appendChild(xmlDoc
        .createTextNode("\n&lt;br /&gt;\n&lt;br /&gt;\nGCComment:\n&lt;br /&gt;\n"
          + comment.commentValue
          + "&lt;br /&gt;\n"));
   // create new WPT
   if (comment.lat && comment.lng) {
    if (GM_getValue(PATCHGPX_ADDFINALWPT)) {
     var newWpt = xmlDoc.createElement('wpt');
     newWpt.setAttribute('lat', comment.lat);
     newWpt.setAttribute('lon', comment.lng);

     var newTime = xmlDoc.createElement('time');
     newTime.appendChild(xmlDoc
       .createTextNode(isoTime(comment.saveTime)));
     newWpt.appendChild(newTime);

     var newName = xmlDoc.createElement('name');
     newName.appendChild(xmlDoc.createTextNode(comment.gccode
       + " - GCC " + comment.state));
     newWpt.appendChild(newName);

     var newDesc = xmlDoc.createElement('desc');
     newDesc.appendChild(xmlDoc.createTextNode(comment.name
       + " - GCC " + comment.state));
     newWpt.appendChild(newDesc);

     var newCmt = xmlDoc.createElement('cmt');
     newCmt.appendChild(xmlDoc
       .createTextNode(comment.commentValue));
     newWpt.appendChild(newCmt);

     // var newSym = xmlDoc.createElement('sym');
     // newSym.appendChild(xmlDoc.createTextNode(''));
     // newWpt.appendChild(newSym);

     // alternativ grüne fahne
     // <sym>Flag, Green</sym>

     // oder goldene fahne mit stern
     // <sym>Civil</sym>
     var newType = xmlDoc.createElement('type');
     newType.appendChild(xmlDoc
       .createTextNode('Waypoint|Final Location'));
     newWpt.appendChild(newType);

     var gc = xmlDoc.createElement('groundspeak:cache');
     gc.setAttribute('xmlns:groundspeak',
       'http://www.groundspeak.com/cache/1/0');
     gc.setAttribute('archived', 'false');
     gc.setAttribute('available', 'true');
     var gcname = xmlDoc.createElement('groundspeak:name');
     gcname.appendChild(document.createTextNode(comment.name
       + " - GCC " + comment.state));
     gc.appendChild(gcname);
     var gclongdesc = document
       .createElement('groundspeak:long_description');
     gclongdesc.appendChild(document
       .createTextNode(comment.commentValue));
     gc.appendChild(gclongdesc);
     newWpt.appendChild(gc);

     toAdd.push(newWpt);
     countWPTAdded++;
    }
    if (GM_getValue(PATCHGPX_CHANGEORIGINAL)) {
     wpt.setAttribute('lat', comment.lat);
     wpt.setAttribute('lon', comment.lng);
     countCoordChanged++;
    }
   }
  } else {
   if (GM_getValue(PATCHGPX_REMOVE_OTHERS)) {
    toRemove.push(wpt);
    countWPTRemoved++;
   }
  }
 }

 while (toRemove.length > 0) {
  var removeWpt = toRemove.pop();
  removeWpt.parentNode.removeChild(removeWpt);
 }
 var gpx = xmlDoc.getElementsByTagName('gpx')[0];
 while (toAdd.length > 0) {
  var addWpt = toAdd.pop();
  gpx.appendChild(addWpt);
 }
 var serializer = new XMLSerializer();
 var result = serializer.serializeToString(xmlDoc);
 var patchResult = document.createElement('p');
 patchResult.innerHTML = "Patching removed " + countWPTRemoved
   + " waypoints.<br/>Patching added " + countWPTAdded
   + " waypoints.<br/>Patching changed Coords of " + countCoordChanged
   + " waypoints.<br/>The GPX now contains "
   + xmlDoc.getElementsByTagName('wpt').length + " waypoints.";
 unsafeWindow.$('#patchResultDiv').append(patchResult);

 openDownloadWindow(result, "PatchGPX", "application/gccomment");
}

var download;
var oldhandler;

function handleGPXFileSelected(filename, gccString) {
 unsafeWindow.$('#patchResultDiv').empty();

 var parser = new DOMParser();
 var xmlDoc = parser.parseFromString(gccString, "text/xml");

 var parseStatus = document.createElement('p');
 parseStatus.innerHTML = 'The file ' + filename + " contains "
   + xmlDoc.getElementsByTagName('wpt').length + " waypoints.";
 unsafeWindow.$('#patchResultDiv').append(parseStatus);
 download.removeAttribute('disabled');
 if (oldhandler)
  download.removeEventListener('mouseup', oldhandler);
 oldhandler = function() {
  patchNDownloadGPX(gccString);
 };
 download.addEventListener('mouseup', oldhandler);
}

function gccommentOnLogPage() {
 var guid = document.getElementById(
   'ctl00_ContentBody_LogBookPanel1_WaypointLink')
   .getAttribute('href').split("guid=")[1];
 log('debug', 'found guid: ' + guid);
 if (guid) {
  var comment = doLoadCommentFromGUID(guid);
  log('debug', 'found comment: ' + comment);
  if (comment) {
   var markfound = document.createElement('a');
   markfound.appendChild(document
     .createTextNode('Mark as found in GCComment'));
   markfound.addEventListener('mouseup', function() {
    doSaveCommentToGUID(guid, comment.gccode, comment.name,
      comment.commentValue, stateOptions[3], comment.lat,
      comment.lng, comment.origlat, comment.origlng);
   });

   var submitButton = document
     .getElementById('ctl00_ContentBody_LogBookPanel1_LogButton');
   submitButton.parentNode.insertBefore(markfound, submitButton);

   var input = document
     .getElementById('ctl00_ContentBody_LogBookPanel1_ddLogType');
   if (input.value == 2)
    markfound.style.display = 'inline';
   else
    markfound.style.display = 'none';

   input.addEventListener('change', function() {
    if (input.value == 2) {
     markfound.style.display = 'inline';
    } else
     markfound.style.display = 'none';
   });
  }
 }
}

function toggleTabOnProfile(tabid) {
 // do specials
 if ((tabid == 'gccommentoverviewtable')
   && (!commentTable || (commentTable.style.display == 'none'))) {
  refreshTable(false);
  displayFilters.style.display = "inline";
 } else {
  displayFilters.style.display = "none";
 }

 // perfom actual toggle
 unsafeWindow.$('#' + tabid).slideToggle('slow');

 // hide others
 if ((tabid != 'configDiv') && (configDiv.style.display != 'none')) {
  unsafeWindow.$('#configDiv').slideToggle('slow');
 }
 if ((tabid != 'importDiv') && (importDiv.style.display != 'none')) {
  unsafeWindow.$('#importDiv').slideToggle('slow');
 }
 if ((tabid != 'patchdiv') && (patchDiv.style.display != 'none')) {
  unsafeWindow.$('#patchdiv').slideToggle('slow');
 }
 if ((tabid != 'gccommentoverviewtable') && commentTable
   && (commentTable.style.display != 'none')) {
  unsafeWindow.$('#gccommentoverviewtable').slideToggle('slow');
  displayFilters.style.display = "none";
 }
}

// wir sind auf der Detailbeschreibungsseite eines Caches
function gccommentOnDetailpage() {
 var findtag = document
   .getElementById('ctl00_ContentBody_uxFindLinksHeader');
 if (findtag) {
  AddComment = document.createElement('a');
  var imgAdd = document.createElement('img');
  imgAdd.src = commentIconAdd;
  imgAdd.title = "Add comment";
  imgAdd.setAttribute('style', 'cursor:pointer');
  AddComment.appendChild(imgAdd);
  AddComment.addEventListener('mouseup', function() {
   AddComment.style.display = 'none';
   detailCommentCacheState.removeAttribute('disabled');
   SaveComment.style.display = 'inline';
   EditCancelComment.style.display = 'inline';
   detailCommentTextArea.style.display = 'inline';
   detailCommentInputLatLng.removeAttribute("disabled");
   setTimeout(function() {
    detailCommentTextArea.focus();
   }, 50);
  }, false);

  EditComment = document.createElement('a');
  var imgEdit = document.createElement('img');
  imgEdit.src = commentIconEdit;
  imgEdit.title = "Edit comment";
  imgEdit.setAttribute('style', 'cursor:pointer');
  EditComment.appendChild(imgEdit);
  EditComment.addEventListener('mouseup', editComment, false);

  EditCancelComment = document.createElement('a');
  var imgEditCancel = document.createElement('img');
  imgEditCancel.src = commentIconEditCancel;
  imgEditCancel.title = "Cancel editing";
  imgEditCancel.setAttribute('style', 'cursor:pointer');
  EditCancelComment.appendChild(imgEditCancel);
  EditCancelComment.addEventListener('mouseup', function() {
   detailCommentTextArea.style.display = 'none';
   detailCommentCacheState.setAttribute('disabled', '');
   SaveComment.style.display = 'none';
   detailCommentTextPane.style.display = 'inline';
   detailCommentInputLatLng.setAttribute("disabled", "");
   EditCancelComment.style.display = 'none';
   if (currentComment == null) {
    AddComment.style.display = 'inline';
    EditComment.style.display = 'none';
    detailCommentTextArea.value = "";
   } else {
    AddComment.style.display = 'none';
    EditComment.style.display = 'inline';
    DeleteComment.style.display = 'inline';
    detailCommentTextArea.value = currentComment.commentValue;
    if (currentComment.lat && currentComment.lng) {
     detailCommentInputLatLng.value = convertDec2DMS(
       currentComment.lat, currentComment.lng);
    } else
     detailCommentInputLatLng.value = DEFAULTCOORDS;
   }
  }, false);

  SaveComment = document.createElement("a");
  var imgSave = document.createElement('img');
  imgSave.src = commentIconSave;
  imgSave.title = "Save comment";
  imgSave.setAttribute('style', 'cursor:pointer');
  SaveComment.appendChild(imgSave);
  SaveComment.addEventListener('mouseup', saveComment, false);

  SaveFinalCoords = document.createElement("a");
  SaveFinalCoords.setAttribute('style',
    'margin-left:3px;margin-right:3px');
  var imgSave = document.createElement('img');
  imgSave.src = commentIconSave;
  imgSave.title = "Save final coordinate";
  imgSave.setAttribute('style', 'cursor:pointer');
  SaveFinalCoords.appendChild(imgSave);
  SaveFinalCoords.addEventListener('mouseup', saveFinalCoords, false);

  DeleteFinalCoords = document.createElement("a");
  DeleteFinalCoords.setAttribute('style',
    'margin-left:3px;margin-right:3px');
  var imgDelete = document.createElement('img');
  imgDelete.src = deleteMysteryIcon;
  imgDelete.title = "Delete final coordinate";
  imgDelete.setAttribute('style', 'cursor:pointer');
  DeleteFinalCoords.appendChild(imgDelete);
  DeleteFinalCoords
    .addEventListener(
      'mouseup',
      function() {
       var check = confirm('Do you really want to delete the final coordinates?');
       if (check) {
        detailFinalInputLatLng.value = DEFAULTCOORDS;
        detailFinalInputLatLng.setAttribute('style',
          'color:grey');
        saveFinalCoords();
       }
      }, false);

  DeleteComment = document.createElement('a');
  var imgDelete = document.createElement('img');
  imgDelete.src = commentIconDelete;
  imgDelete.title = 'Delete comment';
  imgDelete.setAttribute('style', 'cursor:pointer');
  DeleteComment.appendChild(imgDelete);
  DeleteComment
    .addEventListener(
      'mouseup',
      function() {
       var check = confirm('Do you really want to delete this comment?');
       if (check) {
        GM_deleteValue(COMPREFIX + currentCacheGUID);
        currentComment = null;
        detailCommentCacheState.setAttribute(
          'disabled', '');
        detailFinalCacheState.options.selectedIndex = detailCommentCacheState.options.selectedIndex = 0;
        detailCommentTextArea.value = "";
        detailCommentTextPane.innerHTML = "";
        detailCommentTextArea.style.display = 'none';
        detailCommentTextPane.style.display = 'none';
        AddComment.style.display = 'inline';
        EditComment.style.display = 'none';
        SaveComment.style.display = 'none';
        DeleteComment.style.display = 'none';
        EditCancelComment.style.display = 'none';
        detailCommentInputLatLng.setAttribute(
          'disabled', '');
        detailCommentInputLatLng.value = DEFAULTCOORDS;
        detailFinalInputLatLng.value = DEFAULTCOORDS;
        updateSaveTime(-1);
       }
      }, false);

  CopyComment = document.createElement('a');
  var imgCopy = document.createElement('img');
  imgCopy.src = commentIconCopy;
  imgCopy.title = 'Copy Comment from GC-Note';
  imgCopy.setAttribute('style', 'cursor:pointer');
  CopyComment.appendChild(imgCopy);
  CopyComment.addEventListener('mouseup', function() {
   var gcnote = document.getElementById('notestatic');
   var text = gcnote.innerHTML;
   text = text.replace(/<br>/g, "\n");
   if (text != null) {
    editComment();
    detailCommentTextArea.value = detailCommentTextArea.value
      + "\n\ncopy from GC-Note:\n" + text;
   }
  }, false);

  var url = document.getElementById('ctl00_ContentBody_lnkPrintFriendly')
    .getAttribute('href');
  var guidIndex = url.indexOf('guid=');
  var length = "3331cc55-49a2-4883-a5ad-06657e8c1aab".length;
  currentCacheGUID = url.substr(guidIndex + 5, length);
  currentCacheCode = trim(document
    .getElementById('ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode').innerHTML);
  currentCacheName = unescapeXML(trim(document
    .getElementById('ctl00_ContentBody_CacheName').innerHTML));

  var origCoordinates = parseCoordinates(document
    .getElementById('ctl00_ContentBody_LatLon').innerHTML);
  if (origCoordinates.length == 2) {
   currentCommentOrigLat = origCoordinates[0];
   currentCommentOrigLng = origCoordinates[1];
  } else
   log('error',
     'Original Coordinates of cache could not be determined.');

  // laden des aktuellen comments
  currentComment = doLoadCommentFromGUID(currentCacheGUID);

  detailCommentDiv = document.createElement('div');
  detailCommentDiv.setAttribute('name', 'mycomments');
  var header = document.createElement('p');
  header.innerHTML = "<strong>My Comments</strong>";
  detailCommentDiv.appendChild(header);
  detailCommentDiv.id = 'gccommentarea';

  var small = document.createElement('small');
  detailCommentLastSaveTime = document.createTextNode('');
  small.appendChild(detailCommentLastSaveTime);

  detailCommentCacheState = document.createElement('select');
  detailCommentCacheState.setAttribute("name", "detailCommentCacheState");
  detailCommentCacheState.setAttribute('size', 1);
  detailCommentCacheState.setAttribute('disabled', '');
  var option0 = document.createElement('option');
  option0.appendChild(document.createTextNode(stateOptions[0]));
  var option1 = document.createElement('option');
  option1.appendChild(document.createTextNode(stateOptions[1]));
  var option2 = document.createElement('option');
  option2.appendChild(document.createTextNode(stateOptions[2]));
  var option3 = document.createElement('option');
  option3.appendChild(document.createTextNode(stateOptions[3]));
  detailCommentCacheState.appendChild(option0);
  detailCommentCacheState.appendChild(option1);
  detailCommentCacheState.appendChild(option2);
  detailCommentCacheState.appendChild(option3);
  if (currentComment) {
   if (currentComment.state == stateOptions[0]) {
    detailCommentCacheState.options.selectedIndex = 0;
   } else if (currentComment.state == stateOptions[1]) {
    detailCommentCacheState.options.selectedIndex = 1;
   } else if (currentComment.state == stateOptions[2]) {
    detailCommentCacheState.options.selectedIndex = 2;
   } else if (currentComment.state == stateOptions[3]) {
    detailCommentCacheState.options.selectedIndex = 3;
   }
  }

  header.appendChild(document.createTextNode('   '));
  header.appendChild(AddComment);
  header.appendChild(document.createTextNode('   '));
  header.appendChild(EditComment);
  header.appendChild(document.createTextNode('   '));
  header.appendChild(SaveComment);
  header.appendChild(document.createTextNode('   '));
  header.appendChild(EditCancelComment);
  header.appendChild(document.createTextNode('   '));
  header.appendChild(DeleteComment);
  var gcnote = document.getElementById('notestatic');
  if (gcnote != null) {
   header.appendChild(document.createTextNode('   '));
   header.appendChild(CopyComment);
  }
  header.appendChild(document.createTextNode('          '));
  header.appendChild(small);
  header.appendChild(document.createElement('br'));
  header.appendChild(document.createTextNode('The state: '));
  header.appendChild(detailCommentCacheState);

  header.appendChild(document.createTextNode('  Final:'));
  detailCommentInputLatLng = document.createElement('input');
  detailCommentInputLatLng.setAttribute('style',
    'margin-left:5px;margin-right:5px');
  detailCommentInputLatLng.setAttribute("disabled", "");
  detailCommentInputLatLng.setAttribute('size', '30');
  header.appendChild(detailCommentInputLatLng);

  if (currentComment && currentComment.lat && currentComment.lng) {
   detailCommentInputLatLng.value = convertDec2DMS(currentComment.lat,
     currentComment.lng);
  } else {
   detailCommentInputLatLng.value = DEFAULTCOORDS;
   detailCommentInputLatLng.setAttribute('style', 'color:grey');
  }

  detailCommentInputLatLng.addEventListener('click', function() {
   if (detailCommentInputLatLng.value == DEFAULTCOORDS) {
    detailCommentInputLatLng.value = "";
    detailCommentInputLatLng.setAttribute('style', 'color:black');
   }
  }, false);
  detailCommentInputLatLng.addEventListener('blur', function() {
   if (detailCommentInputLatLng.value == "") {
    detailCommentInputLatLng.value = DEFAULTCOORDS;
    detailCommentInputLatLng.setAttribute('style', 'color:grey');
   }
  }, false);

  detailCommentTextArea = document.createElement('textarea');
  detailCommentTextPane = document.createElement('p');
  detailCommentTextPane.setAttribute('style',
    'font-family:monospace;font-size:medium');
  detailCommentTextArea.id = 'gccommenttextarea';
  detailCommentTextArea.cols = 60;
  detailCommentTextArea.rows = 10;
  if (currentComment) {
   detailCommentTextArea.value = currentComment.commentValue;
   detailCommentTextPane.innerHTML = prepareTextPane(currentComment.commentValue);
   if (currentComment.saveTime) {
    updateSaveTime(currentComment.saveTime);
   } else
    updateSaveTime(-1);
  }
  if ((!detailCommentTextArea.value || (detailCommentTextArea.value == 'undefined'))
    && (detailCommentInputLatLng.value == DEFAULTCOORDS)) {
   AddComment.style.display = 'inline';
   EditComment.style.display = "none";
   EditCancelComment.style.display = "none";
   SaveComment.style.display = 'none';
   DeleteComment.style.display = 'none';
   detailCommentTextArea.style.display = 'none';
  } else {
   AddComment.style.display = 'none';
   EditComment.style.display = "inline";
   EditCancelComment.style.display = "none";
   SaveComment.style.display = 'none';
   detailCommentTextArea.style.display = 'none';
   detailCommentTextPane.style.display = 'inline';
   DeleteComment.style.display = 'inline';
  }
  detailCommentDiv.appendChild(detailCommentTextPane);
  detailCommentDiv.appendChild(detailCommentTextArea);

  detailCommentDiv.appendChild(document.createElement('br'));
  detailCommentDiv.appendChild(document.createElement('br'));
  findtag.parentNode.insertBefore(detailCommentDiv, findtag);

  // instant edit when opening the page
  var url = "" + window.location;
  if (url.indexOf('mycomments') > -1) {
   editComment();
  }
 }

 waitingTag = document.createElement('img');
 waitingTag.setAttribute('src', waitingGif);
 waitingTag.setAttribute('id', 'waiting');
 waitingTag.setAttribute('style', 'padding-right:5px');

 // Mystery Mover
 var script = "function insertFinalMarker(lat, lng, mymap) {"
   + "var markermap = null;" + "if (mymap)" + "markermap = mymap;"
   + "else" + "markermap = map;"
   + "var finalLatLng = new google.maps.LatLng(lat, lng);"
   + "var finalmarker = new google.maps.Marker();"
   + "finalmarker.setPosition(finalLatLng);"
   + "finalmarker.setMap(markermap);"
   + "finalmarker.setIcon(new google.maps.MarkerImage('" + finalIcon
   + "'));" + "finalmarker.setTitle('Final coordinate');"
   + "var p1 = markermap.getCenter();"
   + "var p2 = finalmarker.getPosition();"
   + "var s = Math.min(p1.lat(), p2.lat());"
   + "var n = Math.max(p1.lat(), p2.lat());"
   + "var w = Math.min(p1.lng(), p2.lng());"
   + "var e = Math.max(p1.lng(), p2.lng());"
   + "var sw = new google.maps.LatLng(s, w);"
   + "var ne = new google.maps.LatLng(n, e);"
   + "var llb = new google.maps.LatLngBounds(sw, ne);"
   + "markermap.fitBounds(llb);"
   // + "var line = new google.maps.Polyline();"
   // + "var pointArray = new Array();"
   // + "pointArray.push(new google.maps.LatLng(mapLatLng.lat,
   // mapLatLng.lng));"
   // + "pointArray.push(p2);"
   // + "line.setPath(pointArray);"
   // + "line.setMap(map);"
   + "}";
 appendScript("text", script, null);

 var hookTBody = document.getElementById('Print');
 if (hookTBody) {
  // var url =
  // document.getElementById('ctl00_ContentBody_lnkPrintFriendly')
  // .getAttribute('href');
  // var guidIndex = url.indexOf('guid=');
  // var length = "3331cc55-49a2-4883-a5ad-06657e8c1aab".length;
  // currentCacheGUID = url.substr(guidIndex + 5, length);
  // currentCacheCode = trim(document
  // .getElementById('ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode').innerHTML);
  // currentCacheName =
  // trim(document.getElementById('ctl00_ContentBody_CacheName').innerHTML);

  var mysteryRow = document.createElement('div');
  mysteryRow.setAttribute('class', 'LocationData');
  hookTBody.parentNode.insertBefore(mysteryRow, hookTBody);
  var mysteryData = document.createElement('td');
  mysteryRow.appendChild(mysteryData);

  detailFinalInputLatLng = document.createElement('input');
  detailFinalInputLatLng.setAttribute('style',
    'margin-left:5px;margin-right:5px');
  detailFinalInputLatLng.setAttribute('size', '30');

  // var coordComment = doLoadCommentFromGUID(currentCacheGUID);

  detailFinalCacheState = document.createElement('select');
  detailFinalCacheState.setAttribute("name", "detailFinalCacheState");
  detailFinalCacheState.setAttribute('size', 1);
  var option0 = document.createElement('option');
  option0.appendChild(document.createTextNode(stateOptions[0]));
  var option1 = document.createElement('option');
  option1.appendChild(document.createTextNode(stateOptions[1]));
  var option2 = document.createElement('option');
  option2.appendChild(document.createTextNode(stateOptions[2]));
  var option3 = document.createElement('option');
  option3.appendChild(document.createTextNode(stateOptions[3]));
  detailFinalCacheState.appendChild(option0);
  detailFinalCacheState.appendChild(option1);
  detailFinalCacheState.appendChild(option2);
  detailFinalCacheState.appendChild(option3);
  if (currentComment) {
   if (currentComment.state == stateOptions[0]) {
    detailFinalCacheState.options.selectedIndex = 0;
   } else if (currentComment.state == stateOptions[1]) {
    detailFinalCacheState.options.selectedIndex = 1;
   } else if (currentComment.state == stateOptions[2]) {
    detailFinalCacheState.options.selectedIndex = 2;
   } else if (currentComment.state == stateOptions[3]) {
    detailFinalCacheState.options.selectedIndex = 3;
   }
  }

  if (currentComment && currentComment.lat && currentComment.lng) {
   detailFinalInputLatLng.value = convertDec2DMS(currentComment.lat,
     currentComment.lng);

   var newSrc = addToGoogleMapsStatic(document.getElementById(
     'mapPreview').getAttribute('src'), currentComment.lat,
     currentComment.lng, null);
   document.getElementById('mapPreview').setAttribute('src', newSrc);

   var newLnkSrc = addToGoogleMapsStatic(document.getElementById(
     'lnkSmallMap').getAttribute('href'), currentComment.lat,
     currentComment.lng, null);
   newLnkSrc = newLnkSrc.replace('zoom=15', 'zoom=14');
   document.getElementById('lnkSmallMap').setAttribute('href',
     newLnkSrc);

   setTimeout(function() {
    var newStaticSource = addToGoogleMapsStatic(document
      .getElementById('staticMap').getAttribute('src'),
      currentComment.lat, currentComment.lng, null);
    document.getElementById('staticMap').setAttribute('src',
      newStaticSource);
   }, 200);

   // override original method to add final marker
   unsafeWindow.__displayDynamicMap = unsafeWindow.displayDynamicMap;
   unsafeWindow.displayDynamicMap = function() {
    // code copied from gs.com
    var $sm = unsafeWindow.$("#staticMap");
    var $map = unsafeWindow.$('<div />').addClass('map').css( {
     height : 325,
     width : 325
    });
    unsafeWindow.$("#lnk_slippyMap").replaceWith(
      unsafeWindow.$("<span>Showing Dynamic Map</span>"));

    var items = $sm.data("markers");
    unsafeWindow.console.log(items);
    // walk the array to find the full bounds
    var bounds = new unsafeWindow.google.maps.LatLngBounds();
    var markers = [];

    for ( var x = 0, len = items.length; x < len; x++) {
     var item = items[x];
     var ll = new unsafeWindow.google.maps.LatLng(item.lat,
       item.lng);
     bounds.extend(ll);
     markers.push(new unsafeWindow.google.maps.Marker( {
      clickable : false,
      icon : item.marker,
      position : ll,
      zIndex : unsafeWindow.google.maps.Marker.MAX_ZINDEX
        + (item.primary ? 1 : 0)
     }));
    }

    $sm.replaceWith($map);

    var map = new unsafeWindow.google.maps.Map(
      $map.get(0),
      {
       zoom : 14,
       center : bounds.getCenter(),
       mapTypeId : unsafeWindow.google.maps.MapTypeId.ROADMAP,
       mapTypeControl : true,
       navigationControlOptions : {
        style : unsafeWindow.google.maps.NavigationControlStyle.SMALL
       }
      });

    for ( var x = 0, len = markers.length; x < len; x++) {
     markers[x].setMap(map);
    }

    if (bounds.length > 1)
     map.fitBounds(bounds);
    unsafeWindow.insertFinalMarker(currentComment.lat,
      currentComment.lng, map);
   };

   // check, if gc tidy is on and push the final coords to the minimap
   // if (gctidyMinimap) {
   if (typeof unsafeWindow.GCTidyWaypoints == "object") {
    addToGCTidyDetailPage(currentComment.lat, currentComment.lng);
   } else {
    setTimeout(function() {
     if (typeof unsafeWindow.GCTidyWaypoints == "object")
      addToGCTidyDetailPage(currentComment.lat,
        currentComment.lng);
     else
      log('info', 'No GC Tidy found, even after 2s timeout');
    }, 2000);
   }
  } else {
   detailFinalInputLatLng.value = DEFAULTCOORDS;
   detailFinalInputLatLng.setAttribute('style', 'color:grey');
  }
  detailFinalInputLatLng.addEventListener('click', function() {
   if (detailFinalInputLatLng.value == DEFAULTCOORDS) {
    detailFinalInputLatLng.value = "";
    detailFinalInputLatLng.setAttribute('style', 'color:black');
   }
  }, false);
  detailFinalInputLatLng.addEventListener('blur', function() {
   if (detailFinalInputLatLng.value == "") {
    detailFinalInputLatLng.value = DEFAULTCOORDS;
    detailFinalInputLatLng.setAttribute('style', 'color:grey');
   }
  }, false);

  mysteryData.appendChild(document.createTextNode('Final coordinate '));
  mysteryData.appendChild(detailFinalInputLatLng);
  mysteryData.appendChild(detailFinalCacheState);
  mysteryData.appendChild(SaveFinalCoords);
  mysteryData.appendChild(DeleteFinalCoords);
 }

 // check for waypoints table
 var wpttable = document.getElementById('ctl00_ContentBody_Waypoints');
 if (wpttable && currentComment
   && (currentComment.lat && currentComment.lng)) {
  var wpttr = document.createElement('tr');
  var wpttd = document.createElement('td');
  wpttd.setAttribute('class', 'AlignCenter');
  wpttd.setAttribute('isHidden', 'false');
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  var wptViewable = document.createElement('img');
  wptViewable.setAttribute('width', '16');
  wptViewable.setAttribute('height', '16');
  wptViewable.setAttribute('alt', 'viewable');
  wptViewable.setAttribute('src', '/images/icons/icon_viewable.jpg');
  wpttd.appendChild(wptViewable);
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  var wptIcon = document.createElement('img');
  wptIcon.setAttribute('width', '16');
  wptIcon.setAttribute('height', '16');
  wptIcon.setAttribute('alt', 'Final Location');
  wptIcon.setAttribute('src', finalIcon);
  wpttd.appendChild(wptIcon);
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  var wptSpan = document.createElement('span');
  wptSpan.appendChild(document.createTextNode('FL'));
  wpttd.appendChild(wptSpan);
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  wpttd.appendChild(document.createTextNode('FL'));
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  wpttd.appendChild(document
    .createTextNode('Final Location by GCComment'));
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  wpttd.appendChild(document.createTextNode(convertDec2DMS(
    currentComment.lat, currentComment.lng)));
  wpttr.appendChild(wpttd);

  wpttd = document.createElement('td');
  wpttd.appendChild(document.createTextNode("  "));
  wpttr.appendChild(wpttd);
  wpttable.getElementsByTagName('tbody')[0].appendChild(wpttr);

  // note row
  // var wptnote = document.createElement('tr');
  // wptnote.setAttribute('class', 'BorderBottom');
  //
  // wpttd = document.createElement('td');
  // wpttd.appendChild(document.createTextNode(" "));
  // wptnote.appendChild(wpttd);
  //
  // wpttd = document.createElement('td');
  // wpttd.appendChild(document.createTextNode(" Note: "));
  // wptnote.appendChild(wpttd);
  //
  // wpttd = document.createElement('td');
  // wpttd.setAttribute('colspan', '6');
  // wpttd.appendChild(document.createTextNode(" "));
  // wptnote.appendChild(wpttd);
  // wpttable.getElementsByTagName('tbody')[0].appendChild(wptnote);
 }

 // check for "links to maps" table
 var mapLinks = document
   .getElementById('ctl00_ContentBody_MapLinks_MapLinks');
 if (mapLinks && currentComment
   && (currentComment.lat && currentComment.lng)) {
  var items = mapLinks.getElementsByTagName('li');
  var newlink = "";
  for ( var index = 0; index < items.length; index++) {
   var link = items[index].getElementsByTagName('a')[0];
   if (link.getAttribute('href').search('maps.google.com') > -1) {
    newlink = link.getAttribute('href')
      + " to: "
      + convertDec2DMS(currentComment.lat, currentComment.lng)
      + " (Final coordinates)";
   } else if (link.getAttribute('href').search('mapquest.com') > -1) {
    var chunks = link.getAttribute('href').split('&');
    for ( var i = 0; i < chunks.length; i++) {
     var chunk = chunks[i];
     var maplat, maplng;
     if (chunk.search('latitude') > -1) {
      maplat = chunk.split('=')[1];
     } else if (chunk.search('longitude') > -1) {
      maplng = chunk.split('=')[1];
     }
    }
    newlink = "http://www.mapquest.com/?saddr=" + maplat + ","
      + maplng + "&daddr=" + currentComment.lat + ","
      + currentComment.lng + "&zoom=10";
   } else
    continue;

   if (newlink != "") {
    var a = document.createElement('a');
    a.setAttribute('target', '_blank');
    a.setAttribute('href', newlink);
    a.appendChild(document.createTextNode('(incl. final)'));
    link.parentNode.appendChild(document.createTextNode(' '));
    link.parentNode.appendChild(a);
   }
  }
 }
}

function gccommentOnPrintPage() {
 log('debug', 'determining print page');
 setTimeout(function() {
  var hook = document.getElementById('Content');
  // log("debug", "print page: " + hook);
   if (hook == null) {
    log("debug", "gctour print page found");
    // setTimeout(function() {
    var overLay = document
      .getElementsByClassName('dark_msg_overlay')[0];

    if (overLay == null) { // kein overlay vorhanden? dann sofort
     gcTourPrintPage();
    } else { // overlay, erst warten, bis es weg ist und dann
     // rein
     overLay.addEventListener('DOMNodeRemoved', function(evt) {
      // log("info", "removed: " + evt);
       gcTourPrintPage();
      }, false);
    }
    // }, 100);
   } else {
    log("debug", "regular print page found");
    var actionString = document.getElementById('Form1')
      .getAttribute('action');
    currentCacheGUID = actionString.split('&')[0].split('=')[1];
    var comment = doLoadCommentFromGUID(currentCacheGUID);
    if (comment != null) {
     // add marker to map
     if (comment.lat && comment.lng) {
      var mapImg = document.getElementById('map');
      if (mapImg) {
       mapImg.setAttribute('src', addToGoogleMapsStatic(
         mapImg.getAttribute('src'), comment.lat,
         comment.lng, finalIconLink));
      }

      unsafeWindow.__imageResize = unsafeWindow.imageResize;
      unsafeWindow.imageResize = function(width, height) {
       unsafeWindow.__imageResize(width, height);
       var finalMarker = "&markers=color:green|label:F|icon:"
         + finalIconLink
         + "|"
         + comment.lat
         + ","
         + comment.lng;
       var mapImgSrc = mapImg.getAttribute('src').split(
         '&sensor');
       mapImg.setAttribute('src', mapImgSrc[0]
         + finalMarker + "&sensor" + mapImgSrc[1]);
      };
     }

     // add comment sortable
     var contentGroup = hook.lastChild;
     while ((contentGroup.nodeName.toLowerCase() != "div")
       && (contentGroup != null)) {
      contentGroup = contentGroup.previousSibling;
     }

     var commentDiv = document.createElement('div');
     commentDiv
       .setAttribute('class',
         'item ui-widget ui-widget-content ui-helper-clearfix');

     var headerDiv = document.createElement('div');
     headerDiv.setAttribute('class', 'item-header');
     var headText = "<span id='gccommentwidget' class='ui-icon ui-icon-minusthick'></span><h2>My GCComment";

     if (comment.lat && comment.lng)
      headText = headText + " (final at "
        + convertDec2DMS(comment.lat, comment.lng)
        + ")";

     headText = headText + "</h2>";
     headerDiv.innerHTML = headText;

     var contentDiv = document.createElement('div');
     contentDiv.setAttribute('class', 'item-content');
     contentDiv.innerHTML = comment.commentValue.replace(/\n/g,
       '<br/>');

     commentDiv.appendChild(headerDiv);
     commentDiv.appendChild(contentDiv);

     contentGroup.insertBefore(commentDiv,
       contentGroup.firstChild);
     unsafeWindow.$("#gccommentwidget").click(
       function() {
        unsafeWindow.$(this).toggleClass(
          "ui-icon-minusthick").toggleClass(
          "ui-icon-plusthick");
        unsafeWindow.$(this).parents(".item:first")
          .toggleClass("no-print").find(
            ".item-content").toggle();
       });

    }
   }
  }, 1000);
}

function gccommentOnManageLocations() {
 setTimeout(function() {
  var span = document.getElementById('LatLng');
  var coords = parseCoordinates(span.innerHTML);
  log('debug', coords.length);
  if (coords.length == 2) {
   GM_setValue('HOMELAT', "" + coords[0]);
   GM_setValue('HOMELNG', "" + coords[1]);
   log('info', 'stored new Home : ' + GM_getValue('HOMELAT') + " "
     + GM_getValue('HOMELNG'));
  }
 }, 2000);
}

function refreshTable(show) {
 if (commentTable) {
  commentTable.parentNode.removeChild(commentTable);
 }
 commentTable = document.createElement('table');
 commentTable.id = 'gccommentoverviewtable';
 if (!show) {
  commentTable.style.display = 'none';
 } else {
  commentTable.style.display = 'block';
  commentTable.setAttribute('style', 'table-layout:fixed;padding:5px');
 }
 commentTable.setAttribute('class', 'Table');

 var header = document.createElement('tr');
 var headeritem = document.createElement('th');
 headeritem.innerHTML = 'Cache';
 headeritem.setAttribute('style', 'width:200px');
 header.appendChild(headeritem);

 headeritem = document.createElement('th');
 headeritem.innerHTML = 'My comment & final coordinates';
 header.appendChild(headeritem);

 headeritem = document.createElement('th');
 headeritem.innerHTML = 'last save';
 headeritem.setAttribute('style', 'width:75px');
 header.appendChild(headeritem);

 headeritem = document.createElement('th');
 headeritem.innerHTML = 'Actions';
 headeritem.setAttribute('style', 'width:120px');
 header.appendChild(headeritem);
 commentTable.appendChild(header);

 var tr;
 var td_guid;
 var td_comment;
 var td_savetime;
 var td_action;

 var keys = GM_listValues();
 var counter = 0;
 var commentCountWhite = 0;
 var commentCountRed = 0;
 var commentCountGreen = 0;
 var commentCountGray = 0;
 for ( var ind = 0; ind < keys.length; ind++) {
  var commentKey = keys[ind];
  if (commentKey.indexOf(COMPREFIX) == -1)
   continue;

  tr = document.createElement('tr');
  var comment = doLoadCommentFromGUID(commentKey.substr(COMPREFIX.length));

  if (!comment.state || (comment.state == "undefined")
    || (comment.state == undefined))
   comment.state = stateOptions[0];

  if (comment.state == stateOptions[0])
   commentCountWhite++;
  else if (comment.state == stateOptions[1])
   commentCountRed++;
  else if (comment.state == stateOptions[2])
   commentCountGreen++;
  else if (comment.state == stateOptions[3])
   commentCountGray++;

  if (filter && (filter != comment.state))
   continue;

  if (counter++ % 2 == 0)
   tr.setAttribute('class', 'AlternatingRow');

  td_guid = document.createElement('td');
  var img = document.createElement('img');
  if (comment.state == stateOptions[1])
   img.src = state_unsolved;
  else if (comment.state == stateOptions[2])
   img.src = state_solved;
  else if (comment.state == stateOptions[3])
   img.src = state_found;
  else
   img.src = state_default;
  td_guid.appendChild(img);
  td_guid.appendChild(document.createTextNode(' '));

  var guid = commentKey.replace(/gccomment/, '');
  var link = document.createElement('a');
  link.href = 'http://www.geocaching.com/seek/cache_details.aspx?guid=' + guid;
  link.appendChild(document.createTextNode(comment.name + " ("
    + comment.gccode + ")"));
  td_guid.appendChild(link);
  if ((comment.lat != null) && (comment.lng != null)) {
   var haveFinal = document.createElement('img');
   haveFinal.setAttribute('src', finalIcon);
   haveFinal.setAttribute('width', '16px');
   haveFinal.setAttribute('height', '16px');
   haveFinal.setAttribute('style', 'margin-left:3px');
   haveFinal.setAttribute('title', 'I have the final coordinates :)');
   td_guid.appendChild(haveFinal);
  }
  tr.appendChild(td_guid);

  td_comment = document.createElement('td');
  var td_commentValue = "";
  if (comment.lat && comment.lng) {
   td_commentValue = td_commentValue + "Final at "
     + convertDec2DMS(comment.lat, comment.lng);
   if (GM_getValue('HOMELAT') && GM_getValue('HOMELNG')) {
    td_commentValue = td_commentValue
      + " ("
      + calculateDistance(GM_getValue('HOMELAT'),
        GM_getValue('HOMELNG'), comment.lat,
        comment.lng).toFixed(2) + "km from home)";
   }
   td_commentValue = td_commentValue + "</br>";
  }
  if (comment.commentValue) {
   td_commentValue = td_commentValue
     + "<p style='font-family:monospace;font-size:small'>"
     + comment.commentValue.replace(/\n/g, '<br/>') + "</p>";
  }
  td_comment.innerHTML = td_commentValue;
  tr.appendChild(td_comment);

  td_savetime = document.createElement('td');
  if (comment.saveTime)
   td_savetime.innerHTML = "<small>"
     + createTimeString(comment.saveTime) + "</small>";
  tr.appendChild(td_savetime);

  td_action = document.createElement('td');
  var action_del = document.createElement('a');
  var delImg = document.createElement('img');
  delImg.src = commentIconDelete;
  delImg.title = "Delete comment";
  action_del.appendChild(delImg);
  action_del.setAttribute('style', 'margin-right:3px');
  action_del.href = "#" + guid + "=del";
  action_del.addEventListener('click', function() {
   var check = confirm('Do you really want to delete this comment?');
   if (check) {
    var url = "" + this;
    var guid = url.split("#")[1].split("=")[0];
    var action = url.split("#")[1].split("=")[1];

    if (action == "del") {
     GM_deleteValue(COMPREFIX + guid);
    }
    refreshTable(true);
   }
  }, false);
  td_action.appendChild(action_del);

  var action_edit = document.createElement('a');
  var editimg = document.createElement('img');
  editimg.src = commentIconEdit;
  editimg.title = "Edit on Detail page";
  action_edit.appendChild(editimg);
  action_edit.setAttribute('style', 'margin-right:3px');
  action_edit.href = "http://www.geocaching.com/seek/cache_details.aspx?guid="
    + guid + "#mycomments";
  td_action.appendChild(action_edit);

  var action_markunsolved = document.createElement('a');
  var muimg = document.createElement('img');
  muimg.src = state_unsolved;
  muimg.title = "Mark cache as unsolved!";
  action_markunsolved.appendChild(muimg);
  action_markunsolved.setAttribute('style', 'margin-right:3px');
  action_markunsolved.href = "#" + guid + "=markunsolved";
  action_markunsolved.addEventListener('click', changeState, false);
  td_action.appendChild(action_markunsolved);

  var action_marksolved = document.createElement('a');
  var msimg = document.createElement('img');
  msimg.src = state_solved;
  msimg.title = "Mark cache as solved!";
  action_marksolved.appendChild(msimg);
  action_marksolved.setAttribute('style', 'margin-right:3px');
  action_marksolved.href = "#" + guid + "=marksolved";
  action_marksolved.addEventListener('click', changeState, false);
  td_action.appendChild(action_marksolved);

  var action_markfound = document.createElement('a');
  var mfimg = document.createElement('img');
  mfimg.src = state_found;
  mfimg.title = "Mark cache as found!";
  action_markfound.appendChild(mfimg);
  action_markfound.setAttribute('style', 'margin-right:3px');
  action_markfound.href = "#" + guid + "=markfound";
  action_markfound.addEventListener('click', changeState, false);
  td_action.appendChild(action_markfound);

  var action_markdefault = document.createElement('a');
  var mdefimg = document.createElement('img');
  mdefimg.src = state_default;
  mdefimg.title = "Mark cache as default!";
  action_markdefault.appendChild(mdefimg);
  action_markdefault.setAttribute('style', 'margin-right:3px');
  action_markdefault.href = "#" + guid + "=markdefault";
  action_markdefault.addEventListener('click', changeState, false);
  td_action.appendChild(action_markdefault);

  tr.appendChild(td_action);
  commentTable.appendChild(tr);
 }

 gccRoot.appendChild(commentTable);

 GM_setValue('countWhite', "" + commentCountWhite);
 GM_setValue('countRed', "" + commentCountRed);
 GM_setValue('countGreen', "" + commentCountGreen);
 GM_setValue('countGray', "" + commentCountGray);
}

function gcTourPrintPage() {
 log("info", 'weaving into gctour print page');
 var bodychilds = document.getElementsByTagName('body')[0].childNodes;
 for ( var i = 0; i < bodychilds.length; i++) {
  var child = bodychilds[i];
  if ((child.getAttribute('class') != null)
    && (child.getAttribute('class') == 'cacheDetail')) {
   var guid = child.getAttribute('id');
   if (guid != null) {
    var contentDiv = child.getElementsByTagName('div')[5];
    var waypointDiv = contentDiv.getElementsByTagName('div')[3];
    var savedComment = doLoadCommentFromGUID(guid);
    if (savedComment != null) {
     var mycomment = document.createElement('div');
     if ((savedComment.lat != null)
       && (savedComment.lng != null))
      mycomment.innerHTML = mycomment.innerHTML
        + "<b>Final coordinates</b><br/>"
        + convertDec2DMS(savedComment.lat,
          savedComment.lng) + "<br/>";
     mycomment.innerHTML = mycomment.innerHTML
       + "<b>My Comment: </b>"
       + savedComment.commentValue.replace(/\n/g, '<br/>');
     waypointDiv.parentNode.insertBefore(mycomment, waypointDiv);
    }
   }
  }
 }
}

// es wird eine Tabelle angezeigt (suchergebnis, profilseite, etc.).
// Tooltips werden hier eingewebt.
function addCommentBubblesToPage() {
 log("info", "weaving comments into table...");
 appendScript(
   'text',
   "var tooltip = function(){ "
     + "var id = 'tt'; "
     + "var top = 3; "
     + "var left = 3; "
     + "var maxw = 500; "
     + "var speed = 10; "
     + "var timer = 20; "
     + "var endalpha = 95; "
     + "var alpha = 0; "
     + "var tt,t,c,b,h; "
     + "var ie = document.all ? true : false; "
     + "return {  "
     + "show:function(v,w) {   "
     + "if(tt == null) {    "
     + "tt = document.createElement('div');    "
     + "tt.setAttribute('id',id);    "
     + "t = document.createElement('div');    "
     + "t.setAttribute('id',id + 'top');    "
     + "c = document.createElement('div');    "
     + "c.setAttribute('id',id + 'cont');    "
     + "b = document.createElement('div');    "
     + "b.setAttribute('id',id + 'bot');    "
     + "tt.appendChild(t);    "
     + "tt.appendChild(c);    "
     + "tt.appendChild(b);    "
     + "document.body.appendChild(tt);    "
     + "tt.style.opacity = 0;    "
     + "tt.style.filter = 'alpha(opacity=0)';    "
     + "document.onmousemove = this.pos;   "
     + "}   "
     + "tt.style.display = 'block';   "
     + "c.innerHTML = v;   "
     + "tt.style.width = w ? w + 'px' : 'auto';   "
     + "if(!w && ie){    "
     + "t.style.display = 'none';    "
     + "b.style.display = 'none';    "
     + "tt.style.width = tt.offsetWidth;    "
     + "t.style.display = 'block';    "
     + "b.style.display = 'block';   "
     + "}   "
     + "if(tt.offsetWidth > maxw){"
     + "tt.style.width = maxw + 'px'"
     + "}   "
     + "h = parseInt(tt.offsetHeight) + top;   "
     + "clearInterval(tt.timer);   "
     + "tt.timer = setInterval(function(){tooltip.fade(1)},timer);"
     + "},  "
     + "pos:function(e){   "
     + "var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;   "
     + "var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;   "
     + "tt.style.top = (u - h) + 'px';   "
     + "tt.style.left = (l + left) + 'px';  "
     + "},  "
     + "fade:function(d){   "
     + "var a = alpha;   "
     + "if((a != endalpha && d == 1) || (a != 0 && d == -1)){    "
     + "var i = speed;    "
     + "if(endalpha - a < speed && d == 1){     "
     + "i = endalpha - a;    "
     + "}else if(alpha < speed && d == -1){     "
     + "i = a;    "
     + "}    "
     + "alpha = a + (i * d);    "
     + "tt.style.opacity = alpha * .01;    "
     + "tt.style.filter = 'alpha(opacity=' + alpha + ')';   "
     + "}else{    "
     + "clearInterval(tt.timer);    "
     + "if(d == -1){tt.style.display = 'none'}   "
     + "}  "
     + "},  "
     + "hide:function(){   "
     + "clearInterval(tt.timer);   "
     + "tt.timer = setInterval(function(){tooltip.fade(-1)},timer);  "
     + "} };}();", null);

 var style = document.createElement('style');
 style.type = 'text/css';
 style.media = 'screen';
 style.innerHTML = '* {margin:0; padding:0}#text {margin:50px auto; width:500px}.hotspot {color:#900; padding-bottom:1px; border-bottom:1px dotted #900; cursor:pointer}#tt {position:absolute; display:block}#tttop {display:block; height:5px; margin-left:5px; overflow:hidden}#ttcont {display:block; padding:2px 12px 3px 7px; margin-left:5px; background:#666; color:#FFF}#ttbot {display:block; height:5px; margin-left:5px; overflow:hidden}';
 document.getElementsByTagName('head')[0].appendChild(style);

 var anchors = document.getElementsByTagName('a');
 var reg = /cache_details\.aspx\?guid=([^&]*)/;
 var previousAnchor = null;

 for ( var i = 0; i < anchors.length; i++) { // check all links
  var a = anchors[i];
  if (reg.exec(a.href)) { // anchor is a link to a cache
   if (a.href == previousAnchor) {
    continue;
   }
   previousAnchor = a.href;

   var guid = RegExp.$1;
   var comment = doLoadCommentFromGUID(guid);
   if (!comment
     || (!comment.commentValue && !comment.lat && !comment.lng))
    continue;

   var target = document.createElement('img');

   if (!comment.state)
    target.src = state_default;
   else {
    if (comment.state == stateOptions[1])
     target.src = state_unsolved;
    else if (comment.state == stateOptions[2])
     target.src = state_solved;
    else if (comment.state == stateOptions[3])
     target.src = state_found;
    else
     target.src = state_default;
   }

   target.width = '16';
   target.height = '16';
   target.alt = 'Comment available';
   target.addEventListener('mouseover', function(evt) {
    var targetNode = evt.relatedTarget;
    if (!targetNode)
     return;

    var cacheLink, commValue, cID;

    while (targetNode.nodeName.toLowerCase() != "td") {
     targetNode = targetNode.parentNode;
     if (!targetNode)
      break;
    }

    if (!targetNode || (targetNode.nodeName.toLowerCase() != "td"))
     return;

    var anchs = targetNode.getElementsByTagName('a');
    for ( var x = 0; x < anchs.length; x++) {
     if (reg.exec(anchs[x].getAttribute('href'))) {
      cacheLink = anchs[x];
      cID = RegExp.$1;
      commValue = doLoadCommentFromGUID(cID);
      if (!commValue) {
       targetNode.removeChild(tdElement
         .getElementsByTagName('img')[0]);
       return;
      }
      break;
     }
    }
    var commentTooltip = "<strong>My Comment</strong><br/>"
      + commValue.commentValue.replace(/\n/g, '<br/>');
    if ((commValue.lat != null) && (commValue.lng != null)) {
     commentTooltip = commentTooltip
       + "<br/><br/><strong>My Final coords</strong><br/>"
       + convertDec2DMS(commValue.lat, commValue.lng);
    }
    unsafeWindow.tooltip.show(commentTooltip, 400);
   }, false);
   target.setAttribute('onmouseout', 'tooltip.hide();');
   // if (a.parentNode.getElementsByTagName('br').length = 2)
   // a.parentNode.removeChild(a.parentNode
   // .getElementsByTagName('br')[1]);
   a.parentNode.appendChild(document.createTextNode(' '));
   a.parentNode.appendChild(target);
   // a.parentNode.insertBefore(target, a.nextSibling);
   target.style.display = 'inline';
  }
 }
}

// helper detailpage. formatiert die Zeit des letzten Speicherns und fügt es ein
function updateSaveTime(time) {
 var txt = "last saved: " + createTimeString(time);
 var newNode = document.createTextNode(txt);
 detailCommentLastSaveTime.parentNode.insertBefore(newNode,
   detailCommentLastSaveTime);
 detailCommentLastSaveTime.parentNode.removeChild(detailCommentLastSaveTime);
 detailCommentLastSaveTime = newNode;
}

function prepareTextPane(value) {
 var result = value;
 result = result.replace(/(http:\/\/\S*)/g, '<a href="$1">$1<\/a>');
 result = result.replace(/(https:\/\/\S*)/g, '<a href="$1">$1<\/a>');
 result = result.replace(/(file:\/\/\S*)/g, '<a href="$1">$1<\/a>');
 result = result.replace(/(ftp:\/\/\S*)/g, '<a href="$1">$1<\/a>');
 result = result.replace(/\n/g, '<br/>');
 return result;
}

function doSaveCommentWTimeToGUID(guid, gccode, name, commentValue, saveTime,
  state, lat, lng, origlat, origlng) {
 var key = COMPREFIX + guid;
 var value = gccode + DELIM + name + DELIM + commentValue + DELIM + saveTime
   + DELIM + state + DELIM + lat + DELIM + lng + DELIM + origlat
   + DELIM + origlng;
 var keyIndex = COMGCPREFIX + gccode;

 GM_setValue(key, value);
 // index entry for fast gccode-guid determination
 GM_setValue(keyIndex, guid);
 log("info", "saving " + key + " - " + value);
}

function doSaveCommentToGUID(guid, gccode, name, commentValue, state, lat, lng,
  origlat, origlng) {
 var now = new Date();
 doSaveCommentWTimeToGUID(guid, gccode, name, commentValue, now.getTime(),
   state, lat, lng, origlat, origlng);
}

function doLoadCommentFromGUID(guid) {
 var c = GM_getValue(COMPREFIX + guid);
 // log("info", "loaded: " + c);
 if (!c)
  return null;
 var details = c.split(DELIM);
 var comment = new Object();
 comment.guid = guid;
 comment.gccode = details[0];
 comment.name = details[1];
 comment.commentValue = details[2];
 comment.saveTime = details[3];
 comment.state = details[4];
 if ((details[5] != "undefined") && (details[5] != "null")
   && (details[5] != ""))
  comment.lat = details[5];
 if ((details[6] != "undefined") && (details[6] != "null")
   && (details[6] != ""))
  comment.lng = details[6];
 if ((details[7] != "undefined") && (details[7] != "null")
   && (details[7] != ""))
  comment.origlat = details[7];
 if ((details[8] != "undefined") && (details[8] != "null")
   && (details[8] != ""))
  comment.origlng = details[8];
 return comment;
}

function doLoadCommentFromGCCode(gcCode) {
 var guid = getGUIDFromGCCode(gcCode);
 return doLoadCommentFromGUID(guid);
}

function editComment() {
 AddComment.style.display = 'none';
 detailCommentCacheState.removeAttribute('disabled');
 SaveComment.style.display = 'inline';
 detailCommentTextPane.style.display = 'none';
 detailCommentTextArea.style.display = 'block';
 detailCommentInputLatLng.removeAttribute("disabled");
 if (currentComment)
  detailCommentTextArea.value = currentComment.commentValue;
 EditComment.style.display = 'none';
 EditCancelComment.style.display = 'inline';
 setTimeout(function() {
  detailCommentTextArea.focus();
 }, 50);
}

function saveFinalCoords() {
 var cstr = detailFinalInputLatLng.value;
 detailCommentCacheState.options.selectedIndex = detailFinalCacheState.options.selectedIndex;

 var error = "";
 if (cstr == DEFAULTCOORDS) {
  if (currentComment != null)
   doSaveCommentToGUID(
     currentCacheGUID,
     currentComment.gccode,
     currentComment.name,
     currentComment.commentValue,
     detailFinalCacheState.options[detailFinalCacheState.options.selectedIndex].value,
     null, null, currentComment.origlat, currentComment.origlng);
  else { // save new
   doSaveCommentToGUID(
     currentCacheGUID,
     currentCacheCode,
     currentCacheName,
     " ",
     detailFinalCacheState.options[detailFinalCacheState.options.selectedIndex].value,
     null, null, currentCommentOrigLat, currentCommentOrigLng);
  }
  currentComment = doLoadCommentFromGUID(currentCacheGUID);
  detailCommentInputLatLng.value = DEFAULTCOORDS;
  detailFinalInputLatLng.value = DEFAULTCOORDS;
  // log('info', 'deleted final coords');
  // error = "default coords!";
 } else {
  var fin = parseCoordinates(cstr);
  if (fin.length == 2) {
   if (currentComment == null) {
    detailCommentInputLatLng.value = cstr;
    saveComment();
   } else {
    doSaveCommentToGUID(
      currentCacheGUID,
      currentComment.gccode,
      currentComment.name,
      currentComment.commentValue,
      detailFinalCacheState.options[detailFinalCacheState.options.selectedIndex].value,
      fin[0], fin[1], currentCommentOrigLat,
      currentCommentOrigLng);
   }
   currentComment = doLoadCommentFromGUID(currentCacheGUID);
   var clean = convertDec2DMS(currentComment.lat, currentComment.lng);
   detailCommentInputLatLng.value = clean;
   detailFinalInputLatLng.value = clean;
   // saveComment();
   // detailCommentInputLatLng.value = cstr;
   // log("info", "coordinatestring: " + cstr);
  } else {
   error = fin[0];
  }
 }

 if (error == "") {
  // unsafeWindow.insertFinalMarker(lat, lng);
  SaveFinalCoords.parentNode.appendChild(waitingTag);
  waitingTag.setAttribute('style', 'display:inline');
  waitingTag.setAttribute("src", successIcon);
  setTimeout(function() {
   unsafeWindow.$("#waiting").fadeOut('slow', function() {
   });
  }, 5000);

  // if (document.getElementById('gctidy-small-map-link')) {
  if (typeof unsafeWindow.GCTidyWaypoints == "object") {
   var finalwpt = {
    lat : currentComment.lat,
    lng : currentComment.lng,
    type : 'Trailhead',
    title : 'Final Location',
    html : '<div class=\"gctidy-waypoint-infowindow-text\"><p class=\"gctidy-waypoint-cache-title\"><img src=\"' + finalIcon + '\"> <strong>Final!</strong></p></div>'
   };
   unsafeWindow.GCTidyWaypoints.push(finalwpt);
  }
 } else {
  log("info", "parsing failed (" + error + ")");
  SaveFinalCoords.parentNode.appendChild(waitingTag);
  waitingTag.setAttribute('style', 'display:inline');
  waitingTag.setAttribute("src", errorIcon);
  setTimeout(function() {
   unsafeWindow.$("#waiting").fadeOut('slow', function() {
   });
  }, 5000);
 }
}

function saveComment() {
 var fin = parseCoordinates(detailCommentInputLatLng.value);
 var finlat, finlng;
 if (fin.length == 2) {
  finlat = fin[0];
  finlng = fin[1];
 } else if (detailCommentInputLatLng.value != DEFAULTCOORDS) {
  alert('Coordinates could not be parsed. Please correct them before saving.\nError Message:' + fin[0]);
  return;
 }
 detailFinalCacheState.options.selectedIndex = detailCommentCacheState.options.selectedIndex;

 detailCommentCacheState.setAttribute('disabled', '');
 detailCommentTextArea.style.display = 'none';
 SaveComment.style.display = 'none';
 EditCancelComment.style.display = 'none';
 detailCommentTextPane.innerHTML = prepareTextPane(detailCommentTextArea.value);
 detailCommentTextPane.style.display = 'inline';
 detailCommentInputLatLng.setAttribute("disabled", "");
 if ((detailCommentTextArea.value == "")
   && (detailCommentInputLatLng.value == DEFAULTCOORDS)) {
  AddComment.style.display = 'inline';
  EditComment.style.display = 'none';
  DeleteComment.style.display = 'none';
  GM_deleteValue(COMPREFIX + currentCacheGUID);
  updateSaveTime(-1);
  currentComment = null;
  detailCommentCacheState.options.selectedIndex = 0;
 } else {
  AddComment.style.display = 'none';
  EditComment.style.display = 'inline';
  DeleteComment.style.display = 'inline';
  updateSaveTime(new Date().getTime());
  doSaveCommentToGUID(
    currentCacheGUID,
    currentCacheCode,
    currentCacheName,
    detailCommentTextArea.value,
    detailCommentCacheState.options[detailCommentCacheState.options.selectedIndex].value,
    finlat, finlng, currentCommentOrigLat, currentCommentOrigLng);
  currentComment = doLoadCommentFromGUID(currentCacheGUID);
  var clean = DEFAULTCOORDS;
  if (currentComment.lat && currentComment.lng) {
   clean = convertDec2DMS(currentComment.lat, currentComment.lng);
  }
  detailCommentInputLatLng.value = clean;
  detailFinalInputLatLng.value = clean;
 }
}

function changeState() {
 var url = "" + this;
 var guid = url.split("#")[1].split("=")[0];
 var action = url.split("#")[1].split("=")[1];

 var comment = doLoadCommentFromGUID(guid);

 if (!comment)
  return;

 if (action == "markunsolved") {
  doSaveCommentToGUID(guid, comment.gccode, comment.name,
    comment.commentValue, stateOptions[1], comment.lat,
    comment.lng, comment.origlat, comment.origlng);
 } else if (action == "marksolved") {
  doSaveCommentToGUID(guid, comment.gccode, comment.name,
    comment.commentValue, stateOptions[2], comment.lat,
    comment.lng, comment.origlat, comment.origlng);
 } else if (action == "markfound") {
  doSaveCommentToGUID(guid, comment.gccode, comment.name,
    comment.commentValue, stateOptions[3], comment.lat,
    comment.lng, comment.origlat, comment.origlng);
 } else
  doSaveCommentToGUID(guid, comment.gccode, comment.name,
    comment.commentValue, stateOptions[0], comment.lat,
    comment.lng, comment.origlat, comment.origlng);

 refreshTable(true);
}

// ***
// *** MysteryMover
// ***
function mysteryMoverOnMapPage() {
 unsafeWindow.__loadCachesFromJSON = unsafeWindow.loadCachesFromJSON;
 unsafeWindow.loadCachesFromJSON = function(a) {
  unsafeWindow.__loadCachesFromJSON(a);

  setTimeout(function() {
   var amm = document.getElementById('autoMoveMysteries');
   document.getElementsByTagName('body')[0].appendChild(document
     .createTextNode('checker: ' + amm.checked));
   if ((amm != null) && (amm.checked)) {
    var elem = document.getElementById('mysterymoverlink');
    var event = document.createEvent("MouseEvents");
    event.initEvent("click", true, false);
    elem.dispatchEvent(event);
   }
  }, 500);
 };

 unsafeWindow.__cacheTableMouseOut = unsafeWindow.cacheTableMouseOut;
 unsafeWindow.cacheTableMouseOut = function(a) {
  unsafeWindow.__cacheTableMouseOut(a);
  if ((typeof unsafeWindow.mrks[a].gccommentImage != undefined)
    && unsafeWindow.mrks[a].gccommentImage) {
   unsafeWindow.mrks[a].setImage(unsafeWindow.mrks[a].gccommentImage);
  }
 };
 unsafeWindow.__cacheTableMouseOver = unsafeWindow.cacheTableMouseOver;
 unsafeWindow.cacheTableMouseOver = function(a) {
  unsafeWindow.__cacheTableMouseOver(a);
  if ((typeof unsafeWindow.mrks[a].gccommentImage != undefined)
    && unsafeWindow.mrks[a].gccommentImage) {
   unsafeWindow.mrks[a].setImage(unsafeWindow.cm_hvr);
  }
 };

 var move = "var movedMysteryIcon = 'data:image/gif;base64,R0lGODlhCQAZAOYAAA/tDw/sDw/oDw/mDw7lDg7kDg7bDg7ZDgzFDAy/DAy+DAuyCw7jDg7iDg7hDg3TDQ3RDQzDDAu1CwqlCgqjCg/rDw/nDw7eDg7dDg7aDg7YDg7XDg7WDg3PDQ3ODQ3NDQ3MDQ3IDQ3HDQzADAy8DAy7DAy3DAuvCwuqCwumCwqbCgqYChHtERPtExTtFBfuFxruGhzuHCHuISbvJifvJynvKSzvLDfwNzjwOD3wPUTxRGDzYHb1dnf1d3j1eHr1en31fX71foz2jJ34naP4o6v5q7f6t7z6vML6wv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEkALAAAAAAJABkAAAeVgEmCSUSDg0NHRToEhj1GRTIHgwE5QDsDHwmCDBU4LxgREoIGBDABGQkLgw0sAQcKhgwurrCDBTEAB5qDAzO5u4ICNrm1SQ4CNQEcJIMXBC0CECaDGgYFGAgnhiAeIgsphiEIJSiGggcd5uqGQkhBA+Y8Rz8FD4MWND43BwiDBwYONoxQJQhEhFQTKBhaMEHFinXmAgEAOw==';";
 move = move
   + "var cm = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURUrnIjT8ATj5CDb+BP///zP/ANLS0v///zHaLKsAAAAIdFJOU/////////8A3oO9WQAAAFFJREFUeNrk0VEOwCAIA1CwdNz/xqvRLEbxBOsfD76oZSa3iKxjY3zRoIV4xblIg8cR0thOhpj1dcHxC76/CgU7ew27GkdpWEuD8xGXFb8CDAD8WAgNrkSa2QAAAABJRU5ErkJggg==';";
 move = move
   + "var cm_hvr = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURd+3t1rvKUvzGT74C+PAwDP/ADj8Bf///4LPUpoAAAAIdFJOU/////////8A3oO9WQAAAE5JREFUeNrc0dsNACAIA0AQlP03ViG+gAns5zUh0YKIVJdBEFAL48I7xfjFVUxml6YMnjFn/pExf3zzTPaDGG5UnYGuAuisk4yWTtwFGAAPCwgiHEofAAAAAABJRU5ErkJggg==';";
 move = move
   + "var cm_dis = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAYUExURczMzDP/AD/+DzP9ADT2AzP9ATT8Av////A+tykAAAAIdFJOU/////////8A3oO9WQAAAEdJREFUeNpiYGdnZ2RjYWZEAkAhBnYwiwEOQDwmiDADCgCpZ0AXhEhQQZhhRAiTFiasjKBowFSMPdJAwsAoZmFkRItigAADABeaARPvgIzyAAAAAElFTkSuQmCC';";
 move = move + "function doMove(lat, lng, id) {"
   + "mrks[id].setLatLng(new GLatLng(lat, lng));"
   + "mrks[id].setImage(cm);" + "mrks[id].gccommentImage = cm;"
   + "GEvent.clearListeners(mrks[id], 'mouseover');"
   + "GEvent.clearListeners(mrks[id], 'mouseout');"
   + "GEvent.addListener(mrks[id], 'mouseover', function() {"
   + "mrks[id].setImage(cm_hvr);"
   + "$('ctRow' + id).className = 'yHover';});"
   + "GEvent.addListener(mrks[id], 'mouseout', function() {"
   + "if (mrks[id].isAvailable == true) {"
   + " mrks[id].setImage(cm);$('ctRow' + id).className = '';"
   + "} else {"
   + "mrks[id].setImage(cm_dis);$('ctRow' + id).className = '';"
   + "}});" + "}";

 appendScript("text", move, null);

 var chkShowNumbers = document.getElementById("chkShowNumbers");
 if (chkShowNumbers != null) {
  var mmSpan = document.createElement('span');
  var mysterymoverAnchor = document.createElement("a");
  addEvent(mysterymoverAnchor, "click", function() {
   setTimeout(moveMysteries, 0);
  });
  mysterymoverAnchor.id = "mysterymoverlink";
  mysterymoverAnchor.setAttribute('href', "#");
  mysterymoverAnchor.appendChild(document
    .createTextNode("Move Mysteries"));
  var mmImg = document.createElement('img');
  mmImg.setAttribute('src', moveMysteriesIcon);
  mmImg.setAttribute('style', 'margin-right:3px');

  var mmOption = document.createElement('input');
  mmOption.setAttribute('id', 'autoMoveMysteries');
  mmOption.setAttribute('type', 'checkbox');
  mmOption.setAttribute('class', 'Checkbox');
  mmOption.addEventListener('click', function() {
   var amm = GM_getValue(AUTOMOVEMYSTERIES);
   GM_setValue(AUTOMOVEMYSTERIES, "" + (amm + 1) % 2);
  }, false);
  var amm = GM_getValue(AUTOMOVEMYSTERIES);
  if (amm == 1)
   mmOption.setAttribute('checked', 'checked');

  var mmOptionLabel = document.createElement('label');
  mmOptionLabel.setAttribute('for', 'autoMoveMysteries');
  if (document.getElementById('gctidy-open-configuration'))
   mmOptionLabel.appendChild(document.createTextNode('Automatically'));
  else
   mmOptionLabel.appendChild(document.createTextNode(' auto'));

  mmSpan.appendChild(mmImg);
  mmSpan.appendChild(mysterymoverAnchor);
  mmSpan.appendChild(document.createTextNode(' ('));
  mmSpan.appendChild(mmOption);
  mmSpan.appendChild(mmOptionLabel);
  mmSpan.appendChild(document.createTextNode(')'));

  chkShowNumbers.parentNode.insertBefore(mmSpan, chkShowNumbers);
  chkShowNumbers.parentNode.insertBefore(document.createElement('br'),
    chkShowNumbers);
 }
}

function mysteryMoverOnBetaMap() {
 // @TODO GS icons change at less that zoom level 14
 var move = "var movedMysteryIcon = 'data:image/gif;base64,R0lGODlhCQAZAOYAAA/tDw/sDw/oDw/mDw7lDg7kDg7bDg7ZDgzFDAy/DAy+DAuyCw7jDg7iDg7hDg3TDQ3RDQzDDAu1CwqlCgqjCg/rDw/nDw7eDg7dDg7aDg7YDg7XDg7WDg3PDQ3ODQ3NDQ3MDQ3IDQ3HDQzADAy8DAy7DAy3DAuvCwuqCwumCwqbCgqYChHtERPtExTtFBfuFxruGhzuHCHuISbvJifvJynvKSzvLDfwNzjwOD3wPUTxRGDzYHb1dnf1d3j1eHr1en31fX71foz2jJ34naP4o6v5q7f6t7z6vML6wv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEkALAAAAAAJABkAAAeVgEmCSUSDg0NHRToEhj1GRTIHgwE5QDsDHwmCDBU4LxgREoIGBDABGQkLgw0sAQcKhgwurrCDBTEAB5qDAzO5u4ICNrm1SQ4CNQEcJIMXBC0CECaDGgYFGAgnhiAeIgsphiEIJSiGggcd5uqGQkhBA+Y8Rz8FD4MWND43BwiDBwYONoxQJQhEhFQTKBhaMEHFinXmAgEAOw==';";
 move = move
   + "var origfound = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACaSURBVHja7JXLCoAgEEWdiGjpB4WL6KsjAsWvimhKYdAMgny0iO5qBOfMYzEXEJGRlFLuESEhBFAMBuwD12ph9dacPt3J5FKOX6AOgX03QEyXYQGQUmI4Ropo+oq6zS0L9veTFZxTtNLs4GId/+Af/AXwO0eoyCrstT+u26wnTIVNesSLgxi4b1FPrInihrWMc+48r4SZ7gIMANPlS6BG6nS1AAAAAElFTkSuQmCC';";
 move = move
   + "var origsolved= 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAC7SURBVHja7JVLDsIwDETtNkDPwT6rIsQZuCQHghUcgivwS4Y6yCUIKVKp2fVJaaZSPflUGjMAUlbE75cfOBBYNYtxbji7NXSfXz4+KiG1WpMv0BsPNSwtkIzX0SHGQPs6Mhmgp68CP8iFBVlRw6W5kkd+P2ORjfbGlug/MjdWJuPJeDIuhZBmsHkIqbBCIjghQd+CsLk2ED1mbM9LtEniuzXJCST6hrQmqZGddoJ2pyN571+t6R/N9CnAAC9tlQThla5PAAAAAElFTkSuQmCC';";
 move = move
   + "var finaliconfound = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAFRSURBVHjaYvz//z8DDBw6dAjBIQPY2dkxwtiMIIOxGQhURJRhQL1YLWAh10B09RgWHDx48D8Iw8DGvaf/5zfPBdNgMK/tPykAZh4LLpfsO3aJwWOnKwPbjG8MDAUNYLFfGVxgmk2jDKEwsRKrfiZCXoUZBjYQZAlI7EYXGIMt5GdnYJjfzvDm3j38BlspCJGeHIAWiBxciRLmGAaLKCnB2WW8vRhmwFyN4Su0IMEaFDKy0kQ5FB7mne+JC2M1WWGc4YziemAkvjl/Hasc1lTh52QCThX4wKf0s+BgE8EhjzNVwIIDPZxBLgR5HTkuSDIYPTgYJjSADSVkIN6ggCW7fceI8zZJLkZ22bEH70hO2nhznpOVHjx7U9VglEhDy7KEilG8BoOSHbnBQdDFsGR36/FbkgxGqUGwFfKgIIC5FtkH+IIBVIPQrGpipFVlChBgAFhG0uUgufqcAAAAAElFTkSuQmCC';";
 move = move
   + "var finaliconsolved = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJtSURBVHjanFU7axRRFP7uncc+shtfK1toQFKI22hjlTKgWR8ICv4AK+1MFbALCIqCkDKNWttEUiUWBmy2EREsjAgbBK2S9ZHd2ZnZ2Zl7nLnrzL5m9uEHw1zuOfe753733HMYESFE2WImU5ARJgQJcCSA/fvLlRxCyYKTB2s7Q9nIJyC+4rCGaCHFPa7NUhF25hCb6SYmwU17Brozi7qyDyFEm+twtlKUk8RLDebk2yc1L2fhtd7A/+CWkwevZ2Gk9tvbedJx3WDW1QOVQmy+fU/3Hz6Xf4kXj2galA9VKjdhqa5G6WNucSiCnconlN9cgr5uAsurcs6515FQP7fSdbzzoG9dTtNhKG5aXpCZ/pN4xJBMEgabBHNfnspPbngkBbx8jNrenrR5CodnoHPznHWJFs4cn15gf4PCu1dyuBHcEWPDKVWYn4/GK/lnQxxh1EOn6pGEa9QhpgHH03OnJgo00vzJ77550fYjZmx4wdm5E4k690XvX2Lt426sTe19SSFuLF6UWTEK9bsfpGyFGJuUgih+YSjHoM5BhMHRe+9iECSlSDAOyoG1VUk6ihA9NURNMgZpt1MZf+wkcIrJisG0q3z7NXVq81HGxYXz0fOeBiwipvHO4ZMdW0b9KhdUTJnHGftorFOQdtPKoQoBJedHrDrMtmw70TFMu6/ff05EbJsu4MKWYS/V4dyuFWPr60G1KmtzVJ9HYLl6jS77XAFnpzW1mEEOdE6qllV1v4kxbKSMCTtHDtwjtCwXjua013583i2VShdYXzM1mcVVpN0miPmbMi0sKjFNtJsCpM74AfrH38pSJpz+K8AAGeJxOI+fpJMAAAAASUVORK5CYII=';";
 move = move
   + "var commentMarkers = new Array();"
   + "function doMoveBeta(lat, lng, name, origlat, origlng, guid, comment, state, home, wptid) {"
   + "var finalicon = null;"
   + "var linecolor = null;"
   + "var orig = null;"
   + "if (state == 'found'){"
   + "finalicon = finaliconfound;"
   + "linecolor = '#cccccc';"
   + "orig = origfound;"
   + "}else{"
   + "finalicon = finaliconsolved;"
   + "linecolor = '#66ff00';"
   + "orig = origsolved;}"
   + "var latlng = new google.maps.LatLng(lat, lng);"
   + "var marker = new google.maps.Marker({"
   + "position:latlng,"
   + "title:name, icon:new google.maps.MarkerImage(finalicon, null,null, new google.maps.Point(11,11))});"
   + "marker.setMap(map);"
   + "commentMarkers.push(marker);"
   + "if (origlat && origlng && home) {"
   + "var linepath = new Array();"
   + "var finalLatLng = new google.maps.LatLng(lat, lng);"
   + "var origLatLng = new google.maps.LatLng(origlat, origlng);"
   + "linepath.push(finalLatLng);"
   + "linepath.push(origLatLng);"
   + "var distance = google.maps.geometry.spherical.computeDistanceBetween(finalLatLng, origLatLng);"
   + "var line = new google.maps.Polyline();"
   + "line.setPath(linepath);"
   + "line.setMap(map);"
   + "line.setOptions({path:linepath, strokeWeight:'2',map:map,strokeColor:linecolor});"
   + "commentMarkers.push(line);"
   + "var origlatlng = new google.maps.LatLng(origlat, origlng);"
   + "var origImage = new google.maps.MarkerImage(orig, null, null,new google.maps.Point(11,11));"
   + "var origMarker = new google.maps.Marker({position:origlatlng,icon:origImage,map:map,clickable:false});"
   + "commentMarkers.push(origMarker);}"
   + "var infowindow = new google.maps.InfoWindow({"
   + "content: '<img src=\"'+finalicon+'\"/> <a href=\"http://www.geocaching.com/seek/cache_details.aspx?guid='+guid+'\" target=\"blank\">'+name+'</a><br/><h3>Your comment for this <u>'+state+'</u> cache:</h3><p>'+comment+'</p>Distance: '+parseInt(distance) + 'm'});"
   + "google.maps.event.addListener(marker, 'click', function() {"
   + "infowindow.open(map, marker);"
   + "var url='map/beta/map.details?wptid='+wptid + userSession.getMapInfoPackage();"
   + "$.getJSON(url, function(k) {"
   + "var content = $('#cacheDetailsTemplate').tmpl(k)[0];"
   + "var div = document.createElement('div');"
   + "div.innerHTML = '<h3>GCComment for this <u>'+state+'</u> cache (Distance: '+parseInt(distance) + 'm)</h3><p style=\"font-family:monospace;font-size:x-small\">'+comment+'</p>';"
   + "content.appendChild(div);" + "infowindow.setContent(content);"
   + "});"
   + "google.maps.event.addListener(map, 'click', function() {"
   + "infowindow.close();})});" + "}"

   + "function showCachedMarkers() {"
   + "for (var i = 0; i < commentMarkers.length; i++) {"
   + "commentMarkers[i].setMap(map);}" + "}"

   + "function removeCommentMarkers() {"
   + "for (var i = 0; i < commentMarkers.length; i++) {"
   + "commentMarkers[i].setMap(undefined);" + "}"
   + "commentMarkers = new Array();" + "}";

 appendScript("text", move, null);

 var stm_myCaches = document.getElementById("stm_myCaches");
 if (stm_myCaches != null) {
  var mmDiv = document.createElement('div');

  var mysterymoverAnchor = document.createElement("a");
  // addEvent(mysterymoverAnchor, "click", function() {
  // setTimeout(moveMysteriesBeta, 0);
  // });
  mysterymoverAnchor.id = "mysterymoverlink";
  mysterymoverAnchor.setAttribute('href', "#");
  mysterymoverAnchor.appendChild(document
    .createTextNode("Move Mysteries"));
  var mmImg = document.createElement('img');
  mmImg.setAttribute('src', moveMysteriesIcon);
  mmImg.setAttribute('style', 'margin-right:3px');

  var mmOption = document.createElement('input');
  mmOption.setAttribute('id', 'autoMoveMysteriesBeta');
  mmOption.setAttribute('type', 'checkbox');
  mmOption.setAttribute('class', 'Checkbox');
  mmOption
    .addEventListener(
      'click',
      function() {
       var input = document
         .getElementById('autoMoveMysteriesBeta');
       if (input != null) {
        var checked = input.getAttribute('checked') == "checked";
        if (checked) {
         input.removeAttribute('checked');
         unsafeWindow.removeCommentMarkers();
         GM_setValue(AUTOMOVEMYSTERIESBETA, 0);
        } else {
         input.setAttribute('checked', 'checked');
         GM_setValue(AUTOMOVEMYSTERIESBETA, 1);
         moveMysteriesBeta(
           mmSubSolvedOption
             .getAttribute('checked') == "checked",
           mmSubFoundOption
             .getAttribute('checked') == "checked",
           mmSubShowHomeOption
             .getAttribute('checked') == "checked");
        }
       }
      }, false);
  var mmOptionLabel = document.createElement('label');
  mmOptionLabel.setAttribute('for', 'autoMoveMysteriesBeta');
  mmOptionLabel.appendChild(document
    .createTextNode(' Enable Mystery Mover'));

  var mmSub = document.createElement('div');
  mmSub.setAttribute('id', 'mmSub');
  mmSub.setAttribute('style', 'display:none');
  var mmSubSolvedOption = document.createElement('input');
  mmSubSolvedOption.setAttribute('id', 'mmSubSolvedOption');
  // mmSubSolvedOption.setAttribute('checked', 'checked');
  mmSubSolvedOption.setAttribute('type', 'checkbox');
  mmSubSolvedOption.setAttribute('class', 'Checkbox');
  mmSubSolvedOption.setAttribute('style', 'margin-left:20px');
  mmSubSolvedOption
    .addEventListener('click',
      function() {
       var solved = mmSubSolvedOption
         .getAttribute('checked') == "checked";
       var found = mmSubFoundOption
         .getAttribute('checked') == "checked";
       var home = mmSubShowHomeOption
         .getAttribute('checked') == "checked";

       if (solved) {
        mmSubSolvedOption.removeAttribute('checked');
        GM_setValue(AUTOMOVEMYSTERIESBETASOLVED, 0);
       } else {
        mmSubSolvedOption.setAttribute('checked',
          'checked');
        GM_setValue(AUTOMOVEMYSTERIESBETASOLVED, 1);
       }
       moveMysteriesBeta(!solved, found, home);
      }, false);
  mmSub.appendChild(mmSubSolvedOption);
  var mmSubSolvedLabel = document.createElement('label');
  mmSubSolvedLabel.setAttribute('for', 'mmSubSolvedOption');
  mmSubSolvedLabel.appendChild(document
    .createTextNode(' Show solved caches '));
  mmSub.appendChild(mmSubSolvedLabel);
  var solvedImg = document.createElement('img');
  solvedImg.setAttribute('src', state_solved);
  mmSub.appendChild(solvedImg);
  mmSub.appendChild(document.createElement('br'));

  var mmSubFoundOption = document.createElement('input');
  mmSubFoundOption.setAttribute('id', 'mmSubFoundOption');
  // mmSubFoundOption.setAttribute('checked', 'checked');
  mmSubFoundOption.setAttribute('type', 'checkbox');
  mmSubFoundOption.setAttribute('class', 'Checkbox');
  mmSubFoundOption.setAttribute('style', 'margin-left:20px');
  mmSubFoundOption
    .addEventListener('click',
      function() {
       var found = mmSubFoundOption
         .getAttribute('checked') == "checked";
       var solved = mmSubSolvedOption
         .getAttribute('checked') == "checked";
       var home = mmSubShowHomeOption
         .getAttribute('checked') == "checked";
       if (found) {
        mmSubFoundOption.removeAttribute('checked');
        GM_setValue(AUTOMOVEMYSTERIESBETAFOUND, 0);
       } else {
        mmSubFoundOption.setAttribute('checked',
          'checked');
        GM_setValue(AUTOMOVEMYSTERIESBETAFOUND, 1);
       }
       moveMysteriesBeta(solved, !found, home);
      }, false);
  mmSub.appendChild(mmSubFoundOption);
  var mmSubFoundLabel = document.createElement('label');
  mmSubFoundLabel.setAttribute('for', 'mmSubFoundOption');
  mmSubFoundLabel.appendChild(document
    .createTextNode(' Show found caches '));
  mmSub.appendChild(mmSubFoundLabel);
  var foundImg = document.createElement('img');
  foundImg.setAttribute('src', state_found);
  mmSub.appendChild(foundImg);
  mmSub.appendChild(document.createElement('br'));

  var mmSubShowHomeOption = document.createElement('input');
  mmSubShowHomeOption.setAttribute('id', 'mmSubShowHomeOption');
  // mmSubShowHomeOption.setAttribute('checked', 'checked');
  mmSubShowHomeOption.setAttribute('type', 'checkbox');
  mmSubShowHomeOption.setAttribute('class', 'Checkbox');
  mmSubShowHomeOption.setAttribute('style', 'margin-left:20px');
  mmSubShowHomeOption
    .addEventListener('click',
      function() {
       var found = mmSubFoundOption
         .getAttribute('checked') == "checked";
       var solved = mmSubSolvedOption
         .getAttribute('checked') == "checked";
       var home = mmSubShowHomeOption
         .getAttribute('checked') == "checked";
       if (home) {
        mmSubShowHomeOption.removeAttribute('checked');
        GM_setValue(AUTOMOVEMYSTERIESBETAHOME, 0);
       } else {
        mmSubShowHomeOption.setAttribute('checked',
          'checked');
        GM_setValue(AUTOMOVEMYSTERIESBETAHOME, 1);
       }
       moveMysteriesBeta(solved, found, !home);
      }, false);
  mmSub.appendChild(mmSubShowHomeOption);
  var mmSubShowHomeLabel = document.createElement('label');
  mmSubShowHomeLabel.setAttribute('for', 'mmSubShowHomeOption');
  mmSubShowHomeLabel.appendChild(document
    .createTextNode(' Show link to home'));
  mmSub.appendChild(mmSubShowHomeLabel);

  mmOption.addEventListener('click', function() {
   if (mmSub.getAttribute('style') == "display:none")
    mmSub.setAttribute('style', 'display:block');
   else
    mmSub.setAttribute('style', 'display:none');
  }, false);

  var ammbeta = GM_getValue(AUTOMOVEMYSTERIESBETA);
  var ammfound = GM_getValue(AUTOMOVEMYSTERIESBETAFOUND);
  var ammsolved = GM_getValue(AUTOMOVEMYSTERIESBETASOLVED);
  var ammhome = GM_getValue(AUTOMOVEMYSTERIESBETAHOME);

  mmDiv.appendChild(mmOption);
  mmDiv.appendChild(mmOptionLabel);
  mmDiv.appendChild(mmSub);

  // stm_myCaches.appendChild(document.createElement('br'));
  stm_myCaches.getElementsByTagName('div')[0].appendChild(mmDiv);

  if (ammfound == 1)
   mmSubFoundOption.setAttribute('checked', 'checked');
  if (ammsolved == 1)
   mmSubSolvedOption.setAttribute('checked', 'checked');
  if (ammhome == 1)
   mmSubShowHomeOption.setAttribute('checked', 'checked');
  if (ammbeta == 1) {
   waitForMapAndClick();
  }
 }
}

function waitForMapAndClick() {
 if (unsafeWindow.map == null) {
  setTimeout(waitForMapAndClick, 300);
 } else {
  var event = document.createEvent("MouseEvents");
  event.initEvent("click", true, false);
  document.getElementById('autoMoveMysteriesBeta').dispatchEvent(event);
 }
}

var cachedMarkers = false;
function moveMysteriesBeta(solved, found, home) {
 // log("info", "moving mysteries beta ... " + solved + ":" + found);

 var stSolved = null;
 if (solved)
  stSolved = stateOptions[2];

 var stFound = null;
 if (found)
  stFound = stateOptions[3];

 // @TODO remove for performance
 unsafeWindow.removeCommentMarkers();

 if (!cachedMarkers) {
  var keys = GM_listValues();
  for ( var i = 0; i < keys.length; i++) {
   var key = keys[i];
   if (key.indexOf(COMPREFIX) > -1) {
    var guid = key.substring(COMPREFIX.length, key.length);
    var comment = doLoadCommentFromGUID(guid);
    if (((comment.state == stSolved) || (comment.state == stFound))
      && ((comment.lat != undefined) && (comment.lng != undefined))) {
     // log('debug', "doMoveBeta(" + comment.lat + ", "
     // + comment.lng + ", " + comment.name + ", "
     // + comment.origlat + ", " + comment.origlng + ", "
     // + comment.guid + ", "
     // + comment.commentValue.replace(/\n/g, "<br/>"));

     unsafeWindow.doMoveBeta(comment.lat, comment.lng,
       comment.name, parseFloat(comment.origlat),
       parseFloat(comment.origlng), comment.guid,
       comment.commentValue.replace(/\n/g, '<br/>'),
       comment.state, home,
       DBId2GCNew(GC2DBId(comment.gccode)));
    }
   }
  }
  // cachedMarkers = true;
 } else {
  log('info', 'showing markers from cache.');
  unsafeWindow.showCachedMarkers();
 }

}

function moveMysteries() {
 log("info", "moving mysteries...");

 for ( var i = 0; i < unsafeWindow.mrks.length; i++) {
  var wpGCCode = unsafeWindow.mrks[i].waypointId;
  var type = unsafeWindow.mrks[i].wptTypeId;
  var name = unsafeWindow.mrks[i].waypointTitle;

  var coordComment = doLoadCommentFromGCCode(wpGCCode);
  if (coordComment && coordComment.lat && coordComment.lng) {
   unsafeWindow.doMove(coordComment.lat, coordComment.lng, i);
  } else {
  }
 }
}

function addToGCTidyDetailPage(finlat, finlng) {
 var gctidyMinimap = document.getElementById('gctidy-small-map-link');
 var finalwpt = {
  lat : finlat,
  lng : finlng,
  type : 'Trailhead',
  title : 'Final Location',
  html : '<div class=\"gctidy-waypoint-infowindow-text\"><p class=\"gctidy-waypoint-cache-title\"><img src=\"' + finalIcon + '\"> <strong>Final!</strong></p></div>'
 };
 unsafeWindow.GCTidyWaypoints.push(finalwpt);
 var gctstyle = gctidyMinimap.getAttribute('style');
 var newStyle = addToGoogleMapsStatic(gctstyle, finlat, finlng);
 gctidyMinimap.setAttribute('style', newStyle);
}

function addToGoogleMapsStatic(href, finlat, finlng, icon) {
 // log('debug', href);
 var GMstaticDelim = '&sensor';
 var hrefParts = href.split(GMstaticDelim);
 // log('debug', hrefParts);
 var result = hrefParts[0] + "&&markers=color:green|label:F|";
 if (icon)
  result = result + "icon:" + icon + "|";
 result = result + finlat + "," + finlng + '&sensor' + hrefParts[1];
 return result;
}

// ***
// *** import & export
// ***
function buildGCCExportString() {
 var result = "<gccomment>";
 var commentKeys = GM_listValues();
 for ( var i = 0; i < commentKeys.length; i++) {
  var comment = doLoadCommentFromGUID(commentKeys[i]
    .substr(COMPREFIX.length));
  var guidIndex = commentKeys[i].indexOf(COMPREFIX);
  var length = "3331cc55-49a2-4883-a5ad-06657e8c1aab".length;
  var guid = commentKeys[i].substr(guidIndex + 9, length);
  if (commentKeys[i].indexOf(COMPREFIX) > -1) {
   result = result + "<comment>";
   result = result + "<gcid>";
   result = result + guid;
   result = result + "</gcid>";
   result = result + "<gccode>";
   result = result + comment.gccode;
   result = result + "</gccode>";
   result = result + "<name>";
   result = result + escapeXML(comment.name);
   result = result + "</name>";
   result = result + "<content>";
   result = result + escapeXML(comment.commentValue);
   result = result + "</content>";
   result = result + "<save>";
   result = result + comment.saveTime;
   result = result + "</save>";
   result = result + "<state>";
   result = result + comment.state;
   result = result + "</state>";
   result = result + "<finallat>";
   if (comment.lat)
    result = result + comment.lat;
   result = result + "</finallat>";
   result = result + "<finallng>";
   if (comment.lng)
    result = result + comment.lng;
   result = result + "</finallng>";
   result = result + "<origlat>";
   if (comment.origlat)
    result = result + comment.origlat;
   result = result + "</origlat>";
   result = result + "<origlng>";
   if (comment.origlng)
    result = result + comment.origlng;
   result = result + "</origlng>";
   result = result + "</comment>";
  }
 }
 result = result + "</gccomment>";
 GM_setValue(LAST_EXPORT, "" + new Date().getTime());
 return result;
}

function exportToGPX() {
 var result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
   + "<gpx xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1.0\" creator=\"Groundspeak, Inc. All Rights Reserved. http://www.groundspeak.com\" 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 http://www.groundspeak.com/cache/1/0/cache.xsd\" xmlns=\"http://www.topografix.com/GPX/1/0\">\n";

 result = result
   + "  <name>Waypoint listing with final coordinates of geocaches</name>\n";
 result = result + "  <desc>This is an export of " + getUserName()
   + "</desc>\n";
 result = result + "  <author>" + getUserName() + "</author>\n";
 result = result + "  <email>contact@geocaching.com</email>\n";
 result = result + "  <url>http://www.geocaching.com</url>\n";
 result = result
   + "  <urlname>Geocaching - High Tech Treasure Hunting</urlname>\n";
 result = result + "  <time>2011-02-27T21:07:18.0488819Z</time>\n";
 result = result + "  <keywords>cache, geocache, finals</keywords>\n";
 result = result
   + "  <bounds minlat=\"51.0505\" minlon=\"13.73365\" maxlat=\"51.0505\" maxlon=\"13.73365\" />\n";

 var commentKeys = GM_listValues();
 for ( var i = 0; i < commentKeys.length; i++) {
  if (commentKeys[i].indexOf(COMPREFIX) > -1) {
   var comment = doLoadCommentFromGUID(commentKeys[i]
     .substr(COMPREFIX.length));
   if (comment.lat && comment.lng) {
    var newwpt = "  <wpt lat=\""
      + comment.lat
      + "\" lon=\""
      + comment.lng
      + "\">\n"
      + "    <time>"
      + isoTime(comment.saveTime)
      + "</time>\n"
      + "    <name>"
      + comment.gccode
      + "</name>\n"
      + "    <desc>"
      + escapeXML(comment.name)
      + "</desc>\n"
      + "    <cmt>GCComment: "
      + escapeXML(comment.commentValue)
      + "</cmt>\n"
      + "    <url>http://www.geocaching.com/seek/cache_details.aspx?guid="
      + comment.guid
      + "</url>\n"
      + "    <urlname>GCComment Final</urlname>\n"
      + "    <sym>Final Location</sym>\n"
      // alternativ
      // <sym>Flag,
      // Green</sym>
      // gr¸ne
      // fahne
      // oder
      // <sym>Civil</sym>
      // goldene
      // fahne mit
      // stern
      + "    <type>Waypoint|Final Location</type>\n"
      + "  </wpt>\n";
    result = result + newwpt;
   }
  }
 }
 result = result + "</gpx>";
 openDownloadWindow(result, "Export as GPX", "application/gccomment");
}

function exportToCSV() {
 // CSV
 var filestart = "";
 var fileend = "";
 var post = "\",";
 var pre = "\"";
 var lastpost = "\"";
 var linestart = "";
 var lineend = "\n";
 var replaceLineEnd = "  ";
 performExport(filestart, fileend, pre, post, lastpost, linestart, lineend,
   replaceLineEnd);
}

function exportToHTML() {
 // HTML table
 var filestart = "<table>";
 var fileend = "</table>";
 var post = "</td>";
 var lastpost = post;
 var pre = "<td>";
 var linestart = "<tr>";
 var lineend = "</tr>";
 var replaceLineEnd = "<br/>";
 performExport(filestart, fileend, pre, post, lastpost, linestart, lineend,
   replaceLineEnd);
}

function performExport(filestart, fileend, pre, post, lastpost, linestart,
  lineend, replaceLineEnd) {
 var result = "";

 var commentKeys = GM_listValues();
 result = result + filestart;
 for ( var i = 0; i < commentKeys.length; i++) {
  var comment = doLoadCommentFromGUID(commentKeys[i]
    .substr(COMPREFIX.length));
  var guidIndex = commentKeys[i].indexOf(COMPREFIX);
  var length = "3331cc55-49a2-4883-a5ad-06657e8c1aab".length;
  var guid = commentKeys[i].substr(guidIndex + 9, length);
  if (commentKeys[i].indexOf(COMPREFIX) > -1) {
   result = result + linestart;
   result = result + pre + guid + post;
   result = result + pre + comment.gccode + post;
   result = result + pre + comment.name + post;
   if (replaceLineEnd)
    result = result + pre
      + comment.commentValue.replace(/\n/g, replaceLineEnd)
      + post;
   else
    result = result + pre + comment.commentValue + post;

   result = result + pre + comment.saveTime + post;
   result = result + pre + comment.state + post;
   result = result + pre + comment.lat + post;
   result = result + pre + comment.lng + post;
   result = result + pre + comment.origlat + post;
   result = result + pre + comment.origlng + lastpost;
   result = result + lineend;
  }
 }
 result = result + fileend;
 openDownloadWindow(result, "Export comments", "text/xls");
}

function parseXMLImport() {
 // log("debug", "parsing..." + importText.value);
 var parser = new DOMParser();
 var xmlDoc = parser.parseFromString(importText.value, "text/xml");
 var comments = xmlDoc.getElementsByTagName('comment');
 var result = "<br/><br/>import results (" + comments.length + "): <br/>";
 for ( var i = 0; i < comments.length; i++) {
  var imID = comments[i].childNodes[0].childNodes[0].nodeValue;
  var imCode = "";
  if (comments[i].childNodes[1].childNodes[0])
   imCode = comments[i].childNodes[1].childNodes[0].nodeValue;
  var imName = unescapeXML(unescape(comments[i].childNodes[2].childNodes[0].nodeValue));
  var imContent = "";
  if (comments[i].childNodes[3].childNodes[0]) {
   imContent = unescapeXML(unescape(comments[i].childNodes[3].childNodes[0].nodeValue));
  }
  if ((imContent == "null") || (imContent == "undefined"))
   imContent = "";

  var imSave = comments[i].childNodes[4].childNodes[0].nodeValue;

  var imState; // new property "state" with version 40
  if (comments[i].childNodes[5])
   imState = comments[i].childNodes[5].childNodes[0].nodeValue;

  var imLat = "", imLng = ""; // new props lat, lng since v46
  if (comments[i].childNodes[6] && comments[i].childNodes[7]) {
   if (comments[i].childNodes[6].childNodes[0])
    imLat = comments[i].childNodes[6].childNodes[0].nodeValue;
   if (comments[i].childNodes[7].childNodes[0])
    imLng = comments[i].childNodes[7].childNodes[0].nodeValue;
  }

  var imOriglat = "", imOriglng = ""; // new props for orig coordinate of
  // cache
  if (comments[i].childNodes[8] && comments[i].childNodes[9]) {
   if (comments[i].childNodes[8].childNodes[0])
    imOriglat = comments[i].childNodes[8].childNodes[0].nodeValue;
   if (comments[i].childNodes[9].childNodes[0])
    imOriglng = comments[i].childNodes[9].childNodes[0].nodeValue;
  }

  // log('debug', "importing: " + imID + ":" + imCode + ":" + imName + ":"
  // + imContent + ":" + imSave + ":" + imState + ":" + imLat + ":"
  // + imLng + ":" + imOriglat + ":" + imOriglng);

  var existing = doLoadCommentFromGUID(imID);
  if (existing != null) {
   if ((existing.saveTime != null) && (existing.saveTime >= imSave)) {
    result = result
      + "not imported, existing comment more recent or equally old: "
      + imCode + "<br/>";
   } else {
    result = result + "imported: " + imCode
      + ". Overwritten existing comment ("
      + existing.commentValue + ") with " + imContent
      + "<br/>";
    doSaveCommentWTimeToGUID(imID, imCode, imName, imContent,
      imSave, imState, imLat, imLng, imOriglat, imOriglng);
   }
  } else {
   doSaveCommentWTimeToGUID(imID, imCode, imName, imContent, imSave,
     imState, imLat, imLng, imOriglat, imOriglng);
   result = result + "imported: " + imCode + "<br/>";
  }
 }
 importresult.style.display = 'inline';
 importresult.innerHTML = result;

 GM_setValue(LAST_IMPORT, "" + new Date().getTime());
}

// ***
// *** server functions
// ***
function loadFromServer() {
 if (importDiv.style.display == "inline") {
  // cancel import & close importDiv
  unsafeWindow.$('#importDiv').slideToggle('slow');
  return;
 }
 serverImportLink.parentNode.insertBefore(waitingTag, serverImportLink);
 waitingTag.style.display = "inline";
 waitingTag.setAttribute('src', waitingGif);

 GM_xmlhttpRequest( {
  method : 'POST',
  url : "http://" + GM_getValue("gccServer")
    + ":18080/GCComment-ServerServlet/GCCommentServlet",
  data : "<?xml version='1.0' encoding='UTF-8'?><gccommentmessage id='gccomment' method='load' uuid='"
    + GM_getValue("gccUUID")
    + "' username='"
    + escapeXML(getUserName()) + "' />",
  onload : function(responseDetails) {
   performedLoad(responseDetails.responseText);
  },
  onerror : function(responseDetails) {
   syncerror(responseDetails.responseText);
  }
 });
}

function performedLoad(response) {
 waitingTag.setAttribute('src', successIcon);
 if (commentTable)
  commentTable.style.display = "none";
 displayFilters.style.display = "none";
 importText.value = response;
 unsafeWindow.$('#importDiv').slideToggle('slow');

 setTimeout(function() {
  unsafeWindow.$("#waiting").fadeOut('slow', function() {
  });
 }, 3000);
}

function syncerror(answer) {
 waitingTag.setAttribute("src", errorIcon);
 listener = function() {
  unsafeWindow.tooltip.show(
    "<strong>Action failed</strong><br>" + answer, 200);
 };
 waitingTag.addEventListener('mouseover', listener, false);
 waitingTag.setAttribute('onmouseout', 'tooltip.hide();');
 waitingTag.addEventListener('mouseup', function() {
  waitingTag.style.display = "none";
 }, false);
}

function storeToServer() {
 serverExportLink.parentNode.insertBefore(waitingTag, serverExportLink);
 waitingTag.style.display = "inline";
 waitingTag.setAttribute('src', waitingGif);
 waitingTag.removeEventListener('mouseover', listener, false);

 var dataString = "<?xml version='1.0' encoding='UTF-8'?><gccommentmessage id='gccomment' method='store' uuid='"
   + GM_getValue("gccUUID")
   + "' username='"
   + escapeXML(getUserName())
   + "'>"
   + buildGCCExportString()
   + "</gccommentmessage>";
 log('debug', 'Data string size: ' + dataString.length);

 GM_xmlhttpRequest( {
  method : 'POST',
  url : "http://" + GM_getValue("gccServer")
    + ":18080/GCComment-ServerServlet/GCCommentServlet",
  data : dataString,
  onload : function(responseDetails) {
   performedSave(responseDetails.responseText);
  },
  onerror : function(responseDetails) {
   syncerror(responseDetails.responseText);
  }
 });
 log("info", "request sent");
}

function performedSave(response) {
 log("info", "save response: " + response);
 var parser = new DOMParser();
 var xmlDoc = parser.parseFromString(response, "text/xml");
 var response = xmlDoc.getElementsByTagName('response');
 if (response.length > 0) {
  var msg = response[0].getAttribute('msg');
  if (msg != 'storing successful') {
   waitingTag.setAttribute("src", errorIcon);
   // waitingTag.setTitle(msg);
   waitingTag.addEventListener('mouseover', function(evt) {
    unsafeWindow.tooltip.show("<b>The server said:</b><br/>" + msg,
      200);
   }, false);
   waitingTag.setAttribute('onmouseout', 'tooltip.hide();');
  } else {
   waitingTag.setAttribute("src", successIcon);
   setTimeout(function() {
    unsafeWindow.$("#waiting").fadeOut('slow', function() {
    });
   }, 5000);
  }
 } else {
  waitingTag.setAttribute("src", successIcon);
  setTimeout(function() {
   unsafeWindow.$("#waiting").fadeOut('slow', function() {
   });
  }, 5000);
 }
}

function getUserName() {
 var logout = document
   .getElementById('ctl00_ContentBody_WidgetMiniProfile1_LoggedInPanel');
 var username;
 if (logout) {
  username = logout.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
  GM_setValue("GCCUSER", username);
 } else {
  username = GM_getValue('GCCUSER');
 }
 return username;
}

var originalGPX = "";
// Original idea from Schatzjäger2
function sendToGPS() {
 setTimeout(function() {
  var gpxTextArea = document.getElementById('dataString');
  // gpxTextArea.parentNode.setAttribute('style', "");
   var gpx = gpxTextArea.value;
   originalGPX = gpx;
   var anfang = gpx.indexOf('guid=');
   var laenge = 'a5493497-70a7-4e07-946c-6d79c7a59994'.length + 5;
   var currentCacheGUID = gpx.substring(anfang + 5, anfang + laenge);
   currentComment = doLoadCommentFromGUID(currentCacheGUID);
   if (currentComment
     && (currentComment.commentValue || (currentComment.lat && currentComment.lng))) {
    // build special config
    var writebox = document.getElementById('writeBox');
    var configdiv = document.createElement('div');
    configdiv.setAttribute('style',
      'outline:1px solid grey;margin-bottom:5px');
    var configlabel = document.createElement('p');
    configlabel
      .appendChild(document
        .createTextNode('Use GCComment information to configure your GPX '));
    configdiv.appendChild(configlabel);

    // add your comment
    var addComment = document.createElement('input');
    addComment.setAttribute('id', 'addComment');
    addComment.setAttribute('type', 'checkbox');
    addComment.setAttribute('class', 'Checkbox');
    addComment.addEventListener('click', function() {
     var state = addComment.getAttribute('checked');
     if (state)
      addComment.removeAttribute('checked');
     else
      addComment.setAttribute('checked', 'checked');
     GM_setValue(ADDCOMMENTSETTING, state ? 0 : 1);
     patchGarminGPX();
    }, false);
    configdiv.appendChild(addComment);

    var addCommentSetting = GM_getValue(ADDCOMMENTSETTING);
    if (addCommentSetting == 1)
     addComment.setAttribute('checked', 'checked');

    var addCommentLabel = document.createElement('label');
    addCommentLabel.setAttribute('for', 'addComment');
    addCommentLabel.appendChild(document
      .createTextNode('Add your GCComment'));
    configdiv.appendChild(addCommentLabel);

    var addCommentSetting = GM_getValue(ADDCOMMENTSETTING);
    if (addCommentSetting == 1)
     addComment.setAttribute('checked', 'checked');
    configdiv.appendChild(document.createElement('br'));

    // change Original
    var changeOriginal = document.createElement('input');
    changeOriginal.setAttribute('id', 'changeOriginal');
    changeOriginal.setAttribute('type', 'checkbox');
    changeOriginal.setAttribute('class', 'Checkbox');
    changeOriginal.addEventListener('click', function() {
     var state = changeOriginal.getAttribute('checked');
     if (state)
      changeOriginal.removeAttribute('checked');
     else
      changeOriginal.setAttribute('checked', 'checked');
     GM_setValue(CHANGEORIGINALSETTING, state ? 0 : 1);
     patchGarminGPX();
    }, false);
    configdiv.appendChild(changeOriginal);

    var changeOrigSetting = GM_getValue(CHANGEORIGINALSETTING);
    if (changeOrigSetting == 1)
     changeOriginal.setAttribute('checked', 'checked');

    var changeOriginalLabel = document.createElement('label');
    changeOriginalLabel.setAttribute('for', 'changeOriginal');
    changeOriginalLabel
      .appendChild(document
        .createTextNode('Change the original coordinates to your final coordinates'));
    configdiv.appendChild(changeOriginalLabel);

    var changeOrigSetting = GM_getValue(CHANGEORIGINALSETTING);
    if (changeOrigSetting == 1)
     changeOriginal.setAttribute('checked', 'checked');
    configdiv.appendChild(document.createElement('br'));

    if (!currentComment.lat && !currentComment.lng) {
     changeOriginal.setAttribute('disabled', '');
    }

    // add waypoint
    var addWaypoint = document.createElement('input');
    addWaypoint.setAttribute('id', 'addWaypoint');
    addWaypoint.setAttribute('type', 'checkbox');
    addWaypoint.setAttribute('class', 'Checkbox');
    addWaypoint.addEventListener('click', function() {
     var state = addWaypoint.getAttribute('checked');
     if (state)
      addWaypoint.removeAttribute('checked');
     else
      addWaypoint.setAttribute('checked', 'checked');
     GM_setValue(ADDWAYPOINTSETTING, state ? 0 : 1);
     patchGarminGPX();
    }, false);
    configdiv.appendChild(addWaypoint);

    var addWaypointLabel = document.createElement('label');
    addWaypointLabel.setAttribute('for', 'addWaypoint');
    addWaypointLabel
      .appendChild(document
        .createTextNode('Add final coordinates as separate waypoint'));
    configdiv.appendChild(addWaypointLabel);

    var addWaypointSetting = GM_getValue(ADDWAYPOINTSETTING);
    if (addWaypointSetting == 1)
     addWaypoint.setAttribute('checked', 'checked');
    configdiv.appendChild(document.createElement('br'));

    if (!currentComment.lat && !currentComment.lng) {
     addWaypoint.setAttribute('disabled', '');
    }

    writebox.parentNode.insertBefore(configdiv, writebox);
    patchGarminGPX();
    window.resizeTo(450, 550);
   }
  }, 500);
}

function buildGPXWPT(commentObject) {
 var newwpt = "<wpt lat='"
   + commentObject.lat
   + "' lon='"
   + commentObject.lng
   + "'>"
   + "    <time>"
   + isoTime(commentObject.saveTime)
   + "</time>"
   + "    <name>"
   + commentObject.gccode
   + "</name>"
   + "    <cmt>GCComment: "
   + commentObject.commentValue
   + "</cmt>"
   + "    <desc>GCComment Final and Comment</desc>"
   + "    <url>http://www.geocaching.com/seek/cache_details.aspx?guid="
   + commentObject.guid + "</url>"
   + "    <urlname>GCComment Final</urlname>"
   + "    <sym>Final Location</sym>"
   // alternativ
   // <sym>Flag,
   // Green</sym>
   // grüne
   // fahne
   // oder
   // <sym>Civil</sym>
   // goldene
   // fahne mit
   // stern
   + "    <type>Waypoint|Final Location</type>" + "   </wpt>";
 return newwpt;
}

function patchGarminGPX() {
 var gpxTextArea = document.getElementById('dataString');
 var newGPX = originalGPX;
 var positioncomment = originalGPX
   .indexOf('</groundspeak:long_description>');
 if (currentComment.commentValue && (GM_getValue(ADDCOMMENTSETTING) == 1)) {
  newGPX = originalGPX.substring(0, positioncomment)
    + "\n&lt;br /&gt;\n&lt;br /&gt;\nGCComment:\n&lt;br /&gt;\n"
    + currentComment.commentValue + "&lt;br /&gt;\n"
    + originalGPX.substring(positioncomment, originalGPX.length);
 }

 if (currentComment.lat && currentComment.lng) {
  if (GM_getValue(CHANGEORIGINALSETTING) == 1) {
   var latstart = newGPX.indexOf('<wpt lat=\"') + 10;
   var latstop = newGPX.indexOf('\"', latstart) + 1;
   newGPX = newGPX.substring(0, latstart) + currentComment.lat
     + newGPX.substring(latstop - 1, newGPX.length);

   var lngstart = newGPX.indexOf('\" lon=\"') + 7;
   var lngstop = newGPX.indexOf('\"', lngstart) + 1;
   newGPX = newGPX.substring(0, lngstart) + currentComment.lng
     + newGPX.substring(lngstop - 1, newGPX.length);
  }

  if (GM_getValue(ADDWAYPOINTSETTING) == 1) {
   var newwpt = buildGPXWPT(currentComment);
   var endindex = newGPX.indexOf('</gpx>');
   newGPX = newGPX.substring(0, endindex) + newwpt
     + newGPX.substring(endindex, newGPX.length);
  }
 }
 // set text area
 gpxTextArea.value = newGPX;

 // set text child of text area
 gpxTextArea.replaceChild(document.createTextNode(newGPX),
   gpxTextArea.firstChild);
}

function isoTime(time) {
 var saved = new Date();
 saved.setTime(time);
 var result = saved.getFullYear()
   + "-"
   + ((saved.getMonth() < 9) ? "0" + saved.getMonth() : saved
     .getMonth())
   + "-"
   + ((saved.getDate() < 9) ? "0" + saved.getDate() : saved.getDate())
   + "T"
   + ((saved.getHours() < 9) ? "0" + saved.getHours() : saved
     .getHours())
   + ":"
   + ((saved.getMinutes() < 9) ? "0" + saved.getMinutes() : saved
     .getMinutes())
   + ":"
   + ((saved.getSeconds() < 9) ? "0" + saved.getSeconds() : saved
     .getSeconds())
   + "."
   + ((saved.getMilliseconds() < 9) ? "0" + saved.getMilliseconds()
     : saved.getMilliseconds());
 return result;
}

// ***
// *** helper functions
// ***
function trim(zeichenkette) {
 return zeichenkette.replace(/^\s+/, '').replace(/\s+$/, '');
}

function escapeXML(unescaped) {
 var result = unescaped.replace(/&/g, "&amp;");
 result = result.replace(/>/g, "&gt;");
 result = result.replace(/</g, "&lt;");
 result = result.replace(/"/g, "&quot;");
 result = result.replace(/'/g, "&apos;");

 // zeilenumbrüche escapen
 // result = result.replace(/\n/g, "&#10;");

 return result;
}

function unescapeXML(escaped) {
 var result = escaped.replace(/&gt;/g, ">");
 result = result.replace(/&lt;/g, "<");
 result = result.replace(/&quot;/g, "\"");
 result = result.replace(/&amp;/g, "&");
 result = result.replace(/&apos;/g, "'");
 // result = result.replace(/&#10;/g, "\n");
 return result;
}

function updateAvailable(serverVersion) {
 GM_xmlhttpRequest( {
  method : 'GET',
  header : {
   'Cache-Control' : 'max-age=3600, must-revalidate'
  },
  url : updatechangesurl,
  onload : function(responseDetails) {
   handleChangesReply(responseDetails.responseText);
  },
  onerror : function(responseDetails) {
   log("info", "Unable to get changes from Sourceforge! Errorcode "
     + responseDetails.status);
  }
 });

 log("info", "current version: " + version + " latest version: "
   + serverVersion);
 var updateInfo = document.createElement('div');
 updateInfo.setAttribute('id', 'gccupdateinfo');
 var updatelnk = document.createElement('a');
 updatelnk.setAttribute('href',
   'http://userscripts.org/scripts/source/75959.user.js');
 updatelnk.innerHTML = "Click here to update!";
 updateInfo
   .appendChild(document
     .createTextNode("Hooray, a GCComment update is available. The new version is "
       + serverVersion
       + " while your installed version is "
       + version
       + ". "));
 updateInfo.appendChild(updatelnk);
 updateInfo.appendChild(document.createElement('br'));
 updateInfo.appendChild(document.createElement('br'));
 gccRoot.insertBefore(updateInfo, gccRoot.firstChild);
}

function handleChangesReply(xmlString) {
 var updateInfo = document.getElementById('gccupdateinfo');
 var parser = new DOMParser();
 var xmlDoc = parser.parseFromString(xmlString, "text/xml");
 var changes = xmlDoc.getElementsByTagName("change");
 if (changes) {
  for ( var chindex = 0; chindex < changes.length; chindex++) {
   var change = changes[chindex];
   var vversion, date, content;
   for ( var elems = 0; elems < change.childNodes.length; elems++) {
    var elem = change.childNodes[elems];
    if (elem.nodeName == "version")
     vversion = elem.firstChild.nodeValue;
    else if (elem.nodeName == "date")
     date = elem.firstChild.nodeValue;
    else if (elem.nodeName == "content")
     content = elem.firstChild.nodeValue;
   }
   if (vversion <= version)
    break;
   updateInfo.appendChild(document
     .createTextNode('Changes in version ' + vversion + " ("
       + date + ")"));
   updateInfo.appendChild(document.createElement('br'));

   var divv = document.createElement('div');
   divv.innerHTML = content;
   updateInfo.appendChild(divv);
  }

  updateInfo.appendChild(document.createElement('br'));
 }
}

function checkforupdates() {
 var updateDate = eval(GM_getValue('updateDate'));
 if (!updateDate) {
  updateDate = new Date();
  GM_setValue('updateDate', uneval(updateDate));
 }
 var currentDate = new Date();

 // in ms. equals 1 day
 if (currentDate.getTime() - updateDate.getTime() > 86400000) {

  GM_xmlhttpRequest( {
   method : 'GET',
   header : {
    'Cache-Control' : 'max-age=3600, must-revalidate'
   },
   url : updateurl,
   onload : function(responseDetails) {
    // handleChangesReply(responseDetails.responseText);
    var content = responseDetails.responseText;
    var parseResult = /@version\s+([.\d]+)[\r\n]/.exec(content);
    if (parseResult) {
     var serverVersion = parseInt(parseResult[1]);
     log('info', 'updatecheck: installed version=' + version
       + ", server version=" + serverVersion);
     if (serverVersion > version)
      updateAvailable(serverVersion);
    }
   },
   onerror : function(responseDetails) {
    log("info",
      "Unable to get version from Userscripts.org! Errorcode "
        + responseDetails.status);
   }
  });

  GM_setValue('updateDate', uneval(currentDate));
 }
}

// helper detailpage: macht aus dem Time-Long eine lesbare Zeitangabe
function createTimeString(time) {
 if (time < 0)
  return "never";
 else {
  var lastSave = new Date();
  lastSave.setTime(time);
  var month = lastSave.getMonth() + 1;
  var day = lastSave.getDate();
  var hour = lastSave.getHours();
  var minute = lastSave.getMinutes();
  var sec = lastSave.getSeconds();
  if (month < 10)
   month = "0" + month;
  if (day < 10)
   day = "0" + day;
  if (hour < 10)
   hour = "0" + hour;
  if (minute < 10)
   minute = "0" + minute;
  if (sec < 10)
   sec = "0" + sec;

  return lastSave.getFullYear() + "-" + month + "-" + day + " " + hour
    + ":" + minute + ":" + sec;
 }
}

function appendScript(type, script, context) {
 var element = document.createElement('script');
 element.setAttribute('type', 'text/javascript');
 if (type == 'src') {
  element.setAttribute('src', script);
 } else if (type == 'text') {
  element.textContent = script;
 }
 context = context || document;
 context.getElementsByTagName('head')[0].appendChild(element);
 return element;
}

function getNumberOfComments() {
 var keys = GM_listValues();
 var counter = 0;
 for ( var ind = 0; ind < keys.length; ind++) {
  var commentKey = keys[ind];
  if (commentKey.indexOf(COMPREFIX) > -1)
   counter++;
 }
 return counter;
}

function addEvent(obj, type, fn) {
 if (obj.addEventListener)
  obj.addEventListener(type, fn, false);
 else if (obj.attachEvent)
  obj.attachEvent('on' + type, function() {
   return fn.apply(obj, new Array(window.event));
  });
}

function log(level, text) {
 GM_log(level + ": " + text);
}

function getGUIDFromGCCode(gcCode) {
 var value = GM_getValue(COMGCPREFIX + gcCode);
 if (value)
  return value;
 // else
 // log('info', 'no GUID for GCCode ' + gcCode + ' saved. ');
}

function convertDec2DMS(lt, lg) {
 var lat = lt;
 var lng = lg;
 var result = "";
 if (lat < 0) {
  result = result + "S ";
  lat = lat * -1;
 } else
  result = result + "N ";

 if ((lat < 10) && (lat > -10))
  result = result + "0";
 result = result + parseInt(lat) + String.fromCharCode(176) + " ";
 lat = lat - parseInt(lat);
 var latFormatted = (Math.round(parseFloat(lat * 60) * 1000) / 1000)
   .toFixed(3);
 if ((latFormatted < 10) && (latFormatted > -10))
  result = result + "0";
 result = result + latFormatted + " ";

 if (lng < 0) {
  result = result + " W ";
  lng = lng * -1;
 } else
  result = result + " E ";

 if ((lng < 10) && (lng > -10))
  result = result + "00";
 else if ((lng < 100) && (lng > -100))
  result = result + "0";

 result = result + parseInt(lng) + String.fromCharCode(176) + " ";
 lng = lng - parseInt(lng);
 var lngFormatted = (Math.round(parseFloat(lng * 60) * 1000) / 1000)
   .toFixed(3);
 if ((lngFormatted < 10) && (lngFormatted > -10))
  result = result + "0";
 result = result + lngFormatted;

 return result;
}

function parseCoordinates(cstr) {
 var regexDegMin = /([NS])\s*(\d+)\D\s*(\d+\.\d+)\s*([EW])\s*(\d+)\D\s*(\d+\.\d+)/i;

 var fin = new Array();
 var items = regexDegMin.exec(cstr);
 if ((items != null) && (items.length == 7)) {
  log("info", "parsing successful DegMin: " + items);
  var lat1 = RegExp.$2;
  while (lat1.indexOf(0) == 0) {
   lat1 = lat1.substring(1, lat1.length);
  }
  if (lat1.length == 0)
   lat1 = 0;

  var lat2 = RegExp.$3;
  var lat = parseInt(lat1) + parseFloat(lat2) / 60;
  if (RegExp.$1 == "S")
   lat = lat * -1;

  var lng1 = RegExp.$5;
  while (lng1.indexOf(0) == 0) {
   lng1 = lng1.substring(1, lng1.length);
  }
  if (lng1.length == 0)
   lng1 = 0;
  var lng2 = RegExp.$6;
  var lng = parseInt(lng1) + parseFloat(lng2) / 60;
  if (RegExp.$4 == "W")
   lng = lng * -1;

  fin.push(lat);
  fin.push(lng);
  return fin;
 }

 var regexPlain = /(\d+)\s+(\d+\.\d+)\s+(\d+)\s+(\d+\.\d+)/i;
 items = regexPlain.exec(cstr);
 if ((items != null) && (items.length == 5)) {
  log("info", "parsing successful Plain: " + items);
  var lat1 = RegExp.$1;
  while (lat1.indexOf(0) == 0) {
   lat1 = lat1.substring(1, lat1.length);
  }
  if (lat1.length == 0)
   lat1 = 0;

  var lat2 = RegExp.$2;
  var lat = parseInt(lat1) + parseFloat(lat2) / 60;

  var lng1 = RegExp.$3;
  while (lng1.indexOf(0) == 0) {
   lng1 = lng1.substring(1, lng1.length);
  }
  if (lng1.length == 0)
   lng1 = 0;
  var lng2 = RegExp.$4;
  var lng = parseInt(lng1) + parseFloat(lng2) / 60;
  fin.push(lat);
  fin.push(lng);
  return fin;
 }

 var regexDec = /(\d+\.\d+)(,\s*|\s+)(\d+\.\d+)/i;
 items = regexDec.exec(cstr);
 if ((items != null) && (items.length == 4)) {
  log("info", "parsing successful Dec: " + items);
  var lat1 = RegExp.$1;
  while (lat1.indexOf(0) == 0) {
   lat1 = lat1.substring(1, lat1.length);
  }
  if (lat1.length == 0)
   lat1 = 0;

  var lat = parseFloat(lat1);

  var lng1 = RegExp.$3;
  while (lng1.indexOf(0) == 0) {
   lng1 = lng1.substring(1, lng1.length);
  }
  if (lng1.length == 0)
   lng1 = 0;
  var lng = parseFloat(lng1);
  fin.push(lat);
  fin.push(lng);
  return fin;
 }

 fin.push("Coordinates do not match DegMin, Dec, or Plain");
 return fin;
}

function calculateDistance(lat1, lon1, lat2, lon2) {
 if (typeof (Number.prototype.toRad) === "undefined") {
  Number.prototype.toRad = function() {
   return this * Math.PI / 180;
  };
 }
 var R = 6371; // km
 var lat1dec = parseFloat(lat1);
 var lon1dec = parseFloat(lon1);
 var lat2dec = parseFloat(lat2);
 var lon2dec = parseFloat(lon2);
 var dLat = (lat2dec - lat1dec).toRad();
 var dLon = (lon2dec - lon1dec).toRad();
 var lat1 = lat1dec.toRad();
 var lat2 = lat2dec.toRad();

 var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2)
   * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
 var d = R * c;
 return d;
}

function appendCheckBox(parentNode, id, label, extrafunction) {
 var currentValue = GM_getValue(id);
 // log('debug', 'cv: ' + currentValue);
 if ((currentValue == undefined) || (currentValue == null)
   || (currentValue == "undefined"))
  GM_setValue(id, false);
 var checkbox = document.createElement('input');
 checkbox.setAttribute('type', 'checkbox');
 checkbox.setAttribute('id', id);
 checkbox.setAttribute('class', 'Checkbox');
 checkbox.setAttribute('style', 'margin:3px');
 checkbox.addEventListener('mouseup', function() {
  var oldValue = GM_getValue(id);
  GM_setValue(id, !oldValue);
 });

 var checked = GM_getValue(id);
 if (checked) {
  checkbox.setAttribute('checked', 'checked');
 }
 parentNode.appendChild(checkbox);

 if (label) {
  var newLabel = document.createElement('label');
  newLabel.setAttribute('for', id);
  newLabel.appendChild(document.createTextNode(label));
  parentNode.appendChild(newLabel);
  newLabel.addEventListener('mouseup', function() {
   var oldValue = GM_getValue(id);
   GM_setValue(id, !oldValue);
  });
 }

 if (extrafunction) {
  checkbox.addEventListener('mouseup', extrafunction);
  newLabel.addEventListener('mouseup', extrafunction);
 }

 parentNode.appendChild(document.createElement('br'));
}

/**
 * Base64 encode / decode http://www.webtoolkit.info/
 */
var Base64 = {

 // private property
 _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

 // public method for encoding
 encode : function(input) {
  var output = "";
  var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  var i = 0;

  input = Base64._utf8_encode(input);

  while (i < input.length) {

   chr1 = input.charCodeAt(i++);
   chr2 = input.charCodeAt(i++);
   chr3 = input.charCodeAt(i++);

   enc1 = chr1 >> 2;
   enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
   enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
   enc4 = chr3 & 63;

   if (isNaN(chr2)) {
    enc3 = enc4 = 64;
   } else if (isNaN(chr3)) {
    enc4 = 64;
   }

   output = output + this._keyStr.charAt(enc1)
     + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3)
     + this._keyStr.charAt(enc4);

  }

  return output;
 },

 // public method for decoding
 decode : function(input) {
  var output = "";
  var chr1, chr2, chr3;
  var enc1, enc2, enc3, enc4;
  var i = 0;

  input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

  while (i < input.length) {

   enc1 = this._keyStr.indexOf(input.charAt(i++));
   enc2 = this._keyStr.indexOf(input.charAt(i++));
   enc3 = this._keyStr.indexOf(input.charAt(i++));
   enc4 = this._keyStr.indexOf(input.charAt(i++));

   chr1 = (enc1 << 2) | (enc2 >> 4);
   chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
   chr3 = ((enc3 & 3) << 6) | enc4;

   output = output + String.fromCharCode(chr1);

   if (enc3 != 64) {
    output = output + String.fromCharCode(chr2);
   }
   if (enc4 != 64) {
    output = output + String.fromCharCode(chr3);
   }

  }

  output = Base64._utf8_decode(output);

  return output;

 },

 // private method for UTF-8 encoding
 _utf8_encode : function(string) {
  string = string.replace(/\r\n/g, "\n");
  var utftext = "";

  for ( var n = 0; n < string.length; n++) {

   var c = string.charCodeAt(n);

   if (c < 128) {
    utftext += String.fromCharCode(c);
   } else if ((c > 127) && (c < 2048)) {
    utftext += String.fromCharCode((c >> 6) | 192);
    utftext += String.fromCharCode((c & 63) | 128);
   } else {
    utftext += String.fromCharCode((c >> 12) | 224);
    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
    utftext += String.fromCharCode((c & 63) | 128);
   }

  }

  return utftext;
 },

 // private method for UTF-8 decoding
 _utf8_decode : function(utftext) {
  var string = "";
  var i = 0;
  var c = c1 = c2 = 0;

  while (i < utftext.length) {

   c = utftext.charCodeAt(i);

   if (c < 128) {
    string += String.fromCharCode(c);
    i++;
   } else if ((c > 191) && (c < 224)) {
    c2 = utftext.charCodeAt(i + 1);
    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
    i += 2;
   } else {
    c2 = utftext.charCodeAt(i + 1);
    c3 = utftext.charCodeAt(i + 2);
    string += String.fromCharCode(((c & 15) << 12)
      | ((c2 & 63) << 6) | (c3 & 63));
    i += 3;
   }

  }

  return string;
 }
};

function openDownloadWindow(content, title, mimetype) {
 var c = Base64.encode(content);
 window.open("data:" + mimetype + ";base64," + c, title,
   "width=300,height=400,left=100,top=200");
}

function GC2DBId(gcCode) {
 var gcId = 0;

 var sequence = "0123456789ABCDEFGHJKMNPQRTVWXYZ";

 var rightPart = gcCode.substring(2).toUpperCase();

 var base = 31;
 if ((rightPart.length < 4)
   || ((rightPart.length == 4) && (sequence.indexOf(rightPart
     .charAt(0)) < 16))) {
  base = 16;
 }

 for ( var p = 0; p < rightPart.length; p++) {
  gcId *= base;
  gcId += sequence.indexOf(rightPart.charAt(p));
 }

 if (base == 31) {
  gcId += Math.pow(16, 4) - 16 * Math.pow(31, 3);
 }
 return gcId;
}

function DBId2GCNew(newGcId) {
 var gcNewCode = "";
 var sequence = "tHpXJR8gyfzCrdV5G0Kb3Y92N47lTBPAhWnvLZkaexmSwq6sojDcEQMFO";

 var base = 57;

 var rest = 0;
 var divResult = newGcId;

 do {
  rest = divResult % base;
  divResult = Math.floor(divResult / base);
  gcNewCode = sequence.charAt(rest) + gcNewCode;
 } while (divResult != 0);

 return gcNewCode;
}

Continue reading...