WME Road History

Saves state of roads in area and it finds changes between history snapshots.

目前為 2015-03-15 提交的版本,檢視 最新版本

// ==UserScript==
// @name                WME Road History
// @name:pl             WME Road History
// @description         Saves state of roads in area and it finds changes between history snapshots.
// @description:pl      Zapisuje stan obszaru mapy i tworzy historię zmian pomiędzy "migawkami" mapy.
// @include             https://www.waze.com/editor/*
// @include             https://www.waze.com/*/editor/*
// @include             https://editor-beta.waze.com/*
// @version             1.0.29
// @grant               none
// @namespace           https://greasyfork.org/pl/scripts/8593-wme-road-history
// @copyright           2015 wlodek76
// ==/UserScript==

var wmech_version = "1.0.29";

var epsg900913 = new OpenLayers.Projection("EPSG:900913");
var epsg4326   = new OpenLayers.Projection("EPSG:4326");

var lang   = {code:'en',
              amonly         : 'Tools for Area Managers or L3 editors.',
              trAB           : 'Time Restrictions (A do B):',
              trBA           : 'Time Restrictions (B do A):',
              removedtr      : 'Removed TR turn: ',
              changedtr      : 'Changed TR turn: ',
              addedtr        : 'Added TR turn: ',
              removed_uturn  : 'Removed U-Turn: ',
              added_uturn    : 'Added U-Turn: ',
              veh1           : 'Trucks',
              veh2           : 'Public Transportation',
              veh3           : 'Taxis',
              veh4           : 'Buses',
              veh5           : 'HOV - 2',
              veh6           : 'HOV - 3',
              veh7           : 'RV',
              veh8           : 'Towing vehicles',
              veh9           : 'Motorcycles',
              veh10          : 'Private vehicles',
              veh11          : 'Hazardous materials',
              exceptvehicles : 'Except vehicles: ',
              allweek      : 'All Week',
              day1         : 'Su',
              day2         : 'Mo',
              day3         : 'Tu',
              day4         : 'We',
              day5         : 'Th',
              day6         : 'Fr',
              day7         : 'Sa',
              allday       : 'All Day',
              atob         : 'A to B',
              btoa         : 'B to A',
              none         : 'None',
              trbefore     : 'Time restrictions before:',
              trafter      : 'Time restrictions:',
              tollchange   : 'Changed: ',
              tollpart     : 'Toll Road Partially',
              tollfree     : 'Toll Road Free',
              toll         : 'Toll Road',
              changename   : 'Street: ',
              changecity   : 'City: ',
              level        : 'Level: ',
              changedgeom  : 'Changed geometry',
              into         : 'to ',
              to           : 'to',
              noname       : 'No name',
              removedturn  : 'Removed turn: ',
              addedturn    : 'Added turn: ',
              road1        : 'Street',
              road2        : 'Primary Street',
              road3        : 'Freeway',
              road4        : 'Ramp',
              road5        : 'Walking Trail',
              road6        : 'Major Highway',
              road7        : 'Minor Highway',
              road8        : 'Dirt road / 4x4 Trail',
              road10       : 'Pedestrian Boardwalk',
              road17       : 'Private Road',
              road18       : 'Railroad',
              road19       : 'Runway / Taxiway',
              road20       : 'Parking Lot Road',
              road21       : 'Service Road',
              roadtype     : 'RoadType(',
              dirchange0   : '<b class=wmeroadhistory_error>Removed direction</b>',
              dirchange1   : 'Changed to <b class=wmeroadhistory_error>One-way</b>',
              dirchange2   : 'Changed to <b class=wmeroadhistory_error>Two-way</b>',
              dirchangerev : '<b class=wmeroadhistory_error>Reversed direction</b>',
              dirchangeadd : '<b class=wmeroadhistory_error>Added direction</b>',
              newsegment : 'New',
              sec : 'sec.',
              prev : 'Newest',
              next : 'Oldest',
              stop : 'Stop',
              changes: 'Changes',
              segments: 'Segments',
              edits: 'Edits',
              scanarea: 'Scan Area'
             };
var langPL = {code:'pl',
              amonly         : 'Narzędzie przeznaczone dla Area Manager lub edytorów L3.',
              trAB           : 'Ograniczenia czasowe (A do B):',
              trBA           : 'Ograniczenia czasowe (B do A):',
              removedtr      : 'Usunięty TR skrętu: ',
              changedtr      : 'Zmieniony TR skrętu: ',
              addedtr        : 'Dodany TR skrętu: ',
              removed_uturn  : 'Usunięte zawracanie: ',
              added_uturn    : 'Dodane zawracanie: ',
              veh1           : 'Ciężarówki',
              veh2           : 'Transport Publiczny',
              veh3           : 'Taksówki',
              veh4           : 'Autobusy',
              veh5           : 'Więcej niż 2 pasażerów (HOV - 2)',
              veh6           : 'Więcej niż 3 pasażerów (HOV - 3)',
              veh7           : 'Kamper',
              veh8           : 'Pojazdy holujące',
              veh9           : 'Motocykle',
              veh10          : 'Samochody prywatne',
              veh11          : 'Materiały niebezpieczne',
              exceptvehicles : 'Z wyjątkiem pojazdów: ',
              allweek      : 'Każdy tydzień',
              day1         : 'Nd',
              day2         : 'Pon',
              day3         : 'Wt',
              day4         : 'Śr',
              day5         : 'Czw',
              day6         : 'Pt',
              day7         : 'Sob',
              allday       : 'Cały dzień',
              atob         : 'A do B',
              btoa         : 'B do A',
              none         : 'Brak',
              trbefore     : 'Poprzednie ograniczenia czasowe:',
              trafter      : 'Ograniczenia czasowe:',
              tollchange   : 'Zmiana: ',
              tollpart     : 'Droga częściowo płatna',
              tollfree     : 'Droga bezpłatna',
              toll         : 'Droga płatna',
              changename   : 'Nazwa: ',
              changecity   : 'Miasto: ',
              level        : 'Poziom: ',
              changedgeom  : 'Zmiana geometrii',
              into         : 'w ',
              to           : 'do',
              noname       : 'Bez nazwy',
              removedturn  : 'Usunięto skręt: ',
              addedturn    : 'Dodano skręt: ',
              road1        : 'Ulica',
              road2        : 'Główna ulica',
              road3        : 'Autostrada / Droga ekspresowa',
              road4        : 'Wjazd / Zjazd',
              road5        : 'Ścieżka dla pieszych',
              road6        : 'Droga krajowa',
              road7        : 'Droga wojewódzka',
              road8        : 'Droga gruntowa',
              road10       : 'Deptak',
              road17       : 'Droga prywatna',
              road18       : 'Tory kolejowe / tramwajowe',
              road19       : 'Pas startowy / Droga kołowania',
              road20       : 'Droga wewnętrzna',
              road21       : 'Droga serwisowa',
              roadtype     : 'RoadType(',
              dirchange0   : '<b class=wmeroadhistory_error>Usunięto kierunkowość</b>',
              dirchange1   : 'Zmieniono na <b class=wmeroadhistory_error>Jednokierunkowa</b>',
              dirchange2   : 'Zmieniono na <b class=wmeroadhistory_error>Dwukierunkowa</b>',
              dirchangerev : '<b class=wmeroadhistory_error>Odwrócono kierunkowość</b>',
              dirchangeadd : '<b class=wmeroadhistory_error>Dodano kierunkowość</b>',
              newsegment : 'Nowy',
              sec : 'sek.',
              prev : 'Nowsze',
              next : 'Starsze',
              stop : 'Stop',
              changes: 'Zmiany',
              segments: 'Segmentów',
              edits: 'Edycje',
              scanarea: 'Skanuj Obszar'
             };

var DIFF_DIR    = 0x01;
var DIFF_TYPE   = 0x02;
var DIFF_TURNS  = 0x04;
var DIFF_NAMES  = 0x08;
var DIFF_CITY   = 0x10;
var DIFF_TR     = 0x20;
var DIFF_LEVEL  = 0x40;
var DIFF_GEOM   = 0x80;
var DIFF_TOLL   = 0x100;
var DIFF_TS     = 0x200;

var last_LONLAT;
var last_ZOOM;
var wazepending;
var rec_xy1;
var rec_xy2;
var rec = false;
var rec_direction = 1;
var rec_loop_count = 0;
var scanned_segments_list = '';
var scanned_segments = 0;
var scanned_segments_prev = 0;
var added_segments = 0;
var added_segments_prev = 0;
var added_changes = 0;
var added_changes_prev = 0;
var rec_zoom = 5;
var rec_elapsed_time = 0;
var wazeDataBaseName = 'wazeDB';
var wazeDB;
var readconfig = 0;
var LastTimeScan = 0;
var ShowHistMode = 2;
var pageEdits    = 0;
var prevScroll = 0;
var userinfoDispPrev = '';
var showturn = new Array();

//------------------------------------------------------------------------------------------------
window.indexedDB      = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange    = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange

if (!window.indexedDB) {
    window.alert("Your browser doesn't support a stable version of IndexedDB.")
}
//------------------------------------------------------------------------------------------------
var openrequest = window.indexedDB.open( wazeDataBaseName, 1 );

openrequest.onsuccess = function(event) {
    wazeDB = event.target.result;
    console.log("WMERoadHistory.DataBase.OK = ", openrequest.result.name );
};

openrequest.onerror = function(event) {
};

openrequest.onupgradeneeded = function(event) { 
    var db = event.target.result;

    var objectStore1 = db.createObjectStore("segments", { keyPath: "ID", autoIncrement: false });
    objectStore1.createIndex("T",    "T",    { unique: false });
    objectStore1.transaction.oncomplete = function(event) {
    }

    var objectStore2 = db.createObjectStore("changes", { keyPath: "nr", autoIncrement: true });
    objectStore2.createIndex("T",    "T",    { unique: false });
    objectStore2.transaction.oncomplete = function(event) {
    }
}
//------------------------------------------------------------------------------------------------
function bootstrapWMERoadHistory()
{
    var bGreasemonkeyServiceDefined = false;

    try {
        bGreasemonkeyServiceDefined = (typeof Components.interfaces.gmIGreasemonkeyService === "object");
    }
    catch (err) { /* Ignore */ }

    if (typeof unsafeWindow === "undefined" || ! bGreasemonkeyServiceDefined) {
        unsafeWindow    = ( function () {
            var dummyElem = document.createElement('p');
            dummyElem.setAttribute('onclick', 'return window;');
            return dummyElem.onclick();
        }) ();
    }
    
    setTimeout(initialiseWMERoadHistory, 999);
}
//------------------------------------------------------------------------------------------------
function getElementsByClassName(classname, node) {
    if(!node) node = document.getElementsByTagName("body")[0];
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = node.getElementsByTagName("*");
    for (var i=0,j=els.length; i<j; i++)
        if (re.test(els[i].className)) a.push(els[i]);
    return a;
}
//--------------------------------------------------------------------------------------------------------
function getId(node) {
    return document.getElementById(node);
}
//--------------------------------------------------------------------------------------------------------
function precFloat(f, prec)
{
	if (!isFinite(f)) return "&mdash;";

	if (f < 0) {
		f -= Math.pow(0.1, prec) * 0.5;
	}
	else {
		f += Math.pow(0.1, prec) * 0.5;
	}

	var ipart = parseInt(f);
	var fpart = Math.abs(f - ipart);
	f = ipart;

	if (fpart == '0') fpart = '0.0';
	fpart += '0000000000000000';
	if (prec) f += fpart.substr(1, prec + 1);

	return f;
}
//--------------------------------------------------------------------------------------------------------
function createCRC32() {
    var c, i, j,
        crcTable = [];
    for (i = 0; i < 256; i++) {
        c = i;
        for (j = 0; j < 8; j++) {
            c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
        }
        crcTable[i] = c;
    }

    return function (str) {
        var i,
            crc = 0 ^ (-1);

        for (i = 0; i < str.length; i++) {
            crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
        }

        return (crc ^ (-1)) >>> 0;
    };
}
//--------------------------------------------------------------------------------------------------------
var crc32 = createCRC32();
//--------------------------------------------------------------------------------------------------------
function updateSaveButton() {
    var obj = getId('wmeroadhistory_scanarea');
    if (rec == true)  {
        obj.style.backgroundColor = '#C00000';
        obj.style.color           = '#FFFFFF';
        obj.innerHTML             = lang.stop;
    }
    else {
        obj.style.backgroundColor = '';
        obj.style.color           = '';
        obj.innerHTML             = lang.scanarea;
    }
}
//--------------------------------------------------------------------------------------------------------
function stopRec(finished) {
    var WM = unsafeWindow.Waze.map;
    
    rec = false;
    updateSaveButton(rec);

    WM.panTo(last_LONLAT);
    WM.zoomTo(last_ZOOM);

    if (ShowHistMode == 0) wmeroadhistoryTAB2();
    if (ShowHistMode == 1) wmeroadhistoryTAB1();
    if (ShowHistMode == 2) wmeroadhistoryTAB2();
}
//--------------------------------------------------------------------------------------------------------
function getMidPointLen(seg) {

	var points, p1, p2;
	points = seg.geometry.components.length;
    
    var x      = 0;
    var y      = 0;
    var length = 0;

	if (points == 2) {
		p1 = seg.geometry.components[0];
		p2 = seg.geometry.components[1];
        
		x = p1.x + (p2.x - p1.x) * 0.5;
        y = p1.y + (p2.y - p1.y) * 0.5;

        var dx = p2.x - p1.x;
        var dy = p2.y - p1.y;
        length += Math.sqrt(dx*dx + dy*dy);
    }
    else {

        for(var i=0; i<points-1; i++) {
            p1 = seg.geometry.components[i + 0];
            p2 = seg.geometry.components[i + 1];

            var dx = p2.x - p1.x;
            var dy = p2.y - p1.y;
            length += Math.sqrt(dx*dx + dy*dy);
        }
        var midlen = length / 2.0;

        var length1 = 0;
        var length2 = 0;
        for(var i=0; i<points-1; i++) {
            p1 = seg.geometry.components[i + 0];
            p2 = seg.geometry.components[i + 1];
            var dx = p2.x - p1.x;
            var dy = p2.y - p1.y;
            length1 = length2;
            length2 = length2 + Math.sqrt(dx*dx + dy*dy);

            if (midlen >= length1 && midlen < length2) {
                var proc = (midlen - length1) / (length2 - length1);
                x = p1.x + (p2.x - p1.x) * proc;
                y = p1.y + (p2.y - p1.y) * proc;
            }
        }
    }
    
    var xyd = { x:x, y:y, d:length};
    
    return xyd;
}
//------------------------------------------------------------------------------------------------
function changesDB(diff, segID, segtime, segeditor, segx, segy, segnames, segcity, before, after, segkind, segequal) {

    var item = { ID: segID, T: segtime, E: segeditor, D: diff, x: segx, y: segy, N: segnames, C: segcity, K: segkind, Q: segequal};
    if (diff & DIFF_DIR)   item.drA   = before.D;
    if (diff & DIFF_DIR)   item.drB   =  after.D;
    if (diff & DIFF_TYPE)  item.tyA   = before.K;
    if (diff & DIFF_TYPE)  item.tyB   =  after.K;
    if (diff & DIFF_TURNS) item.arA   = before.A;
    if (diff & DIFF_TURNS) item.arB   =  after.A;
    if (diff & DIFF_NAMES) item.naA   = before.N;
    if (diff & DIFF_NAMES) item.naB   =  after.N;
    if (diff & DIFF_CITY)  item.ciA   = before.C;
    if (diff & DIFF_CITY)  item.ciB   =  after.C;
    if (diff & DIFF_TR)    item.trA   = before.TR;
    if (diff & DIFF_TR)    item.trB   =  after.TR;
    if (diff & DIFF_TS)    item.tsA   = before.TS;
    if (diff & DIFF_TS)    item.tsB   =  after.TS;
    if (diff & DIFF_LEVEL) item.lvA   = before.L;
    if (diff & DIFF_LEVEL) item.lvB   =  after.L;
    if (diff & DIFF_GEOM)  item.geA   = before.G;
    if (diff & DIFF_GEOM)  item.geB   =  after.G;
    if (diff & DIFF_TOLL)  item.tolA  = before.TL;
    if (diff & DIFF_TOLL)  item.tolB  =  after.TL;
    
    var objectStore = wazeDB.transaction('changes', 'readwrite').objectStore('changes');
    var request = objectStore.add( item );
    request.onsuccess = function() {
        added_changes++;
    }
    request.onerror = function() {
    }
}
//--------------------------------------------------------------------------------------------------------
function addDB(segID, roadtime, roadeditor, roaddir, roadkind, roadarrows, roadnames, roadcity, roadtr, roadts, roadlevel, roadgeom, roadtoll, roadx, roady, roadequal, roadpoints) {

    var objectStore = wazeDB.transaction('segments', 'readwrite').objectStore('segments');
    var request = objectStore.get( segID );
    request.onsuccess = function() {
        if(request.result) {
            var item = { ID: segID, T: roadtime, E: roadeditor, D: roaddir, K: roadkind, A: roadarrows, N: roadnames, C: roadcity, TR: roadtr, TS: roadts, L: roadlevel, G: roadgeom, TL: roadtoll, x: roadx, y: roady, Q:roadequal, P:roadpoints };
            var rekord = request.result;

            var diff = 0;
            if (roaddir     != rekord.D)   diff |= DIFF_DIR;
            if (roadkind    != rekord.K)   diff |= DIFF_TYPE;
            if (roadarrows  != rekord.A)   diff |= DIFF_TURNS;
            if (roadnames   != rekord.N)   diff |= DIFF_NAMES;
            if (roadcity    != rekord.C)   diff |= DIFF_CITY;
            if (roadtr      != rekord.TR)  diff |= DIFF_TR;
            if (roadts      != rekord.TS)  diff |= DIFF_TS;
            if (roadlevel   != rekord.L)   diff |= DIFF_LEVEL;
            if (roadgeom    != rekord.G)   diff |= DIFF_GEOM;
            if (roadtoll    != rekord.TL)  diff |= DIFF_TOLL;
            
            if (diff) {
                if (roadtime == rekord.T) {
                    var t = new Date();
                    roadtime   = parseInt(t.getTime() / 1000);
                    roadeditor = '?';
                }
                
                changesDB(diff, segID, roadtime, roadeditor, roadx, roady, roadnames, roadcity, rekord, item, roadkind, roadequal);
                objectStore.put( item );
            }
        }
        else {
            var item = { ID: segID, T: roadtime, E: roadeditor, D: roaddir, K: roadkind, A: roadarrows, N: roadnames, C: roadcity, TR: roadtr, TS:roadts, L: roadlevel, G: roadgeom, TL: roadtoll, x: roadx, y: roady, Q:roadequal, P:roadpoints };
            objectStore.put( item );
            added_segments++;
        }
    }
    request.onerror = function() {
    }
}
//--------------------------------------------------------------------------------------------------------
function SCAN_SEGMENTS() {

    for (var seg in Waze.model.segments.objects) {
        var segment    = Waze.model.segments.get(seg);
        var attributes = segment.attributes;
        var line       = getId(segment.geometry.id);
        var segID      = attributes.id;

        if (line !== null && segID !== null) {
            
            var s = 'S' + segID + '·';
            
            if (scanned_segments_list.indexOf(s) == -1) {
                scanned_segments_list += s;
                scanned_segments++;

                var roadtime      = parseInt(attributes.updatedOn / 1000);
                var roadcreated   = parseInt(attributes.createdOn / 1000);
                var roadequal     = 0;
                
                if (roadtime == roadcreated) roadequal = 1;
                
                var roadeditor = parseInt(attributes.updatedBy);
                var user = Waze.model.users.get(roadeditor);
                if (user === null || typeof(user) === "undefined") roadeditor = '-';
                else                                               roadeditor = user.userName + '(' + user.normalizedLevel + ')';
                
                var roadkind = parseInt(attributes.roadType);
                var roaddir  = (attributes.fwdDirection ? 1 : 0) * 2 + (attributes.revDirection ? 1 : 0);

                var roadarrows = '';

                for (s in attributes.fromConnections) { roadarrows += 'A' + parseInt(s) + '·'; }
                for (s in attributes.toConnections)   { roadarrows += 'B' + parseInt(s) + '·'; }

                var roadnames = '';
                var roadcity = '';
                
                var street = Waze.model.streets.get(attributes.primaryStreetID);
                if (street != undefined) {
                    if (street.name != null) {
                        roadnames += street.name;
                    }
                    if (street.cityID != null) {
                        roadcity = Waze.model.cities.get(street.cityID).isEmpty ? '·' : Waze.model.cities.get(street.cityID).name;
                    }
                }
                for(var j=0; j<attributes.streetIDs.length; j++) {
                    var sid = attributes.streetIDs[j];
                    if (sid !== null) {
                        var street = Waze.model.streets.get(sid);
                        if (street != undefined) {
                            if (street.name != null) {
                                if (roadnames != '') roadnames += ", ";
                                roadnames += street.name;
                            }
                        }
                    }
                }
                
                var roadtr = '';
                
                var tr = attributes.fwdRestrictions;
                if (tr.length) {
                    roadtr += 'AB¹';
                    for(var i=0; i<tr.length; i++) {
                        roadtr += (tr[i].allDay==true ? 1 : 0) + '·';
                        roadtr += tr[i].days + '·';
                        roadtr += tr[i].description + '·';
                        roadtr += (tr[i].enabled ? 1 : 0) + '·';
                        roadtr += (tr[i].fromDate == null ? ''      : tr[i].fromDate) + '·';
                        roadtr += (tr[i].fromTime == null ? '00:00' : tr[i].fromTime) + '·';
                        roadtr += (tr[i].toDate == null   ? ''      : tr[i].toDate)   + '·';
                        roadtr += (tr[i].toTime == null   ? '23:59' : tr[i].toTime)   + '·';
                        roadtr += tr[i].vehicleTypes + '¹';
                    }
                    roadtr += '²';
                }
                
                var tr = attributes.revRestrictions;
                if (tr.length) {
                    roadtr += 'BA¹';
                    for(var i=0; i<tr.length; i++) {
                        roadtr += (tr[i].allDay==true ? 1 : 0) + '·';
                        roadtr += tr[i].days + '·';
                        roadtr += tr[i].description + '·';
                        roadtr += (tr[i].enabled ? 1 : 0) + '·';
                        roadtr += (tr[i].fromDate == null ? ''      : tr[i].fromDate) + '·';
                        roadtr += (tr[i].fromTime == null ? '00:00' : tr[i].fromTime) + '·';
                        roadtr += (tr[i].toDate == null   ? ''      : tr[i].toDate)   + '·';
                        roadtr += (tr[i].toTime == null   ? '23:59' : tr[i].toTime)   + '·';
                        roadtr += tr[i].vehicleTypes + '¹';
                    }
                    roadtr += '²';
                }
                
                var roadts = '';

                for(trseg in attributes.toRestrictions) {
                    var tr = attributes.toRestrictions[trseg];
                    roadts += 'B' + trseg + '¹';
                    for(var i=0; i<tr.length; i++) {
                        roadts += (tr[i].allDay==true ? 1 : 0) + '·';
                        roadts += tr[i].days + '·';
                        roadts += tr[i].description + '·';
                        roadts += (tr[i].enabled ? 1 : 0) + '·';
                        roadts += (tr[i].fromDate == null ? ''      : tr[i].fromDate) + '·';
                        roadts += (tr[i].fromTime == null ? '00:00' : tr[i].fromTime) + '·';
                        roadts += (tr[i].toDate == null   ? ''      : tr[i].toDate)   + '·';
                        roadts += (tr[i].toTime == null   ? '23:59' : tr[i].toTime)   + '·';
                        roadts += tr[i].vehicleTypes + '¹';
                    }
                    roadts += '²';
                }

                for(trseg in attributes.fromRestrictions) {
                    var tr = attributes.fromRestrictions[trseg];
                    roadts += 'A' + trseg + '¹';
                    for(var i=0; i<tr.length; i++) {
                        roadts += (tr[i].allDay==true ? 1 : 0) + '·';
                        roadts += tr[i].days + '·';
                        roadts += tr[i].description + '·';
                        roadts += (tr[i].enabled ? 1 : 0) + '·';
                        roadts += (tr[i].fromDate == null ? ''      : tr[i].fromDate) + '·';
                        roadts += (tr[i].fromTime == null ? '00:00' : tr[i].fromTime) + '·';
                        roadts += (tr[i].toDate == null   ? ''      : tr[i].toDate)   + '·';
                        roadts += (tr[i].toTime == null   ? '23:59' : tr[i].toTime)   + '·';
                        roadts += tr[i].vehicleTypes + '¹';
                    }
                    roadts += '²';
                }
                

                var roadlevel = parseInt(attributes.level);
                var roadgeom  = crc32(attributes.geometry.toString());
                var roadtoll  = (attributes.fwdToll ? 1 : 0) * 2 + (attributes.revToll ? 1 : 0);
                
                var xyd = getMidPointLen( segment );
                var roadx = parseInt( xyd.x );
                var roady = parseInt( xyd.y );
                
                var roadpoints = new Array();
                var points = attributes.geometry.components;
                var num = points.length;
                if (num >= 2) {
                    roadpoints.push ( parseInt(points[0].x + 0.5) );
                    roadpoints.push ( parseInt(points[0].y + 0.5) );
                    roadpoints.push ( parseInt(points[num-1].x + 0.5) );
                    roadpoints.push ( parseInt(points[num-1].y + 0.5) );
                }
                
                addDB(segID, roadtime, roadeditor, roaddir, roadkind, roadarrows, roadnames, roadcity, roadtr, roadts, roadlevel, roadgeom, roadtoll, roadx, roady, roadequal, roadpoints);
            }
        }
    }

    updateCountTime();
}
//--------------------------------------------------------------------------------------------------------
function updateCountTime() {
    var tNow = new Date();
    var t = parseInt( (tNow.getTime() - rec_elapsed_time) / 1000);
    var ts = '';
    if (t < 60) {
        ts = t + ' ' + lang.sec;
    }
    else {
        var a = parseInt(t / 60);
        var b = t - a*60;
        if (b<10) ts = a + ':0' + b + ' min.'
        else      ts = a + ':'  + b + ' min.'
    }
    
    var bs = '';
    var be = '';
    if (added_changes) {
        bs = '<b>';
        be = '</b>';
    }
    
    getId('wmeroadhistory_log').innerHTML = lang.segments + ': ' + added_segments + ' &nbsp; ' + bs + lang.changes + ': '  + added_changes + be + ' &nbsp; ' + '(' + ts + ')';
}
//--------------------------------------------------------------------------------------------------------
function selectShowTurn(segs) {
    
    var num = segs.length;
    for(var i=0; i<num; i++) {

        var segment = Waze.model.segments.get( segs[i] );
        if (segment !== undefined) {

            var line = getId(segment.geometry.id);
            if (line !== null) {
                
                var color     = line.getAttribute("stroke");
                var opacity   = line.getAttribute("stroke-opacity");
                var lineWidth = line.getAttribute("stroke-width");

                var selected = false;
                if (opacity == 1 || lineWidth == 9) selected = true;
                if (color == '#CC3738') selected = false;
                if (color == '#FF0506') selected = false;

                if (!selected) {
                    if (i < num-2) {
                        line.setAttribute("stroke", "#dd7700");
                        line.setAttribute("stroke-opacity", 0.001 );
                        line.setAttribute("stroke-width", 2);
                    }
                    else {
                        if (i == num-2) {
                            line.setAttribute("stroke", "#CC3738");
                            line.setAttribute("stroke-opacity", 0.5 );
                            line.setAttribute("stroke-width", 9);
                        }
                        else {
                            line.setAttribute("stroke", "#FF0506");
                            line.setAttribute("stroke-opacity", 0.8 );
                            line.setAttribute("stroke-width", 9);
                        }
                    }
                }
            }
        }
    }
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryLOOP() {
    if (added_segments     != added_segments_prev || added_changes != added_changes_prev) {
        added_segments_prev = added_segments;
        added_changes_prev  = added_changes;
        updateCountTime();
    }
    
    //--------------pokazanie graficznego skrętu
    if ( showturn.length >= 2 ) {
        selectShowTurn(showturn);
    }


    //--------------przywrócenie pozycji sidebar, która resetuje się po zaznaczeniu segmentu
    if (getId('wmeroadhistory_scanarea').onclick == null) {
        getId('wmeroadhistory_list').innerHTML = '<p class=wmeroadhistory_amonly>' + lang.amonly + '</p>';
    }
    var scanarea      = getId('wmeroadhistory_scanarea');
    var tab           = getId('wmeroadhistory_tab');
    var sidebar       = getId('sidebar');
    var userinfoDisp  = getId('user-info').style.display;
    if (tab.className == 'active') {
        if (userinfoDisp == 'block') {
            if (userinfoDisp != userinfoDispPrev) {
                sidebar.scrollTop = prevScroll;
                //alert('sidebar restore');
            }
            prevScroll = sidebar.scrollTop;
        }
        userinfoDispPrev = userinfoDisp;
    }

    if (rec) {

        var p = wazepending.className.indexOf("hidden");
        if (p >= 0) {

            var WM   = unsafeWindow.Waze.map;
            var zoom = WM.getZoom();
            var W    = WM.getSize().w;
            var H    = WM.getSize().h;

            if (zoom == rec_zoom) {

                W -= 30;
                H -= 30;

                rec_loop_count++;

                SCAN_SEGMENTS();

                var cent = WM.getCenter();
                if (rec_direction == 1 && cent.lon > rec_xy2.lon) rec_direction = 2;
                if (rec_direction == 3 && cent.lon < rec_xy1.lon) rec_direction = 4;

                if      (rec_direction == 1)   WM.pan( W, 0);
                else if (rec_direction == 2) { WM.pan( 0, H); rec_direction = 3; }
                else if (rec_direction == 3)   WM.pan(-W, 0);
                else if (rec_direction == 4) { WM.pan( 0, H); rec_direction = 1; }

                if (cent.lon > rec_xy2.lon && cent.lat < rec_xy2.lat) {
                    stopRec(true);
                    LastTimeScan = rec_elapsed_time;
                }
            }
        }
    }
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistorySCANAREA() {

    var WM = unsafeWindow.Waze.map;

    if (rec) {
        stopRec(false);
    }
    else {

        while ( showturn.length ) { showturn.pop(); }

        last_LONLAT = WM.getCenter();
        last_ZOOM   = WM.getZoom();

        var W = WM.getSize().w;
        var H = WM.getSize().h;

        var e1 = new OL.Geometry.Point(0, 0);
        var e2 = new OL.Geometry.Point(W, H);

        rec_xy1    = WM.getLonLatFromViewPortPx(e1);
        rec_xy2    = WM.getLonLatFromViewPortPx(e2);

        rec_direction = 1;
        getId('wmeroadhistory_log').innerHTML = '&nbsp;';

        scanned_segments_list = '';
        scanned_segments = 0;
        scanned_segments_prev = 0;
        added_segments = 0;
        added_segments_prev = 0;
        added_changes = 0;
        added_changes_prev = 0;

        var tNow = new Date();
        rec_elapsed_time = tNow.getTime();

        rec_zoom = last_ZOOM + 1;
        if (rec_zoom < 5)  rec_zoom = 5;
        if (rec_zoom > 10) rec_zoom = 10;

        if (typeof Waze == 'undefined')              Waze = unsafeWindow.Waze;
        if (typeof Waze.loginManager == 'undefined') Waze.loginManager = unsafeWindow.Waze.loginManager;
        if (typeof Waze.loginManager == 'undefined') Waze.loginManager = unsafeWindow.loginManager;
        if (Waze.loginManager !== null && Waze.loginManager.isLoggedIn()) {
            thisUser = Waze.loginManager.user;
            var lev = thisUser.normalizedLevel;
            if (thisUser !== null && (lev*lev >= lev+lev+lev || thisUser.isAreaManager)) {

                rec = true;
                WM.zoomTo(rec_zoom);
                WM.panTo(rec_xy1);

                updateSaveButton(rec);
            }
        }
    }
}
//--------------------------------------------------------------------------------------------------------
function htmlEntities(str) {
    return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/\'/g, '&#39;').replace(/\r/g, ' ').replace(/\n/g, ' ');
}
//--------------------------------------------------------------------------------------------------------
function gotoXY(x, y) {
    var WM = unsafeWindow.Waze.map;
    var xy = new OL.LonLat( x, y );
    
    WM.panTo(xy);
    WM.zoomTo(7);
}
//--------------------------------------------------------------------------------------------------------
function createLink(segx, segy, zoom, idsegments) {
    var WM = unsafeWindow.Waze.map;

    var docurl = document.URL;
    var docurlparams = docurl.split('&');
    
    var layers = '';
    var link = '';
    for(var i=0; i<docurlparams.length; i++) {
        if (docurlparams[i].indexOf( 'waze.com' ) >= 0) link   = docurlparams[i];
        if (docurlparams[i].indexOf( 'layers' )   >= 0) layers = docurlparams[i];
    }

    var lonlat = new OL.LonLat(segx, segy).transform(epsg900913, epsg4326);

    link += '&lon='  + parseInt(lonlat.lon * 1000000 + 0.5) / 1000000;
    link += '&lat='  + parseInt(lonlat.lat * 1000000 + 0.5) / 1000000;
    if (layers != '') link += '&' + layers;
    link += '&zoom=' + zoom;
    link += '&segments=' + idsegments;
    
    return link;
}
//--------------------------------------------------------------------------------------------------------
function gotoTURN(event) {
    var WM = unsafeWindow.Waze.map;
    
    var segs = event.target.id.split('_');
    var seg1 = parseInt( segs[1] );
    var segN = segs[2];
    var seg2 = parseInt( segs[3] );

    var objectStore = wazeDB.transaction('segments', 'readonly').objectStore('segments');
    var request = objectStore.get( seg1 );
    request.onsuccess = function() {
        var rekord = request.result;
        if(rekord) {
            
            if (rekord.P.length >= 2) {
                if (segN == 'A') {
                    var x = rekord.P[ 0 ];
                    var y = rekord.P[ 1 ];
                }
                else {
                    var x = rekord.P[ rekord.P.length - 2 ];
                    var y = rekord.P[ rekord.P.length - 1 ];
                }
                var xy = new OL.LonLat( x, y );
                
                showturn.push(seg1);
                showturn.push(seg2);

                WM.panTo(xy);
                WM.zoomTo(7);
            }
            
        }
    }
    
}
//--------------------------------------------------------------------------------------------------------
function foundPELinkName( pe, seg2 ) {
    
    var objectStore = wazeDB.transaction('segments', 'readonly').objectStore('segments');
    var request = objectStore.get( seg2 );
    request.onsuccess = function() {
        var rekord = request.result;
        if (rekord) {
            if (rekord.N == '') pe.innerHTML = lang.into + lang.noname;
            else                pe.innerHTML = lang.into + rekord.N;
        }
    }
}
//--------------------------------------------------------------------------------------------------------
function formatRestriction(str, bs, be) {
    var items = str.split('·');
    
    var li = document.createElement('p');
    
    if (items[4]=='') li.innerHTML += bs +  lang.allweek                                                         + be + '<br>';
    else              li.innerHTML += bs +  items[4] + ' <span style="font-weight:normal">..</span> ' + items[6] + be + '<br>';  
    
    if (items[0] == 0) li.innerHTML += bs + items[5] + ' - ' + items[7] + be + '<br>';
    
    if (items[1] != 127) {
        var html = bs;
        if (items[1] & 0x01) { if (html!='') html+=' · '; html += lang.day1; }
        if (items[1] & 0x02) { if (html!='') html+=' · '; html += lang.day2; }
        if (items[1] & 0x04) { if (html!='') html+=' · '; html += lang.day3; }
        if (items[1] & 0x08) { if (html!='') html+=' · '; html += lang.day4; }
        if (items[1] & 0x10) { if (html!='') html+=' · '; html += lang.day5; }
        if (items[1] & 0x20) { if (html!='') html+=' · '; html += lang.day6; }
        if (items[1] & 0x40) { if (html!='') html+=' · '; html += lang.day7; }
        html += be + '<br>';
        li.innerHTML += html;
    }
    if (items[2]!='') li.innerHTML += '<i>&quot;' + htmlEntities(items[2]) + '&quot;</i><br>';
    
    if (items[8] != '-1') {
        li.innerHTML += lang.exceptvehicles + '<br>';
        var html = bs;
        if ((items[8] & 0x01)==0)  html += '- ' + lang.veh1  + '<br>';
        if ((items[8] & 0x02)==0)  html += '- ' + lang.veh2  + '<br>';
        if ((items[8] & 0x04)==0)  html += '- ' + lang.veh3  + '<br>';
        if ((items[8] & 0x08)==0)  html += '- ' + lang.veh4  + '<br>';
        if ((items[8] & 0x10)==0)  html += '- ' + lang.veh5  + '<br>';
        if ((items[8] & 0x20)==0)  html += '- ' + lang.veh6  + '<br>';
        if ((items[8] & 0x40)==0)  html += '- ' + lang.veh7  + '<br>';
        if ((items[8] & 0x80)==0)  html += '- ' + lang.veh8  + '<br>';
        if ((items[8] & 0x100)==0) html += '- ' + lang.veh9  + '<br>';
        if ((items[8] & 0x200)==0) html += '- ' + lang.veh10 + '<br>';
        if ((items[8] & 0x400)==0) html += '- ' + lang.veh11 + '<br>';
        html += be;
        li.innerHTML += html;
    }
    
    return li;
}
//--------------------------------------------------------------------------------------------------------
function showEdits(histmode, fromPage) {

    var objlist = getId('wmeroadhistory_list');
    if (objlist == null) return;

    var range, transaction, store, index;

    if (histmode == 1) {
        range = IDBKeyRange.upperBound( 9999999999 );
        transaction = wazeDB.transaction(["changes"], "readonly");
        store = transaction.objectStore("changes");
        index = store.index("T");
    }
    else {
        range = IDBKeyRange.upperBound( 9999999999 );
        transaction = wazeDB.transaction(["segments"], "readonly");
        store = transaction.objectStore("segments");
        index = store.index("T");
    }

    var count = 0;
    var page = 0;
    var end = 0;

    var t = new Date();
    var curtime = parseInt( t.getTime() / 1000);

    index.openCursor(range, "prev").onsuccess = function(event) {
        var cursor = event.target.result;
        if (cursor) {

            if (page < fromPage) {
                page++;
                cursor.advance( 50 );
            }
            else if (count < 50) {
                
                var segid     = cursor.value.ID;
                var segtime   = cursor.value.T;
                var segeditor = cursor.value.E;
                var segnames  = cursor.value.N;
                var segcity   = cursor.value.C;
                var segx      = cursor.value.x;
                var segy      = cursor.value.y;
                var segkind   = cursor.value.K;
                var segequal  = cursor.value.Q;

                var h1 = document.createElement('h1');
                var h2 = document.createElement('h2');
                var ul = document.createElement('ul');
                var h4 = document.createElement('h4');
                var h5 = document.createElement('h5');
                var h6 = document.createElement('h6');
                var hr = document.createElement('hr');

                if (histmode == 1) {


                    if (cursor.value.drA != null && cursor.value.drB != null) {
                        
                        var li = document.createElement('li');
                        
                        if (cursor.value.drA == 0)     li.innerHTML = lang.dirchangeadd;

                        if (cursor.value.drA == 1) {
                            if (cursor.value.drB == 0) li.innerHTML = lang.dirchange0;
                            if (cursor.value.drB == 2) li.innerHTML = lang.dirchangerev;
                            if (cursor.value.drB == 3) li.innerHTML = lang.dirchange2;
                        }

                        if (cursor.value.drA == 2) {
                            if (cursor.value.drB == 0) li.innerHTML = lang.dirchange0;
                            if (cursor.value.drB == 1) li.innerHTML = lang.dirchangerev;
                            if (cursor.value.drB == 3) li.innerHTML = lang.dirchange2;
                        }

                        if (cursor.value.drA == 3) {
                            if (cursor.value.drB == 0) li.innerHTML = lang.dirchange0;
                            if (cursor.value.drB == 1) li.innerHTML = lang.dirchange1;
                            if (cursor.value.drB == 2) li.innerHTML = lang.dirchange1;
                        }
                        
                        ul.appendChild(li);
                    }


                    var tyA = cursor.value.tyA;
                    var tyB = cursor.value.tyB;
                    if (tyA != null && tyB != null) {
                        
                        var li = document.createElement('li');
                        
                        var html = '';

                        switch (tyA) {
                            case 1:  html += lang.road1;  break;
                            case 2:  html += lang.road2;  break;
                            case 3:  html += lang.road3;  break;
                            case 4:  html += lang.road4;  break;
                            case 5:  html += lang.road5;  break;
                            case 6:  html += lang.road6;  break;
                            case 7:  html += lang.road7;  break;
                            case 8:  html += lang.road8;  break;
                            case 10: html += lang.road10; break;
                            case 17: html += lang.road17; break;
                            case 18: html += lang.road18; break;
                            case 19: html += lang.road19; break;
                            case 20: html += lang.road20; break;
                            default: html += lang.roadtype + tyA + ')'; break;
                        }
                        
                        html += ' » <b class=wmeroadhistory_kind >';
                        
                        switch (tyB) {
                            case 1:  html += lang.road1;  break;
                            case 2:  html += lang.road2;  break;
                            case 3:  html += lang.road3;  break;
                            case 4:  html += lang.road4;  break;
                            case 5:  html += lang.road5;  break;
                            case 6:  html += lang.road6;  break;
                            case 7:  html += lang.road7;  break;
                            case 8:  html += lang.road8;  break;
                            case 10: html += lang.road10; break;
                            case 17: html += lang.road17; break;
                            case 18: html += lang.road18; break;
                            case 19: html += lang.road19; break;
                            case 20: html += lang.road20; break;
                            default: html += lang.roadtype + tyB + ')'; break;
                        }

                        html += '</b>';
                        li.innerHTML = html;

                        ul.appendChild(li);
                    }

                    
                    
                    var arA       = cursor.value.arA;
                    var arB       = cursor.value.arB;
                    if (arA != null && arB != null) {

                        var turnsA = arA.split('·');
                        var turnsB = arB.split('·');

                        for(var i=0; i<turnsA.length - 1; i++) {
                            var p = arB.indexOf( turnsA[i] + '·' );
                            if (p < 0) {

                                var seg1 = segid;
                                var segN = turnsA[i].substr(0,1);
                                var seg2 = turnsA[i].substr(1,12);

                                var li = document.createElement('li');
                                if (seg1 == seg2) li.innerHTML += '<b class=wmeroadhistory_uturn >' + lang.removed_uturn + '</b>';
                                else              li.innerHTML += '<b class=wmeroadhistory_error >' + lang.removedturn + '</b>'; 

                                var pe = document.createElement('p');
                                pe.innerHTML = 'link';
                                pe.className = 'wmeroadhistory_turnlink';
                                pe.id = 'turnlink_' + seg1 + '_' + segN + '_' + seg2;

                                foundPELinkName( pe, parseInt(seg2) );

                                pe.onclick = (function(event) {
                                    gotoTURN(event);
                                });
                                li.appendChild(pe);

                                ul.appendChild(li);
                            }
                        }

                        for(var i=0; i<turnsB.length - 1; i++) {
                            var p = arA.indexOf( turnsB[i] + '·' );
                            if (p < 0) {

                                var seg1 = segid;
                                var segN = turnsB[i].substr(0,1);
                                var seg2 = turnsB[i].substr(1,12);

                                var li = document.createElement('li');
                                if (seg1 == seg2) li.innerHTML += '<b class=wmeroadhistory_uturn >' + lang.added_uturn + '</b>';
                                else              li.innerHTML += '<b class=wmeroadhistory_error >' + lang.addedturn + '</b>';
                                
                                var pe = document.createElement('p');
                                pe.innerHTML = 'link';
                                pe.className = 'wmeroadhistory_turnlink';
                                pe.id = 'turnlink_' + seg1 + '_' + segN + '_' + seg2;

                                foundPELinkName( pe, parseInt(seg2) );

                                pe.onclick = (function(event) {
                                    gotoTURN(event);
                                });
                                li.appendChild(pe);

                                ul.appendChild(li);
                            }
                        }
                    }

                   
                    if (cursor.value.naA != null && cursor.value.naB != null) {
                        var li = document.createElement('li');
                        li.innerHTML = lang.changename + cursor.value.naA + ' » ' + cursor.value.naB;
                        ul.appendChild(li);
                    }

                    if (cursor.value.ciA != null && cursor.value.ciB != null) {
                        var li = document.createElement('li');
                        li.innerHTML = lang.changecity + cursor.value.ciA + ' » ' + cursor.value.ciB;
                        ul.appendChild(li);
                    }

                    if (cursor.value.geA != null && cursor.value.geB != null) {
                        var li = document.createElement('li');
                        li.innerHTML = lang.changedgeom;
                        ul.appendChild(li);
                    }

                    if (cursor.value.lvA != null && cursor.value.lvB != null) {
                        var li = document.createElement('li');
                        li.innerHTML = lang.level + cursor.value.lvA + ' » ' + cursor.value.lvB;
                        ul.appendChild(li);
                    }

                    if (cursor.value.tolA != null && cursor.value.tolB != null) {
                        var li = document.createElement('li');

                        if (cursor.value.tolA == 0) li.innerHTML += lang.tollfree;
                        if (cursor.value.tolA == 1) li.innerHTML += lang.tollpart;
                        if (cursor.value.tolA == 2) li.innerHTML += lang.tollpart;
                        if (cursor.value.tolA == 3) li.innerHTML += lang.toll;
                        
                        if (cursor.value.tolB == 0) li.innerHTML += ' » <b class=wmeroadhistory_toll>' + lang.tollfree + '</b>';
                        if (cursor.value.tolB == 1) li.innerHTML += ' » <b class=wmeroadhistory_toll>' + lang.tollpart + '</b>';
                        if (cursor.value.tolB == 2) li.innerHTML += ' » <b class=wmeroadhistory_toll>' + lang.tollpart + '</b>';
                        if (cursor.value.tolB == 3) li.innerHTML += ' » <b class=wmeroadhistory_toll>' + lang.toll     + '</b>';

                        ul.appendChild(li);
                    }
                    
                    var trBefore = cursor.value.trA;
                    var trAfter  = cursor.value.trB;
                    if (trBefore != null && trAfter != null) {

                        var before = trBefore.split('²');
                        var after  = trAfter.split('²');
                        
                        var abBefore = '';
                        var abAfter  = '';
                        var baBefore = '';
                        var baAfter  = '';
                        
                        for(var i=0; i<before.length - 1; i++) {
                            if (before[i].indexOf('AB¹') == 0) abBefore = before[i];
                            if (before[i].indexOf('BA¹') == 0) baBefore = before[i];
                        }

                        for(var i=0; i<after.length - 1; i++) {
                            if (after[i].indexOf('AB¹') == 0) abAfter = after[i];
                            if (after[i].indexOf('BA¹') == 0) baAfter = after[i];
                        }
                        
                        if (abBefore != abAfter) {

                            var li = document.createElement('li');
                            li.innerHTML = '<b class=wmeroadhistory_trafter>' + lang.trAB + '</b>';
                            ul.appendChild(li);

                            if (abAfter == '') {
                                var li = document.createElement('p');
                                li.innerHTML = '<b class=wmeroadhistory_trafter>' + lang.none + '</b>';
                                ul.appendChild(li);
                            }
                            else {
                                var lines = abAfter.split('¹');
                                for(var i=1; i<lines.length-1; i++) {
                                    var li = formatRestriction( lines[i], '<b class=wmeroadhistory_trafter>', '</b>');
                                    ul.appendChild(li);
                                }
                            }

                            var lines = abBefore.split('¹');
                            for(var i=1; i<lines.length-1; i++) {
                                var li = formatRestriction( lines[i], '', '');
                                li.className = 'wmeroadhistory_trbefore';
                                ul.appendChild(li);
                            }
                        }

                        if (baBefore != baAfter) {

                            var li = document.createElement('li');
                            li.innerHTML = '<b class=wmeroadhistory_trafter>' + lang.trBA + '</b>';
                            ul.appendChild(li);

                            if (baAfter == '') {
                                var li = document.createElement('p');
                                li.innerHTML = '<b class=wmeroadhistory_trafter>' + lang.none + '</b>';
                                ul.appendChild(li);
                            }
                            else {
                                var lines = baAfter.split('¹');
                                for(var i=1; i<lines.length-1; i++) {
                                    var li = formatRestriction( lines[i], '<b class=wmeroadhistory_trafter>', '</b>');
                                    ul.appendChild(li);
                                }
                            }

                            var lines = baBefore.split('¹');
                            for(var i=1; i<lines.length-1; i++) {
                                var li = formatRestriction( lines[i], '', '');
                                li.className = 'wmeroadhistory_trbefore';
                                ul.appendChild(li);
                            }

                        }

                    }

                    
                    
                    
                    var trBefore = cursor.value.tsA;
                    var trAfter  = cursor.value.tsB;
                    if (trBefore != null && trAfter != null) {
                        var before = trBefore.split('²');
                        var after  = trAfter.split('²');
                        
                        for(var i=0; i<before.length - 1; i++) {
                            var bi = before[i].split('¹');
                            
                            var aifound;

                            for(var i=0; i<after.length - 1; i++) {
                                var ai = after[i].split('¹');
                                if (ai[0] == bi[0]) {
                                    aifound = ai;
                                }
                            }
                            
                            if (aifound && aifound.length > 2) {
                                
                                var li = document.createElement('li');
                                li.innerHTML = '<b class=wmeroadhistory_trturn>' + lang.changedtr + '</b>';

                                var seg1 = segid;
                                var segN = bi[0].substr(0,1);
                                var seg2 = bi[0].substr(1,12);

                                var pe = document.createElement('p');
                                pe.innerHTML = 'link';
                                pe.className = 'wmeroadhistory_turnlink';
                                pe.id = 'turnlink_' + seg1 + '_' + segN + '_' + seg2;

                                foundPELinkName( pe, parseInt(seg2) );

                                pe.onclick = (function(event) {
                                    gotoTURN(event);
                                });
                                li.appendChild(pe);
                                ul.appendChild(li);
                                
                                if (aifound.length <= 2) {
                                    var li = document.createElement('p');
                                    li.innerHTML = '<b class=wmeroadhistory_trturn>' + lang.none + '</b>';
                                    ul.appendChild(li);
                                }
                                else {
                                    for(var k=1; k<aifound.length-1; k++) {
                                        var li = formatRestriction( aifound[k], '<b class=wmeroadhistory_trturn>', '</b>');
                                        ul.appendChild(li);
                                    }
                                }

                                for(var k=1; k<bi.length-1; k++) {
                                    var li = formatRestriction( bi[k], '', '');
                                    ul.appendChild(li);
                                }
                            }
                            else {
                                var li = document.createElement('li');
                                li.innerHTML = '<b class=wmeroadhistory_trturn>' + lang.removedtr + '</b>';

                                var seg1 = segid;
                                var segN = bi[0].substr(0,1);
                                var seg2 = bi[0].substr(1,12);

                                var pe = document.createElement('p');
                                pe.innerHTML = 'link';
                                pe.className = 'wmeroadhistory_turnlink';
                                pe.id = 'turnlink_' + seg1 + '_' + segN + '_' + seg2;

                                foundPELinkName( pe, parseInt(seg2) );

                                pe.onclick = (function(event) {
                                    gotoTURN(event);
                                });
                                li.appendChild(pe);
                                ul.appendChild(li);

                                //var li = document.createElement('p');
                                //li.innerHTML = '<b class=wmeroadhistory_trturn>' + lang.none + '</b>';
                                //ul.appendChild(li);

                                for(var k=1; k<bi.length-1; k++) {
                                    var li = formatRestriction( bi[k], '', '');
                                    ul.appendChild(li);
                                }
                            }
                        }


                        for(var i=0; i<after.length - 1; i++) {
                            var ai = after[i].split('¹');
                            
                            var p = trBefore.indexOf( ai[0] + '¹' );
                            if (p < 0) {
                                var li = document.createElement('li');
                                li.innerHTML = '<b class=wmeroadhistory_trturn>' + lang.addedtr + '</b>';

                                var seg1 = segid;
                                var segN = ai[0].substr(0,1);
                                var seg2 = ai[0].substr(1,12);

                                var pe = document.createElement('p');
                                pe.innerHTML = 'link';
                                pe.className = 'wmeroadhistory_turnlink';
                                pe.id = 'turnlink_' + seg1 + '_' + segN + '_' + seg2;

                                foundPELinkName( pe, parseInt(seg2) );

                                pe.onclick = (function(event) {
                                    gotoTURN(event);
                                });
                                li.appendChild(pe);
                                ul.appendChild(li);

                                for(var k=1; k<ai.length-1; k++) {
                                    var li = formatRestriction( ai[k], '<b class=wmeroadhistory_trturn>', '</b>');
                                    ul.appendChild(li);
                                }
                            }
                        }
                    }

                    

                }

                var t = new Date;
                t.setTime( segtime * 1000 );
                var czas = t.toLocaleDateString() + ', ' + t.toLocaleTimeString().substr(0, 5);


                if (segnames == '') h1.innerHTML = '<b>' + lang.noname + '</b>';
                else                h1.innerHTML = '<b>' + htmlEntities(segnames) + '</b>';

                h1.onclick = (function() { gotoXY(segx, segy); });
                
                if      (segkind == 1)   h1.style.color = '#488193';  // street
                else if (segkind == 2)   h1.style.color = '#488193';  // primary street
                else if (segkind == 3)   h1.style.color = '#488193';  // freeways
                else if (segkind == 4)   h1.style.color = '#488193';  // ramps
                else if (segkind == 6)   h1.style.color = '#488193';  // major highway
                else if (segkind == 7)   h1.style.color = '#488193';  // minor highway
                else if (segkind == 8)   h1.style.color = '#808080';  // dirt roads
                else if (segkind == 18)  h1.style.color = '#c0c0c0';  // pkp
                else if (segkind == 21)  h1.style.color = '#808080';  // service road
                else if (segkind == 120) h1.style.color = '#808080';  // service road
                else                     h1.style.color = '#c0c0c0';

                if (segequal && curtime - segtime < 7*24*3600) {
                    h4.innerHTML = '<b class=wmeroadhistory_newseg>' + lang.newsegment + '</b>';
                }

                h2.innerHTML = htmlEntities(segcity);
                h5.innerHTML = czas;
                h6.innerHTML = htmlEntities(segeditor);
                if (segeditor.indexOf('(1)') >= 0)           h6.className = 'wmeroadhistory_rank1';
                if (segeditor.indexOf('(2)') >= 0)           h6.className = 'wmeroadhistory_rank2';
                if (segeditor.indexOf('(3)') >= 0)           h6.className = 'wmeroadhistory_rank3';
                if (segeditor.indexOf('(4)') >= 0)           h6.className = 'wmeroadhistory_rank4';
                if (segeditor.indexOf('(5)') >= 0)           h6.className = 'wmeroadhistory_rank5';
                if (segeditor.indexOf('Inactive User') >= 0) h6.className = 'wmeroadhistory_rank0';
                

                if (count < objlist.childNodes.length) {
                    var div = objlist.childNodes[count];
                    
                    div.innerHTML = '';
                    
                    div.appendChild(h1);
                    div.appendChild(h4);
                    div.appendChild(h2);
                    div.appendChild(ul);
                    div.appendChild(h5);
                    div.appendChild(h6);
                    div.appendChild(hr);
                }
                else {
                    var newdiv = document.createElement('div');

                    newdiv.appendChild(h1);
                    newdiv.appendChild(h4);
                    newdiv.appendChild(h2);
                    newdiv.appendChild(ul);
                    newdiv.appendChild(h5);
                    newdiv.appendChild(h6);
                    newdiv.appendChild(hr);

                    objlist.appendChild(newdiv);
                }
                
                count++;
                cursor.continue();
            }
            else {
            }
        }
        else {
            if (count == 0) {
                if (pageEdits > page) pageEdits = page - 1;
                if (pageEdits < 0) pageEdits = 0;
            }
        }
    }
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryTAB1() {
    
    ShowHistMode = 1;
    updateTabs();
    
    //reset zaznaczonego skrętu na mapie
    showturn.push(0);
    showturn.push(0);
    
    var objlist = getId('wmeroadhistory_list');
    objlist.innerHTML = '';

    pageEdits = 0;
    showEdits(ShowHistMode, pageEdits);

    getId('wmeroadhistory_list_buttons_1').style.visibility = '';
    getId('wmeroadhistory_list_buttons_2').style.visibility = '';
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryTAB2() {

    ShowHistMode = 2;
    updateTabs();

    //reset zaznaczonego skrętu na mapie
    showturn.push(0);
    showturn.push(0);
    
    var objlist = getId('wmeroadhistory_list');
    objlist.innerHTML = '';

    pageEdits = 0;
    showEdits(ShowHistMode, pageEdits);

    getId('wmeroadhistory_list_buttons_1').style.visibility = '';
    getId('wmeroadhistory_list_buttons_2').style.visibility = '';
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryPREV() {
    
    pageEdits--;
    if (pageEdits < 0) pageEdits = 0;
    showEdits(ShowHistMode, pageEdits);
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryNEXT() {

    pageEdits++;
    showEdits(ShowHistMode, pageEdits);
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryPREVDOWN() {
    
    pageEdits--;
    if (pageEdits < 0) pageEdits = 0;
    getId('sidebar').scrollTop = 0;
    showEdits(ShowHistMode, pageEdits);
}
//--------------------------------------------------------------------------------------------------------
function wmeroadhistoryNEXTDOWN() {

    pageEdits++;
    getId('sidebar').scrollTop = 0;
    showEdits(ShowHistMode, pageEdits);
}
//--------------------------------------------------------------------------------------------------------
function updateTabs() {
    
    if (ShowHistMode == 1) {
        getId('wmeroadhistory_tab1').className = 'wmeroadhistory_tab_active';
        getId('wmeroadhistory_tab2').className = '';
    }
    if (ShowHistMode == 2) {
        getId('wmeroadhistory_tab2').className = 'wmeroadhistory_tab_active';
        getId('wmeroadhistory_tab1').className = '';
    }
    
}
//--------------------------------------------------------------------------------------------------------
function initialiseWMERoadHistory()
{
    var docurl = window.document.URL;
    if (docurl.indexOf( "/pl/" ) >=0 ) lang = langPL;
    
    var addon       = document.createElement('section');
	addon.id        = "wmeroadhistory-addon";
    addon.innerHTML = ''
    + '<div style="margin-bottom: 5px;"><b style="margin:0px; padding:0px;"><a href="https://greasyfork.org/en/scripts/" target="_blank"><u>WME Road History</u></a></b> &nbsp; v' + wmech_version + '</div>'
    + '<button id=wmeroadhistory_scanarea class="btn btn-default" style="min-width:150px; margin: 0px; "></button>&nbsp;'
    + '<div    id=wmeroadhistory_log style="margin-bottom:10px;">&nbsp;</div>'
    + '<div class=wmeroadhistory_noselect>'
    +     '<div id=wmeroadhistory_tab1>' + lang.changes + '</div>'
    +     '<div id=wmeroadhistory_tab2>' + lang.edits + '</div>'
    +     '<div id=wmeroadhistory_tab9></div>'
    + '</div>'
    + '<div id=wmeroadhistory_list_buttons_1 style="text-align: center; margin:0px; background: #f8f8f8; padding: 5px; visibility: hidden; ">'
    +     '<button id=wmeroadhistory_prev class="btn btn-default" style="margin: 2px; padding:0px; font-weight:normal; height:20px; padding-left:20px; padding-right:20px; " >&lt;&lt; ' + lang.prev + '</button>'
    +     '<button id=wmeroadhistory_next class="btn btn-default" style="margin: 2px; padding:0px; font-weight:normal; height:20px; padding-left:20px; padding-right:20px; " >' + lang.next + ' &gt;&gt;</button>'
    + '</div>'
    + '<div id=wmeroadhistory_list></div>'
    + '<div id=wmeroadhistory_list_buttons_2 style="text-align: center; margin:0px; background: #f8f8f8; padding: 5px; visibility: hidden; ">'
    +     '<button id=wmeroadhistory_prev2 class="btn btn-default" style="margin: 2px; padding:0px; font-weight:normal; height:20px; padding-left:20px; padding-right:20px; " >&lt;&lt; ' + lang.prev + '</button>'
    +     '<button id=wmeroadhistory_next2 class="btn btn-default" style="margin: 2px; padding:0px; font-weight:normal; height:20px; padding-left:20px; padding-right:20px; " >' + lang.next + ' &gt;&gt;</button>'
    + '</div>'
	+ '<style>'
    +     '.wmeroadhistory_hovbutton:hover  { cursor:pointer; color: #0000FF; text-decoration: underline; }'
    +     '#wmeroadhistory_list div         { padding-left: 15px; border: 0px solid #f0f0f0; border-bottom-width: 1px; margin-top: 2px; }'
    +     '#wmeroadhistory_list div         { background-position: 0px 3px; background-repeat: no-repeat; }'
    +     '#wmeroadhistory_list div         { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAMCAIAAAA/PgD0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAA7ElEQVR4nGWNQUvDQBSE34Z1N65dU0mMaSkoItriqVdP/nOP/gEPYkV6MSgloUVsTbPvjYd4qHT4Tt8wjAIA0PP7x+yz2rTh8EBfF9nN8EwpUgw8PL3W2+CdU0oB+Ppep7G+v72KXsrFspWecyASAES9I1dvZVYu9LxeGWuDgHZirZnXK90wQEJ72bBoH5vqJ+x3aWyj8zRpmRnYpWW+SBM9SLw39bL5Nz2xukh8JMB0lAfmIPIH83SUCxAJ4djZ8Wk/iLAgsEzyvndWCBFAAE0GaRqbIJI5My6yTqpq3XQfTQiPb+Xd5dBo3ZlfDOiS3+b9cP0AAAAASUVORK5CYII="); }'
    +     '#wmeroadhistory_list h1          { -webkit-touch-callout: none;  -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }'
    +     '#wmeroadhistory_list h1          { margin: 0px; padding: 0px; line-height: 100%; font-size: 15px; display: inline-block; }'
    +     '#wmeroadhistory_list h1:hover    { cursor: pointer; color: #0D5270; text-decoration: underline; }'
    +     '#wmeroadhistory_list h2          { margin: 0px; padding: 0px; line-height: 100%; color: #606060; font-size: 100%;  }'
    +     '#wmeroadhistory_list ul          { margin: 0px; padding: 0px; margin-left: 30px; margin-top: 5px; font-family: Tahoma; font-size: 11px; margin-bottom:5px; color: #606060; line-height: 18px; }'
    +     '#wmeroadhistory_list h4          { margin: 0px; padding: 0px; line-height: 100%; color: #606060; font-family: Tahoma; font-size: 11px; display: inline-block; }'
    +     '#wmeroadhistory_list h5          { margin: 0px; padding: 0px; line-height: 100%; color: #606060; font-family: Tahoma; font-size: 11px; float:left; margin-top: 5px; }'
    +     '#wmeroadhistory_list h6          { margin: 0px; padding: 0px; line-height: 100%; font-family: Tahoma; font-size: 11px; float:right; font-weight: normal; margin-top: 5px; }'
    +     '#wmeroadhistory_list p           { margin: 0px; }'
    +     '#wmeroadhistory_list hr          { margin: 0px; clear: both; border: 0px; outline: 0px; height: 5px; }'
    +     '#wmeroadhistory_tab1             { font-size: 12px; display: inline-block; width: 100px; height: 30px; line-height: 30px; border: 1px solid #e0e0e0; border-radius: 5px 5px 0 0; border-bottom-width: 0px; text-align: center; }'
    +     '#wmeroadhistory_tab2             { font-size: 12px; display: inline-block; width: 100px; height: 30px; line-height: 30px; border: 1px solid #e0e0e0; border-radius: 5px 5px 0 0; border-bottom-width: 0px; text-align: center; }'
    +     '#wmeroadhistory_tab1:hover       { background: #d0d0d0; cursor: pointer; }'
    +     '#wmeroadhistory_tab2:hover       { background: #d0d0d0; cursor: pointer; }'
    +     '#wmeroadhistory_tab9             { width: 100%; height:1px; background: #e0e0e0; }'
    +     '.wmeroadhistory_tab_active       { font-weight: bold;   background: #e9e9e9; }'
    +     '.wmeroadhistory_tab_noactive     { font-weight: normal; background: #f8f8f8; }'
    +     '.wmeroadhistory_noselect         { -webkit-touch-callout: none;  -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }'
    +     '.wmeroadhistory_rank0            { color: #808080 }'
    +     '.wmeroadhistory_rank1            { color: #E12222 }'
    +     '.wmeroadhistory_rank2            { color: #EB712D }'
    +     '.wmeroadhistory_rank3            { color: #349B20 }'
    +     '.wmeroadhistory_rank4            { color: #3176E9 }'
    +     '.wmeroadhistory_rank5            { color: #C000C0 }'
    +     '.wmeroadhistory_newseg           { color: #00c000; font-weight: bold; background: #E8FFDF; border-radius: 5px 5px 5px 5px; padding-left: 5px; padding-right: 5px; margin: 1px; }'
    +     '.wmeroadhistory_turnlink         { display: inline-block; color: #0091FF; text-decoration: underline; }'
    +     '.wmeroadhistory_turnlink:hover   { color: #000000; text-decoration: underline; cursor: pointer; }'
    +     '.wmeroadhistory_turnlink         { -webkit-touch-callout: none;  -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }'
    +     '.wmeroadhistory_error            { color: #D72C2C }'
    +     '.wmeroadhistory_kind             { color: #404040 }'
    +     '.wmeroadhistory_toll             { color: #CC38CC }'
    +     '.wmeroadhistory_trbefore         { color: #808080 }'
    +     '.wmeroadhistory_trafter          { color: #2971D6 }'
    +     '.wmeroadhistory_uturn            { color: #808080 }'
    +     '.wmeroadhistory_trturn           { color: #DF4F00 }'
    +     '.wmeroadhistory_amonly           { color: #59899e; font-weight:bold; }'
	+ '</style>'
    ;

    var userTabs = getId('user-info');
	var navTabs = getElementsByClassName('nav-tabs', userTabs)[0];
	var tabContent = getElementsByClassName('tab-content', userTabs)[0];

	var newtab = document.createElement('li');
	newtab.innerHTML = '<a id=sidepanel-wmeroadhistory-tab href="#sidepanel-wmeroadhistory" data-toggle="tab" style="" >Road History</a>';
    newtab.id = 'wmeroadhistory_tab';
	navTabs.appendChild(newtab);

	addon.id = "sidepanel-wmeroadhistory";
	addon.className = "tab-pane";
	tabContent.appendChild(addon);

    if (typeof Waze == 'undefined')              Waze = unsafeWindow.Waze;
    if (typeof Waze.loginManager == 'undefined') Waze.loginManager = unsafeWindow.Waze.loginManager;
    if (typeof Waze.loginManager == 'undefined') Waze.loginManager = unsafeWindow.loginManager;
    if (Waze.loginManager !== null && Waze.loginManager.isLoggedIn()) {
        thisUser = Waze.loginManager.user;
        var lev = thisUser.normalizedLevel;
        if (thisUser !== null && (lev*lev >= lev+lev+lev || thisUser.isAreaManager)) {
            getId('wmeroadhistory_scanarea').onclick  = wmeroadhistorySCANAREA;
            getId('wmeroadhistory_tab1').onclick      = wmeroadhistoryTAB1;
            getId('wmeroadhistory_tab2').onclick      = wmeroadhistoryTAB2;
            getId('wmeroadhistory_prev').onclick      = wmeroadhistoryPREV;
            getId('wmeroadhistory_next').onclick      = wmeroadhistoryNEXT;
            getId('wmeroadhistory_prev2').onclick     = wmeroadhistoryPREVDOWN;
            getId('wmeroadhistory_next2').onclick     = wmeroadhistoryNEXTDOWN;
        }
    }

    updateSaveButton();

    var list = document.getElementsByTagName("div");
    for(var i=0; i<list.length; i++) {
        var id = list[i].id;
        var p = id.indexOf("PendingOperation");
        if (p>=0) {
            wazepending = list[i];
        }
    }
    
    window.setInterval(wmeroadhistoryLOOP, 500);
}
//--------------------------------------------------------------------------------------------------------------
bootstrapWMERoadHistory();