Forked from cuylerstuwe/mturk-slow-or-just-me.user.js
Last active
September 13, 2018 23:06
-
-
Save brandonhellman/a6bd57089dd9c2f34f32019b4f0b7c1a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name mTurk Slow or Just Me? | |
// @namespace salembeats | |
// @version 1.23 | |
// @description UPDATE: Better formatting for box+whisker plot area. NOTE: Requires Kadauchi's "MTurk Dashboard Enhancer" script to function properly. | |
// @author Cuyler Stuwe (salembeats) | |
// @include https://worker.mturk.com/dashboard* | |
// ==/UserScript== | |
// 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 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 todaysDateYYYYMMDD() { | |
const now = new 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 todaysTotal() { | |
const lastRecordedDate = localStorage.getItem("WMTD_date"); | |
if(lastRecordedDate === todaysDateYYYYMMDD()) { | |
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: todaysDateYYYYMMDD(), | |
total: todaysTotal() || todaysTotalMTS() | |
}); | |
return payload; | |
} | |
async function submitUserEarnings() { | |
const apiEndpoint = `https://ne26dv9hq6.execute-api.us-west-2.amazonaws.com/dev/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", ` | |
<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"> </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> | |
`); | |
} | |
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)); | |
} | |
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"}); | |
} | |
else if(earningsApiResponse.errorMessage === "Your request is missing fields: total") { | |
e.target.innerText = "Work before comparing!"; | |
} | |
}); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment