-
Notifications
You must be signed in to change notification settings - Fork 0
/
stuff.txt
1 lines (1 loc) · 48.7 KB
/
stuff.txt
1
{"keys":[],"siteData":{"siteData":{"sites":[{"active":true,"instructions":"// Did you know that if you surround something in quotes in Google, it will limit search results to only show results that match that quote 100%. This can be annoying when copying and pasting an error message that includes a quote. If you make a search that includes quotes, this will give you a blue circle with a quote symbol inside it. Click on this button, and it will remove the quotes from your search.\n\nfunction searchUrlIncludes(includeStr) {\n let url = window.location.href;\n let searchStart = 'https://www.google.com/search?q=';\n let query = url.substring(url.indexOf(searchStart) + searchStart.length);\n return query.includes(includeStr);\n}\n\nlet quoteAscii = '%22';\nif (!searchUrlIncludes(quoteAscii)) {\n return;\n}\n\nlet removeBtn = document.createElement('button');\nremoveBtn.style = `\n background: none;\n border-radius: 50%;\n width: 28px;\n height: 28px;\n margin: auto 10px auto 0px;\n padding: 0;\n font-size: 40px;\n color: rgb(138, 180, 248);\n border: 2px solid rgb(138, 180, 248);\n cursor: pointer;\n`;\nremoveBtn.innerText = '\"';\nremoveBtn.onclick = quotelessSearch;\ndocument.getElementsByClassName('Tg7LZd')[0].after(removeBtn);\nfunction quotelessSearch(e) {\n e.preventDefault();\n let url = window.location.href;\n window.open(url.replaceAll(quoteAscii, ''), '_self');\n \n}","title":"remove quotes from search","uid":"8238358626096597","url":"google.com/search?q="},{"active":true,"instructions":"// This gives Canvas a nice unique look with pink links\n\nlet style = document.createElement('style');\ndocument.head.append(style);\nstyle.innerHTML = `\na {\n color: #eb00ff !important;\n}\n.btn-primary {\n color: #fff !important;\n}\n`;","title":"Unique Canvas Style","uid":"7233739670050241","url":"canvas.*.edu"},{"active":true,"instructions":"// important: if you don't use Canvas through ASU, change this to include your subdomain\nconst CANVAS_DOMAIN = \"canvas.asu.edu\";\n// change this to the src of the img representing no profile picture. You can right click on that photo, click \"Inspect Element\", and look in that area of the HTML code for src=<some url>\nDEFAULT_PROFILE_PATH = 'https://asu.instructure.com/images/messages/avatar-50.png';\n\n// Nobody ever adds profile pictures to their Canvas, and that's boring. This gives users with no profile pictures a unique avatar, corresponding to their name.\n\n\nlet iteration = 0;\nlet maxIterations = 10;\niterateCreate();\nfunction iterateCreate() {\n createAvatars();\n iteration ++;\n if (iteration < maxIterations) {\n setTimeout(iterateCreate, 100 * (iteration / 3)**2);\n }\n}\n\nfunction createAvatars() {\n [...document.getElementsByTagName('img')].forEach(img => {\n let name = img.alt;\n if (img.src == DEFAULT_PROFILE_PATH || img.src == 'https://\" + CANVAS_DOMAIN \n + \"/images/messages/avatar-50.png') {\n img.src = `https://avatars.dicebear.com/api/adventurer/${name}.svg`;\n }\n });\n\n [...document.getElementsByTagName('span')].forEach(img => {\n let name = img.getAttribute('alt');\n if (img.style.backgroundImage == `url(\"https://${CANVAS_DOMAIN}/images/messages/avatar-50.png\")' || name == 'Unknown') {\n img.style.backgroundImage = `url('https://avatars.dicebear.com/api/adventurer/${name}.svg')`;\n }\n });\n}\n","title":"Add avatars to anonymous profile pictures","uid":"5034753745706347","url":"canvas.*.edu"},{"active":false,"instructions":"// change TITLE to whatever you want\nconst TITLE = \"Clickbait Bogus\"\n\n// I made this to change youtube titles to \"Harry Potter\" for my cousin, who finds that hilarious. I also change the release dates; you can uncomment that block of code below to change them as well\n// This is meant for the Youtube home page\n\nsetTitles(TITLE);\n//setDates('June 24 2017');\n\nfunction setTitles(title) {\n [...document.querySelectorAll('yt-formatted-string#video-title')].forEach(title => {\n title.innerText = TITLE;\n });\n}\n\nfunction setDates(date) {\n [...document.querySelectorAll('.style-scope.ytd-video-meta-block')].forEach(thingy => {\n if (thingy.innerText.includes('ago')) {\n thingy.innerText = date;\n }\n });\n}","title":"Change YouTube Titles to Your Message","uid":"2131479650223699","url":"youtube.com"},{"active":true,"instructions":"// Change YouTube's primary color to a random color. You can change the color again by pressing the \"Color\" button at the top of the screen.\n\nfunction style() {\nlet color = Tab.getRandomRGB();\nTab.getStyle().innerText = `\n* {\n color: ${color} !important;\n fill: ${color} !important;\n}\n#logo * {\n fill: white !important;\n}\n#logo [fill='#FF0000'] {\n fill: red !important;\n}\n`;\n}\nstyle();\n\nlet btn = document.createElement('span');\nbtn.innerText = 'Color';\nbtn.className = 'title';\nbtn.style = `\n font-size: 20px;\n cursor: pointer;\n`;\nbtn.onclick = style;\ndocument.getElementById('center').prepend(btn);\n","title":"Youtube Style + Color Toggle","uid":"6619589258059203","url":"www.youtube.com"},{"active":false,"instructions":"// change TITLE to whatever you want\nconst TITLE = \"Watch Mojo top 10 best chrome extensions\"\n\n// I made this to change youtube titles to \"Harry Potter\" for my cousin, who finds that hilarious. I also change the release dates; you can uncomment that block of code below to change them as well\n// This is meant to change the title of a specific video you are currently watching\n\nsetTitle(TITLE);\n//setDate('Apr 24, 2027');\n\nfunction setTitle(title) {\n [...document.querySelectorAll('yt-formatted-string.style-scope.ytd-watch-metadata')][0].innerText = title;\n}\nfunction setDate(date) {\n[...document.querySelectorAll('span.bold.style-scope.yt-formatted-string')][2].innerText = date;\n}","title":"Change Title of Current Video to Your Message ","uid":"8663782804303129","url":"youtube.com/watch"},{"active":true,"instructions":"// Sometimes random youtube thumbnails can show any host of bizarre content, and I don't want to be at a public place with who knows what showing up on my laptop screen. This can blur thumbnails by default, and you can press \"Display\" on the left menu to unblur.\n// YouTube music changes its UI often - I've needed to update this many times - so the button may not appear correctly or at all in the future.\n\n// set this to true if you want thumbnails blurred by default\nconst DEFAULT_HIDDEN = true;\n\nconst id = 'remove-img-style';\n\nif (DEFAULT_HIDDEN)\n hideThumbnails();\n\nfunction hideThumbnails() {\n let style = document.createElement('style');\n style.id = id;\n style.innerHTML = `\n img {\n opacity: 0.5;\n filter: blur(20px);\n /*display: none !important;*/\n }`;\n document.head.append(style);\n}\n\nfunction showThumbnails() {\n if (document.getElementById(id))\n document.getElementById(id).remove();\n}\n\nconst imitate_buttons_txt = 'Home';\n \nlet btn;\n[...document.getElementsByTagName('ytmusic-guide-entry-renderer')].forEach(div => {\n if (!btn && div.innerText == imitate_buttons_txt) {\n btn = document.createElement('button');\n btn.style = 'cursor: pointer;border-radius: 10px;text-align: left;width: -webkit-fill-available;height: 54px;padding-left: 62px;font-size: 17px;margin: 0px;background:transparent;border:none;';\n\n btn.innerText = 'Display';\n div.before(btn);\n }\n});\n\nbtn.onclick = (e) => {\n if (btn.classList.contains('visible')) {\n hideThumbnails();\n } else {\n showThumbnails();\n }\n btn.classList.toggle('visible');\n};\n\nbtn.onmouseenter = () => {\n btn.style.background = 'rgb(52,52,52)';\n}\n\nbtn.onmouseleave= () => {\n btn.style.background = 'transparent';\n}\n","title":"get rid of thumbnails","uid":"3985036446936477","url":"music.youtube.com"},{"active":true,"instructions":"// Change YouTube Music's primary color. Press the color button on the left menu to change it again.\n// YouTube music changes its UI often - I've needed to update this many times - so the button may not appear correctly or at all in the future.\n\nconst imitate_buttons_txt = 'Home';\n \nlet btn;\n[...document.getElementsByTagName('ytmusic-guide-entry-renderer')].forEach(div => {\n if (!btn && div.innerText == imitate_buttons_txt) {\n //btn = div.cloneNode(true);\n btn = document.createElement('button');\n btn.style = 'cursor: pointer;border-radius: 10px;border:none;text-align: left;width: -webkit-fill-available;height: 54px;padding-left: 62px;font-size: 17px;margin: 0px;background: transparent;';\n\n btn.innerText = 'Color';\n div.before(btn);\n }\n});\n\n\nbtn.onclick = (e) => {\n e.preventDefault();\n e.stopPropagation();\n Tab.setColor(Tab.getRandomRGB());\n};\n\nbtn.onmouseenter = () => {\n btn.style.background = 'rgb(52,52,52)';\n}\n\nbtn.onmouseleave= () => {\n btn.style.background = 'transparent';\n}\n\n//document.getElementsByTagName('ytmusic-guide-section-renderer')[0].prepend(btn);\n\n// set color\nTab.setColor(Tab.getRandomRGB());","title":"Youtube Music Color Toggle","uid":"3484623575556657","url":"music.youtube.com"},{"active":true,"instructions":"Tab.setColor(Tab.getRandomRGB());","title":"give white text random color","uid":"6784401155786199","url":"netflix.com"},{"active":false,"instructions":"// I use this to calculate stats about my grades in Canvas. Go to the bottom of the page to see how I use it and see if you want to try using it for your Canvas page\n\nconst gradeRows = [...document.getElementsByClassName('student_assignment')];\nconst grades = parseGrades(gradeRows);\nfunction parseGrades(gradeRows) {\n const grades = [];\n for (const row of gradeRows) {\n let muted = false;\n let title = null;\n let score = NaN;\n let possible = NaN;\n let percent = null;\n // Invalid Date\n let date = new Date('');\n\n muted = row.getAttribute('data-muted') === 'true';\n\n const titleEl = row.getElementsByClassName('title')[0];\n if (titleEl && titleEl.innerText) {\n title = titleEl.innerText;\n title = title.replaceAll('\\n', ' ');\n }\n \n const gradeEl = row.getElementsByClassName('grade')[0];\n if (!gradeEl) {\n grade = NaN;\n muted = true;\n } else {\n let grade = gradeEl.innerText;\n grade = grade.replace('Click to test a different score', '');\n grade = grade.trim();\n if (!grade || grade === '-') {\n score = NaN;\n percent = null;\n muted = true;\n } else {\n if (grade.includes('%')) {\n percent = grade;\n } else {\n score = Number.parseFloat(grade);\n }\n }\n }\n\n const pointsPossibleEl = row.getElementsByClassName('points_possible')[0];\n if (!pointsPossibleEl) {\n possible = NaN;\n percent = null;\n } else {\n possible = pointsPossibleEl.innerText;\n if (!possible) {\n possible = NaN;\n percent = null;\n } else {\n possible = Number.parseFloat(possible);\n }\n }\n\n if (percent !== null && !isNaN(possible)) {\n let tempPercent = percent.replace('%', '');\n tempPercent = Number.parseFloat(tempPercent);\n tempPercent /= 100;\n score = tempPercent * possible;\n } else if (!isNaN(score) && !isNaN(possible) && possible !== 0) {\n percent = (100 * score / possible) + '%';\n }\n\n const dateEl = row.getElementsByClassName('due')[0];\n // new Date('MM DD YYYY HH:MM');\n if (dateEl && dateEl.innerText) {\n let dateText = dateEl.innerText;\n const year = new Date().getYear() + 1900\n dateText = dateText.replace('by', year);\n if (dateText.includes('pm')) {\n dateText = dateText.replace('pm', '');\n let colonIndex = dateText.indexOf(':');\n let start = dateText.substring(0, colonIndex);\n let end = dateText.substring(colonIndex);\n let spaceBeforeHourIndex = start.lastIndexOf(' ');\n let hourIndex = spaceBeforeHourIndex + 1;\n let hourText = start.substring(hourIndex);\n start = start.substring(0, hourIndex);\n let hour = Number.parseInt(hourText);\n hour += 12;\n dateText = start + hour + end;\n } else {\n dateText = dateText.replace('am', '');\n }\n date = new Date(dateText);\n }\n \n\n \n grades.push({\n muted,\n title,\n score,\n possible,\n percent,\n date\n });\n }\n return grades;\n}\n\n/*\n * HELPFUL FUNCTIONS\n * (for viewing + manipulating grade info)\n */\n\n// Calculate average for non-null scores including includes and (optional) excluding exclude\nfunction calculateAverage(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let total = 0;\n let totalPossible = 0;\nfor (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.score) && !isNaN(grade.possible)) {\n total += grade.score;\n totalPossible += grade.possible;\n }\n}\n return 100 * total / totalPossible;\n}\n\n// Calculate total for non-null scores including includes and (optional) excluding exclude\nfunction calculateTotal(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let total = 0;\nfor (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.score)) {\n total += grade.score;\n }\n}\n return total;\n}\n\n// Calculate total for non-null scores including a possible score including includes and (optional) excluding exclude\nfunction calculateTotalsWithPossible(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let total = 0;\nfor (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.score) && !isNaN(grade.possible)) {\n total += grade.score;\n }\n}\n return total;\n}\n\n// Calculate total possible for non-null possible scores no matter whether they've been scored including includes and (optional) excluding exclude\nfunction calculateTotalPossible(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let totalPossible = 0;\nfor (grade of grades) {\n if ( grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.possible)) {\n totalPossible += grade.possible;\n }\n}\n return totalPossible;\n}\n\n// Calculate total possible for non-null scores which have been scored including includes and (optional) excluding exclude\nfunction calculateTotalPossibleWithScore(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let totalPossible = 0;\nfor (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.score) && !isNaN(grade.possible)) {\n totalPossible += grade.possible;\n }\n}\n return totalPossible;\n}\n\n// Calculate average for non-null scores including includes and (optional) excluding exclude\nfunction calculateAverage(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let total = 0;\n let totalPossible = 0;\nfor (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude) && !isNaN(grade.score) && !isNaN(grade.possible)) {\n total += grade.score;\n totalPossible += grade.possible;\n }\n}\n return 100 * total / totalPossible;\n}\n\n// get number of items including includes and (optional) excluding exclude\nfunction getNumberMatching(includes='', exclude='SCREW BEST PRACTICES THIS IS HOW IM DOING THIS WE BALL') {\n let number = 0;\n for (grade of grades) {\n if (grade.title && grade.title.includes(includes) && !grade.title.includes(exclude)) {\n number ++;\n }\n }\n return number;\n}\n\n// get grades passing func\nfunction getGradesIf(func=() => {return null;}) {\n passing = [];\n grades.forEach(grade => {\n if (func(grade)) {\n passing.push(grade);\n }\n });\n return passing;\n}\n\n/*\n MANIPULATE GRADES\n*/\n\n// all grades\nconsole.log('grades : ');\nconsole.log(grades);\n\nconsole.log(\"Average of All Grades : \");\n// average of all grades\nconsole.log(calculateAverage());\n\nconsole.log(\"Earned / Possible & Graded: \");\nconsole.log(`${calculateTotal()} / ${calculateTotalPossibleWithScore()}`);\n\nconsole.log(\"Earned / Possible : \");\nconsole.log(`${calculateTotal()} / ${calculateTotalPossible()}`);\n\nconsole.log(\"Average Recitation : \");\nconsole.log(calculateAverage(\"Recitation\"));\n\nconsole.log(\"Average Quiz: \");\nconsole.log(calculateAverage(\"Quiz\"));\n\nconsole.log(\"Average Homework: \");\nconsole.log(calculateAverage(\"Assignment #\"));\n\nconsole.log(\"Average WebWork: \");\nconsole.log(calculateAverage(\"WeBWorK\"));\n\nconsole.log(getGradesIf(\n (grade) => {\n return grade.title && grade.title.includes(\"WeBWorK\") && grade.score > 2.5;\n}));\n\nlet totScore = 0;\nlet totPossible = 0;\ngetGradesIf(\n (grade) => {\n return grade.title && grade.title.includes(\"WeBWorK\") && grade.score > 2.5;\n}).forEach(grade => {\n totScore += grade.score;\n totPossible += grade.possible;\n});\n\nconsole.log(`${totScore} / ${totPossible}`);\nconsole.log(totScore / totPossible);\n\nconsole.log(\"Earned / Possible : \");\nconsole.log(`${calculateTotal('Lab')} / ${calculateTotalPossible('Lab')}`);","title":"Get Grade Data","uid":"2586417287582743","url":"canvas.*.edu/courses/*/grades"},{"active":false,"instructions":"// TODO: add UI text warning user is in practice mode\n\n// typed answers\n[...document.getElementsByTagName('p')].forEach(p => {\n let inputs = [...p.getElementsByTagName('input')];\n let values = [];\n \n for (let i = 0; i < inputs.length; i++) {\n if (!values.includes(inputs[i].value)) {\n values.push(inputs[i].value);\n }\n }\n [...p.getElementsByTagName('span')].forEach(span => {\n if (span.className == 'mq-root-block' && values.includes(span.innerText.replaceAll('−','-'))) {\n span.innerText = '';\n }\n });\n});\n\n// select questions\n[...document.getElementsByTagName('option')].forEach(option => {\n option.removeAttribute('selected');\n});","title":"Practice Mode - hide previous answers","uid":"8428651362942197","url":"webwork2.asu.edu"},{"active":true,"instructions":"waitThenDoContent();\n\n//const observer = new MutationObserver(waitThenDoContent);\n\n//const loadEl = document.getElementById('loading-alert');\n//observer.observe(loadEl, { attributes : true, attributeFilter : ['style'] });\n\nfunction waitThenDoContent() {\n setTimeout(content, 100);\n}\n\nfunction content() {\nconst professorParentEls = [...document.getElementsByClassName('class-results-cell instructor')];\nprofessorParentEls.forEach(parent => {\n const professorLinkSpan = parent.getElementsByTagName('span')[0].getElementsByTagName('span')[0].getElementsByTagName('span')[0].getElementsByTagName('span')[0];\n// return if already has link\n if (professorLinkSpan.getElementsByClassName('RMP').length > 0) {\n return;\n}\n const nameAnchor = professorLinkSpan.getElementsByTagName('a')[0].href;\n const nameComponents = nameAnchor.split('&sp=S');\n const name = nameComponents[nameComponents.length - 2] + '%20' + nameComponents[nameComponents.length - 1];\n \n const anchor = document.createElement('a');\n anchor.innerText = 'RMP';\n anchor.className = 'RMP';\n anchor.style = 'display: block;'\n anchor.href= `https://www.ratemyprofessors.com/search/teachers?query=${name}&sid=U2Nob29sLTQ1`;\n professorLinkSpan.append(anchor);\n \n});\n}","title":"Add RMP option to professor names","uid":"4848278153266735","url":"webapp4.asu.edu/catalog/classlist, catalog.apps.asu.edu/catalog/classes/classlist"},{"active":true,"instructions":"let urls = [\n 'https://canvas.asu.edu/',\n 'https://webwork2.asu.edu/webwork2/Tracogna_MAT_343_C_Fall_2022',\n 'https://www.gradescope.com/courses/413771',\n'https://dojo.pwn.college/cse365/challenges'\n];\n\nconst header = document.getElementsByTagName('header')[0];\n\nlet btn = document.createElement('button');\nbtn.onclick = openUrls;\nbtn.innerText = 'Check Sites';\n\n// auto get styling classnames (classnames are subject to change)\n[...header.getElementsByTagName('button')].forEach(button => {\n if (button.innerText == 'Today') {\n btn.className = button.className;\n }\n});\n\nheader.getElementsByClassName('BXL82c')[0].after(btn);\n\nfunction openUrls() {\n urls.forEach(url => {\n openUrl(url);\n });\n}\n\nfunction openUrl(url) {\n window.open(url, '_blank');\n}","title":"Check Sites for HW","uid":"2321603458960351","url":"calendar.google.com"},{"active":false,"instructions":"const header = addHeader();\nlet timeoutCount = 0;\nconst maxTimeouts = 20;\nlet items = [...document.getElementsByClassName('item_name')];\n\ngetNextDueAssignment();\n\ngetNextDueQuiz();\n\nfunction getNextDueQuiz() {\n let matches = getItems('Quiz');\n console.log(matches);\n let nextDue = matches[matches.length - 1];\n console.log(nextDue);\n\n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText;\n title.style = 'transform: translateY(-23px);'\n homeworkLink.append(title);\n}\n\nfunction getNextDueAssignment() {\n let matches = getItems('Assignment');\n let nextDue;\n let now = Date.now();\n for (let i = 0; i < matches.length && !nextDue; i++) {\n let text= matches[i].getElementsByTagName('a')[0].innerText;\n let due = text.substring(text.indexOf(',') + 1, text.lastIndexOf(','));\n due = due.replaceAll('th', '');\n due = due.replaceAll('st', '');\n due = due.replaceAll('rd', '');\n due = due.replaceAll('nd', '');\n if (new Date(due + ' 2022 17:00 MST').getTime() > now) {\n nextDue = {\n item: matches[i],\n due: due\n };\n }\n }\n if (!nextDue) {\n return countedTimeout(getNextDueAssignment, 10);\n } \n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.item.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText.substring(0, anchor.innerText.indexOf('-'));\n homeworkLink.append(title);\n let due = document.createElement('span');\n due.innerText = nextDue.due + ' 5:00';\n due.style = `\n color: var(--ic-brand-font-color-dark-lightened-15);\n font-size: 14px;\n`;\n homeworkLink.append(due);\n\n}\n\nfunction createHeader(tagName, id) {\n let headItem = document.createElement(tagName);\n headItem.className = 'added-header';\n if (id) {\n headItem.id = `added-header-${id}`;\n }\n header.prepend(headItem);\n return headItem;\n}\n\nfunction getItems(name, ignore='') {\n name = name.toLowerCase();\n ignore = ignore.toLowerCase();\n let matches = [];\n for (let i = 0; i < items.length; i++) {\n let anchor = items[i].getElementsByTagName('a')[0];\n if (anchor) {\n let text = anchor.innerText.toLowerCase();\n if (text.includes(name)) {\n if (!ignore || !text.includes(ignore)) {\n matches.push(items[i]);\n }\n }\n }\n }\n return matches;\n}\n\nfunction addHeader() {\n let header = document.createElement('header');\n header.id = 'header-features';\n document.getElementsByClassName('header-bar')[0].append(header);\n addHeaderStyling();\n return header;\n}\n\nfunction addHeaderStyling() {\n let style = document.createElement('style');\n style.id = 'header-styling';\n style.innerHTML = `\n #header-features {\n width: 100%;\n }\n #header-features .added-header {\n padding: 10px;\n display: inline-block;\n margin: 10px;\n }\n `;\n document.head.append(style);\n}\n\nfunction countedTimeout(callback, time) {\n timeoutCount ++;\n if (timeoutCount < maxTimeouts) {\n setTimeout(callback, time);\n }\n}","title":"CSE 230: useful header for modules","uid":"5414208299116751","url":"https://canvas.asu.edu/courses/109887/modules"},{"active":false,"instructions":"// if homework is NOT complete / past due\nif (![...document.querySelectorAll('[data-testid=assessment-completion-alert]')].length) {\n return;\n}\n\n\nlet inputs \n = [...document.getElementsByClassName('form-control input-sm')];\n\nlet testInputs = inputs.slice(0, inputs.length/2);\nlet correctInputs = inputs.slice(inputs.length/2);\n\ntestInputs.forEach(input => {\n input.disabled = false;\n});\n\n\nfunction checkAnswer() {\n let tried = Number.parseFloat(document.activeElement.value);\n let solutionInput = correctInputs[testInputs.indexOf(document.activeElement)];\n let solution = Number.parseFloat(solutionInput.value);\n let tolerance = solutionInput.parentElement.parentElement.getAttribute('data-tolerance');\n\nif (tolerance) {\n tolerance = Number.parseFloat(tolerance.substring(1));\n} else {\n tolerance = 0;\n}\n\n if (Math.abs(tried - solution) <= tolerance) {\n displayCorrect();\n } else {\n displayIncorrect();\n }\n}\n\nfunction displayCorrect() {\n document.activeElement.style.borderColor = 'green';\ndocument.activeElement.style.backgroundColor = 'rgb(200,255,200)';\n}\n\nfunction displayIncorrect() {\n document.activeElement.style.borderColor = 'red';\n document.activeElement.style.backgroundColor = 'rgb(255,200,200)';\n}\n\ndocument.addEventListener('keydown', (e) => {\n if (e.key == 'Enter') {\n if (testInputs.includes(document.activeElement)) {\n e.preventDefault();\n checkAnswer();\n }\n }\n});\n","title":"post due date practice","uid":"3475211871000669","url":"education.wiley.com"},{"active":true,"instructions":"const header = addHeader();\nlet timeoutCount = 0;\nconst maxTimeouts = 20;\nlet items = [...document.getElementsByClassName('item_name')];\n\ngetNextDueHomework();\n\ngetNextDueQuiz();\n\ngetNextDueExam();\n\ngetWeekToDoList();\n\nfunction getWeekToDoList() {\n let matches = getItems('To-Do');\n let nextDue;\n let now = Date.now();\n for (let i = 0; i < matches.length && !nextDue; i++) {\n let text= matches[i].getElementsByTagName('a')[0].innerText;\n let due = text.substring(text.lastIndexOf('-') + 1);\n due = due.trim();\n if (new Date(due + ' 2022 23:59 MST').getTime() > now) {\n nextDue = {\n item: matches[i],\n due: due\n };\n }\n }\n\nif (!nextDue) {\n return countedTimeout(getWeekToDoList, 10);\n } \n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.item.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText.substring(0, anchor.innerText.indexOf(':'));\n homeworkLink.append(title);\n let due = document.createElement('span');\n due.innerText = nextDue.due;\n due.style = `\n color: var(--ic-brand-font-color-dark-lightened-15);\n font-size: 14px;\n`;\n homeworkLink.append(due);\n}\n\nfunction getNextDueExam() {\n let matches = getItems('Exam', 'Practice');\n let nextDue;\n let now = Date.now();\n for (let i = 0; i < matches.length && !nextDue; i++) {\n let text= matches[i].getElementsByTagName('a')[0].innerText;\n let due = text.substring(text.indexOf(':') + 4, text.indexOf('('));\n due = due.trim();\n if (new Date(due + ' 2022 23:59 MST').getTime() > now) {\n nextDue = {\n item: matches[i],\n due: due\n };\n }\n }\n\nif (!nextDue) {\n return countedTimeout(getNextDueExam, 10);\n } \n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.item.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText.substring(0, anchor.innerText.indexOf(':'));\n homeworkLink.append(title);\n let due = document.createElement('span');\n due.innerText = nextDue.due;\n due.style = `\n color: var(--ic-brand-font-color-dark-lightened-15);\n font-size: 14px;\n`;\n homeworkLink.append(due);\n}\n\nfunction getNextDueQuiz() {\n let matches = getItems('Quiz');\n // get rid of repondus lockdown browser quiz\n matches.splice(0,1);\n let nextDue;\n let now = Date.now();\n for (let i = 0; i < matches.length && !nextDue; i++) {\n let text= matches[i].getElementsByTagName('a')[0].innerText;\n let due = text.substring(text.indexOf('-') + 1, text.indexOf('('));\n due = due.trim();\n if (new Date(due + ' 2022 23:59 MST').getTime() > now) {\n nextDue = {\n item: matches[i],\n due: due\n };\n }\n }\n\nif (!nextDue) {\n return countedTimeout(getNextDueQuiz, 10);\n } \n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.item.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText.substring(0, anchor.innerText.indexOf(':'));\n homeworkLink.append(title);\n let due = document.createElement('span');\n due.innerText = nextDue.due;\n due.style = `\n color: var(--ic-brand-font-color-dark-lightened-15);\n font-size: 14px;\n`;\n homeworkLink.append(due);\n}\n\nfunction getNextDueHomework() {\n let matches = getItems('Homework', 'Help');\n let nextDue;\n let now = Date.now();\n for (let i = 0; i < matches.length && !nextDue; i++) {\n let due = matches[i].parentElement.parentElement.getElementsByClassName('due_date_display')[0].innerText;\n if (new Date(due + ' 2022 23:59 MST').getTime() > now) {\n nextDue = {\n item: matches[i],\n due: due\n };\n }\n }\n \n if (!nextDue) {\n return countedTimeout(getNextDueHomework, 10);\n } \n let homeworkLink = createHeader('a', 'homework');\n let anchor = nextDue.item.getElementsByTagName('a')[0];\n homeworkLink.href = anchor.href;\n let title = document.createElement('div');\n title.innerText = anchor.innerText;\n homeworkLink.append(title);\n let due = document.createElement('span');\n due.innerText = nextDue.due;\n due.style = `\n color: var(--ic-brand-font-color-dark-lightened-15);\n font-size: 14px;\n`;\n homeworkLink.append(due);\n\n}\n\nfunction createHeader(tagName, id) {\n let headItem = document.createElement(tagName);\n headItem.className = 'added-header';\n if (id) {\n headItem.id = `added-header-${id}`;\n }\n header.prepend(headItem);\n return headItem;\n}\n\nfunction getItems(name, ignore='') {\n name = name.toLowerCase();\n ignore = ignore.toLowerCase();\n let matches = [];\n for (let i = 0; i < items.length; i++) {\n let anchor = items[i].getElementsByTagName('a')[0];\n if (anchor) {\n let text = anchor.innerText.toLowerCase();\n if (text.includes(name)) {\n if (!ignore || !text.includes(ignore)) {\n matches.push(items[i]);\n }\n }\n }\n }\n return matches;\n}\n\nfunction addHeader() {\n let header = document.createElement('header');\n header.id = 'header-features';\n document.getElementsByClassName('header-bar')[0].append(header);\n addHeaderStyling();\n return header;\n}\n\nfunction addHeaderStyling() {\n let style = document.createElement('style');\n style.id = 'header-styling';\n style.innerHTML = `\n #header-features {\n width: 100%;\n }\n #header-features .added-header {\n padding: 10px;\n display: inline-block;\n margin: 10px;\n }\n `;\n document.head.append(style);\n}\n\nfunction countedTimeout(callback, time) {\n timeoutCount ++;\n if (timeoutCount < maxTimeouts) {\n setTimeout(callback, time);\n }\n}","title":"IEE 380: useful header for modules","uid":"7236415769661081","url":"https://canvas.asu.edu/courses/108703/modules"},{"active":true,"instructions":"// if not on quiz submission page\nif (![...document.getElementsByClassName('quiz-submission')].length) {\n return;\n}\n// if all questions are graded\nif (![...document.getElementsByClassName('question-not-graded-text')].length) {\n return;\n}\nlet unscored = [];\nlet scores = [...document.getElementsByClassName('user_points')];\nscores.forEach(score => {\n score = score.innerText;\n if (!score.includes('Not yet graded')) {\n return;\n }\n let ptsPossible = score.substring(score.indexOf('/') + 1);\n ptsPossible = ptsPossible.replace('pts', '');\n ptsPossible = ptsPossible.trim();\n unscored.push(ptsPossible);\n});\n\nlet unscoredTotal = 0;\nunscored.forEach(pts => {\n unscoredTotal += Number.parseFloat(pts);\n});\n\nlet quizScore = document.getElementsByClassName('quiz_score')[0];\nlet quizScoreText = quizScore.innerText;\nlet earnedScore = Number.parseFloat(quizScore.getElementsByClassName('score_value')[0].innerText);\nlet flag = 'out of ';\nlet outOfTotal = quizScoreText.substring(quizScoreText.indexOf(flag) + flag.length);\noutOfTotal = outOfTotal.replaceAll('*', '');\noutOfTotal = outOfTotal.trim();\n\nlet possibleScoreDisplay = document.createElement('div');\npossibleScoreDisplay.className = 'quiz_score possible_quiz_score';\npossibleScoreDisplay.innerText = 'Possible score for this quiz: ';\nlet scoreSpan = document.createElement('span');\nscoreSpan.className = 'score_value';\nscoreSpan.innerText = (earnedScore + unscoredTotal);\npossibleScoreDisplay.append(scoreSpan);\npossibleScoreDisplay.append(` out of ${outOfTotal} **`);\nquizScore.after(possibleScoreDisplay);\n\n// disclaimer\nlet counter = 0;\ndisclaimer();\nfunction disclaimer() {\nlet disclaimerBox = document.getElementsByClassName('submission-pending-review')[0];\nif (!disclaimerBox) {\n if (counter < 10) {\n counter ++;\n setTimeout(disclaimer, 20);\n }\n return;\n}\nlet br = document.createElement('br');\ndisclaimerBox.append(br);\nlet em = document.createElement('em');\nem.innerText = '**';\ndisclaimerBox.append(em);\ndisclaimerBox.append(' If all questions not yet graded are correct');\n}","title":"calc ungraded quiz problems","uid":"4926092342086385","url":"canvas.asu.edu/*/quizzes"},{"active":true,"instructions":"document.body.addEventListener('keydown', (e) => {\n if (e.key === 'c' && e.ctrlKey) {\n navigator.clipboard.writeText(window.getSelection().toString());\n }\n});","title":"Let me copy paste on canvas","uid":"3599678232758851","url":"canvas.asu.edu/*/quizzes, canvas.asu.edu/*/submissions"},{"active":true,"instructions":"addSubtitleStyle();\nlet check = 0;\nif ([...document.getElementsByClassName('profile-link')].length > 0) {\n[...document.getElementsByClassName('profile-link')].forEach(btn => {\n btn.addEventListener('click', () => {\n createBtn();\n });\n });\n} else {\n createBtn();\n}\n\nfunction createBtn() {\n if ([...document.getElementsByClassName('navigation-menu')].length < 1) {\n if (check < 5) {\n check++;\n setTimeout(createBtn, 100);\n }\n return;\n }\n let btn = document.createElement('li');\n btn.className = 'navigation-tab';\n btn.onclick = () => {\n Tab.setColor(Tab.getRandomRGB())\n };\n let a = document.createElement('a');\n a.innerText = 'Color';\n btn.append(a);\n document.getElementsByClassName('navigation-menu')[0].after(btn);\n}\n\n// subtitles should prob just stay white\nfunction addSubtitleStyle() {\n let style = document.createElement('style');\n style.innerHTML = `\n .player-timedtext * {\n color: #fff !important;\n }`;\n document.head.append(style);\n}","title":"Netflix Color Toggle","uid":"684056911660053","url":"netflix.com"},{"active":true,"instructions":"// Do you use pearson for an online textbook? If so, you can't highlight text without a pop up appearing over a portion of the textbook. The pop up offers features that I'm sure are helpful to some students, but I like highlighting text as I read and don't want the pop up distracting me.\n\nlet style = document.createElement('style');\ndocument.head.append(style);\nstyle.innerHTML = `\n.contentSelector {\n display:none;\n}\n`;","title":"Prevent annoying popup after highlighting text","uid":"4123629968406641","url":"revel-ise.pearson.com"}]}},"noteData":{"noteData":{"notes":[{"memo":"How to use this extension:\n...\nSites:\nSites are used to run code on certain websites you interact with. Each site includes a title, a url, a code block, a Reload button, and an Automatic/Manual button. If the Site is Automatic, it will run automatically upon entering the website matching the url. Otherwise, you will need to press the Reload button to get the code to run. Note that by default, any website that includes the url's text will work on the site. You can use a * as a match any pattern (e.g. canvas.*.edu matches canvas.asu.edu and canvas.unr.edu), and you can delimit multiple urls by separating them with commas (e.g. google.com, yahoo.com). You can limit matches patterns to match the url exactly by using quotes (e.g. \"https://google.com\" does NOT match https://google.com/search?q=dog). Be careful - if you use quotes, you will need to precede your domain with https:// or the appropriate scheme.\n\nNotes:\nNotes are self explanatory - you're using one now! Notes include a title and a body of text.\n\nScrapers:\nScrapers are used to scrape data from a certain URL. Each includes a window for displaying response information, a title, a URL, and a window for writing code. It also has a \"Reload Data\" button, and a button marked \"Active\" or \"Inactive\". If it is \"Active\", it will automatically run when you open the popup. Otherwise, you will need to hit \"Reload Data\" to run the scraper. \"Features\" has not been implemented (and will probably never be implemented), but you can press the buttons all you want :)\nFor coding the scrapers, you will receive an XML Http Request object inside of the code block starting with \".xhr {{\" and ending with \"}}\". Don't let the syntax disturb you, everything else is vanilla JavaScript - this is just the way I wanted to distinguish between code that runs before receiving the xhr object (before the code block) and code that runs after receiving the xhr object (inside the xhr code block). To display results in the window, use the methods display(string text) or displayHTML(string HTML)\n\nGamble:\nNot sure whether you want to take a break from work? Wondering if you should buy that new item? Debating on reading one more chapter?\nFlip the card, and see if you win :D or lose :(\n\nCalculator:\nUse the Weber-84 Graphing Calculator, or use one of many functions for probability and calculus. \nFull list of functions:\n - p\n - mean\n - variance\n - deviation\n - sum\n - derivative\n - integral\n ... and a lot more probability functions.\nUse \" -l * \" to see the list of most of the functions.\nUse \" -l \" infront of a function to see how to use it.\n\nCode: \nSometimes you need to code on the go. Use this in popup mode to quickly confirm how some JavaScript method works.Use this in tab mode to send code to the tab when you want to have the tab take up the full browser window, without needing to open the web console.\n\nMustache:\nPerhaps most useful of all this extension's features, press the mustache button to have a mustache appear in the top left of the page. Drag the mustache onto your boss's face, and scroll on the mustache to change its size.\n\nCool Style:\nPress the + to receive access to sliders which can change your tab's foreground and background colors. If you're feeling daring or you're in the mood to punish your eyes, you can also press the Cool Style button to receive a random combo of colors and font.\n\nData:\nCopy this extension's data to save a backup or share with your friends, and import your friend's data. At the moment, this just pertains to your Sites, Notes, and Scrapers.\nNote on importing data: I'm not 100% confident in the import function working correctly under each edge case. You shouldn't be saving crucial data on here anyways as this certainly does NOT use the safest memory model, but I'd paste a copy of my data to a text editor of choice before importing new data on top of anything I don't want deleted.\nThe import function is supposed to work by combining your existing data with the imported data, but I made it really dynamically so I don't need to change the algorithm whenever I add a new data structure, so import at your own risk.","title":"Welcome to Browser Tools!","uid":"1738293408143309"}]}},"scraperData":{"scraperData":{"scrapers":[{"active":false,"instructions":".xhr {{\n // Add information about stocks you own to see how you've performed\n const ownedStonks = [\n {\n symbol: 'NFLX',\n value: 435.55, // value/share at time of purchase\n spent: 1000, // amount spent\n date: new Date('5/4/2020') // time of purchase\n },\n {\n symbol: '^GSPC',\n value: 4320.06,\n spent: 5000,\n date: new Date('9/22/2023')\n },\n {\n symbol: 'BTC-USD',\n value: 41733.58, // value/share at time of purchase\n spent: 1000, // amount spent\n date: new Date('1/19/2022') // time of purchase\n },\n ];\n\n console.log(xhr.response);\n const BASE_URL = 'https://finance.yahoo.com/quote/';\n const SYMBOL = getUrl().substring(BASE_URL.length);\n\n let dataText = xhr.response;\n\n const DATA_FLAG = 'data-field=\"regularMarketPrice\"';\n const SYMBOL_FLAG = 'data-symbol=';\n\n let price;\n let increment = 0;\n while (dataText.includes(DATA_FLAG) && increment < 30) {\n increment ++;\n\n dataText = dataText.substring(dataText.indexOf(DATA_FLAG) - 12);\n let symbolTxt = dataText.substring(dataText.indexOf(SYMBOL_FLAG) + SYMBOL_FLAG.length + 1, dataText.indexOf(SYMBOL_FLAG) + SYMBOL_FLAG.length + SYMBOL.length + 1);\n if (symbolTxt == SYMBOL) {\n const VALUE_FLAG = 'value=\"';\n dataText = dataText.substring(dataText.indexOf(VALUE_FLAG) + VALUE_FLAG.length);\n dataText = dataText.substring(0, dataText.indexOf('\"'));\n price = dataText;\n } else {\n dataText = dataText.substring(DATA_FLAG.length + SYMBOL_FLAG.length);\n }\n }\n \n let displayText = `\n ${SYMBOL}\n Price: ${price}\n `;\n\n if (ownedStonk()) {\n let stonk = ownedStonk();\n let formatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n});\n let daysSince = Math.round((Date.now() - stonk.date.getTime()) / 1000 / 60 / 60 / 24);\n let profit = (price - stonk.value) * stonk.spent / stonk.value;\n displayText += `\n Profit: ${ formatter.format( profit ) }\n That's ${ formatter.format( profit / daysSince ) } per day\n`.trim();\n }\n\n displayText = displayText.trim();\n display(displayText);\n\n function ownedStonk() {\n for (let i = 0; i < ownedStonks.length; i++) {\n if (ownedStonks[i].symbol === SYMBOL) {\n return ownedStonks[i];\n }\n }\n }\n\n}}","title":"Ticker Price","uid":"8221539677112051","url":"https://finance.yahoo.com/quote/NFLX"},{"active":false,"instructions":".xhr {{\n console.log(xhr.response);\n const MAX_STR_LENGTH = 450;\n let parser = new DOMParser();\n let xmlDoc = parser.parseFromString(xhr.response,\"text/html\");\n console.log(xmlDoc);\n\n let pEls = [...xmlDoc.getElementsByTagName('p')];\n let str;\n for (let i = 0; i < 25 && i < pEls.length && !str; i++) {\n let pEl = pEls[i].innerHTML.trim();\n if (pEl) {\n str = pEl;\n }\n }\n if (!str) {\n display('no good data xP');\n return;\n }\n\n while (str.includes('<')) {\n let start = str.indexOf('<');\n let end = str.indexOf('>', start);\n let replace = str.substring(start, end + 1);\n str = str.replaceAll(replace, '');\n }\n if (str.length > MAX_STR_LENGTH) {\n str = str.substring(0, MAX_STR_LENGTH);\n str += '....'\n }\n if (str.includes('Other reasons this message may be displayed:') || str.includes('may refer to:')) {\n display(`No results for ${getSearch()};\nhere's a cat instead`);\n playCatAnim();\n return;\n }\n // remove citations (of form [#] )\n str = str.replace(/\\[\\d+\\]/g, '');\n display(str);\n\n function getSearch() {\n return getUrl().substring('https://en.wikipedia.org/wiki/'.length);\n }\n function playCatAnim() {\n let style = document.createElement('style');\n style.style = 'display: none;';\n style.innerHTML = `\ncat {\n font-size: 20px;\n color: #11f;\n display: inherit;\n animation: dance 1s infinite ease-in-out;\n}\n\n@keyframes dance {\n from, to {\n transform: translateX(20px) rotateY(-10deg);\n }\n\n 50%{\n transform: translateX(40px) rotateY(20deg);\n }\n}\n`;\n let cat = document.createElement('cat');\n cat.innerText = '^w^';\n let div = document.createElement('div');\n div.append(style);\n div.append(cat);\n displayHTML(div.innerHTML);\n }\n}}","title":"Search Wikipedia","uid":"1357988140751051","url":"https://en.wikipedia.org/wiki/Dog"},{"active":false,"instructions":"// currently doesn't use right code :/\nlet url = 'https://avatars.dicebear.com/api/adventurer/' + randomCode() + '.svg';\nsetUrl(url);\n\n.xhr {{\n parser = new DOMParser();\n let xmlDoc = parser.parseFromString(xhr.response,\"text/xml\");\n displayHTML(xmlDoc.documentElement.outerHTML);\n display('Code: ' + getUrl().replace('https://avatars.dicebear.com/api/adventurer/', '').replace('.svg',''));\n}}\n\nfunction randomCode() {\n let chars = 'abcdefghijklm';\n let codeLength = Math.round(Math.random() * 20);\n let code = '';\n for (let i = 0; i < codeLength; i++) {\n code += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return code;\n}","title":"Get Neat Avatar","uid":"357968260173515","url":"https://avatars.dicebear.com/api/adventurer/abkmhjbbjhd.svg"},{"active":false,"instructions":" /*\n * Filter Stuff:\n */\n\n // change filter to whatever duration you want to see\n let filter = 'This year';\n\n const uploadDateFilters = [\n 'Last hour',\n 'Today',\n 'This week',\n 'This month',\n 'This year'\n ];\n const arrBuffCodes = [\n '\\x01',\n '\\x02',\n '\\x03',\n '\\x04',\n '\\x05',\n ]\n let arrBuffStart = '\\x12\\x06\\b';\n let arrBuffEnd = '\\x10\\x01\\x18\\x01';\n let encodedFilter = arrBuffStart + arrBuffCodes[uploadDateFilters.indexOf(filter)] + arrBuffEnd;\n encodedFilter = encodeURIComponent(encodeURIComponent(btoa(encodedFilter)));\n let url = getUrl();\n let flag = '&sp=';\n url = url.substring(0, url.indexOf(flag) + flag.length);\n setUrl(url + encodedFilter);\n console.log(getUrl());\n\n.xhr {{\n const EMBED = 'EMBED';\n const THUMBNAIL = 'THUMBNAIL';\n const DISPLAY_TYPE = EMBED;\n\n let response = xhr.response;\n let searchString = 'https://i.ytimg.com/vi/';\n let ytCodes = response.split(searchString);\n ytCodes.splice(0,1);\n for(let i = 0; i < ytCodes.length; i++) {\n ytCodes[i] = ytCodes[i].substring(0,ytCodes[i].indexOf('/')); \n }\n let ytCode = randomCode(ytCodes);\n if (DISPLAY_TYPE === EMBED) {\n createIframe(ytCode);\n } else {\n createThumbnailImg(ytCode);\n }\n\n function randomCode(ytCodes) {\n let index = Math.floor(Math.random() * ytCodes.length);\n return ytCodes[index];\n }\n \n function createIframe(ytCode) {\n let iframe = document.createElement('iframe');\n iframe.src= \"https://www.youtube.com/embed/\" + ytCode + '?autoplay=1';\n iframe.setAttribute('allow','accelerometer; autoplay; encrypted-media; fullscreen; gyroscope;');\n iframe.setAttribute('allowfullscreen', '');\n displayHTML(iframe.outerHTML);\n }\n\n function createThumbnailImg(ytCode) {\n let img = document.createElement('img');\n img.src = \"http://img.youtube.com/vi/\" + ytCode + \"/mqdefault.jpg\";\n wipeDisplay();\n getHtml().append(img);\n }\n\n}}","title":"YouTube Art TimeLapse","uid":"6741573365861041","url":"https://www.youtube.com/results?search_query=art+timelapse&sp=EgYIBRABGAE%253D"},{"active":false,"instructions":".xhr {{\n let obj = JSON.parse(xhr.responseText);\n\n let tracking = obj.data.trackings[0];\n\n let status = tracking.latest_status;\n let eta = tracking.estimated_delivery_date;\n\n let lastCheckpoint = tracking.checkpoints[tracking.checkpoints.length - 1];\n let lastCity = lastCheckpoint.address.city;\n let lastArrivalTime = lastCheckpoint.created_at;\n \n for (let i = 1; i < status.length; i++) {\n if (isUpperCase(status.charAt(i))) {\n status = status.substring(0, i) + ' ' + status.substring(i);\n i += 2;\n }\n }\n\n eta = getTimeText(eta);\n lastArrivalTime = getTimeText(lastArrivalTime);\n \n\n let displayText = \n`Status: ${status}\n ETA: ${eta}\n Last seen in ${lastCity}\n at ${lastArrivalTime}`;\n display(displayText);\n\n function isUpperCase(char) {\n return char === char.toUpperCase();\n }\n\n function getTimeText(time) {\n let date = new Date(time);\n return date.toLocaleString();\n }\n}}","title":"Package Status","uid":"4809708115249365","url":"https://track.aftership.com/api/v2/trackings?ids="}]}}}