Mturk Hourly

Record time spent working on HITs. Forked from Mturk Dashboard.

目前為 2017-12-02 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Mturk Hourly
// @namespace    https://gf.qytechs.cn/users/11205
// @version      2.0.1
// @description  Record time spent working on HITs.  Forked from Mturk Dashboard.
// @author       Kerek
// @include      https://www.mturk.com/mturk/dashboard*
// @grant        GM_log
// @grant        GM_setClipboard
// @require      https://code.jquery.com/jquery-3.0.0-beta1.min.js
// @include      https://worker.mturk.com/dashboard*
// @include https://www.mturk.com/mturk/statusdetail*
// @include       https://www.mturk.com/mturk/accept*
// @include       https://www.mturk.com/mturk/preview*
// @include       https://www.mturk.com/mturk/continue*
// @include       https://www.mturk.com/mturk/submit
// @include       https://www.mturk.com/mturk/return*
// @include https://worker.mturk.com/projects/*/tasks/*assignment_id=*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      mturk.com
// ==/UserScript==

if (location.href.indexOf(`https://www.mturk.com/mturk/dashboard`) !== -1) {
    var LOADED = $("#total_earnings_amount").length;
    if (LOADED){

        // Functions that can be commented out if you don't want it to run.
        Todays_Projected_Earnings();
        Todays_Bonuses();
        //Best_Worst_Case();
        //Real_Stats();
        //Changes();
        //Yearly();
        //Goal();

    }
}

else if (location.href.indexOf(`https://worker.mturk.com/dashboard`) !== -1) {
    initialize();

    // Functions that can be commented out if you don't want it to run.
    //allApprovedRate();
    //allRejectedRate();
    //fourDigitPercents();
    //rejectionsBelow99();
    //rejectionsBelow95();
    //totalLast45Days();
    //hitStatusChanges(); // partially working
    todaysActivity();
}

else if (location.href.indexOf('worker.mturk.com') > -1){
    var hit_returned = false;
    if(typeof(Storage)!=="undefined")
    {
        $('button:contains("Return")').click(function(){
            hit_returned = true;
        });
        store_data('openWorker');
        window.addEventListener('beforeunload', function(){
            store_data('closeWorker');
        });
    }
}

else{
    var hit_returned = false;
    if(typeof(Storage)!=="undefined")
    {
        $('img[src="/images/return_hit.gif"]').parent().click(function(){
            hit_returned = true;
        });
        store_data('open');
        window.addEventListener('beforeunload', function(){store_data('close');});

        var $requesters = $('td[class="statusdetailRequesterColumnValue"]');
        var gmHourlyLog = JSON.parse(GM_getValue('gmHourlyLog')) || {};


        if ($requesters.length > 0)
        {
            $requesters.each(function(){
                var hitId = $(this).find('a').attr('href').split('hitId=')[1].split('&')[0];
                console.log(hitId);
                var $feedback_value = $(this).parent().find('td[class="statusdetailStatusColumnValue"]').next();
                var feedback_str = '';
                var time_data = localStorage.getItem('time_data.' + hitId);
                if (time_data === null){
                    time_data = gmHourlyLog[hitId];
                }
                if (time_data){
                    feedback_str = create_feedback_str(time_data);
                }
                var status_value = $feedback_value.html() + feedback_str;
                $feedback_value.html(status_value);
            });
        }
    }
}

// Don't touch anything below here.
function Todays_Projected_Earnings(){
    var TPEhitLOG = {}; var TPEdetailsLOG = {}; var TPEhourlyLOG = {}; var pe = 0;

    var today = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).prop("href");

    var $peTR = $('<div id="TPE_div" class="even" style="display:table-row">');
    var $peTD1 = $('<td class="metrics-table-first-value">');
    var $peTD2 = $('<td>');
    var $peA = $('<a href="javascript:void(0)">Today\'s Projected Earnings</a>');
    var $TPE_details = $('<span style="color: blue; font-size: 10px; cursor: pointer; float: right;">Details<img style="margin-left: 5px;" src="/media/more.gif" border="0/"></span>');
    var $peSPAN = $('<span class="reward">$0.00</span>');
    $("td.metrics-table-first-value:contains(Total Earnings)").parent().after($peTR);
    $peTR.append($peTD1.append($peA,$TPE_details),$peTD2.append($peSPAN));

    var $TPED_table = $('<table style="display: none;" width="760" align="center" cellspacing="0" cellpadding="0">');
    var $TPED_tboday = $('<tbody>');
    var $TPED_tr_1 = $('<tr id="TPE_tr"  height="25px"><td width="10" bgcolor="#7fb4cf" style="padding-left: 10px;"></td><td width="100%" bgcolor="#7fb4cf" class="white_text_14_bold">Today\'s Projected Earnings Details&nbsp;&nbsp;<a id="fourmEXPORT" href="javascript:void(0)" class="whatis" >(Forum Export)</a></td><td width="10" align="right" bgcolor="#7fb4cf"></td></tr>');
    var $TPED_tr_2 = $('<tr><td class="container-content" colspan="3"><table class="metrics-table" width="100%"><tbody><tr><td width="100%"><table class="metrics-table" width="100%"><tbody id="tbody2"></tbody></table></td></tr></tbody></table></td></tr>');
    var $TPED_tr_h = $('<tr class="metrics-table-header-row"><th class="metrics-table-first-header">Requester</th><th>Submitted</th><th>Projected</th></tr>');
    var $TPED_tr_h = $('<tr class="metrics-table-header-row"><th class="metrics-table-first-header">Requester</th><th>Submitted</th><th>Projected</th><th>Hourly</th></tr>');


    $("#subtabs_and_searchbar").next().next().after($TPED_table);
    $TPED_table.append($TPED_tboday);
    $TPED_tboday.append($TPED_tr_1,$TPED_tr_2);
    $("#tbody2").append($TPED_tr_h);

    $("#fourmEXPORT").click(function(){
        var exportcode = "";
        var bonus = $("#bonus").text();
        if (bonus !== "$0.00"){
            var total = (Number(pe)+Number(bonus.replace(/[^0-9.]/g, ""))).toFixed(2);
            exportcode += "[b]Today's Projected Earnings: $"+Number(pe).toFixed(2)+" + Bonuses: "+bonus+" = $"+total+"[/b]\n";

        }
        else {
            exportcode += "[b]Today's Projected Earnings: $"+Number(pe).toFixed(2)+"[/b]\n";
        }

        var today_submitted   = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().text();
        var today_approved    = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().text();
        var today_rejected    = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().text();
        var today_pending     = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().next().text();


        exportcode +=
            '[spoiler=Today\'s Projected Earnings Overview][table]' +
            '[tr][td]Submitted[/td][td]' + today_submitted + '[/td][/tr]' +
            '[tr][td]Approved[/td][td]' + today_approved + '[/td][/tr]' +
            '[tr][td]Rejected[/td][td]' + today_rejected + '[/td][/tr]' +
            '[tr][td]Pending[/td][td]' + today_pending + '[/td][/tr]' +
            '[/table][/spoiler]';


        GM_setClipboard(exportcode);
        alert("Forum Export copied to your clipboard.");
    });

    $peA.click(function(){
        if ($peA.text() === "Today's Projected Earnings"){
            var confirmation = confirm("Are you sure you want to recalculate Today's Projected Earnings?");
            if (confirmation === true){
                TPEhitLOG = {}; TPEdetailsLOG = {}; var TPEhourlyLOG = {}; pe = 0;
                $("#tbody2").find("tr.odd, tr.even").remove();
                getDATA(today);
                $peSPAN.text("$0.00");
            }
        }
    });

    $TPE_details.click(function(){
        $TPE_details.find("img").attr("src", ($TPE_details.find("img").attr("src") === "/media/more.gif") ? "/media/less.gif" : "/media/more.gif");
        $TPED_table.toggle();
    });

    if (today){
        var date = today.split("encodedDate=")[1];
        if (date === localStorage.TPE_date){
            if (localStorage.TPEhitLOG){
                TPEhitLOG = JSON.parse(localStorage.TPEhitLOG);
            }
            pe = Number(localStorage.TPE_pe) || 0;
            $peSPAN.text("$"+Number(pe).toFixed(2));
            getDATA(localStorage.TPE_lastpage);
        }
        else {
            localStorage.TPE_date = date;
            localStorage.Goal_progress = 0;
            TPEhitLOG = {}; pe = 0;
            $peSPAN.text("$0.00");
            getDATA(today);
        }
    }

    function getDATA(URL){
        var page = URL.match(/Number=([0-9]*)/g);
        if (page){
            $peA.text("Calculating Page "+page.toString().replace(/[^0-9.]/g, ""));
        }
        else {
            localStorage.removeItem("TPEhitLOG");
            localStorage.Goal_progress = 0;
            $peA.text("Calculating Page 1");
        }

        $.get(URL, function(data){
            var $data = $(data);
            var $hits = $data.find("#dailyActivityTable").find("tr[valign='top']");
            var pagereqerr = $data.find("td.error_title:contains(You have exceeded the maximum allowed page request rate for this website.)").length;
            var noactivity = $data.find("#dailyActivityTable").find("td:contains(You have no HIT activity on this day matching the selected status.)").length;
            if ($hits.length){
                console.log("hit length");
                var url = $data.find("a:contains(Next)[href*=statusdetail]").eq(0).prop("href");
                for (var i = 0; i < $hits.length; i++){
                    var req = $hits.eq(i).find("td.statusdetailRequesterColumnValue").text().trim();
                    var title = $hits.eq(i).find("td.statusdetailTitleColumnValue").text().trim();
                    var reward = $hits.eq(i).find("td.statusdetailAmountColumnValue").text().trim();
                    var status = $hits.eq(i).find("td.statusdetailStatusColumnValue").text().trim();
                    var reqid = $hits.eq(i).find("a").prop("href").split("requesterId=")[1].split("&")[0];
                    var hitid = $hits.eq(i).find("a").prop("href").split("HIT+")[1];

                    if (!TPEhitLOG[hitid]){
                        TPEhitLOG[hitid] = {
                            req    : req,
                            title  : title,
                            reward : reward,
                            status : status,
                            reqid  : reqid,
                            hitid  : hitid
                        };
                    }
                }
                if (url){
                    getDATA(url);
                }
                else {
                    pe = 0;
                    for(var key in TPEhitLOG){
                        if (TPEhitLOG[key].status !== "Rejected"){
                            pe += parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, ""));
                        }
                        if (!TPEdetailsLOG[TPEhitLOG[key].reqid]){
                            TPEdetailsLOG[TPEhitLOG[key].reqid] = {
                                req    : TPEhitLOG[key].req,
                                submit : 1,
                                reward : parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, "")),
                                reqid  : TPEhitLOG[key].reqid
                            };
                        }
                        else {
                            TPEdetailsLOG[TPEhitLOG[key].reqid].submit = TPEdetailsLOG[TPEhitLOG[key].reqid].submit + 1;
                            TPEdetailsLOG[TPEhitLOG[key].reqid].reward = TPEdetailsLOG[TPEhitLOG[key].reqid].reward + parseFloat(TPEhitLOG[key].reward.replace(/[^0-9.]/g, ""));
                        }
                        if (!TPEhourlyLOG[TPEhitLOG[key].reqid]){
                            var time_data = localStorage.getItem('time_data.' + TPEhitLOG[key].hitid.split('&')[0]);
                            if (time_data != null){
                                var starts = time_data.split("$#$")[3].split('?');
                                var last_start = starts[starts.length-1];

                                var stops = time_data.split("$#$")[4].split('?');
                                var last_stop = stops[stops.length-1];

                                if (last_start.length && last_stop.length){
                                    TPEhourlyLOG[TPEhitLOG[key].reqid] = {
                                        req : TPEhitLOG[key].req,
                                        intervals :[[last_start,last_stop]],
                                        totalReward : parseFloat(time_data.split("$#$")[2]),
                                    };
                                }

                            }
                        }
                        else{
                            var time_data = localStorage.getItem('time_data.' + TPEhitLOG[key].hitid.split('&')[0]);
                            if (time_data != null){

                                var starts = time_data.split("$#$")[3].split('?');
                                var last_start = starts[starts.length-1];
                                var stops = time_data.split("$#$")[4].split('?');
                                var last_stop = stops[stops.length-1];
                                if (last_start.length && last_stop.length){

                                    TPEhourlyLOG[TPEhitLOG[key].reqid].intervals.push([last_start,last_stop]);
                                }
                                TPEhourlyLOG[TPEhitLOG[key].reqid].totalReward += parseFloat(time_data.split("$#$")[2]);
                            }
                        }
                    }

                    if (!TPEdetailsLOG.bonuses && $("#bonus").length){
                        TPEdetailsLOG.bonuses  = {
                            req    : "Bonuses",
                            submit : "N/A",
                            reward : parseFloat($("#bonus").text().replace(/[^0-9.]/g, "")),
                            reqid  : "N/A"
                        };
                    }
                    else if ($("#bonus").length){
                        TPEdetailsLOG.bonuses.reward = parseFloat($("#bonus").text().replace(/[^0-9.]/g, ""));
                    }

                    var d_sorted = Object.keys(TPEdetailsLOG).sort(function(a,b){return TPEdetailsLOG[a].reward - TPEdetailsLOG[b].reward;});
                    var oddeven = true;
                    var total_intervals = [];
                    var total_recorded_earnings = 0;
                    for (var j = d_sorted.length-1; j > -1; j--){
                        var dkey = d_sorted[j];
                        var d_req = TPEdetailsLOG[dkey].req;
                        var d_submitted = TPEdetailsLOG[dkey].submit;
                        var d_reward = Number(TPEdetailsLOG[dkey].reward).toFixed(2);
                        var d_hourly = "N/A";
                        if (d_req !== "Bonuses" && TPEhourlyLOG[TPEdetailsLOG[dkey].reqid]){
                            var intervals = TPEhourlyLOG[TPEdetailsLOG[dkey].reqid].intervals;
                            var d_intervals_sum = 0;
                            for (i=0;i<intervals.length;i++){
                                d_intervals_sum += (intervals[i][1]-intervals[i][0]);
                            }
                            var d_intervals_avg = d_intervals_sum / intervals.length;
                            var d_intervals = mergeIntervals(intervals);
                            d_intervals = combineIntervals(intervals,Math.max(2*60*1000,Math.min(10*d_intervals_avg,10*60*1000)));
                            total_intervals = total_intervals.concat(d_intervals);
                            total_recorded_earnings += TPEhourlyLOG[TPEdetailsLOG[dkey].reqid].totalReward;
                            console.log(d_req, "padding", Math.min(10*d_intervals_avg,10*60*1000)/(60*1000) + " min");
                            var d_time = 0;
                            for (i=0;i<d_intervals.length; i++){
                                var s = new Date(parseInt(d_intervals[i][0]));
                                var f = new Date(parseInt(d_intervals[i][1]));
                                console.log(d_req, i, s.toLocaleTimeString(),f.toLocaleTimeString());
                                d_time += (d_intervals[i][1] - d_intervals[i][0])/(1000*60*60);
                            }
                            d_hourly = "$" + (TPEhourlyLOG[TPEdetailsLOG[dkey].reqid].totalReward / d_time).toFixed(2);
                        }
                        if (oddeven){
                            oddeven = false;
                            $("#tbody2").append('<tr class="odd"><td class="metrics-table-first-value">'+d_req+'</td><td>'+d_submitted+'</td><td><span class="reward">$'+d_reward+'</span></td><td><span class="reward">'+d_hourly+'</span></tr>');
                        }
                        else {
                            oddeven = true;
                            $("#tbody2").append('<tr class="even"><td class="metrics-table-first-value">'+d_req+'</td><td>'+d_submitted+'</td><td><span class="reward">$'+d_reward+'</span><td><span class="reward">'+d_hourly+'</span></td></tr>');
                        }
                    }
                    total_intervals = mergeIntervals(total_intervals);
                    var total_time = 0;
                    for (i=0;i<total_intervals.length; i++){
                        var s = new Date(parseInt(total_intervals[i][0]));
                        var f = new Date(parseInt(total_intervals[i][1]));
                        console.log(i, s.toLocaleTimeString(),f.toLocaleTimeString());
                        total_time += (total_intervals[i][1] - total_intervals[i][0])/(1000*60*60);
                    }
                    var total_hourly = '$' + (total_recorded_earnings/total_time).toFixed(2);
                    var hour = Math.floor(total_time);
                    var min = Math.floor((total_time - hour)*60);
                    var sec = Math.floor((total_time - hour - min/60)*3600);
                    var time_display = (hour>0?pad(hour,2) + ":":"") + pad(min,2) + ":" + pad(sec,2);
                    if (oddeven){
                        oddeven = false;
                        $("#tbody2").append('<tr class="odd"><td class="metrics-table-first-value">Total Hourly</td><td>'+time_display+'</td><td><span class="reward">$'+total_recorded_earnings.toFixed(2)+'</span></td><td><span class="reward">'+total_hourly+'</span></tr>');
                    }
                    else {
                        oddeven = true;
                        $("#tbody2").append('<tr class="even"><td class="metrics-table-first-value">Total Hourly</td><td>'+time_display+'</td><td><span class="reward">$'+total_recorded_earnings.toFixed(2)+'</span><td><span class="reward">'+total_hourly+'</span></td></tr>');
                    }
                    localStorage.TPEhitLOG = JSON.stringify(TPEhitLOG);
                    localStorage.TPE_lastpage = URL;
                    localStorage.TPE_pe = pe;
                    $peA.text("Today's Projected Earnings");
                    $peSPAN.text("$"+Number(pe).toFixed(2));
                    localStorage.Goal_percent = ((Number(localStorage.TPE_pe)/Number(localStorage.Goal_goal))*100);
                    localStorage.Goal_progress = Number(pe)-Number(localStorage.Goal_goal);
                    if ($("#goalDIV").length){
                        $("#progress").width(Number(localStorage.Goal_percent)+"%");
                        $("#progressper").text(Number(localStorage.Goal_progress).toFixed(2));
                    }
                    Unsynced();
                }
            }
            else if (noactivity){
                console.log("no activity");
                localStorage.TPE_lastpage = URL;
                localStorage.TPE_pe = 0;
                localStorage.Goal_progress = 0;
                $peA.text("Today's Projected Earnings");
                $peSPAN.text("$0.00");
            }
            else if (pagereqerr) {
                console.log("set timeout");
                setTimeout(function(){ getDATA(URL); }, 2000);
            }
        });
    }

    function Unsynced(){
        var hitscalced = Object.keys(TPEhitLOG).length;
        var submitted  = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().text());

        if (hitscalced < submitted){
            $peSPAN.css({backgroundColor:"red"});
        }
        else {
            $peSPAN.css({backgroundColor:""});
        }
    }
}

function create_feedback_str(time_data)
{

    var last_start = time_data.split("$#$")[3].split('?');
    last_start = new Date(parseInt(last_start[last_start.length - 1]));
    var last_finish = time_data.split("$#$")[4].split('?');
    last_finish = new Date(parseInt(last_finish[last_finish.length - 1]));

    console.log(time_data, last_start, last_finish, time_data.split("$#$")[3].split('?'), time_data.split("$#$")[4].split('?'));
    var reward = time_data.split("$#$")[2];
    var time_spent = last_finish - last_start;
    var h = Math.floor(time_spent/(1000*60*60));
    var m = Math.floor((time_spent - h*1000*60*60)/(1000*60));
    var s = Math.floor((time_spent - h*1000*60*60 - m*1000*60)/(1000));
    return "Opened: " + last_start.toLocaleTimeString() + "<br>Submitted: " + last_finish.toLocaleTimeString()+ "<br>Time: " + (h > 0 ? (pad(h,2) + ":"):"") + pad(m,2) + ":" + pad(s,2) + "<br>Hourly: $" + (reward/((last_finish-last_start)/(60*60*1000))).toFixed(2) ;
}

function store_data(action_type)
{
    if (action_type.indexOf('Worker') > -1){
        if (!hit_returned){
            var now_in_milliseconds = new Date().getTime();
            var hitReview_hitId = window.location.href.split('tasks/')[1].split('?')[0];
            console.log(hitReview_hitId);

            var $data_holder = $('a:contains("HIT Details"):eq(0)').parent().attr('data-react-props');
            var requester_name = JSON.parse($data_holder).modalOptions.requesterName;
            var hit_title = JSON.parse($data_holder).modalOptions.projectTitle;
            var hit_reward = JSON.parse($data_holder).modalOptions.monetaryReward.amountInDollars;
            var open_list = "";
            var close_list = "";
            var stored_copy = localStorage.getItem('time_data.' + hitReview_hitId);
            if (stored_copy !== null){
                open_list = stored_copy.split('$#$')[3];
                close_list = stored_copy.split('$#$')[4];
            }
            if (action_type == "openWorker"){
                open_list += "?" + now_in_milliseconds;
            }
            else if (action_type == "closeWorker"){
                close_list += "?" + now_in_milliseconds;
            }
            var autoapprove_data = requester_name + "$#$" + hit_title + "$#$"+ hit_reward +"$#$" + open_list + "$#$" + close_list;
            console.log(autoapprove_data);
            localStorage.setItem('time_data.' + hitReview_hitId, autoapprove_data);

        }
    }
    else{

        var $isAccepted = $('input[type="hidden"][name="isAccepted"][value="true"]');
        if ($isAccepted.length > 0 && !hit_returned)
        {
            var hitReview_hitId = $('form[name="hitForm"][action="/mturk/hitReview"] input[name="hitId"]').val();
            console.log(hitReview_hitId);
            var hit_reward = $('form[name="hitForm"][action="/mturk/submit"] input[name="prevReward"]').val().replace('USD','');
            console.log(hit_reward);
            var requester_name = $('td.capsule_field_title:contains("Requester:"):eq(0)').next().text().trim();
            var hit_title = $('table:contains("Requester:"):eq(0) table:eq(0)').text().trim();
            var now_in_milliseconds = new Date().getTime();
            var open_list = "";
            var close_list = "";
            var stored_copy = localStorage.getItem('time_data.' + hitReview_hitId);
            if (stored_copy !== null){
                open_list = stored_copy.split('$#$')[3];
                close_list = stored_copy.split('$#$')[4];
            }
            if (action_type == "open"){
                open_list += "?" + now_in_milliseconds;
            }
            else{
                close_list += "?" + now_in_milliseconds;
            }
            var autoapprove_data = requester_name + "$#$" + hit_title + "$#$"+ hit_reward +"$#$" + open_list + "$#$" + close_list;
            console.log(autoapprove_data);
            localStorage.setItem('time_data.' + hitReview_hitId, autoapprove_data);
        }
    }
}

function mergeIntervals(intervals) {
    // test if there are at least 2 intervals
    if(intervals.length <= 1)
        return intervals;

    var stack = [];
    var top   = null;

    // sort the intervals based on their start values
    intervals = intervals.sort(function (startValue, endValue) {
        if (startValue[0] > endValue[0]) {
            return 1;
        }
        if (startValue[0] < endValue[0]) {
            return -1;
        }
        return 0;
    });

    // push the 1st interval into the stack
    stack.push(intervals[0]);

    // start from the next interval and merge if needed
    for (var i = 1; i < intervals.length; i++) {
        // get the top element
        top = stack[stack.length - 1];

        // if the current interval doesn't overlap with the
        // stack top element, push it to the stack
        if (top[1] < intervals[i][0]) {
            stack.push(intervals[i]);
        }
        // otherwise update the end value of the top element
        // if end of current interval is higher
        else if (top[1] < intervals[i][1])
        {
            top[1] = intervals[i][1];
            stack.pop();
            stack.push(top);
        }
    }

    return stack;
}

function combineIntervals(intervals, padding) {
    // test if there are at least 2 intervals
    if(intervals.length <= 1)
        return intervals;

    var stack = [];
    var top = null;

    // push the 1st interval into the stack
    stack.push(intervals[0]);

    // start from the next interval and merge if needed
    for (var i = 1; i < intervals.length; i++) {
        // get the top element
        top = stack[stack.length - 1];

        // if the current interval doesn't overlap with the
        // stack top element, push it to the stack
        if ((intervals[i][0]-top[1]) > padding) {
            //  console.log("hi",(intervals[i][0]-top[1]) + padding);
            stack.push(intervals[i]);
        }
        // otherwise update the end value of the top element
        // if end of current interval is higher
        else if (top[1] < intervals[i][1])
        {
            top[1] = intervals[i][1];
            stack.pop();
            stack.push(top);
        }
    }
    //console.log("stack",stack);
    return stack;
}

function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function Remove_Old_Data(){
    var today = new Date();
    var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
    if (localStorage.getItem('mturkHourlyRemovalDate') != date){
        console.log('mturk hourly data older than 45 days has been cleared');

        //thanks to @ChrisTurk for the old key removal code:
        Object.keys(localStorage)
            .forEach(function(key){
            if (/^time_data\./.test(key)) {
                console.log(localStorage[key]);
                var stored = localStorage[key].split(/\?/).pop(); // grabs last timestamp from the stack
                // days * hours * min * sec * 1000 [millisec 'cause of the way its stored]
                if (($.now()-stored) > 14*24*60*60*1000) {
                    // console.log('older than 14 days');
                    localStorage.removeItem(key); //uncomment this line to delete keys
                } else {
                    //  console.log('fresh memes'); //less than 1 day old, don't delete it.
                }
            }
        });
        localStorage.setItem('mturkHourlyRemovalDate',date);
    }
}

function Goal(){
    if (!localStorage.Goal_percent){
        localStorage.Goal_percent = 0;
    }
    if (!localStorage.Goal_progress){
        localStorage.Goal_progress = 0;
    }
    if (!localStorage.Goal_goal){
        localStorage.Goal_goal = 25.00;
    }
    if ($("#bonusDIV").length){
        var $goalDIV0 = $('<div id="goalDIV" class="even" style="display:table-row">');
        $($goalDIV0).append('<td class="metrics-table-first-value"><div id="progressbar" style="width: 100%; height: 7px; border: 1px solid #7fb4cf; border-radius: 3px; overflow: hidden; margin-top: 3px; text-align: center; -webkit-user-select: none; -moz-user-select: none;"><div id="progress" style="height: 100%; background-color: #7fb4cf; -webkit-user-select: none; -moz-user-select: none;"></div></div></td><td><span id="progressper" class="reward">0%</span></td>');
        $("#bonusDIV").after($goalDIV0);
    }
    else {
        var $goalDIV1 = $('<div id="goalDIV" class="odd" style="display:table-row">');
        $($goalDIV1).append('<td class="metrics-table-first-value"><div id="progressbar" style="width: 100%; height: 7px; border: 1px solid #7fb4cf; border-radius: 3px; overflow: hidden; margin-top: 3px; text-align: center; -webkit-user-select: none; -moz-user-select: none;"><div id="progress" style="height: 100%; background-color: #7fb4cf; -webkit-user-select: none; -moz-user-select: none;"></div></div></td><td><span id="progressper" class="reward">0%</span></td>');
        $("#TPE_div").after($goalDIV1);
    }

    $("#progress").width(Number(localStorage.Goal_percent)+"%");
    $("#progressper").text(Number(localStorage.Goal_progress).toFixed(2));

    $("#progressbar").dblclick(function(e){
        e.preventDefault();
        var goal = prompt("Please enter your goal", localStorage.Goal_goal);
        if (goal !== null) {
            localStorage.Goal_goal = goal.replace(/[^0-9.]/g, "");
            localStorage.Goal_percent = ((Number(localStorage.TPE_pe)/Number(localStorage.Goal_goal))*100);
            localStorage.Goal_progress = Number(localStorage.TPE_pe)-Number(localStorage.Goal_goal);
            $("#progress").width(Number(localStorage.Goal_progress)+"%");
            $("#progressper").text(Number(localStorage.Goal_progress).toFixed(2));
        }
    });
}

function Todays_Bonuses(){
    var today = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).prop("href");

    var $bonusDIV = $('<div id="bonusDIV" class="odd" style="display:table-row">');
    $($bonusDIV).append('<td class="metrics-table-first-value"><a href="javascript:void(0)">Today\'s Bonuses</a></td><td><span id="bonus" class="reward">$0.00</span></td>');
    $("#TPE_div").after($bonusDIV);

    if (today){
        var date = today.split("encodedDate=")[1];
        if (date === localStorage.TB_date){
            if (!localStorage.today_start_bonuses){
                localStorage.today_start_bonuses = Number($("#bonus_earnings_amount").text().replace(/[^0-9.]/g, ""));
            }
            Bonuses(localStorage.today_start_bonuses);
        }
        else {
            var today_approved = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().text());
            if (today_approved === 0){
                localStorage.today_start_bonuses = (Number($("#bonus_earnings_amount").text().replace(/[^0-9.]/g, ""))-Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().next().next().text().replace(/[^0-9.]/g, "")));
            }
            else {
                localStorage.today_start_bonuses = Number($("#bonus_earnings_amount").text().replace(/[^0-9.]/g, ""));
            }
            localStorage.TB_date = date;
            Bonuses(localStorage.today_start_bonuses);
        }
    }

    function Bonuses(starting_bonus){
        var total_bonuses  = $("#bonus_earnings_amount").text().replace(/[^0-9.]/g, "");
        $("#bonus").text("$"+(Math.round((Number(total_bonuses)-Number(starting_bonus))*100)/100).toFixed(2));
    }
}

function Real_Stats(){
    var approved = Number($("td.metrics-table-first-value:contains(... Approved)").next().text());
    var rejected = Number($("td.metrics-table-first-value:contains(... Rejected)").next().text());

    $("td.metrics-table-first-value:contains(... Approved)").next().next().text(Math.round(((approved)/(approved+rejected))*1000000)/10000+"%");
    $("td.metrics-table-first-value:contains(... Rejected)").next().next().text(Math.round(((rejected)/(approved+rejected))*1000000)/10000+"%");
}

function Best_Worst_Case(){
    var submitted = Number($("td.metrics-table-first-value:contains(HITs Submitted)").next().text());
    var rejected  = Number($("td.metrics-table-first-value:contains(... Rejected)").next().text());
    var approved  = Number($("td.metrics-table-first-value:contains(... Approved)").next().text());
    var pending   = Number($("td.metrics-table-first-value:contains(... Pending)").next().text());

    var $under99 = $('<span style="color: orange;"> ('+Math.round((rejected-((1.0 - 99/100)*submitted))/((1.0 - 99/100)-1))+' ≥ 99%)</span>');
    var $under95 = $('<span style="color: red;"> ('+Math.round((rejected-((1.0 - 95/100)*submitted))/((1.0 - 95/100)-1))+' ≥ 95%)</span>');
    var $worst   = $('<span style="color: red;">\n'+Math.round(approved/(approved+rejected+pending) * 1000000)/10000+'%</span>');

    $("td.metrics-table-first-value:contains(... Pending)").append($under99,$under95);
    $("td.metrics-table-first-value:contains(... Pending)").next().next().text(Math.round(((submitted-rejected)/submitted)*1000000)/10000+"%").css({"color": "green"}).append($worst);
}

function Changes(){
    var today = $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).prop("href");

    if (today){
        var date = today.split("encodedDate=")[1];
        if (date !== localStorage.Changes_date){
            localStorage.Changes_date = date;
            localStorage.today_submitted = 0;
            localStorage.today_approved  = 0;
            localStorage.today_rejected  = 0;
            localStorage.today_pending   = 0;
        }
    }

    var earnings_hits     = Number($("#approved_hits_earnings_amount").text().replace(/[^0-9.]/g, ""));
    var earnings_bonuses  = Number($("#bonus_earnings_amount").text().replace(/[^0-9.]/g, ""));
    var earnings_total    = Number($("#total_earnings_amount").text().replace(/[^0-9.]/g, ""));
    var earnings_transfer = Number($("#transfer_earnings").text().replace(/[^0-9.]/g, ""));
    var hits_submitted    = Number($("td.metrics-table-first-value:contains(HITs Submitted)").next().text());
    var hits_approved     = Number($("td.metrics-table-first-value:contains(... Approved)").next().text());
    var hits_rejected     = Number($("td.metrics-table-first-value:contains(... Rejected)").next().text());
    var hits_pending      = Number($("td.metrics-table-first-value:contains(... Pending)").next().text());
    var today_submitted   = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().text());
    var today_approved    = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().text());
    var today_rejected    = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().text());
    var today_pending     = Number($("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().next().text());

    if (Number(localStorage.earnings_hits) !== earnings_hits){
        $("#approved_hits_earnings_amount").prev().append('<span id="earnings_hits" style="float:right;">+$'+(Math.round((earnings_hits-Number(localStorage.earnings_hits))*100)/100).toFixed(2)+'</span>');
        localStorage.earnings_hits = earnings_hits;
    }
    if (Number(localStorage.earnings_bonuses) !== earnings_bonuses){
        $("#bonus_earnings_amount").prev().append('<span id="earnings_bonuses" style="float:right;">+$'+(Math.round((earnings_bonuses-Number(localStorage.earnings_bonuses))*100)/100).toFixed(2)+'</span>');
        localStorage.earnings_bonuses = earnings_bonuses;
    }
    if (Number(localStorage.earnings_total) !== earnings_total){
        $("#total_earnings_amount").prev().append('<span id="earnings_total" style="float:right;">+$'+(Math.round((earnings_total-Number(localStorage.earnings_total))*100)/100).toFixed(2)+'</span>');
        localStorage.earnings_total = earnings_total;
    }
    if (Number(localStorage.earnings_transfer) !== earnings_transfer){
        if (Number(localStorage.earnings_transfer) > earnings_transfer){
            $("#transfer_earnings").prev().append('<span id="earnings_transfer" style="float:right;">-$'+(Math.round((Number(localStorage.earnings_transfer)-earnings_transfer)*100)/100).toFixed(2)+'</span>');
        }
        else {
            $("#transfer_earnings").prev().append('<span id="earnings_transfer" style="float:right;">+$'+(Math.round((earnings_transfer-Number(localStorage.earnings_transfer))*100)/100).toFixed(2)+'</span>');
        }
        localStorage.earnings_transfer = earnings_transfer;
    }
    if (Number(localStorage.hits_submitted) !== hits_submitted){
        $("td.metrics-table-first-value:contains(HITs Submitted)").append('<span id="hits_submitted" style="float:right;">+'+(hits_submitted-Number(localStorage.hits_submitted))+'</span>');
        localStorage.hits_submitted = hits_submitted;
    }
    if (Number(localStorage.hits_approved) !== hits_approved){
        $("td.metrics-table-first-value:contains(... Approved)").append('<span id="hits_approved" style="float:right;">+'+(hits_approved-Number(localStorage.hits_approved))+'</span>');
        localStorage.hits_approved = hits_approved;
    }
    if (Number(localStorage.hits_rejected) !== hits_rejected){
        $("td.metrics-table-first-value:contains(... Rejected)").append('<span id="hits_rejected" style="float:right;">+'+(hits_rejected-Number(localStorage.hits_rejected))+'</span>');
        localStorage.hits_rejected = hits_rejected;
    }
    if (Number(localStorage.hits_pending) !== hits_pending){
        if (Number(localStorage.hits_pending) > hits_pending){
            $("td.metrics-table-first-value:contains(... Pending)").append('<span id="hits_pending" style="float:right;">-'+(Number(localStorage.hits_pending)-hits_pending)+'</span>');
        }
        else {
            $("td.metrics-table-first-value:contains(... Pending)").append('<span id="hits_pending" style="float:right;">+'+(hits_pending-Number(localStorage.hits_pending))+'</span>');
        }
        localStorage.hits_pending = hits_pending;
    }
    if (Number(localStorage.today_submitted) !== today_submitted){
        $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().append('<span id="today_submitted" style="float:left;">+'+(today_submitted-Number(localStorage.today_submitted))+'</span>');
        localStorage.today_submitted = today_submitted;
    }
    if (Number(localStorage.today_approved) !== today_approved){
        $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().append('<span id="today_approved" style="float:left;">+'+(today_approved-Number(localStorage.today_approved))+'</span>');
        localStorage.today_approved = today_approved;
    }
    if (Number(localStorage.today_rejected) !== today_rejected){
        $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().append('<span id="today_rejected" style="float:left;">+'+(today_rejected-Number(localStorage.today_rejected))+'</span>');
        localStorage.today_rejected = today_rejected;
    }
    if (Number(localStorage.today_pending) !== today_pending){
        if (Number(localStorage.today_pending) > today_pending){
            $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().next().append('<span id="today_pending" style="float:left;">-'+(Number(localStorage.today_pending)-today_pending)+'</span>');
        }
        else {
            $("a[href^='/mturk/statusdetail?encodedDate']:contains(Today)").eq(0).parent().next().next().next().next().append('<span id="today_pending" style="float:left;">+'+(today_pending-Number(localStorage.today_pending))+'</span>');
        }
        localStorage.today_pending = today_pending;
    }
}

function Yearly(){
    var totalearnings = Number($("#total_earnings_amount").text().replace(/[^0-9.]/g, ""));
    var $reward = $("#table_yearly_earnings").find("span.reward");

    for (var i = 0; i < $reward.length; i++){
        totalearnings -= Number($reward.eq(i).text().replace(/[^0-9.]/g, ""));
    }

    var earnings2016 = Number((totalearnings).toFixed(2)).toLocaleString("en");

    var $thisyear = $('<tr class="odd"><td class="metrics-table-first-value">2017</td><td id="yearly_earnings_amount"><span class="reward">$'+earnings2016+'</span></td></tr>');
    $("#table_yearly_earnings").find("tr.metrics-table-header-row").after($thisyear);
}

function Hide_HIT_DB(pending, PEday, PEweek){
    var tbody    = $("#approved_hits_earnings_amount").parent().parent().addClass("tbody");
    var $css = '<style type="text/css">\n';
    if (pending){
        $css += ".tbody > .odd:nth-child(8), .even:nth-child(8) {display: none;}\n";
    }
    if (PEday){
        $css += ".tbody > .odd:nth-child(9), .even:nth-child(9) {display: none;}\n";
    }
    if (PEweek){
        $css += ".tbody > .odd:nth-child(10), .even:nth-child(10) {display: none;}\n";
    }
    $("head").append($css);
}

function initialize() {
    Object.assign(String.prototype, {
        number () {
            return Number(this.replace(/[^0-9.]/g, ``));
        }
    });

    const rows = document.getElementById(`dashboard-hits-overview`).getElementsByClassName(`row`);

    window.dashboard = {
        hits_overview: {
            approved: rows[0].getElementsByClassName(`text-xs-right`)[0].textContent.number(),
            pending: rows[2].getElementsByClassName(`text-xs-right`)[0].textContent.number(),
            rejected: rows[3].getElementsByClassName(`text-xs-right`)[0].textContent.number(),
        },
        daily_hit_statistics_overview: {
            total: {
                submitted: 0,
                approved: 0,
                rejected: 0,
                pending: 0,
                earnings: 0,
            }
        },
        earnings_to_date: {
            bonuses: document.getElementById(`dashboard-earnings-to-date`).getElementsByClassName(`text-xs-right`)[2].textContent.number()
        }
    };

    for (const row of document.getElementsByClassName(`daily_hit_statuses`)) {
        const col = row.children;
        const date = col[0].children[0].href.match(/([0-9])+/)[0];

        window.dashboard.daily_hit_statistics_overview[date] = {};

        [`submitted`, `approved`, `rejected`, `pending`, `earnings`].forEach((currentValue, index) => {
            const value = col[index + 1].textContent.number();

            window.dashboard.daily_hit_statistics_overview[date][currentValue] = value;
            window.dashboard.daily_hit_statistics_overview.total[currentValue] += value;
        });
    }
}

function allApprovedRate() {
    const overview = dashboard.hits_overview;

    const row = document.createElement(`div`);
    row.className = `row m-b-sm`;

    const col1 = document.createElement(`div`);
    col1.className = `col-xs-7`;
    row.appendChild(col1);

    const strong = document.createElement(`strong`);
    strong.textContent = `All Approved Rate`;
    col1.appendChild(strong);

    const col2 = document.createElement(`div`);
    col2.className = `col-xs-5 text-xs-right`;
    col2.textContent = `${((overview.approved + overview.pending) / (overview.approved + overview.pending + overview.rejected) * 100).toFixed(4)}%`;
    row.appendChild(col2);

    const additional = document.getElementById(`HitsOverviewAdditionalInfo`);
    additional.parentNode.insertBefore(row, additional);
}

function allRejectedRate() {
    const overview = dashboard.hits_overview;

    const row = document.createElement(`div`);
    row.className = `row m-b-sm`;

    const col1 = document.createElement(`div`);
    col1.className = `col-xs-7`;
    row.appendChild(col1);

    const strong = document.createElement(`strong`);
    strong.textContent = `All Rejected Rate`;
    col1.appendChild(strong);

    const col2 = document.createElement(`div`);
    col2.textContent = `${(overview.approved / (overview.approved + overview.rejected + overview.pending) * 100).toFixed(4)}%`;
    col2.className = `col-xs-5 text-xs-right`;
    row.appendChild(col2);

    const additional = document.getElementById(`HitsOverviewAdditionalInfo`);
    additional.parentNode.insertBefore(row, additional);
}

function fourDigitPercents() {
    const overview = dashboard.hits_overview;

    for (const row of document.getElementById(`dashboard-hits-overview`).getElementsByClassName(`row`)) {
        if (row.textContent.indexOf(`Approval Rate`) !== -1) {
            row.getElementsByClassName(`text-xs-right`)[0].textContent = `${(overview.approved / (overview.approved + overview.rejected) * 100).toFixed(4)}%`;
        }
        if (row.textContent.indexOf(`Rejection Rate`) !== -1) {
            row.getElementsByClassName(`text-xs-right`)[0].textContent = `${(overview.rejected / (overview.approved + overview.rejected) * 100).toFixed(4)}%`;
        }
    }
}

function rejectionsBelow99() {
    const overview = dashboard.hits_overview;

    const row = document.createElement(`div`);
    row.className = `row m-b-sm`;

    const col1 = document.createElement(`div`);
    col1.className = `col-xs-7`;
    row.appendChild(col1);

    const strong = document.createElement(`strong`);
    strong.textContent = `Rejections ≤ 99%`;
    col1.appendChild(strong);

    const col2 = document.createElement(`div`);
    col2.textContent = Math.round((overview.rejected - (0.01 * (overview.approved + overview.rejected + overview.pending))) / -0.99).toLocaleString();
    col2.className = `col-xs-5 text-xs-right`;
    row.appendChild(col2);

    const additional = document.getElementById(`HitsOverviewAdditionalInfo`);
    additional.insertBefore(row, additional.lastChild);
}

function rejectionsBelow95() {
    const overview = dashboard.hits_overview;

    const row = document.createElement(`div`);
    row.className = `row m-b-sm`;

    const col1 = document.createElement(`div`);
    col1.className = `col-xs-7`;
    row.appendChild(col1);

    const strong = document.createElement(`strong`);
    strong.textContent = `Rejections ≤ 95%`;
    col1.appendChild(strong);

    const col2 = document.createElement(`div`);
    col2.textContent = Math.round((overview.rejected - (0.05 * (overview.approved + overview.rejected + overview.pending))) / -0.95).toLocaleString();
    col2.className = `col-xs-5 text-xs-right`;
    row.appendChild(col2);

    const additional = document.getElementById(`HitsOverviewAdditionalInfo`);
    additional.insertBefore(row, additional.lastChild);
}

function totalLast45Days() {
    const table = document.querySelector(`.mturk-table.hits-statuses`);

    const row = table.insertRow(1);
    row.className = `daily_hit_statuses`;

    const date = row.insertCell(0);
    date.textContent = `Total`;
    date.className = `hidden-xs-down col-sm-2 col-md-2`;

    const submitted = row.insertCell(1);
    submitted.textContent = window.dashboard.daily_hit_statistics_overview.total.submitted;
    submitted.className = `text-xs-right col-xs-3 col-sm-2 col-md-2`;

    const approved = row.insertCell(2);
    approved.textContent = window.dashboard.daily_hit_statistics_overview.total.approved;
    approved.className = `text-xs-right col-xs-3 col-sm-2 col-md-2`;

    const rejected = row.insertCell(3);
    rejected.textContent = window.dashboard.daily_hit_statistics_overview.total.rejected;
    rejected.className = `text-xs-right col-xs-3 col-sm-2 col-md-2`;

    const pending = row.insertCell(4);
    pending.textContent = window.dashboard.daily_hit_statistics_overview.total.pending;
    pending.className = `text-xs-right col-xs-3 col-sm-2 col-md-2`;

    const earnings = row.insertCell(5);
    earnings.textContent = `$${window.dashboard.daily_hit_statistics_overview.total.earnings.toLocaleString(`en-US`, { minimumFractionDigits: 2 })}`;
    earnings.className = `text-xs-right col-xs-3 col-sm-2 col-md-2`;
}

function hitStatusChanges() {
    const oldDashboard = localStorage.dashboard ? JSON.parse(localStorage.dashboard) : null;
    localStorage.dashboard = JSON.stringify(dashboard);

    for (const row of document.getElementsByClassName(`daily_hit_statuses`)) {
        const col = row.children;
        const date = col[0].children[0] ? col[0].children[0].href.match(/([0-9])+/)[0] : `total`;

        [`submitted`, `approved`, `rejected`, `pending`, `earnings`].forEach((currentValue, index) => {
            const value = col[index + 1].textContent.number();
            const oldValue = oldDashboard ? oldDashboard.daily_hit_statistics_overview[date][currentValue] : 0;

            if (value !== oldValue) {
                const change = value - oldValue;
                const changeString = change.toFixed(2).toString().replace(`.00`, ``);

                if (Math.round(change * 100) !== 0) {
                    const span = document.createElement(`span`);
                    span.textContent = change > 0 ? `+${changeString}` : changeString;
                    span.style.float = `left`;
                    span.style.fontSize = `70%`;
                    col[index + 1].appendChild(span);
                }
            }
        });
    }
}

function todaysActivity() {
    const container = document.createElement(`div`);
    container.className = `row m-b-xl`;

    const col = document.createElement(`div`);
    col.className = `col-xs-12`;
    container.appendChild(col);

    const h2 = document.createElement(`h2`);
    h2.className = `m-b-md`;
    h2.textContent = `Today's Activity`;
    col.appendChild(h2);

    const row = document.createElement(`div`);
    row.className = `row`;
    col.appendChild(row);

    const col2 = document.createElement(`div`);
    col2.className = `col-xs-12`;
    row.appendChild(col2);

    const border = document.createElement(`div`);
    border.className = `border-gray-lightest p-a-sm`;
    col2.appendChild(border);

    const earningsRow = document.createElement(`div`);
    earningsRow.className = `row m-b-sm`;
    border.appendChild(earningsRow);

    const earningsText = document.createElement(`div`);
    earningsText.className = `col-xs-7 col-sm-6 col-lg-7`;
    earningsRow.appendChild(earningsText);

    const earningsStrong = document.createElement(`strong`);
    earningsStrong.textContent = `Projected Earnings`;
    earningsText.appendChild(earningsStrong);

    const earningsValue = document.createElement(`div`);
    earningsValue.className = `col-xs-5 col-sm-6 col-lg-5 text-xs-right`;
    earningsValue.textContent = localStorage.todaysearnings || `$0.00`;
    earningsRow.appendChild(earningsValue);

    const bonusesRow = document.createElement(`div`);
    bonusesRow.className = `row m-b-sm`;
    border.appendChild(bonusesRow);

    const bonusesText = document.createElement(`div`);
    bonusesText.className = `col-xs-7 col-sm-6 col-lg-7`;
    bonusesRow.appendChild(bonusesText);

    const bonusesStrong = document.createElement(`strong`);
    bonusesStrong.textContent = `Bonuses`;
    bonusesText.appendChild(bonusesStrong);

    const bonusesValue = document.createElement(`div`);
    bonusesValue.className = `col-xs-5 col-sm-6 col-lg-5 text-xs-right`;
    bonusesValue.textContent = localStorage.todaysbonuses || `$0.00`;
    bonusesRow.appendChild(bonusesValue);

    const hourlyRow = document.createElement(`div`);
    hourlyRow.className = `row m-b-sm`;
    border.appendChild(hourlyRow);

    const hourlyText = document.createElement(`div`);
    hourlyText.className = `col-xs-6 col-sm-6 col-lg-6`;
    hourlyRow.appendChild(hourlyText);

    const hourlyStrong = document.createElement(`strong`);
    hourlyStrong.textContent = `Total Hourly`;
    hourlyText.appendChild(hourlyStrong);

    const hourlyTime = document.createElement(`div`);
    hourlyTime.className = `col-xs-3 col-sm-3 col-lg-3 text-xs-right`;
    hourlyTime.textContent = `00:00:00`;
    hourlyRow.appendChild(hourlyTime);

    const hourlyValue = document.createElement(`div`);
    hourlyValue.className = `col-xs-3 col-sm-3 col-lg-3 text-xs-right`;
    hourlyValue.textContent = `$0.00`;
    hourlyRow.appendChild(hourlyValue);

    const collapse = document.createElement(`div`);
    collapse.id = `TodaysActivityAdditionalInfo`;
    collapse.className = `collapse`;
    border.appendChild(collapse);

    const hr = document.createElement(`hr`);
    hr.className = `m-b-sm m-t-0`;
    collapse.appendChild(hr);

    const hr2 = document.createElement(`hr`);
    hr2.className = `m-b-sm m-t-0`;
    border.appendChild(hr2);

    const control = document.createElement(`a`);
    control.className = `collapse-more-less`;
    control.href = `#TodaysActivityAdditionalInfo`;
    control.setAttribute(`aria-controls`, `TodaysActivityAdditionalInfo`);
    control.setAttribute(`aria-expanded`, `false`);
    control.setAttribute(`data-toggle`, `collapse`);
    border.appendChild(control);

    const more = document.createElement(`span`);
    more.className = `more`;
    control.appendChild(more);

    const plus = document.createElement(`i`);
    plus.className = `fa fa-plus-circle`;
    more.appendChild(plus);

    const moreText = document.createTextNode(`\nMore\n`);
    more.appendChild(moreText);

    const less = document.createElement(`span`);
    less.className = `less`;
    control.appendChild(less);

    const minus = document.createElement(`i`);
    minus.className = `fa fa-minus-circle`;
    less.appendChild(minus);

    const lessText = document.createTextNode(`\nLess\n`);
    less.appendChild(lessText);

    const side = document.querySelector(`.col-md-push-8`);
    side.insertBefore(container, side.firstChild);

    const today = document.querySelector(`a[href^="https://www.mturk.com/mturk/statusdetail"]`);

    if (today.textContent === `Today`) {
        const date = today.href.match(/([0-9])+/)[0];

        if (date === localStorage.WMTD_date) {
            if (!localStorage.WMTD_bonusStart) {
                localStorage.WMTD_bonusStart = window.dashboard.earnings_to_date.bonuses;
            }
        }
        else {
            if (window.dashboard.daily_hit_statistics_overview[date].approved === 0) {
                localStorage.WMTD_bonusStart = dashboard.earnings_to_date.bonuses - dashboard.daily_hit_statistics_overview[date].earnings;
            }
            else {
                localStorage.WMTD_bonusStart = dashboard.earnings_to_date.bonuses;
            }
        }

        bonusesValue.textContent = `$${(dashboard.earnings_to_date.bonuses - localStorage.WMTD_bonusStart).toLocaleString(`en-US`, { minimumFractionDigits: 2 })}`;

        const hitLog = date === localStorage.WMTD_date ? localStorage.WMTD_hitLog ? JSON.parse(localStorage.WMTD_hitLog) : {} : {};

        const get = async (url, rescan) => {
            try {
                const page = url.match(/Number=([0-9]*)/);

                earningsValue.textContent = `Calculating Page ${page ? page[1] : `1`}`;

                const response = await new Promise((resolve) => {
                    GM_xmlhttpRequest({
                        method: `GET`,
                        url: url,
                        onload: resolve
                    });
                });
                const text = response.responseText;

                if (text.indexOf(`You have exceeded the maximum allowed page request rate for this website.`) !== -1) {
                    return setTimeout(get, 2000, url, rescan);
                }

                if (text.indexOf(`You have no HIT activity on this day matching the selected status.`) !== -1) {
                    return false;
                }

                localStorage.WMTD_lastPage = url;

                const doc = new DOMParser().parseFromString(text, `text/html`);

                const hits = doc.getElementById(`dailyActivityTable`).querySelectorAll(`tr[valign="top"]`);

                if (hits.length) {
                    for (const hit of hits) {
                        const td = hit.children;
                        const obj = {
                            req: td[0].textContent.trim(),
                            tit: td[1].textContent.trim(),
                            rew: td[2].textContent.trim().number(),
                            sta: td[3].textContent.trim(),
                            rid: td[0].getElementsByTagName(`a`)[0].href.match(/requesterId=([A-Z0-9]+)/)[1],
                            hid: td[0].getElementsByTagName(`a`)[0].href.match(/hitId=([A-Z0-9]+)/)[1]
                        };

                        hitLog[obj.hid] = obj;
                    }

                    const logLength = Object.keys(hitLog).length;
                    const expectedLength = (page ? page[1].number() * 25 - 25 : 0) + hits.length;

                    if (!rescan && logLength !== expectedLength) {
                        return get(today.href, true);
                    }
                    else {
                        localStorage.WMTD_hitLog = JSON.stringify(hitLog);
                    }

                    const next = doc.querySelector(`img[src="/media/right_arrow.gif"]`);

                    if (next) {
                        return get(next.parentElement.href.replace(`worker`, `www`), rescan);
                    }
                    else {

                        let projectedEarnings = 0;
                        const reqLog = {};
                        const hourlyLog = {};
                        const gmHourlyLog = {};

                        for (const key in hitLog) {
                            if (hitLog[key].status !== `Rejected`) {
                                projectedEarnings += hitLog[key].rew;
                            }
                            if (!reqLog[hitLog[key].rid]){
                                reqLog[hitLog[key].rid] = {
                                    req: hitLog[key].req,
                                    submit: 1,
                                    reward: hitLog[key].rew,
                                    reqid: hitLog[key].rid
                                };
                            }
                            else {
                                reqLog[hitLog[key].rid].submit += 1;
                                reqLog[hitLog[key].rid].reward += hitLog[key].rew;
                            }
                            if (!hourlyLog[hitLog[key].reqid]){
                                var time_data = localStorage.getItem('time_data.' + hitLog[key].hid.split('&')[0]);
                                if (time_data != null){
                                    gmHourlyLog[hitLog[key].hid] = time_data;
                                    var starts = time_data.split("$#$")[3].split('?');
                                    var last_start = starts[starts.length-1];
                                    var stops = time_data.split("$#$")[4].split('?');
                                    var last_stop = stops[stops.length-1];
                                    if (last_start.length && last_stop.length){
                                        hourlyLog[hitLog[key].rid] = {
                                            req : hitLog[key].req,
                                            intervals :[[last_start,last_stop]],
                                            totalReward : parseFloat(time_data.split("$#$")[2]),
                                        };
                                    }
                                }
                            }
                            else{
                                var time_data = localStorage.getItem('time_data.' + hitLog[key].hid.split('&')[0]);
                                if (time_data != null){
                                    gmHourlyLog[hitLog[key].hid] = time_data;
                                    var starts = time_data.split("$#$")[3].split('?');
                                    var last_start = starts[starts.length-1];
                                    var stops = time_data.split("$#$")[4].split('?');
                                    var last_stop = stops[stops.length-1];
                                    if (last_start.length && last_stop.length){
                                        hourlyLog[hitLog[key].rid].intervals.push([last_start,last_stop]);
                                    }
                                    hourlyLog[hitLog[key].rid].totalReward += parseFloat(time_data.split("$#$")[2]);
                                }
                            }
                        }

                        console.log(gmHourlyLog);
                        GM_setValue('gmHourlyLog',JSON.stringify(gmHourlyLog));

                        const sort = Object.keys(reqLog).sort((a, b) => reqLog[a].reward - reqLog[b].reward);

                        const fragment = document.createDocumentFragment();

                        var total_intervals = [];
                        var total_recorded_earnings = 0;
                        for (var j = sort.length-1; j > -1; j--){
                            var dkey = sort[j];
                            var d_req = reqLog[dkey].req;
                            var d_submitted = reqLog[dkey].submit;
                            var d_reward = Number(reqLog[dkey].reward).toFixed(2);
                            var d_hourly = "N/A";
                            if (d_req !== "Bonuses" && hourlyLog[reqLog[dkey].reqid]){
                                var intervals = hourlyLog[reqLog[dkey].reqid].intervals;
                                var d_intervals_sum = 0;
                                for (i=0;i<intervals.length;i++){
                                    d_intervals_sum += (intervals[i][1]-intervals[i][0]);
                                }
                                var d_intervals_avg = d_intervals_sum / intervals.length;
                                var d_intervals = mergeIntervals(intervals);
                                d_intervals = combineIntervals(intervals,Math.max(2*60*1000,Math.min(10*d_intervals_avg,10*60*1000)));
                                total_intervals = total_intervals.concat(d_intervals);
                                total_recorded_earnings += hourlyLog[reqLog[dkey].reqid].totalReward;
                                var d_time = 0;
                                for (i=0;i<d_intervals.length; i++){
                                    var s = new Date(parseInt(d_intervals[i][0]));
                                    var f = new Date(parseInt(d_intervals[i][1]));
                                    console.log(d_req, i, s.toLocaleTimeString(),f.toLocaleTimeString());
                                    d_time += (d_intervals[i][1] - d_intervals[i][0])/(1000*60*60);
                                }
                                d_hourly = "$" + (hourlyLog[reqLog[dkey].reqid].totalReward / d_time).toFixed(2);
                            }
                            reqLog[dkey].hourly = d_hourly;
                        }
                        total_intervals = mergeIntervals(total_intervals);
                        var total_time = 0;
                        for (i=0;i<total_intervals.length; i++){
                            var s = new Date(parseInt(total_intervals[i][0]));
                            var f = new Date(parseInt(total_intervals[i][1]));
                            console.log(i, s.toLocaleTimeString(),f.toLocaleTimeString());
                            total_time += (total_intervals[i][1] - total_intervals[i][0])/(1000*60*60);
                        }

                        var total_hourly = '$' + (total_recorded_earnings/total_time).toFixed(2);
                        var hour = Math.floor(total_time);
                        var min = Math.floor((total_time - hour)*60);
                        var sec = Math.floor((total_time - hour - min/60)*3600);
                        var time_display = (hour>0?pad(hour,2) + ":":"") + pad(min,2) + ":" + pad(sec,2);

                        hourlyValue.textContent = total_hourly;
                        hourlyTime.textContent = time_display;

                        for (let i = sort.length - 1; i > -1; i--) {
                            const key = sort[i];
                            const req = reqLog[key].req;
                            const submit = reqLog[key].submit;
                            const reward = `$${reqLog[key].reward.toLocaleString(`en-US`, { minimumFractionDigits: 2 })}`;
                            const hourly = reqLog[key].hourly;

                            const reqRow = document.createElement(`div`);
                            reqRow.className = `row m-b-sm`;
                            fragment.appendChild(reqRow);

                            const requester = document.createElement(`div`);
                            requester.className = `col-xs-6`;
                            reqRow.appendChild(requester);

                            const requesterStrong = document.createElement(`strong`);
                            requesterStrong.textContent = req;
                            requester.appendChild(requesterStrong);

                            const submitValue = document.createElement(`div`);
                            submitValue.className = `col-xs-2 text-xs-right`;
                            submitValue.textContent = submit;
                            reqRow.appendChild(submitValue);

                            const rewardValue = document.createElement(`div`);
                            rewardValue.className = `col-xs-2 text-xs-right`;
                            rewardValue.textContent = reward;
                            reqRow.appendChild(rewardValue);

                            const hourlyValue = document.createElement(`div`);
                            hourlyValue.className = `col-xs-2 text-xs-right`;
                            hourlyValue.textContent = hourly;
                            reqRow.appendChild(hourlyValue);
                        }

                        collapse.appendChild(fragment);

                        earningsValue.textContent = `$${projectedEarnings.toLocaleString(`en-US`, { minimumFractionDigits: 2 })}`;
                    }
                }
            }
            catch (error) {
                console.error(error);
            }
        };

        get(date === localStorage.WMTD_date ? localStorage.WMTD_lastPage ? localStorage.WMTD_lastPage : today.href : today.href, false);

        localStorage.WMTD_date = date;
    }
    else {
        earningsValue.textContent = `N/A`;
        bonusesValue.textContent = `N/A`;
    }
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址