Reversewigo solver ✓🐵

Reversewigo solver ✓🐵 - solve reverse wherigo automatically on cache page. Solver code originated from Rick Rickhardson's reverse-wherigo source (public domain). Also, creates show source button for mystery cacahes.

19.01.2021 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name        Reversewigo solver ✓🐵
// @namespace    http://tampermonkey.net/
// @version      0.08
// @description  Reversewigo solver ✓🐵  - solve reverse wherigo automatically on cache page. Solver code originated from Rick Rickhardson's reverse-wherigo source (public domain). Also, creates show source button for mystery cacahes.
// @author       [email protected]
// @include      https://www.geocaching.com/geocache/*
// ==/UserScript==

// placeholder for calculated reverse wherigo coordinates
// used by pollDOM to update them to popup dialog
// TODO: definitely not the best practise but a quick hack that seems to work (for now)
var newCoordinates = "";


/* async */ function dd2dm(latdd, londd) {
    var lat = latdd;
    var lon = londd;

    var latResult, lonResult, dmsResult;

    lat = parseFloat(lat);
    lon = parseFloat(lon);

    latResult = /* await */ lat_dd2dm(lat);
    lonResult = /* await */ lon_dd2dm(lon);
 
    // Joining both variables and separate them with a space.
    dmsResult = latResult + ' ' + lonResult;

    // Return the resultant string
    return { result: dmsResult, lat: latResult, lon: lonResult };
}

/* async */ function lat_dd2dm(val) {
    var valDeg, valMin, result;

    val = Number(val);
    result = (val >= 0)? 'N' : 'S';
    result += " ";

    val = Math.abs(val);
    valDeg = Math.floor(val);

    if( valDeg < 10 ) {
    result += "0" + valDeg;
    }
    else {
    result += valDeg;
    }
    result += "\xB0";
    result += " ";

    valMin = ((val - valDeg) * 60).toFixed(3);
    if( valMin < 10) {
        result += "0" + valMin;
    }
    else {
        result += valMin;
    }
    return result;
}

/* async */ function lon_dd2dm(val) {
    var valDeg, valMin, result;

    val = Number(val);

    result = (val >= 0)? 'E' : 'W';
    result += " ";

    val = Math.abs(val);
    valDeg = Math.floor(val);

    if( valDeg < 10 ) {
        result += "00" + valDeg;
    }
    else if( valDeg < 100) {
        result += "0" + valDeg;
    }
    else {
        result += valDeg;
    }
    result += "\xB0";
    result += " ";

    valMin = ((val - valDeg) * 60).toFixed(3);
    if( valMin < 10) {
        result += "0" + valMin;
    }
    else {
        result += valMin;
    }
    return result;
}

/* async */ function code2LatLon(varA, varB, varC) {
    let latSign, lonSign, lonValue, latValue;

    //
    if ((varA % 1000 - varA % 100) / 100 == 1) {
        latSign = 1;
        lonSign = 1;
    }
    else if ((varA % 1000 - varA % 100) / 100 == 2) {
        latSign = -1;
        lonSign = 1;
    }
    else if ((varA % 1000 - varA % 100) / 100 == 3) {
        latSign = 1;
        lonSign = -1;
    }
    else if ((varA % 1000 - varA % 100) / 100 == 4) {
        latSign = -1;
        lonSign = -1;
    }

    if ( ((varC % 100000 - varC % 10000) / 10000 + (varC % 100 - varC % 10) / 10) % 2 === 0) {
        // A4 B2  B5 C3 A6 C2 A1
        latValue = Number(((varA % 10000 - varA % 1000) / 1000 * 10 + (varB % 100 - varB % 10) / 10 + (varB % 100000 - varB % 10000) / 10000 * 0.1 + (varC % 1000 - varC % 100) / 100 * 0.01 + (varA % 1000000 - varA % 100000) / 100000 * 0.001 + (varC % 100 - varC % 10) / 10 * 1.0E-4 + varA % 10 * 1.0E-5));
    }
    else if ( ((varC % 100000 - varC % 10000) / 10000 + (varC % 100 - varC % 10) / 10) % 2 !== 0) {
        // B6 A1   A4 C6 C3 C2 A6
        latValue = Number(((varB % 1000000 - varB % 100000) / 100000 * 10 + varA % 10 + (varA % 10000 - varA % 1000) / 1000 * 0.1 + (varC % 1000000 - varC % 100000) / 100000 * 0.01 + (varC % 1000 - varC % 100) / 100 * 0.001 + (varC % 100 - varC % 10) / 10 * 1.0E-4 + (varA % 1000000 - varA % 100000) / 100000 * 1.0E-5))
    }

    if ( ((varC % 100000 - varC % 10000) / 10000 + (varC % 100 - varC % 10) / 10) % 2 === 0 ) {
        // A5 C6  C1 B3 B6 A2
        lonValue = Number(((varA % 100000 - varA % 10000) / 10000 * 100 + (varC % 1000000 - varC % 100000) / 100000 * 10 + varC % 10 + (varB % 1000 - varB % 100) / 100 * 0.1 + (varB % 1000000 - varB % 100000) / 100000 * 0.01 + (varA % 100 - varA % 10) / 10 * 0.001 + (varC % 100000 - varC % 10000) / 10000 * 1.0E-4 + varB % 10 * 1.0E-5));
    }
    else if ( ((varC % 100000 - varC % 10000) / 10000 + (varC % 100 - varC % 10) / 10) % 2 !== 0 ) {
        // B2 C1 A2  A5 B3 B1 ??
        lonValue = Number(((varB % 100 - varB % 10) / 10 * 100 + varC % 10 * 10 + (varA % 100 - varA % 10) / 10 + (varA % 100000 - varA % 10000) / 10000 * 0.1 + (varB % 1000 - varB % 100) / 100 * 0.01 + varB % 10 * 0.001 + (varC % 100000 - varC % 10000) / 10000 * 1.0E-4 + (varB % 100000 - varB % 10000) / 10000 * 1.0E-5));
    }

    latValue = latSign * latValue;
    lonValue = lonSign * lonValue;

    return { lat: latValue, lon: lonValue }
}

function fix(v, left, right) {
    return (v < 0 ? '-' : ' ') + Math.abs(v).toFixed(right).padStart(left + right + 1, '0');
}

function haversineDistance(lat1,lon1,lat2,lon2) {
    const R = 6371e3; // metres
    const φ1 = lat1 * Math.PI/180; // φ, λ in radians
    const φ2 = lat2 * Math.PI/180;
    const Δφ = (lat2-lat1) * Math.PI/180;
    const Δλ = (lon2-lon1) * Math.PI/180;
    
    const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
              Math.cos(φ1) * Math.cos(φ2) *
              Math.sin(Δλ/2) * Math.sin(Δλ/2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    
    const d = R * c; // in metres
    return d;
  }
  
  function dm2dd( nsew, deg, min ) {
      let sign;
      if( nsew == 'N' || nsew == 'E' ) {
          sign = 1;
      }
      else {
          sign = -1;
      }
  
      let numdeg = parseInt(deg);
      let nummin = parseFloat(min);
  
      let dd = sign * (numdeg + nummin/60);
      return dd;
  }
  

function createShowSourceButton() {
    let mybutton = document.createElement("button");
    mybutton.innerHTML = "Source";
    let noteref = document.getElementsByClassName("minorCacheDetails Clear")[0];
    noteref.appendChild(mybutton);

    mybutton.addEventListener("click", function() {
        var desc1 = document.getElementById("ctl00_ContentBody_ShortDescription").innerHTML;
        var desc2 = document.getElementById("ctl00_ContentBody_LongDescription").innerHTML;
        alert( desc1 + desc2 )
    });
}

function createShowSolveREReverseButton() {
    let mybutton = document.createElement("solvebutton");
    mybutton.innerHTML = "Solve RE";
    let noteref = document.getElementsByClassName("minorCacheDetails Clear")[0];
    noteref.appendChild(mybutton);

    mybutton.addEventListener("click", function() {
        solveReverseRE();
    });

    /*
    mybutton.addEventListener("click", function() {
        $( function() {
            $( "#dialog" ).dialog({width: "auto"})
            .next(".ui-widget-overlay")
            .css({
                opacity: 1.0,
                filter: "Alpha(Opacity=100)",
                backgroundColor: "black"
            });
          } );
        solveReverseRE();
    });
    */
}

function createDialog( ) {
    let mydialog = document.createElement("div");
    mydialog.id = "dialog";
    mydialog.title = "Results";
    let resultmsg = document.createElement("p");
    resultmsg.id = "resultmsg";
    mydialog.appendChild(resultmsg);
//    let noteref = document.getElementsByClassName("minorCacheDetails Clear")[0];
    let noteref = document.getElementById("ctl00_ContentBody_detailWidget");
    noteref.appendChild(mydialog);
}

// TODO: definitely not the best practice, but works (for now)
function pollDOM() {
    const newCrd = document.getElementById('newCoordinates');

    if (newCrd != null) {
      // Do something with el
      newCrd.value = newCoordinates;

      let submitBtn = document.getElementsByClassName("btn-cc-parse")[0];
      submitBtn.click();
      } else {
      setTimeout(pollDOM, 300); // try again in 300 milliseconds
    }
}

function updateCoordinates( newCoords ) {
    let crd = document.getElementById("uxLatLonLink");
    crd.click();

    newCoordinates = newCoords;

    pollDOM();
    console.debug("XX: " + newCoords);
}


/* async */ function solveReverseRE() {
    console.debug("Attempting to parse codes from note.");

    //let resultmsg = document.getElementById("resultmsg");
    let resultmsg = document.getElementsByClassName("Note Disclaimer")[0];

    
    let codes = document.getElementById("viewCacheNote").textContent.split('\n');
    for(let i=0; i<codes.length; i++) {
      codes[i] = codes[i].trim().split(" ");
    }
    if (codes.length != 3) {
        console.error("ERROR Parsing codes => Expected syntax: <code 1 from> <code 1 to> <code 1 regexp>\n <code 2 from> ...");
        return;
    }
  
    console.debug("Parsed: " + JSON.stringify(codes));
    
    let code1from = parseInt( codes[0][0] );
    let code1to = parseInt( codes[0][1] );
  
    let code2from = parseInt( codes[1][0] );
    let code2to = parseInt( codes[1][1] );
  
    let code3from = parseInt( codes[2][0] );
    let code3to  = parseInt( codes[2][1] );
  
    let code1re = RegExp( codes[0][2] );
    let code2re = RegExp( codes[1][2] );
    let code3re = RegExp( codes[2][2] );
  
    let coords = document.getElementById("uxLatLon").textContent.split(" ");
    if( coords.length != 6 ) {
        console.error("Error parsing coordinates");
        return;
    }
  
    let bogusLat = dm2dd( coords[0], coords[1], coords[2] );
    let bogusLon = dm2dd( coords[3], coords[4], coords[5] );    
    
    console.debug("Parsed coords: " + JSON.stringify(coords));
    console.debug("Converted coords: " + bogusLat + "  " + bogusLon);
  
    console.log("code1,code2,code3,lat(dd),lon(dd),lat(gps),lon(gps),dist(m)");
    let counter = 0;
    console.debug("Iterating [" + code1from.toString().padStart(6, "0") + " -> " + code1to.toString().padStart(6, "0") + "],[" 
                                + code2from.toString().padStart(6, "0") + " -> " + code2to.toString().padStart(6, "0") + "],[" 
                                + code3from.toString().padStart(6, "0") + " -> " + code3to.toString().padStart(6, "0") + "]");
                                // [001234->001235],[321333->421333],[444111->444222]
    for( let i = code1from; i <= code1to; i++ ) {
          let code1 = i.toString().padStart(6, "0");
          if( code1re.test( code1 ) == false ) {
            continue;
          }
  
          for( let j = code2from; j <= code2to; j++ ) {
            let code2 = j.toString().padStart(6, "0");
            if( code2re.test( code2 ) == false ) {
              continue;
            }
  
            console.debug("Testing [" + i.toString().padStart(6, "0") + "],[" + j.toString().padStart(6, "0") + "],[" + code3from.toString().padStart(6, "0") + " -> " + code3to.toString().padStart(6, "0") + "]" );
            for( let k = code3from; k <= code3to; k++ ) {
              let code3 = k.toString().padStart(6, "0");
              if( code3re.test( code3 ) == false ) {
                continue;
              }
  
              let ddlatlon = /* await */ code2LatLon( code1, code2, code3 );
              if( ddlatlon.lat == NaN || ddlatlon.lon == NaN ) continue;
              else {
                let dist = haversineDistance( bogusLat, bogusLon, ddlatlon.lat, ddlatlon.lon );
    
                if( dist < 3220 ) {
                    counter = counter+1;
                    let dmlatlon = /* await */ dd2dm( ddlatlon.lat, ddlatlon.lon);
                    let result = code1 + "," + code2 + "," + code3 + "," + fix(ddlatlon.lat, 2, 6) + "," + fix(ddlatlon.lon, 3, 6) + "," + dmlatlon.lat + "," + dmlatlon.lon + "," + dist.toFixed(0) ;  
                    console.log(result);
                    resultmsg.innerText = resultmsg.innerText + "\n" + result;
                }
              }
            }
          }
      }
      console.log("Total " + counter + " matches found");
  }

  (/* async */ function() {
    'use strict';
    let from, result;

    let cacheType = document.getElementsByClassName("cacheImage")[0].title;

    createShowSourceButton();
    

    if( cacheType == "Wherigo Cache" ) {
        createShowSolveREReverseButton();
        createDialog();

        let re = /[0-9]{6}/g;
        let codes = document.getElementsByClassName("UserSuppliedContent")[1].innerText.match( re );
        if( codes !== null && (codes.length == 3 || codes.length == 6 || codes.length == 9) ) {

            let ddlatlon = /* await */ code2LatLon( codes[0], codes[1], codes[2] );
            let dmlatlon = /* await */ dd2dm( ddlatlon.lat, ddlatlon.lon);
            from = codes[0] + " " + codes[1] + " " + codes[2] + " => ";
            let resultDD = fix(ddlatlon.lat, 2, 6) + " " + fix(ddlatlon.lon, 3, 6);
            let resultDMD = dmlatlon.lat + " " + dmlatlon.lon;
            result = resultDMD;
            console.debug( from + " " + resultDD + " = " + resultDMD );
            document.getElementsByClassName("Note Disclaimer")[0].innerHTML = "<strong> Reversewigo final coordinates =  " + result + " </strong>";

            updateCoordinates( resultDMD );
        }
        else {
            console.warn("WARNING: no codes found from description - trying to find codes from user note:");
            codes = document.getElementById("viewCacheNote").innerText.match( re );
            if( codes !== null && (codes.length == 3 || codes.length == 6 || codes.length == 9) ) {
                let ddlatlon = /* await */ code2LatLon( codes[0], codes[1], codes[2] );
                let dmlatlon = /* await */ dd2dm( ddlatlon.lat, ddlatlon.lon);
                from = codes[0] + " " + codes[1] + " " + codes[2] + " => ";
                let resultDD = fix(ddlatlon.lat, 2, 6) + " " + fix(ddlatlon.lon, 3, 6);
                let resultDMD = dmlatlon.lat + " " + dmlatlon.lon;
                result = resultDMD;
                console.log( from + " " + resultDD + " = " + resultDMD );
                document.getElementsByClassName("Note Disclaimer")[0].innerHTML = "<strong> Reversewigo final coordinates =  " + result + " </strong>";
                updateCoordinates( resultDMD );
            }
            else {
                result = "Error: Three reverse wherigo codes not found";
                console.log( result );
                document.getElementsByClassName("Note Disclaimer")[0].innerHTML = "<strong> Reversewigo final coordinates =  " + result + " </strong>";
            }

        }
    }
})();