09/27 - Turmeric Thursday!

Status
Not open for further replies.

jklmnop

data sanitation engineer
Moderator
Joined
Jan 10, 2016
Messages
4,862
Reaction score
13,273
Points
863
Gender
Female
Welcome to today's MTurk Crowd work thread!

Please check out the forum guidelines.

Maybe you need some help getting started?

Want more info about how the forum works?

Would you like to contribute an idea about the future of the forum? Feel free to share your thoughts here.

If you are interested in creating a daily thread, please tag @dibs to let everyone know that you would like to claim the next day. It is first come, first serve and thread must be created and posted by 3a EST/12a PST.

Please let a mod know if you have any questions, and have a great turking day! - MTC staff

 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Help us pretest this survey on cloud database satisfaction | Accept
Requester: Pivotal Perspectives Team [A13T9H8Q53Q65K] Contact
TV: [Hrly=$11.50] [Pay=3.10] [Fast=5.00] [Comm=null] [Rej=0] [ToS=0] [Blk=0]
TO: [Pay=2.23] [Fast=2.81] [Comm=1.76] [Fair=3.47] [Reviews=33] [ToS=0]
TO2: [Hrly=4.78] [Pen=0.50 days] [Res=0%] [Rec=10%] [Rej=0] [ToS=2] [Brk=2]
Reward: 0.25
Duration: 7200
Available: 1
Description: Test the survey by answering a few screening quesitons, get a $4.5 bonus for completing the entire 15 minute survey
Qualifications: HIT approval rate (%) GreaterThan 95; Total approved HITs GreaterThan 5000; Location EqualTo US
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Fun psychology / vision / language experiment! | Accept
Requester: Shane Steinert-Threlkeld [A15O9ZYX0UM05V] Contact
TV: No Reviews
TO: [Pay=3.88] [Fast=5.00] [Comm=0.00] [Fair=5.00] [Reviews=8] [ToS=0]
TO2: No Reviews
Reward: 4.00
Duration: 2700
Available: 1
Description: You will be asked to judge whether certain sentences are true or false in the context of an image.
Qualifications: HIT approval rate (%) GreaterThanOrEqualTo 95; Location EqualTo US
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Answer a survey about a new brand | Accept
Requester: Jaclyn Atlas [A26G8FFON9DWMB] Contact
TV: No Reviews
TO: [Pay=5.00] [Fast=5.00] [Comm=0.00] [Fair=5.00] [Reviews=1] [ToS=0]
TO2: No Reviews
Reward: 1.00
Duration: 3600
Available: 1
Description: Give us your opinion about our products
Qualifications: Location In US-CA, US-CO, US-CT, US-DC, US-DE, US-IL, US-MA, US-MD, US-ME, US-MI, US-NH, US-NJ, US-NY, US-OH, US-OR, US-PA, US-RI, US-VT; LinkedIn Account Holder EqualTo 1; Household Income - $100,000 or more EqualTo 1
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Food Technology: Attitudes and Risks Study | Accept
Requester: TTU Language and Social Interaction Lab [AN608R8T7BJUK] Contact
TV: [Hrly=$12.06] [Pay=3.67] [Fast=null] [Comm=null] [Rej=0] [ToS=0] [Blk=0]
TO: [Pay=3.52] [Fast=4.50] [Comm=3.33] [Fair=4.50] [Reviews=53] [ToS=0]
TO2: [Hrly=0.01] [Pen=0.92 days] [Res=100%] [Rec=33%] [Rej=1] [ToS=0] [Brk=1]
Reward: 4.00
Duration: 10800
Available: 1
Description: Answer survey questions about food technologies
Qualifications: Location In AU, BS, CA, GB, IE, NZ, US; HIT approval rate (%) GreaterThanOrEqualTo 99; Total approved HITs GreaterThan 50
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

GTR

Well-Known Member
Joined
Feb 10, 2016
Messages
10,278
Reaction score
22,985
Points
1,313
Gender
Male
TC Rank
# 2 / 7 ( Top 29% )

i'm comin after you number 1
 
  • Like
Reactions: CrazyCatLady

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
TC Rank
# 2 / 7 ( Top 29% )

i'm comin after you number 1
Hate to sound like an idiot. Actually, I don't mind sounding like an idiot. :p
Aaaaanywayy, what are those numbers referring to? If I were to guess, Fantasy Foosball? But, I've seen the posts enough that I have to ask what the frack I'm looking at. Inquiring minds want to know.
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Prediction Task, Scientific Survey | Accept
Requester: Simon Kloker [A2FGLI45XXCGZ0] Contact
TV: No Reviews
TO: No Reviews
TO2: No Reviews
Reward: 1.60
Duration: 2700
Available: 1
Description: This is a survey for scientific purposes. You will be asked to assess future events and fill some further questionnaires.
Qualifications: Total approved HITs GreaterThan 100; Completed Prediction Task already DoesNotExist ; HIT approval rate (%) GreaterThan 90; Location EqualTo US
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td]
under 15min[/td][/tr]
 

GTR

Well-Known Member
Joined
Feb 10, 2016
Messages
10,278
Reaction score
22,985
Points
1,313
Gender
Male
Hate to sound like an idiot. Actually, I don't mind sounding like an idiot. :p
Aaaaanywayy, what are those numbers referring to? If I were to guess, Fantasy Foosball? But, I've seen the posts enough that I have to ask what the frack I'm looking at. Inquiring minds want to know.
it's a earnings script to compare how big your PE is to others
mTurk Slow or Just Me? ("SOJM")

Code:
// ==UserScript==
// @name         mTurk Slow or Just Me? ("SOJM")
// @namespace    salembeats
// @version      1.67
// @description  UPDATE: Quick HUD added to compare yourself to the "normal" range (the middle 50% of responses, represented by the box in the box/whisker plot). NOTE: Requires Kadauchi's "MTurk Dashboard Enhancer" script to function properly.
// @author       Cuyler Stuwe (salembeats)
// @include      https://worker.mturk.com/dashboard*
// ==/UserScript==

const globals = {
    CLIENT_VERSION: "synchronicity",
    API_BASE: "https://ne26dv9hq6.execute-api.us-west-2.amazonaws.com/dev"
};

// Minified, synchronous SHA-256 transform function copied from: http://geraintluff.github.io/sha256/
var sha256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;64>n;p++)if(!o[p]){for(d=0;313>d;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;64>d;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=16>d?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;8>d;d++)l[d]=l[d]+r[d]|0}for(d=0;8>d;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(16>y?0:"")+y.toString(16)}return i};

function exists(thing) {
    return thing !== undefined && thing !== null;
}

function amazonDate() {
    return new Date(Date.now() + (new Date().getTimezoneOffset()*60*1000) - (420*60*1000));
}

function medianOfSortedValues(sortedValuesArray) {

    const middlePosition = Math.floor(sortedValuesArray.length/2);

    if(sortedValuesArray.length % 2) {
        return sortedValuesArray[middlePosition];
    }
    else {
        return (sortedValuesArray[middlePosition-1] + sortedValuesArray[middlePosition]) / 2.0;
    }

}

function sidesOfMedian(sortedValuesArray) {

    const hasEvenNumberOfItems = ( sortedValuesArray.length % 2 === 0 );

    if(hasEvenNumberOfItems) {
        return [
            sortedValuesArray.slice(0, (sortedValuesArray.length / 2)),
            sortedValuesArray.slice((sortedValuesArray.length / 2), sortedValuesArray.length)
        ];
    }
    else {
        const indexToSplitOn = ((sortedValuesArray.length + 1) / 2) - 1;

        return [
            sortedValuesArray.slice(0, indexToSplitOn),
            sortedValuesArray.slice(indexToSplitOn + 1, sortedValuesArray.length)
        ];
    }
}


function hitLogTotalUsd() {

    const hitLog = JSON.parse(localStorage.getItem("WMTD_hitLog"));

    return Object.keys(hitLog).reduce((acc, currentHitLogKey) => {

        return (acc + hitLog[currentHitLogKey].reward.amount_in_dollars);

    }, 0);

}

function dateYYYYMMDD(date) {

    const now = date;
    const [year, month, day] = [now.getFullYear(), now.getMonth() + 1, now.getDate()].map(num => num.toLocaleString("en-US", {minimumIntegerDigits: 2, useGrouping: false}));
    const todaysDateStr = `${year}-${month}-${day}`;
    return todaysDateStr;

}

function todaysDateYYYYMMDD() {
    return dateYYYYMMDD(new Date());
}

function amazonDateYYYYMMDD() {
    return dateYYYYMMDD(amazonDate());
}

function lastWorkLoggedDateYYYYMMDD() {
    return localStorage.getItem("WMTD_date");
}

function todaysTotal() {

    const lastRecordedDate = lastWorkLoggedDateYYYYMMDD();

    if(lastRecordedDate === amazonDateYYYYMMDD()) {

        return hitLogTotalUsd();

    }
    else {

        return null;

    }

}

function todaysTotalMTS() {
  const mtsProjectedEarnings = document.getElementById('mts-ht-earnings').textContent;
  return Number(mtsProjectedEarnings.replace(/[^0-9.]/g, ''));
}

function workerId() {

    const workerIdCopyElement = document.querySelector(`[data-react-class="require('reactComponents/common/CopyText')['default']"]`);
    return JSON.parse(workerIdCopyElement.dataset.reactProps).textToCopy;

}

function workerIdHash() {

    return sha256(workerId());

}

function userEarningsPayload() {

    const payload = JSON.stringify({
        idHash: workerIdHash(),
        date: lastWorkLoggedDateYYYYMMDD(),
        total: todaysTotal() || todaysTotalMTS(),
        clientVersion: globals.CLIENT_VERSION
    });

    return payload;

}

async function submitUserEarnings() {

    const apiEndpoint = `${globals.API_BASE}/store`;

    const responseStream = await fetch(apiEndpoint, {
        method: "POST",
        body: userEarningsPayload(),
        headers: {
            "Content-Type": "application/json"
        }
    });

    const response = await responseStream.json();
    return response;

}

function injectAveragePERow() {
    const el = document.getElementById("TodaysActivityAdditionalInfo") || document.getElementById('dashboard-available-earnings').querySelector('.border-gray-lightest').children[0];

    el.insertAdjacentHTML("beforebegin", `
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Today's Community Average</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <a id="retrieveCommunityAverage" href="javascript:void(0);">Retrieve Community Average</a>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Low, Med, High</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="tcLowMedHigh">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong><span style="color: white; background: rgb(127,127,127);">Normal Range</span> vs. <span style="background: black; color: white;">You</span></strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="normalRange">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Box+Whisker Plot</strong>
            </div>
            <div style="text-align: center;">
                <img id="boxplotImage" style="max-width: 270px;" src="">
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="rank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Nearest Competitor</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="nearestCompetitor"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="leagueRank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leagueLeaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Best</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localBest"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Past Avg</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localAverage"></div>
            </div>
        </div>
    `);
}

function boxplotRenderUrl(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined
}) {
    return (`http://www.imathas.com/stattools/boxplot.php?n=1&showlabels=0&title0=&ds0q0=${params.low.replace("$", "")}&ds0q1=${params.firstQuartile.replace("$", "")}&ds0q2=${params.median.replace("$", "")}&ds0q3=${params.thirdQuartile.replace("$", "")}&ds0q4=${params.high.replace("$", "")}&title1=&ds1q0=&ds1q1=&ds1q2=&ds1q3=&ds1q4=&title2=&ds2q0=&ds2q1=&ds2q2=&ds2q3=&ds2q4=&xmin=0&xmax=${Math.floor((+params.high.replace("$", "")) + 5)}&ticks=5&axistitle=&imgwidth=300&imgheight=120`);
}

function embedBoxAndWhiskerData(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined}) {
    document.getElementById("tcLowMedHigh").dataset.boxAndWhiskerPoints = JSON.stringify(params);
    document.getElementById("boxplotImage").setAttribute("src", boxplotRenderUrl(params));
}

function rank(userEarnings, allUsersAscendingSortedEarnings) {

    return ( [...allUsersAscendingSortedEarnings].reverse().indexOf(userEarnings) + 1 );

}

function nearestCompetitorTotalAndGapTuple(userEarnings, allUsersAscendingSortedEarnings) {

    const hasCompetitors = ( allUsersAscendingSortedEarnings.length > 1 );
    if(!hasCompetitors) { return [userEarnings, 0]; }

    const userEarningsIndex = allUsersAscendingSortedEarnings.indexOf(userEarnings);

    const isLeader = ( userEarningsIndex === allUsersAscendingSortedEarnings.length - 1 );

    const tiedEarningsErrorFactor = 0.01;

    let nearestCompetitorEarnings;
    if(isLeader) {
        nearestCompetitorEarnings = [...allUsersAscendingSortedEarnings].reverse().find(earnings => {
            return earnings < ( userEarnings - tiedEarningsErrorFactor );
        });
    }
    else {
        nearestCompetitorEarnings = allUsersAscendingSortedEarnings.find(earnings => {
            return earnings > ( userEarnings + tiedEarningsErrorFactor );
        });
    }

    const nearestCompetitorGap = nearestCompetitorEarnings - userEarnings;

    return [nearestCompetitorEarnings, nearestCompetitorGap];
}

function displayRank(rank, numberOfPositions) {

    const relativeThresholdAtWhichToDisplayTopPercentile = 0.5;

    const topPercentileZeroToOne = ( 1 - ( (numberOfPositions - rank) / numberOfPositions ) );

    const formattedTopPercentile = topPercentileZeroToOne.toLocaleString("en-US", {style: "percent"});

    document.getElementById("rank").innerHTML = `# <strong>${rank}</strong> / ${numberOfPositions} ${topPercentileZeroToOne <= relativeThresholdAtWhichToDisplayTopPercentile ? `( Top <strong>${formattedTopPercentile}</strong> )` : ""}`;
}

function displayNearestCompetitorInfo(nearestCompetitorTotalAndGapTuple) {

    const [nearestCompetitorTotal, nearestCompetitorGap] = nearestCompetitorTotalAndGapTuple;

    const sign = ( nearestCompetitorGap >= 0 ? "+" : "-" );
    const color = ( sign === "+" ? "green" : "red" );
    const absoluteGap = Math.abs(nearestCompetitorGap);

    const [nearestCompetitorTotalFormatted, absoluteGapFormatted] = [nearestCompetitorTotal, absoluteGap].map(val => val.toLocaleString("en-US", {style: "currency", currency: "USD"}));

    document.getElementById("nearestCompetitor").innerHTML = `${nearestCompetitorTotalFormatted} ( <span style="color: ${color};">${sign} ${absoluteGapFormatted}</span> )`;

}

function leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings) {
    const descendingEarnings = [...allUsersAscendingSortedEarnings].reverse();

    return descendingEarnings.map((earnings, index) => {
        return (`
            <option>[#${index+1}]: ${earnings.toLocaleString("en-US", {style: "currency", currency: "USD"})}</option>
        `);
    }).join("");
}

function displayLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function displayLeagueLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leagueLeaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function localAllTimeBest(usdAmountToSetTo) {
    if(exists(usdAmountToSetTo)) {
        localStorage.setItem("sojmLocalAllTimeBest", usdAmountToSetTo);
    }
    return +(localStorage.getItem("sojmLocalAllTimeBest") || "0");
}

function updateLocalAllTimeBestIfAppropriateTo(usdAmountToSetTo) {
    if(usdAmountToSetTo > localAllTimeBest()) {
        return localAllTimeBest(usdAmountToSetTo);
    }
    else {
        return localAllTimeBest();
    }
}

function getLocalDailyHighs() {
    return JSON.parse(localStorage.getItem("sojmLocalDailyHighs") || "{}");
}

function includeInLocalDailyHigh(amount, dateYYYYMMDD) {
    const highs = getLocalDailyHighs();
    highs[dateYYYYMMDD] = amount;
    localStorage.setItem("sojmLocalDailyHighs", JSON.stringify(highs));
}

function getHistoricalLocalDailyHighAverage() {

    const highsExceptToday = getLocalDailyHighs();
    delete highsExceptToday[amazonDateYYYYMMDD()];

    const datesTracked = Object.keys(highsExceptToday);
    const numberOfDatesTracked = datesTracked.length;

    const totalAmountTracked = datesTracked.reduce((acc, dateTracked) => {
        return (acc + highsExceptToday[dateTracked]);
    }, 0);

    return ( totalAmountTracked / numberOfDatesTracked );

}

function displayLocalBest() {
    document.getElementById("localBest").innerHTML = `<span style="color: gray;">${(localAllTimeBest() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function displayLocalAverage() {
    document.getElementById("localAverage").innerHTML = `<span style="color: gray;">${(getHistoricalLocalDailyHighAverage() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function gaps(sortedAscendingEarnings) {
    const ascendingSortedGaps = sortedAscendingEarnings.reduce((acc, num) => {
        return { prevNumber: num, gaps: [ ...acc.gaps, num - acc.prevNumber ] }
    }, { prevNumber: 0, gaps: [] }).gaps.sort((a, b) => (a-b));

    return ascendingSortedGaps;
}

function averageGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    const numberOfGaps = gapsFromSortedValues.length;
    const sumOfGaps = gapsFromSortedValues.reduce((acc, gap) => {
        return ( acc + gap );
    }, 0);
    return ( sumOfGaps / numberOfGaps );
}

function medianGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    return medianOfSortedValues(gapsFromSortedValues);
}

function indicesOfInflectionPoints(sortedAscendingEarnings) {

    const avgGap = averageGap(sortedAscendingEarnings);

    const inflectionPointIndices = [];

    for(let i = 0; i < sortedAscendingEarnings.length - 1; i++) {

        const earningsAtI = sortedAscendingEarnings[i];
        const earningsAboveI = sortedAscendingEarnings[i + 1];
        const gap = earningsAboveI - earningsAtI;

        if(gap >= avgGap) {
            inflectionPointIndices.push(i + 1);
        }

    }

    return inflectionPointIndices;
}

function hasInflectionPoints(ascendingSortedValues) {
    return ( indicesOfInflectionPoints(ascendingSortedValues).length > 0 );
}

function splitAtFirstInflectionPoint(ascendingSortedValues) {
    const firstInflectionPointIndex = indicesOfInflectionPoints(ascendingSortedValues)[0];
    return [
        ascendingSortedValues.slice(0, firstInflectionPointIndex),
        ascendingSortedValues.slice(firstInflectionPointIndex)
    ];
}

function splitIntoLeagues(ascendingSortedValues, maximumLeagueCount) {
    if(!hasInflectionPoints(ascendingSortedValues) || maximumLeagueCount === 1) {
        return [ascendingSortedValues];
    }
    else {
        const [lowerLeague, upperLeague] = splitAtFirstInflectionPoint(ascendingSortedValues);
        return [lowerLeague, ...splitIntoLeagues(upperLeague, (exists(maximumLeagueCount) ? maximumLeagueCount - 1 : null))];
    }
}

function findLeagueAndRankIndex(earnings, leagues) {
    for(let leagueIndex = 0; leagueIndex < leagues.length; leagueIndex++) {
        const league = leagues[leagueIndex];
        for(let rankIndex = 0; rankIndex < league.length; rankIndex++) {
            const earningsAtRank = league[rankIndex];
            if(earnings === earningsAtRank) {
                return {
                    leagueIndex,
                    rankIndex
                };
            }
        }
    }

    return undefined;
}

function leagueIndexToTitle(leagueIndex, numberOfLeagues) {

    const maximumNumberOfLeagues = 5;
    const offset = maximumNumberOfLeagues - numberOfLeagues;
    const adjustedLeagueIndex = leagueIndex + offset;

    return ([
        "Bronze",
        "Silver",
        "Gold",
        "Platinum",
        "Diamond"
    ])[adjustedLeagueIndex];
}

function leagueTitleToCSSColor(leagueTitle) {
    return ({
        "Bronze": "brown",
        "Silver": "gray",
        "Gold": "orange",
        "Platinum": "silver",
        "Diamond": "aqua"
    })[leagueTitle];
}

function displayLeagueRank(leagueTitle, leaguePosition, leagueSize) {
    document.getElementById("leagueRank").innerHTML = `<span style="font-weight: 700; color: ${leagueTitleToCSSColor(leagueTitle)};">${leagueTitle}</span>: ( # <strong>${leaguePosition}</strong> / ${leagueSize} )`;
}

function displayNormalRangeVsYou(firstQuartile, thirdQuartile, total) {

    const generateUserTotalHTML = (lowMedHigh) => `<span style="background: black; color: ${lowMedHigh === "low" ? ("rgb(255, 150, 150)") : ( lowMedHigh === "med" ? "rgb(150, 255, 150)" : "rgb(150, 150, 255)" )}">${total.toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
    const generateNormalBoundHTML = (value) => `<span style="color: white; background: rgb(127,127,127);">${value}</span>`;

    const isBelowNormal = ( total < +firstQuartile.replace("$", "") );
    const isAboveNormal = ( total > +thirdQuartile.replace("$", "") );
    const isWithinNormal = !isBelowNormal && !isAboveNormal;

    let normalRangeHTML = ``;

    if(isBelowNormal) {
        normalRangeHTML += `${generateUserTotalHTML("low")} - `;
    }

    normalRangeHTML += `${generateNormalBoundHTML(firstQuartile)} -`;

    if(isWithinNormal) {
        normalRangeHTML += ` ${generateUserTotalHTML("med")} -`;
    }

    normalRangeHTML += ` ${generateNormalBoundHTML(thirdQuartile)}`;

    if(isAboveNormal) {
        normalRangeHTML += ` - ${generateUserTotalHTML("high")}`;
    }

    document.getElementById("normalRange").innerHTML = normalRangeHTML;
}

async function main() {

    injectAveragePERow();

    document.getElementById("retrieveCommunityAverage").addEventListener("click", async e => {

        const earningsApiResponse = await submitUserEarnings();

        if(exists(earningsApiResponse.averageEarningsForToday)) {

            const sortedIndividualEarnings = [...earningsApiResponse.individualEarningsForToday].sort((a,b) => a-b);

            const lowestIndividualEarnings = sortedIndividualEarnings[0].toLocaleString("en-US", {style: "currency", currency: "USD"});
            const medianIndividualEarnings = medianOfSortedValues(sortedIndividualEarnings).toLocaleString("en-US", {style: "currency", currency: "USD"});
            const highestIndividualEarnings = sortedIndividualEarnings[sortedIndividualEarnings.length-1].toLocaleString("en-US", {style: "currency", currency: "USD"});

            const [firstQuartile, thirdQuartile] = sidesOfMedian(sortedIndividualEarnings).map(side => medianOfSortedValues(side).toLocaleString("en-US", {style: "currency", currency: "USD"}));

            embedBoxAndWhiskerData({low: lowestIndividualEarnings,
                                    high: highestIndividualEarnings,
                                    median: medianIndividualEarnings,
                                    firstQuartile,
                                    thirdQuartile});

            document.getElementById("tcLowMedHigh").innerHTML = `
                <span style='color: red;'>${lowestIndividualEarnings}</span>,
                <span style='color: orange;'>${medianIndividualEarnings}</span>,
                <span style='color: green;'>${highestIndividualEarnings}</span>`;

            e.target.innerText = earningsApiResponse.averageEarningsForToday.toLocaleString("en-US", {style: "currency", currency: "USD"});

            const total = ( todaysTotal() || todaysTotalMTS() );

            displayNormalRangeVsYou( firstQuartile, thirdQuartile, total );

            displayRank( rank(total, sortedIndividualEarnings), sortedIndividualEarnings.length );
            displayNearestCompetitorInfo( nearestCompetitorTotalAndGapTuple(total, sortedIndividualEarnings) );
            displayLeaderboard( sortedIndividualEarnings );

            includeInLocalDailyHigh( total, amazonDateYYYYMMDD() );
            updateLocalAllTimeBestIfAppropriateTo( total );

            displayLocalBest();
            displayLocalAverage();

            const maxNumberOfLeagues = 5;

            const leagues = splitIntoLeagues( sortedIndividualEarnings, maxNumberOfLeagues );
            const numberOfLeagues = leagues.length;
            const { leagueIndex, rankIndex } = findLeagueAndRankIndex( total, leagues );
            const league = leagues[leagueIndex];
            const leagueSize = league.length;
            const leaguePosition = leagueSize - rankIndex;
            const leagueTitle = leagueIndexToTitle(leagueIndex, numberOfLeagues );

            displayLeagueRank(leagueTitle, leaguePosition, leagueSize);
            displayLeagueLeaderboard( league );

        }
        else if(["Your request is missing fields: total", "Your report is outdated"].includes(earningsApiResponse.errorMessage)) {
            e.target.innerText = "Work before comparing!";
        }
        else {
            e.target.innerText = earningsApiResponse.errorMessage;
        }

    });
}

main();
 
  • Like
Reactions: cb456 and alk69

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Fun psychology / vision / language experiment! (bug fixed) | Accept
Requester: Shane Steinert-Threlkeld [A15O9ZYX0UM05V] Contact
TV: No Reviews
TO: [Pay=3.88] [Fast=5.00] [Comm=0.00] [Fair=5.00] [Reviews=8] [ToS=0]
TO2: No Reviews
Reward: 4.00
Duration: 2700
Available: 1
Description: You will be asked to judge whether certain sentences are true or false in the context of an image.
Qualifications: HIT approval rate (%) GreaterThanOrEqualTo 95; Location EqualTo US
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

alk69

Well-Known Member
Joined
Mar 22, 2016
Messages
4,289
Reaction score
9,874
Points
763
Age
77
Location
over the edge
Gender
Female
it's a earnings script to compare how big your PE is to others
mTurk Slow or Just Me? ("SOJM")

Code:
// ==UserScript==
// @name         mTurk Slow or Just Me? ("SOJM")
// @namespace    salembeats
// @version      1.67
// @description  UPDATE: Quick HUD added to compare yourself to the "normal" range (the middle 50% of responses, represented by the box in the box/whisker plot). NOTE: Requires Kadauchi's "MTurk Dashboard Enhancer" script to function properly.
// @author       Cuyler Stuwe (salembeats)
// @include      https://worker.mturk.com/dashboard*
// ==/UserScript==

const globals = {
    CLIENT_VERSION: "synchronicity",
    API_BASE: "https://ne26dv9hq6.execute-api.us-west-2.amazonaws.com/dev"
};

// Minified, synchronous SHA-256 transform function copied from: http://geraintluff.github.io/sha256/
var sha256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;64>n;p++)if(!o[p]){for(d=0;313>d;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;64>d;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=16>d?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;8>d;d++)l[d]=l[d]+r[d]|0}for(d=0;8>d;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(16>y?0:"")+y.toString(16)}return i};

function exists(thing) {
    return thing !== undefined && thing !== null;
}

function amazonDate() {
    return new Date(Date.now() + (new Date().getTimezoneOffset()*60*1000) - (420*60*1000));
}

function medianOfSortedValues(sortedValuesArray) {

    const middlePosition = Math.floor(sortedValuesArray.length/2);

    if(sortedValuesArray.length % 2) {
        return sortedValuesArray[middlePosition];
    }
    else {
        return (sortedValuesArray[middlePosition-1] + sortedValuesArray[middlePosition]) / 2.0;
    }

}

function sidesOfMedian(sortedValuesArray) {

    const hasEvenNumberOfItems = ( sortedValuesArray.length % 2 === 0 );

    if(hasEvenNumberOfItems) {
        return [
            sortedValuesArray.slice(0, (sortedValuesArray.length / 2)),
            sortedValuesArray.slice((sortedValuesArray.length / 2), sortedValuesArray.length)
        ];
    }
    else {
        const indexToSplitOn = ((sortedValuesArray.length + 1) / 2) - 1;

        return [
            sortedValuesArray.slice(0, indexToSplitOn),
            sortedValuesArray.slice(indexToSplitOn + 1, sortedValuesArray.length)
        ];
    }
}


function hitLogTotalUsd() {

    const hitLog = JSON.parse(localStorage.getItem("WMTD_hitLog"));

    return Object.keys(hitLog).reduce((acc, currentHitLogKey) => {

        return (acc + hitLog[currentHitLogKey].reward.amount_in_dollars);

    }, 0);

}

function dateYYYYMMDD(date) {

    const now = date;
    const [year, month, day] = [now.getFullYear(), now.getMonth() + 1, now.getDate()].map(num => num.toLocaleString("en-US", {minimumIntegerDigits: 2, useGrouping: false}));
    const todaysDateStr = `${year}-${month}-${day}`;
    return todaysDateStr;

}

function todaysDateYYYYMMDD() {
    return dateYYYYMMDD(new Date());
}

function amazonDateYYYYMMDD() {
    return dateYYYYMMDD(amazonDate());
}

function lastWorkLoggedDateYYYYMMDD() {
    return localStorage.getItem("WMTD_date");
}

function todaysTotal() {

    const lastRecordedDate = lastWorkLoggedDateYYYYMMDD();

    if(lastRecordedDate === amazonDateYYYYMMDD()) {

        return hitLogTotalUsd();

    }
    else {

        return null;

    }

}

function todaysTotalMTS() {
  const mtsProjectedEarnings = document.getElementById('mts-ht-earnings').textContent;
  return Number(mtsProjectedEarnings.replace(/[^0-9.]/g, ''));
}

function workerId() {

    const workerIdCopyElement = document.querySelector(`[data-react-class="require('reactComponents/common/CopyText')['default']"]`);
    return JSON.parse(workerIdCopyElement.dataset.reactProps).textToCopy;

}

function workerIdHash() {

    return sha256(workerId());

}

function userEarningsPayload() {

    const payload = JSON.stringify({
        idHash: workerIdHash(),
        date: lastWorkLoggedDateYYYYMMDD(),
        total: todaysTotal() || todaysTotalMTS(),
        clientVersion: globals.CLIENT_VERSION
    });

    return payload;

}

async function submitUserEarnings() {

    const apiEndpoint = `${globals.API_BASE}/store`;

    const responseStream = await fetch(apiEndpoint, {
        method: "POST",
        body: userEarningsPayload(),
        headers: {
            "Content-Type": "application/json"
        }
    });

    const response = await responseStream.json();
    return response;

}

function injectAveragePERow() {
    const el = document.getElementById("TodaysActivityAdditionalInfo") || document.getElementById('dashboard-available-earnings').querySelector('.border-gray-lightest').children[0];

    el.insertAdjacentHTML("beforebegin", `
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Today's Community Average</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <a id="retrieveCommunityAverage" href="javascript:void(0);">Retrieve Community Average</a>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Low, Med, High</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="tcLowMedHigh">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong><span style="color: white; background: rgb(127,127,127);">Normal Range</span> vs. <span style="background: black; color: white;">You</span></strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="normalRange">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Box+Whisker Plot</strong>
            </div>
            <div style="text-align: center;">
                <img id="boxplotImage" style="max-width: 270px;" src="">
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="rank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Nearest Competitor</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="nearestCompetitor"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="leagueRank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leagueLeaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Best</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localBest"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Past Avg</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localAverage"></div>
            </div>
        </div>
    `);
}

function boxplotRenderUrl(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined
}) {
    return (`http://www.imathas.com/stattools/boxplot.php?n=1&showlabels=0&title0=&ds0q0=${params.low.replace("$", "")}&ds0q1=${params.firstQuartile.replace("$", "")}&ds0q2=${params.median.replace("$", "")}&ds0q3=${params.thirdQuartile.replace("$", "")}&ds0q4=${params.high.replace("$", "")}&title1=&ds1q0=&ds1q1=&ds1q2=&ds1q3=&ds1q4=&title2=&ds2q0=&ds2q1=&ds2q2=&ds2q3=&ds2q4=&xmin=0&xmax=${Math.floor((+params.high.replace("$", "")) + 5)}&ticks=5&axistitle=&imgwidth=300&imgheight=120`);
}

function embedBoxAndWhiskerData(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined}) {
    document.getElementById("tcLowMedHigh").dataset.boxAndWhiskerPoints = JSON.stringify(params);
    document.getElementById("boxplotImage").setAttribute("src", boxplotRenderUrl(params));
}

function rank(userEarnings, allUsersAscendingSortedEarnings) {

    return ( [...allUsersAscendingSortedEarnings].reverse().indexOf(userEarnings) + 1 );

}

function nearestCompetitorTotalAndGapTuple(userEarnings, allUsersAscendingSortedEarnings) {

    const hasCompetitors = ( allUsersAscendingSortedEarnings.length > 1 );
    if(!hasCompetitors) { return [userEarnings, 0]; }

    const userEarningsIndex = allUsersAscendingSortedEarnings.indexOf(userEarnings);

    const isLeader = ( userEarningsIndex === allUsersAscendingSortedEarnings.length - 1 );

    const tiedEarningsErrorFactor = 0.01;

    let nearestCompetitorEarnings;
    if(isLeader) {
        nearestCompetitorEarnings = [...allUsersAscendingSortedEarnings].reverse().find(earnings => {
            return earnings < ( userEarnings - tiedEarningsErrorFactor );
        });
    }
    else {
        nearestCompetitorEarnings = allUsersAscendingSortedEarnings.find(earnings => {
            return earnings > ( userEarnings + tiedEarningsErrorFactor );
        });
    }

    const nearestCompetitorGap = nearestCompetitorEarnings - userEarnings;

    return [nearestCompetitorEarnings, nearestCompetitorGap];
}

function displayRank(rank, numberOfPositions) {

    const relativeThresholdAtWhichToDisplayTopPercentile = 0.5;

    const topPercentileZeroToOne = ( 1 - ( (numberOfPositions - rank) / numberOfPositions ) );

    const formattedTopPercentile = topPercentileZeroToOne.toLocaleString("en-US", {style: "percent"});

    document.getElementById("rank").innerHTML = `# <strong>${rank}</strong> / ${numberOfPositions} ${topPercentileZeroToOne <= relativeThresholdAtWhichToDisplayTopPercentile ? `( Top <strong>${formattedTopPercentile}</strong> )` : ""}`;
}

function displayNearestCompetitorInfo(nearestCompetitorTotalAndGapTuple) {

    const [nearestCompetitorTotal, nearestCompetitorGap] = nearestCompetitorTotalAndGapTuple;

    const sign = ( nearestCompetitorGap >= 0 ? "+" : "-" );
    const color = ( sign === "+" ? "green" : "red" );
    const absoluteGap = Math.abs(nearestCompetitorGap);

    const [nearestCompetitorTotalFormatted, absoluteGapFormatted] = [nearestCompetitorTotal, absoluteGap].map(val => val.toLocaleString("en-US", {style: "currency", currency: "USD"}));

    document.getElementById("nearestCompetitor").innerHTML = `${nearestCompetitorTotalFormatted} ( <span style="color: ${color};">${sign} ${absoluteGapFormatted}</span> )`;

}

function leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings) {
    const descendingEarnings = [...allUsersAscendingSortedEarnings].reverse();

    return descendingEarnings.map((earnings, index) => {
        return (`
            <option>[#${index+1}]: ${earnings.toLocaleString("en-US", {style: "currency", currency: "USD"})}</option>
        `);
    }).join("");
}

function displayLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function displayLeagueLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leagueLeaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function localAllTimeBest(usdAmountToSetTo) {
    if(exists(usdAmountToSetTo)) {
        localStorage.setItem("sojmLocalAllTimeBest", usdAmountToSetTo);
    }
    return +(localStorage.getItem("sojmLocalAllTimeBest") || "0");
}

function updateLocalAllTimeBestIfAppropriateTo(usdAmountToSetTo) {
    if(usdAmountToSetTo > localAllTimeBest()) {
        return localAllTimeBest(usdAmountToSetTo);
    }
    else {
        return localAllTimeBest();
    }
}

function getLocalDailyHighs() {
    return JSON.parse(localStorage.getItem("sojmLocalDailyHighs") || "{}");
}

function includeInLocalDailyHigh(amount, dateYYYYMMDD) {
    const highs = getLocalDailyHighs();
    highs[dateYYYYMMDD] = amount;
    localStorage.setItem("sojmLocalDailyHighs", JSON.stringify(highs));
}

function getHistoricalLocalDailyHighAverage() {

    const highsExceptToday = getLocalDailyHighs();
    delete highsExceptToday[amazonDateYYYYMMDD()];

    const datesTracked = Object.keys(highsExceptToday);
    const numberOfDatesTracked = datesTracked.length;

    const totalAmountTracked = datesTracked.reduce((acc, dateTracked) => {
        return (acc + highsExceptToday[dateTracked]);
    }, 0);

    return ( totalAmountTracked / numberOfDatesTracked );

}

function displayLocalBest() {
    document.getElementById("localBest").innerHTML = `<span style="color: gray;">${(localAllTimeBest() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function displayLocalAverage() {
    document.getElementById("localAverage").innerHTML = `<span style="color: gray;">${(getHistoricalLocalDailyHighAverage() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function gaps(sortedAscendingEarnings) {
    const ascendingSortedGaps = sortedAscendingEarnings.reduce((acc, num) => {
        return { prevNumber: num, gaps: [ ...acc.gaps, num - acc.prevNumber ] }
    }, { prevNumber: 0, gaps: [] }).gaps.sort((a, b) => (a-b));

    return ascendingSortedGaps;
}

function averageGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    const numberOfGaps = gapsFromSortedValues.length;
    const sumOfGaps = gapsFromSortedValues.reduce((acc, gap) => {
        return ( acc + gap );
    }, 0);
    return ( sumOfGaps / numberOfGaps );
}

function medianGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    return medianOfSortedValues(gapsFromSortedValues);
}

function indicesOfInflectionPoints(sortedAscendingEarnings) {

    const avgGap = averageGap(sortedAscendingEarnings);

    const inflectionPointIndices = [];

    for(let i = 0; i < sortedAscendingEarnings.length - 1; i++) {

        const earningsAtI = sortedAscendingEarnings[i];
        const earningsAboveI = sortedAscendingEarnings[i + 1];
        const gap = earningsAboveI - earningsAtI;

        if(gap >= avgGap) {
            inflectionPointIndices.push(i + 1);
        }

    }

    return inflectionPointIndices;
}

function hasInflectionPoints(ascendingSortedValues) {
    return ( indicesOfInflectionPoints(ascendingSortedValues).length > 0 );
}

function splitAtFirstInflectionPoint(ascendingSortedValues) {
    const firstInflectionPointIndex = indicesOfInflectionPoints(ascendingSortedValues)[0];
    return [
        ascendingSortedValues.slice(0, firstInflectionPointIndex),
        ascendingSortedValues.slice(firstInflectionPointIndex)
    ];
}

function splitIntoLeagues(ascendingSortedValues, maximumLeagueCount) {
    if(!hasInflectionPoints(ascendingSortedValues) || maximumLeagueCount === 1) {
        return [ascendingSortedValues];
    }
    else {
        const [lowerLeague, upperLeague] = splitAtFirstInflectionPoint(ascendingSortedValues);
        return [lowerLeague, ...splitIntoLeagues(upperLeague, (exists(maximumLeagueCount) ? maximumLeagueCount - 1 : null))];
    }
}

function findLeagueAndRankIndex(earnings, leagues) {
    for(let leagueIndex = 0; leagueIndex < leagues.length; leagueIndex++) {
        const league = leagues[leagueIndex];
        for(let rankIndex = 0; rankIndex < league.length; rankIndex++) {
            const earningsAtRank = league[rankIndex];
            if(earnings === earningsAtRank) {
                return {
                    leagueIndex,
                    rankIndex
                };
            }
        }
    }

    return undefined;
}

function leagueIndexToTitle(leagueIndex, numberOfLeagues) {

    const maximumNumberOfLeagues = 5;
    const offset = maximumNumberOfLeagues - numberOfLeagues;
    const adjustedLeagueIndex = leagueIndex + offset;

    return ([
        "Bronze",
        "Silver",
        "Gold",
        "Platinum",
        "Diamond"
    ])[adjustedLeagueIndex];
}

function leagueTitleToCSSColor(leagueTitle) {
    return ({
        "Bronze": "brown",
        "Silver": "gray",
        "Gold": "orange",
        "Platinum": "silver",
        "Diamond": "aqua"
    })[leagueTitle];
}

function displayLeagueRank(leagueTitle, leaguePosition, leagueSize) {
    document.getElementById("leagueRank").innerHTML = `<span style="font-weight: 700; color: ${leagueTitleToCSSColor(leagueTitle)};">${leagueTitle}</span>: ( # <strong>${leaguePosition}</strong> / ${leagueSize} )`;
}

function displayNormalRangeVsYou(firstQuartile, thirdQuartile, total) {

    const generateUserTotalHTML = (lowMedHigh) => `<span style="background: black; color: ${lowMedHigh === "low" ? ("rgb(255, 150, 150)") : ( lowMedHigh === "med" ? "rgb(150, 255, 150)" : "rgb(150, 150, 255)" )}">${total.toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
    const generateNormalBoundHTML = (value) => `<span style="color: white; background: rgb(127,127,127);">${value}</span>`;

    const isBelowNormal = ( total < +firstQuartile.replace("$", "") );
    const isAboveNormal = ( total > +thirdQuartile.replace("$", "") );
    const isWithinNormal = !isBelowNormal && !isAboveNormal;

    let normalRangeHTML = ``;

    if(isBelowNormal) {
        normalRangeHTML += `${generateUserTotalHTML("low")} - `;
    }

    normalRangeHTML += `${generateNormalBoundHTML(firstQuartile)} -`;

    if(isWithinNormal) {
        normalRangeHTML += ` ${generateUserTotalHTML("med")} -`;
    }

    normalRangeHTML += ` ${generateNormalBoundHTML(thirdQuartile)}`;

    if(isAboveNormal) {
        normalRangeHTML += ` - ${generateUserTotalHTML("high")}`;
    }

    document.getElementById("normalRange").innerHTML = normalRangeHTML;
}

async function main() {

    injectAveragePERow();

    document.getElementById("retrieveCommunityAverage").addEventListener("click", async e => {

        const earningsApiResponse = await submitUserEarnings();

        if(exists(earningsApiResponse.averageEarningsForToday)) {

            const sortedIndividualEarnings = [...earningsApiResponse.individualEarningsForToday].sort((a,b) => a-b);

            const lowestIndividualEarnings = sortedIndividualEarnings[0].toLocaleString("en-US", {style: "currency", currency: "USD"});
            const medianIndividualEarnings = medianOfSortedValues(sortedIndividualEarnings).toLocaleString("en-US", {style: "currency", currency: "USD"});
            const highestIndividualEarnings = sortedIndividualEarnings[sortedIndividualEarnings.length-1].toLocaleString("en-US", {style: "currency", currency: "USD"});

            const [firstQuartile, thirdQuartile] = sidesOfMedian(sortedIndividualEarnings).map(side => medianOfSortedValues(side).toLocaleString("en-US", {style: "currency", currency: "USD"}));

            embedBoxAndWhiskerData({low: lowestIndividualEarnings,
                                    high: highestIndividualEarnings,
                                    median: medianIndividualEarnings,
                                    firstQuartile,
                                    thirdQuartile});

            document.getElementById("tcLowMedHigh").innerHTML = `
                <span style='color: red;'>${lowestIndividualEarnings}</span>,
                <span style='color: orange;'>${medianIndividualEarnings}</span>,
                <span style='color: green;'>${highestIndividualEarnings}</span>`;

            e.target.innerText = earningsApiResponse.averageEarningsForToday.toLocaleString("en-US", {style: "currency", currency: "USD"});

            const total = ( todaysTotal() || todaysTotalMTS() );

            displayNormalRangeVsYou( firstQuartile, thirdQuartile, total );

            displayRank( rank(total, sortedIndividualEarnings), sortedIndividualEarnings.length );
            displayNearestCompetitorInfo( nearestCompetitorTotalAndGapTuple(total, sortedIndividualEarnings) );
            displayLeaderboard( sortedIndividualEarnings );

            includeInLocalDailyHigh( total, amazonDateYYYYMMDD() );
            updateLocalAllTimeBestIfAppropriateTo( total );

            displayLocalBest();
            displayLocalAverage();

            const maxNumberOfLeagues = 5;

            const leagues = splitIntoLeagues( sortedIndividualEarnings, maxNumberOfLeagues );
            const numberOfLeagues = leagues.length;
            const { leagueIndex, rankIndex } = findLeagueAndRankIndex( total, leagues );
            const league = leagues[leagueIndex];
            const leagueSize = league.length;
            const leaguePosition = leagueSize - rankIndex;
            const leagueTitle = leagueIndexToTitle(leagueIndex, numberOfLeagues );

            displayLeagueRank(leagueTitle, leaguePosition, leagueSize);
            displayLeagueLeaderboard( league );

        }
        else if(["Your request is missing fields: total", "Your report is outdated"].includes(earningsApiResponse.errorMessage)) {
            e.target.innerText = "Work before comparing!";
        }
        else {
            e.target.innerText = earningsApiResponse.errorMessage;
        }

    });
}

main();
So, what you're saying is, it's a pissing contest. Well, remember what they say about ''upwind''.......the more I think about this, the more hilarious it is. You really need a script for that?...people are becoming too dependent on scripts.
 
Last edited:

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
it's a earnings script to compare how big your PE is to others
mTurk Slow or Just Me? ("SOJM")

Code:
// ==UserScript==
// @name         mTurk Slow or Just Me? ("SOJM")
// @namespace    salembeats
// @version      1.67
// @description  UPDATE: Quick HUD added to compare yourself to the "normal" range (the middle 50% of responses, represented by the box in the box/whisker plot). NOTE: Requires Kadauchi's "MTurk Dashboard Enhancer" script to function properly.
// @author       Cuyler Stuwe (salembeats)
// @include      https://worker.mturk.com/dashboard*
// ==/UserScript==

const globals = {
    CLIENT_VERSION: "synchronicity",
    API_BASE: "https://ne26dv9hq6.execute-api.us-west-2.amazonaws.com/dev"
};

// Minified, synchronous SHA-256 transform function copied from: http://geraintluff.github.io/sha256/
var sha256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;64>n;p++)if(!o[p]){for(d=0;313>d;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;64>d;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=16>d?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;8>d;d++)l[d]=l[d]+r[d]|0}for(d=0;8>d;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(16>y?0:"")+y.toString(16)}return i};

function exists(thing) {
    return thing !== undefined && thing !== null;
}

function amazonDate() {
    return new Date(Date.now() + (new Date().getTimezoneOffset()*60*1000) - (420*60*1000));
}

function medianOfSortedValues(sortedValuesArray) {

    const middlePosition = Math.floor(sortedValuesArray.length/2);

    if(sortedValuesArray.length % 2) {
        return sortedValuesArray[middlePosition];
    }
    else {
        return (sortedValuesArray[middlePosition-1] + sortedValuesArray[middlePosition]) / 2.0;
    }

}

function sidesOfMedian(sortedValuesArray) {

    const hasEvenNumberOfItems = ( sortedValuesArray.length % 2 === 0 );

    if(hasEvenNumberOfItems) {
        return [
            sortedValuesArray.slice(0, (sortedValuesArray.length / 2)),
            sortedValuesArray.slice((sortedValuesArray.length / 2), sortedValuesArray.length)
        ];
    }
    else {
        const indexToSplitOn = ((sortedValuesArray.length + 1) / 2) - 1;

        return [
            sortedValuesArray.slice(0, indexToSplitOn),
            sortedValuesArray.slice(indexToSplitOn + 1, sortedValuesArray.length)
        ];
    }
}


function hitLogTotalUsd() {

    const hitLog = JSON.parse(localStorage.getItem("WMTD_hitLog"));

    return Object.keys(hitLog).reduce((acc, currentHitLogKey) => {

        return (acc + hitLog[currentHitLogKey].reward.amount_in_dollars);

    }, 0);

}

function dateYYYYMMDD(date) {

    const now = date;
    const [year, month, day] = [now.getFullYear(), now.getMonth() + 1, now.getDate()].map(num => num.toLocaleString("en-US", {minimumIntegerDigits: 2, useGrouping: false}));
    const todaysDateStr = `${year}-${month}-${day}`;
    return todaysDateStr;

}

function todaysDateYYYYMMDD() {
    return dateYYYYMMDD(new Date());
}

function amazonDateYYYYMMDD() {
    return dateYYYYMMDD(amazonDate());
}

function lastWorkLoggedDateYYYYMMDD() {
    return localStorage.getItem("WMTD_date");
}

function todaysTotal() {

    const lastRecordedDate = lastWorkLoggedDateYYYYMMDD();

    if(lastRecordedDate === amazonDateYYYYMMDD()) {

        return hitLogTotalUsd();

    }
    else {

        return null;

    }

}

function todaysTotalMTS() {
  const mtsProjectedEarnings = document.getElementById('mts-ht-earnings').textContent;
  return Number(mtsProjectedEarnings.replace(/[^0-9.]/g, ''));
}

function workerId() {

    const workerIdCopyElement = document.querySelector(`[data-react-class="require('reactComponents/common/CopyText')['default']"]`);
    return JSON.parse(workerIdCopyElement.dataset.reactProps).textToCopy;

}

function workerIdHash() {

    return sha256(workerId());

}

function userEarningsPayload() {

    const payload = JSON.stringify({
        idHash: workerIdHash(),
        date: lastWorkLoggedDateYYYYMMDD(),
        total: todaysTotal() || todaysTotalMTS(),
        clientVersion: globals.CLIENT_VERSION
    });

    return payload;

}

async function submitUserEarnings() {

    const apiEndpoint = `${globals.API_BASE}/store`;

    const responseStream = await fetch(apiEndpoint, {
        method: "POST",
        body: userEarningsPayload(),
        headers: {
            "Content-Type": "application/json"
        }
    });

    const response = await responseStream.json();
    return response;

}

function injectAveragePERow() {
    const el = document.getElementById("TodaysActivityAdditionalInfo") || document.getElementById('dashboard-available-earnings').querySelector('.border-gray-lightest').children[0];

    el.insertAdjacentHTML("beforebegin", `
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Today's Community Average</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <a id="retrieveCommunityAverage" href="javascript:void(0);">Retrieve Community Average</a>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Low, Med, High</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="tcLowMedHigh">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong><span style="color: white; background: rgb(127,127,127);">Normal Range</span> vs. <span style="background: black; color: white;">You</span></strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="normalRange">&nbsp;</div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Box+Whisker Plot</strong>
            </div>
            <div style="text-align: center;">
                <img id="boxplotImage" style="max-width: 270px;" src="">
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="rank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>Nearest Competitor</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="nearestCompetitor"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>TC Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Rank</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="leagueRank"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>League Leaderboard</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <select id="leagueLeaderboard"></select>
            </div>
        </div>
        <hr/>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Best</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localBest"></div>
            </div>
        </div>
        <div class="row m-b-sm">
            <div class="col-xs-7 col-sm-6 col-lg-7">
                <strong>This Computer's Past Avg</strong>
            </div>
            <div class="col-xs-5 col-sm-6 col-lg-5 text-xs-right">
                <div id="localAverage"></div>
            </div>
        </div>
    `);
}

function boxplotRenderUrl(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined
}) {
    return (`http://www.imathas.com/stattools/boxplot.php?n=1&showlabels=0&title0=&ds0q0=${params.low.replace("$", "")}&ds0q1=${params.firstQuartile.replace("$", "")}&ds0q2=${params.median.replace("$", "")}&ds0q3=${params.thirdQuartile.replace("$", "")}&ds0q4=${params.high.replace("$", "")}&title1=&ds1q0=&ds1q1=&ds1q2=&ds1q3=&ds1q4=&title2=&ds2q0=&ds2q1=&ds2q2=&ds2q3=&ds2q4=&xmin=0&xmax=${Math.floor((+params.high.replace("$", "")) + 5)}&ticks=5&axistitle=&imgwidth=300&imgheight=120`);
}

function embedBoxAndWhiskerData(params = {
    low: undefined,
    high: undefined,
    median: undefined,
    firstQuartile: undefined,
    thirdQuartile: undefined}) {
    document.getElementById("tcLowMedHigh").dataset.boxAndWhiskerPoints = JSON.stringify(params);
    document.getElementById("boxplotImage").setAttribute("src", boxplotRenderUrl(params));
}

function rank(userEarnings, allUsersAscendingSortedEarnings) {

    return ( [...allUsersAscendingSortedEarnings].reverse().indexOf(userEarnings) + 1 );

}

function nearestCompetitorTotalAndGapTuple(userEarnings, allUsersAscendingSortedEarnings) {

    const hasCompetitors = ( allUsersAscendingSortedEarnings.length > 1 );
    if(!hasCompetitors) { return [userEarnings, 0]; }

    const userEarningsIndex = allUsersAscendingSortedEarnings.indexOf(userEarnings);

    const isLeader = ( userEarningsIndex === allUsersAscendingSortedEarnings.length - 1 );

    const tiedEarningsErrorFactor = 0.01;

    let nearestCompetitorEarnings;
    if(isLeader) {
        nearestCompetitorEarnings = [...allUsersAscendingSortedEarnings].reverse().find(earnings => {
            return earnings < ( userEarnings - tiedEarningsErrorFactor );
        });
    }
    else {
        nearestCompetitorEarnings = allUsersAscendingSortedEarnings.find(earnings => {
            return earnings > ( userEarnings + tiedEarningsErrorFactor );
        });
    }

    const nearestCompetitorGap = nearestCompetitorEarnings - userEarnings;

    return [nearestCompetitorEarnings, nearestCompetitorGap];
}

function displayRank(rank, numberOfPositions) {

    const relativeThresholdAtWhichToDisplayTopPercentile = 0.5;

    const topPercentileZeroToOne = ( 1 - ( (numberOfPositions - rank) / numberOfPositions ) );

    const formattedTopPercentile = topPercentileZeroToOne.toLocaleString("en-US", {style: "percent"});

    document.getElementById("rank").innerHTML = `# <strong>${rank}</strong> / ${numberOfPositions} ${topPercentileZeroToOne <= relativeThresholdAtWhichToDisplayTopPercentile ? `( Top <strong>${formattedTopPercentile}</strong> )` : ""}`;
}

function displayNearestCompetitorInfo(nearestCompetitorTotalAndGapTuple) {

    const [nearestCompetitorTotal, nearestCompetitorGap] = nearestCompetitorTotalAndGapTuple;

    const sign = ( nearestCompetitorGap >= 0 ? "+" : "-" );
    const color = ( sign === "+" ? "green" : "red" );
    const absoluteGap = Math.abs(nearestCompetitorGap);

    const [nearestCompetitorTotalFormatted, absoluteGapFormatted] = [nearestCompetitorTotal, absoluteGap].map(val => val.toLocaleString("en-US", {style: "currency", currency: "USD"}));

    document.getElementById("nearestCompetitor").innerHTML = `${nearestCompetitorTotalFormatted} ( <span style="color: ${color};">${sign} ${absoluteGapFormatted}</span> )`;

}

function leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings) {
    const descendingEarnings = [...allUsersAscendingSortedEarnings].reverse();

    return descendingEarnings.map((earnings, index) => {
        return (`
            <option>[#${index+1}]: ${earnings.toLocaleString("en-US", {style: "currency", currency: "USD"})}</option>
        `);
    }).join("");
}

function displayLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function displayLeagueLeaderboard(allUsersAscendingSortedEarnings) {
    document.getElementById("leagueLeaderboard").innerHTML = leaderboardOptionElementsFrom(allUsersAscendingSortedEarnings);
}

function localAllTimeBest(usdAmountToSetTo) {
    if(exists(usdAmountToSetTo)) {
        localStorage.setItem("sojmLocalAllTimeBest", usdAmountToSetTo);
    }
    return +(localStorage.getItem("sojmLocalAllTimeBest") || "0");
}

function updateLocalAllTimeBestIfAppropriateTo(usdAmountToSetTo) {
    if(usdAmountToSetTo > localAllTimeBest()) {
        return localAllTimeBest(usdAmountToSetTo);
    }
    else {
        return localAllTimeBest();
    }
}

function getLocalDailyHighs() {
    return JSON.parse(localStorage.getItem("sojmLocalDailyHighs") || "{}");
}

function includeInLocalDailyHigh(amount, dateYYYYMMDD) {
    const highs = getLocalDailyHighs();
    highs[dateYYYYMMDD] = amount;
    localStorage.setItem("sojmLocalDailyHighs", JSON.stringify(highs));
}

function getHistoricalLocalDailyHighAverage() {

    const highsExceptToday = getLocalDailyHighs();
    delete highsExceptToday[amazonDateYYYYMMDD()];

    const datesTracked = Object.keys(highsExceptToday);
    const numberOfDatesTracked = datesTracked.length;

    const totalAmountTracked = datesTracked.reduce((acc, dateTracked) => {
        return (acc + highsExceptToday[dateTracked]);
    }, 0);

    return ( totalAmountTracked / numberOfDatesTracked );

}

function displayLocalBest() {
    document.getElementById("localBest").innerHTML = `<span style="color: gray;">${(localAllTimeBest() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function displayLocalAverage() {
    document.getElementById("localAverage").innerHTML = `<span style="color: gray;">${(getHistoricalLocalDailyHighAverage() || 0).toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
}

function gaps(sortedAscendingEarnings) {
    const ascendingSortedGaps = sortedAscendingEarnings.reduce((acc, num) => {
        return { prevNumber: num, gaps: [ ...acc.gaps, num - acc.prevNumber ] }
    }, { prevNumber: 0, gaps: [] }).gaps.sort((a, b) => (a-b));

    return ascendingSortedGaps;
}

function averageGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    const numberOfGaps = gapsFromSortedValues.length;
    const sumOfGaps = gapsFromSortedValues.reduce((acc, gap) => {
        return ( acc + gap );
    }, 0);
    return ( sumOfGaps / numberOfGaps );
}

function medianGap(ascendingSortedValues) {
    const gapsFromSortedValues = gaps(ascendingSortedValues);
    return medianOfSortedValues(gapsFromSortedValues);
}

function indicesOfInflectionPoints(sortedAscendingEarnings) {

    const avgGap = averageGap(sortedAscendingEarnings);

    const inflectionPointIndices = [];

    for(let i = 0; i < sortedAscendingEarnings.length - 1; i++) {

        const earningsAtI = sortedAscendingEarnings[i];
        const earningsAboveI = sortedAscendingEarnings[i + 1];
        const gap = earningsAboveI - earningsAtI;

        if(gap >= avgGap) {
            inflectionPointIndices.push(i + 1);
        }

    }

    return inflectionPointIndices;
}

function hasInflectionPoints(ascendingSortedValues) {
    return ( indicesOfInflectionPoints(ascendingSortedValues).length > 0 );
}

function splitAtFirstInflectionPoint(ascendingSortedValues) {
    const firstInflectionPointIndex = indicesOfInflectionPoints(ascendingSortedValues)[0];
    return [
        ascendingSortedValues.slice(0, firstInflectionPointIndex),
        ascendingSortedValues.slice(firstInflectionPointIndex)
    ];
}

function splitIntoLeagues(ascendingSortedValues, maximumLeagueCount) {
    if(!hasInflectionPoints(ascendingSortedValues) || maximumLeagueCount === 1) {
        return [ascendingSortedValues];
    }
    else {
        const [lowerLeague, upperLeague] = splitAtFirstInflectionPoint(ascendingSortedValues);
        return [lowerLeague, ...splitIntoLeagues(upperLeague, (exists(maximumLeagueCount) ? maximumLeagueCount - 1 : null))];
    }
}

function findLeagueAndRankIndex(earnings, leagues) {
    for(let leagueIndex = 0; leagueIndex < leagues.length; leagueIndex++) {
        const league = leagues[leagueIndex];
        for(let rankIndex = 0; rankIndex < league.length; rankIndex++) {
            const earningsAtRank = league[rankIndex];
            if(earnings === earningsAtRank) {
                return {
                    leagueIndex,
                    rankIndex
                };
            }
        }
    }

    return undefined;
}

function leagueIndexToTitle(leagueIndex, numberOfLeagues) {

    const maximumNumberOfLeagues = 5;
    const offset = maximumNumberOfLeagues - numberOfLeagues;
    const adjustedLeagueIndex = leagueIndex + offset;

    return ([
        "Bronze",
        "Silver",
        "Gold",
        "Platinum",
        "Diamond"
    ])[adjustedLeagueIndex];
}

function leagueTitleToCSSColor(leagueTitle) {
    return ({
        "Bronze": "brown",
        "Silver": "gray",
        "Gold": "orange",
        "Platinum": "silver",
        "Diamond": "aqua"
    })[leagueTitle];
}

function displayLeagueRank(leagueTitle, leaguePosition, leagueSize) {
    document.getElementById("leagueRank").innerHTML = `<span style="font-weight: 700; color: ${leagueTitleToCSSColor(leagueTitle)};">${leagueTitle}</span>: ( # <strong>${leaguePosition}</strong> / ${leagueSize} )`;
}

function displayNormalRangeVsYou(firstQuartile, thirdQuartile, total) {

    const generateUserTotalHTML = (lowMedHigh) => `<span style="background: black; color: ${lowMedHigh === "low" ? ("rgb(255, 150, 150)") : ( lowMedHigh === "med" ? "rgb(150, 255, 150)" : "rgb(150, 150, 255)" )}">${total.toLocaleString("en-US", {style: "currency", currency: "USD"})}</span>`;
    const generateNormalBoundHTML = (value) => `<span style="color: white; background: rgb(127,127,127);">${value}</span>`;

    const isBelowNormal = ( total < +firstQuartile.replace("$", "") );
    const isAboveNormal = ( total > +thirdQuartile.replace("$", "") );
    const isWithinNormal = !isBelowNormal && !isAboveNormal;

    let normalRangeHTML = ``;

    if(isBelowNormal) {
        normalRangeHTML += `${generateUserTotalHTML("low")} - `;
    }

    normalRangeHTML += `${generateNormalBoundHTML(firstQuartile)} -`;

    if(isWithinNormal) {
        normalRangeHTML += ` ${generateUserTotalHTML("med")} -`;
    }

    normalRangeHTML += ` ${generateNormalBoundHTML(thirdQuartile)}`;

    if(isAboveNormal) {
        normalRangeHTML += ` - ${generateUserTotalHTML("high")}`;
    }

    document.getElementById("normalRange").innerHTML = normalRangeHTML;
}

async function main() {

    injectAveragePERow();

    document.getElementById("retrieveCommunityAverage").addEventListener("click", async e => {

        const earningsApiResponse = await submitUserEarnings();

        if(exists(earningsApiResponse.averageEarningsForToday)) {

            const sortedIndividualEarnings = [...earningsApiResponse.individualEarningsForToday].sort((a,b) => a-b);

            const lowestIndividualEarnings = sortedIndividualEarnings[0].toLocaleString("en-US", {style: "currency", currency: "USD"});
            const medianIndividualEarnings = medianOfSortedValues(sortedIndividualEarnings).toLocaleString("en-US", {style: "currency", currency: "USD"});
            const highestIndividualEarnings = sortedIndividualEarnings[sortedIndividualEarnings.length-1].toLocaleString("en-US", {style: "currency", currency: "USD"});

            const [firstQuartile, thirdQuartile] = sidesOfMedian(sortedIndividualEarnings).map(side => medianOfSortedValues(side).toLocaleString("en-US", {style: "currency", currency: "USD"}));

            embedBoxAndWhiskerData({low: lowestIndividualEarnings,
                                    high: highestIndividualEarnings,
                                    median: medianIndividualEarnings,
                                    firstQuartile,
                                    thirdQuartile});

            document.getElementById("tcLowMedHigh").innerHTML = `
                <span style='color: red;'>${lowestIndividualEarnings}</span>,
                <span style='color: orange;'>${medianIndividualEarnings}</span>,
                <span style='color: green;'>${highestIndividualEarnings}</span>`;

            e.target.innerText = earningsApiResponse.averageEarningsForToday.toLocaleString("en-US", {style: "currency", currency: "USD"});

            const total = ( todaysTotal() || todaysTotalMTS() );

            displayNormalRangeVsYou( firstQuartile, thirdQuartile, total );

            displayRank( rank(total, sortedIndividualEarnings), sortedIndividualEarnings.length );
            displayNearestCompetitorInfo( nearestCompetitorTotalAndGapTuple(total, sortedIndividualEarnings) );
            displayLeaderboard( sortedIndividualEarnings );

            includeInLocalDailyHigh( total, amazonDateYYYYMMDD() );
            updateLocalAllTimeBestIfAppropriateTo( total );

            displayLocalBest();
            displayLocalAverage();

            const maxNumberOfLeagues = 5;

            const leagues = splitIntoLeagues( sortedIndividualEarnings, maxNumberOfLeagues );
            const numberOfLeagues = leagues.length;
            const { leagueIndex, rankIndex } = findLeagueAndRankIndex( total, leagues );
            const league = leagues[leagueIndex];
            const leagueSize = league.length;
            const leaguePosition = leagueSize - rankIndex;
            const leagueTitle = leagueIndexToTitle(leagueIndex, numberOfLeagues );

            displayLeagueRank(leagueTitle, leaguePosition, leagueSize);
            displayLeagueLeaderboard( league );

        }
        else if(["Your request is missing fields: total", "Your report is outdated"].includes(earningsApiResponse.errorMessage)) {
            e.target.innerText = "Work before comparing!";
        }
        else {
            e.target.innerText = earningsApiResponse.errorMessage;
        }

    });
}

main();
Oh. Hmph. Don't really have anything to say about that. Not my thing, I guess. But, good for you!:) No matter what your rank, you'll always be number 2 to me!:D
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
Title: Answer a survey about customization | Accept
Requester: Jessica [A2V4A1ZCXSQCC6] Contact
TV: No Reviews
TO: [Pay=5.00] [Fast=5.00] [Comm=0.00] [Fair=5.00] [Reviews=2] [ToS=0]
TO2: [Hrly=8.94] [Pen=null] [Res=null] [Rec=null] [Rej=0] [ToS=0] [Brk=0]
Reward: 1.30
Duration: 10800
Available: 1
Description: We are conducting an academic survey about customization. Select the link below to complete the survey. Please note, there are 2 qualifying questions, if you don't qualify, we will not be able to pay for your time. The survey will take approx 10 minutes.
Qualifications: HIT approval rate (%) GreaterThan 90; Total approved HITs GreaterThan 50; Location EqualTo US
[tr][td]
HIT exported from Mturk Suite v2.3.12
[/td][/tr]
[tr][td][/td][/tr]
 

GTR

Well-Known Member
Joined
Feb 10, 2016
Messages
10,278
Reaction score
22,985
Points
1,313
Gender
Male
Oh. Hmph. Don't really have anything to say about that. Not my thing, I guess. But, good for you!:) No matter what your rank, you'll always be number 2 to me!:D
I am just messin around with it and joking for the most part, but i could care less who has a big PE and who has a small one :wink:
 

Jerami

Well-Known Member
Contributor
Crowd Pleaser
HIT Poster
Joined
Jan 24, 2016
Messages
14,405
Reaction score
25,210
Points
2,238
I am just messin around with it and joking for the most part, but i could care less who has a big PE and who has a small one :wink:
I don't have a small PE! Why did you wink? Who said they've seen my PE?! :bolt:
 
  • Like
Reactions: GTR

GTR

Well-Known Member
Joined
Feb 10, 2016
Messages
10,278
Reaction score
22,985
Points
1,313
Gender
Male
I don't have a small PE! Why did you wink? Who said they've seen my PE?! :bolt:
if you use that script everyone will see your PE
 

cassius

Well-Known Member
Joined
Jan 14, 2016
Messages
8,897
Reaction score
18,565
Points
938
if you use that script everyone will see your PE
There is probably a nefarious reason for that somewhere. Really, who wants everyone to know what their business is. People work here and set their own goals. They don't walk to a whip so to speak.
 

splishsplash

40 Something Doomer Giver of bad advice
Joined
Jan 9, 2018
Messages
169
Reaction score
297
Points
263
Age
42
Gender
Male
There is probably a nefarious reason for that somewhere. Really, who wants everyone to know what their business is. People work here and set their own goals. They don't walk to a whip so to speak.
Script is cracking the whipe

Today's Community Average :: Work before comparing!
Well FU, script!

Actually, SOJM could be useful... indeed I want to know what the average is sometimes, too bad it's just users of that script.
 
Status
Not open for further replies.