DripStat DropOut

Calculates stats in DripStat, and provides a control panel for automation.

当前为 2014-08-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DripStat DropOut
  3. // @namespace anonycat
  4. // @version 0.9.260
  5. // @description Calculates stats in DripStat, and provides a control panel for automation.
  6. // @match https://dripstat.com/game/
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10. //Throttle auto purchases to one every 3 seconds, to minimize risk of desyncs with the server
  11. var lastBuy = 0;
  12.  
  13. //Track how many manual clicks have been made by second over the last 60 seconds
  14. var clickHistory = [];
  15. while (lastBuy < 60)
  16. {clickHistory[lastBuy++] = 0;}
  17.  
  18. //Convert upgrade indices to their order in the shop
  19. var upgIndex = [1,1,1,1,1,1,1,1,1,1,1];
  20.  
  21. var cache=[0,0,0,0,0,0];
  22. var oldByteCount = 0;
  23. var first = 1;
  24.  
  25. function byteConvert(val)
  26. {
  27. if(val < 1000)
  28. return +val.toFixed(2)+" B";
  29. else
  30. return NumUtils.byteConvert(val,2);
  31. }
  32.  
  33. function byteConvert2(val)
  34. {
  35. if(val < 1000)
  36. return val.toFixed(0)+" B";
  37. else
  38. return NumUtils.byteConvert(val,2);
  39. }
  40.  
  41. function loop()
  42. {
  43. if(typeof(localStats) == "undefined")
  44. return;
  45. var powerupCounter = 1;
  46. var mult = 0;
  47. var multm = 0;
  48. var bpc = CoffeeCup.calcBytesPerClick();
  49. var bpcBoosts = localStats.powerUps[0].purchasedUpgrades.length;
  50. var bpsDiff = localStats.byteCount - oldByteCount;
  51. if(first)
  52. {
  53. first=0;
  54. init();
  55. }
  56. else
  57. {
  58. if(oldByteCount)
  59. {
  60. clickHistory.pop();
  61. clickHistory.unshift(Math.round(Math.max(0,(bpsDiff - localStats.bps)/bpc)));
  62. }
  63. //Check for any changes in the control panel and save the new values if found.
  64. if(localStats.dropout.autoBuy != cache[0])
  65. {
  66. cache[0]=localStats.dropout.autoBuy;
  67. GM_setValue("ab",cache[0]+1);
  68. }
  69. if(localStats.dropout.autoClick != cache[1])
  70. {
  71. cache[1]=localStats.dropout.autoClick;
  72. GM_setValue("ac",cache[1]+1);
  73. }
  74. if(localStats.dropout.autoDrip != cache[2])
  75. {
  76. cache[2]=localStats.dropout.autoDrip;
  77. GM_setValue("ad",cache[2]+1);
  78. }
  79. if(localStats.dropout.clickRate != cache[3])
  80. {
  81. cache[3]=localStats.dropout.clickRate;
  82. GM_setValue("cr",cache[3]+1);
  83. }
  84. if(localStats.dropout.cupmultl != cache[4])
  85. {
  86. cache[4]=localStats.dropout.cupmultl;
  87. GM_setValue("ml",cache[4]+1);
  88. }
  89. if(localStats.dropout.cupmultm != cache[5])
  90. {
  91. cache[5]=localStats.dropout.cupmultm;
  92. GM_setValue("mm",cache[5]+1);
  93. }
  94. }
  95. var avg10 = 0;
  96. var avg60 = 0;
  97. for(var a = 0; a < 60; a++)
  98. {
  99. avg60 += clickHistory[a];
  100. if(a<10)
  101. avg10 += clickHistory[a];
  102. }
  103. avg10 /= 10;
  104. avg60 /= 60;
  105. if (localStats.dropout.autoClick)
  106. {
  107. multm = localStats.dropout.cupmultm;
  108. mult = Math.min(20-clickHistory[0],Math.floor(Math.random()*(2 * multm - localStats.dropout.cupmultl)+localStats.dropout.cupmultl));
  109. if(mult)
  110. localStats.byteCount += bpc * mult;
  111. if(localStats.byteCount >= localStats.memoryCapacity)
  112. localStats.byteCount = localStats.memoryCapacity;
  113. }
  114. var bps = bpc * localStats.dropout.clickRate * (avg60 + multm) + localStats.bps;
  115. if (localStats.dropout.autoDrip && localStats.byteCount == localStats.memoryCapacity)
  116. dripper.dripGlobal();
  117. //Upgrades aren't necessarily in order, so untangle their order first
  118. $(".upgcontainer").each(function(upg) {
  119. if(this.children[0].className == "item")
  120. {
  121. var pos = Number(this.children[0].style.backgroundPosition.split(' ')[1].split('px')[0]) / -50;
  122. upgIndex[pos] = upg+1;
  123. if($(this).find('.upgROI').length==0)
  124. $(this).append("<div class='upgROI'></div>");
  125. }
  126. })
  127. var data = Array();
  128. var upgdata = [1,1,1,1,1,1,1,1,1,1,1];
  129. var min = 1e+38;
  130. var bytesNeeded=0;
  131. var minObj = {};
  132. localStats.powerUps.slice(0).forEach(function(powerUp) {
  133. powerUp.position = "pu"+powerupCounter;
  134. var hasUpgrade = false;
  135. //Don't calculate ROI on upgrades that have zero powerups fueling them
  136. if(powerUp.count)
  137. powerUp.upgrades.forEach(function(upgrade) {
  138. if(hasUpgrade)
  139. return;
  140. hasUpgrade = true;
  141. upgrade.position = "upg"+upgIndex[powerupCounter-1];
  142. //Let's see which upgrade provides the biggest bang for the buck
  143. //(computed as "time taken before this upgrade will recoup its own cost").
  144. //If the price is so high that the current buffer can't possibly hold enough
  145. //(even if we cashed out for more space right now),
  146. //the "real" price includes what it takes to earn that extra buffer space.
  147. //If there's an object we can afford right now,
  148. //which will pay itself back in 2 hours,
  149. //and another object that would nominally pay itself back in 1h50m,
  150. //except that we can't afford it for 20 more minutes,
  151. //we should account for that in the time before recouping.
  152. //Add the time spent waiting to accrue sufficient funds.
  153. //Oh, and if we need 100MB for something, but can only hold 80MB
  154. //(with 70MB of it filled already), we can't just drip 20MB and keep the rest.
  155. //We have to drip everything at once, shooting all the way to 150MB.
  156. //Thus we can't make any progress on affording the item until a drip,
  157. //and then it costs a full additional 100MB after starting from scratch.
  158.  
  159. if(upgrade.price > localStats.byteCount + localStats.memoryCapacity)
  160. bytesNeeded = 2 * upgrade.price - (localStats.memoryCapacity + localStats.byteCount);
  161. else if(upgrade.price > localStats.memoryCapacity)
  162. bytesNeeded = upgrade.price;
  163. else if(upgrade.price > localStats.byteCount)
  164. bytesNeeded = upgrade.price - localStats.byteCount;
  165. else
  166. bytesNeeded = 0;
  167. //Cursor upgrades boost clicking too, so if autoclicks are on, take the rate
  168. //and overall BPS into account when determining its value.
  169. if(powerupCounter == 1)
  170. upgrade.value = upgrade.price/((powerUp.totalBps * (1 + localStats.dropout.clickRate * (avg60 + multm) * bpcBoosts * 0.1) + localStats.dropout.clickRate * (avg60 + multm) * bpc) / 10) + bytesNeeded / bps;
  171. else
  172. upgrade.value = upgrade.price/(powerUp.totalBps * (0.1 + localStats.dropout.clickRate * (avg60 + multm) * bpcBoosts * 0.01)) + bytesNeeded / bps;
  173. min = Math.min(min, upgrade.value);
  174. if(upgrade.value == min)
  175. minObj = upgrade;
  176. upgdata[upgIndex[powerupCounter-1]-1]=upgrade.value;
  177. });
  178. powerupCounter++;
  179. //Same procedure on the main power-ups themselves.
  180. if(powerUp.currentPrice > localStats.byteCount + localStats.memoryCapacity)
  181. bytesNeeded = 2 * powerUp.currentPrice - (localStats.memoryCapacity + localStats.byteCount);
  182. else if(powerUp.currentPrice > localStats.memoryCapacity)
  183. bytesNeeded = powerUp.currentPrice;
  184. else if(powerUp.currentPrice > localStats.byteCount)
  185. bytesNeeded = powerUp.currentPrice - localStats.byteCount;
  186. else
  187. bytesNeeded = 0;
  188. powerUp.value = powerUp.currentPrice/(powerUp.currentBps * (1 + localStats.dropout.clickRate * (avg60 + multm) * bpcBoosts * 0.1)) + bytesNeeded / bps;
  189. data.push(powerUp.value);
  190. if(!(powerUp.name == "Spring Framework" && springPowerup.isLocked))
  191. {
  192. min = Math.min(min, powerUp.value);
  193. if(powerUp.value == min)
  194. minObj = powerUp;
  195. }
  196. });
  197. $('.storeItem, .upgcontainer').css('background-color', '');
  198. var selector = minObj.position;
  199. $("#"+selector).css('background-color', '#B2EDED');
  200. $('.storeItem').each(function(index){
  201. if($(this).find('.storeROI').length==0)
  202. $(this).html("<div class='storeItemAmount'>"+localStats.powerUps[index].count+"</div>"
  203. +"<div class='storeItemName'>"+localStats.powerUps[index].name+"</div>"
  204. +"<div class='storePriceRow'>"
  205. +"<div class='storePrice'>"+byteConvert2(localStats.powerUps[index].currentPrice)+"</div>"
  206. +"<div class='storeROI'>("+String(data[index]).toHHMMSS()+")</div></div>"
  207. +"<div class='powerup-one'>"+byteConvert(localStats.powerUps[index].currentBps)+"ps each</div>"
  208. +"<div class='powerup-all'>"+byteConvert2(localStats.powerUps[index].totalBps)+"ps total</div>");
  209. else
  210. {
  211. $(this).find('.storeROI').html("("+String(data[index]).toHHMMSS()+")");
  212. $(this).find('.powerup-one').html(byteConvert(localStats.powerUps[index].currentBps)+'ps each');
  213. $(this).find('.powerup-all').html(byteConvert2(localStats.powerUps[index].totalBps)+'ps total');
  214. }
  215. });
  216. $('.upgROI').each(function(index){
  217. $(this).html(String(upgdata[index]).toHHMMSS());
  218. });
  219. var label = minObj.name;
  220. if(minObj.powerup) //Is our best deal an upgrade or a powerup? They use different syntax.
  221. {
  222. label = "<span style='color:#F00'>"+label+"</span>";
  223. var price = minObj.price;
  224. }
  225. else
  226. var price = minObj.currentPrice;
  227. var limitTime = Number((localStats.memoryCapacity - localStats.byteCount)/bps).toFixed(0);
  228. var limitstr = "";
  229. if(price > localStats.byteCount + localStats.memoryCapacity)
  230. {
  231. var time = Number((2 * price - (localStats.memoryCapacity + localStats.byteCount))/bps).toFixed(0);
  232. if(localStats.memoryCapacity==localStats.byteCount)
  233. limitstr = " (Drip NOW!)";
  234. }
  235. else if(price > localStats.memoryCapacity)
  236. {
  237. var time = Number(price/bps).toFixed(0);
  238. limitstr = " (Drip NOW!)";
  239. if(localStats.dropout.autoDrip >= 2)
  240. dripper.dripGlobal();
  241. }
  242. else
  243. var time = Number((price - localStats.byteCount)/bps).toFixed(0);
  244. //Now to fill the control panel.
  245. $("#next-purchase-label").html("Next purchase: <strong>"+label+"</strong>");
  246. $("#next-purchase-payback").html("Pays for itself in "+String(minObj.value).toHHMMSS());
  247. if(time <= 0)
  248. $("#next-purchase-time").html("Affordable now");
  249. else
  250. $("#next-purchase-time").html("Affordable in "+String(time).toHHMMSS()+limitstr);
  251. if(limitTime <= 0)
  252. $("#max-space-label").html("Capacity is maxed out!");
  253. else
  254. $("#max-space-label").html("Capacity maxes out in "+String(limitTime).toHHMMSS());
  255. $("#click-rate-10").html(String(avg10.toFixed(1)));
  256. $("#click-rate-60").html(String(avg60.toFixed(1)));
  257. if(localStats.dropout.autoBuy && price<=localStats.byteCount && lastBuy >= 3)
  258. {
  259. minObj.buy(localStats);
  260. lastBuy = 0;
  261. }
  262. else if (lastBuy < 3)
  263. lastBuy += 1;
  264. if(springPowerup.isLocked && mine.beanCount > 0 && AnonymousUserManager.canGrabBean() && localStats.byteCount > 0)
  265. {
  266. if($('.vex').length)
  267. vex.closeAll();
  268. Mine.onGrab();
  269. }
  270. if($("#networkError")[0].style['cssText'] == "display: block;")
  271. window.location.reload(false);
  272. oldByteCount = localStats.byteCount;
  273. }
  274.  
  275. function init()
  276. {
  277. localStats.dropout = new Object;
  278. //Should powerups and upgrades be automatically purchased as they become affordable?
  279. //(As of level 5, also includes facilities for grabbing spring beans that appear)
  280. localStats.dropout.autoBuy = GM_getValue("ab",1)-1;
  281. //Should the BPS rate be increased to simulate automatic cup clicks?
  282. localStats.dropout.autoClick = GM_getValue("ac",1)-1;
  283. //Should memory automatically be dripped?
  284. //0 = no auto-drip, 1 = auto-drip when buffer is full, 2 = auto-drip as needed to create enough space to pay for upgrades
  285. localStats.dropout.autoDrip = GM_getValue("ad",1)-1;
  286.  
  287. //Should we take manual clicks into account when figuring out the payback rate of powerups?
  288. localStats.dropout.clickRate = GM_getValue("cr",2)-1;
  289.  
  290. //If autoclicking is enabled, each second will pick a random multiplier and count off that many cup clicks.
  291. //A multiplier of 0 means no clicking, only natural BPS intake.
  292. //Multipliers greater than 20 are rejected by the server, so we won't ever generate such a thing here.
  293. //Lowest possible multiplier to select
  294. localStats.dropout.cupmultl = GM_getValue("ml",1)-1;
  295. //Average multiplier
  296. localStats.dropout.cupmultm = GM_getValue("mm",6)-1;
  297. //There is no variable for the highest multiplier; it's automatically figured as 2*Middle - Low (but capped at 20).
  298. //zero-valued options don't always store correctly...solution, store X+1!
  299. cache=[localStats.dropout.autoBuy, localStats.dropout.autoClick, localStats.dropout.autoDrip, localStats.dropout.clickRate, localStats.dropout.cupmultl, localStats.dropout.cupmultm];
  300. GM_setValue("ab",cache[0]+1);
  301. GM_setValue("ac",cache[1]+1);
  302. GM_setValue("ad",cache[2]+1);
  303. GM_setValue("cr",cache[3]+1);
  304. GM_setValue("ml",cache[4]+1);
  305. GM_setValue("mm",cache[5]+1);
  306. //string (int) seconds to formatted time
  307. String.prototype.toHHMMSS = function () {
  308. var seconds = parseInt(this, 10); // don't forget the second param
  309. if(seconds <= 0)
  310. return "no time";
  311. var days = Math.floor(seconds / 86400);
  312. seconds -= days*86400;
  313. var hours = Math.floor(seconds / 3600);
  314. seconds -= hours*3600;
  315. var minutes = Math.floor(seconds / 60);
  316. seconds -= minutes*60;
  317. if (hours < 10 && days) {hours = "0"+hours;}
  318. if (minutes < 10 && hours) {minutes = "0"+minutes;}
  319. if (seconds < 10) {seconds = "0"+seconds;}
  320. //NOTE: this output contains zero-width spaces before each colon, mostly to fit in upgrade boxes
  321. if(days)
  322. return days+"d "+hours+"​:"+minutes+"​:"+seconds;
  323. else if(hours)
  324. return hours+"​:"+minutes+"​:"+seconds;
  325. else
  326. return minutes+"​:"+seconds;
  327. }
  328. //function to update the control panel
  329. localStats.dropout.updatehud = function(type) {
  330. if(type & 1)
  331. {
  332. if(this.autoBuy)
  333. {
  334. $(".apn").css('background-color', '');
  335. $(".apy").css('background-color', '#AFA');
  336. }
  337. else
  338. {
  339. $(".apy").css('background-color', '');
  340. $(".apn").css('background-color', '#FAA');
  341. }
  342. }
  343. if(type & 2)
  344. {
  345. if(this.autoClick)
  346. {
  347. $(".acn").css('background-color', '');
  348. $(".acy").css('background-color', '#AFA');
  349. }
  350. else
  351. {
  352. $(".acy").css('background-color', '');
  353. $(".acn").css('background-color', '#FAA');
  354. }
  355. }
  356. if(type & 4)
  357. {
  358. if(this.autoDrip==2)
  359. {
  360. $(".drip0").css('background-color', '');
  361. $(".drip1").css('background-color', '');
  362. $(".drip2").css('background-color', '#AFA');
  363. }
  364. else if(this.autoDrip)
  365. {
  366. $(".drip2").css('background-color', '');
  367. $(".drip0").css('background-color', '');
  368. $(".drip1").css('background-color', '#AAF');
  369. }
  370. else
  371. {
  372. $(".drip2").css('background-color', '');
  373. $(".drip1").css('background-color', '');
  374. $(".drip0").css('background-color', '#FAA');
  375. }
  376. }
  377. if(type & 8)
  378. {
  379. if(this.clickRate)
  380. {
  381. $(".crn").css('background-color', '');
  382. $(".cry").css('background-color', '#AFA');
  383. }
  384. else
  385. {
  386. $(".cry").css('background-color', '');
  387. $(".crn").css('background-color', '#FAA');
  388. }
  389. }
  390. if(type & 16)
  391. $("#multl").html("Min. Rate: "+String(this.cupmultl));
  392. if(type & 32)
  393. $("#multm").html("Avg. Rate: "+String(this.cupmultm));
  394. }
  395. //Create the control panel with divs
  396. $('#bpsChartContainer').parent().append("<table style='width:100%; height:105px; line-height:1.3; border-collapse: collapse'><tr>"
  397. +"<td rowspan=2 style='width:33%; border: 2px solid black'><div id='next-purchase-container'></div></td>"
  398. +"<td colspan=2 style='width:12%; height:35px; border: 2px solid black; border-bottom: none' class='apy apn' onclick='localStats.dropout.autoBuy = 1 - localStats.dropout.autoBuy; localStats.dropout.updatehud(1)'>Auto Buy</td>"
  399. +"<td colspan=3 style='width:18%; border: 2px solid black; border-bottom: none' class='drip0 drip1 drip2' onclick='localStats.dropout.autoDrip = (1 + localStats.dropout.autoDrip) % 3; localStats.dropout.updatehud(4)'>Auto Drip</td>"
  400. +"<td colspan=2 style='width:12%; border: 2px solid black; border-bottom: none' class='acy acn' onclick='localStats.dropout.autoClick = 1 - localStats.dropout.autoClick; localStats.dropout.updatehud(2)'>Auto Click</td>"
  401. +"<td style='width:15%; border: 2px solid black; border-right:1px solid black'> Auto Click <div id='multl'></div></td>"
  402. +"<td style='width:5%; border-top: 2px solid black; border-bottom: 2px solid black; background-color: #AFA' onclick='localStats.dropout.cupmultl = Math.min(localStats.dropout.cupmultl + 1, localStats.dropout.cupmultm); localStats.dropout.updatehud(16)'> + </td>"
  403. +"<td style='width:5%; border: 2px solid black; border-left: 1px solid black; background-color: #FAA' onclick='localStats.dropout.cupmultl = Math.max(localStats.dropout.cupmultl - 1, 0); localStats.dropout.updatehud(16)'> - </td></tr>"
  404. +"<tr><td style='width:6%; height:35px; border: 2px solid black; border-top: 1px solid black' class='apn' onclick='localStats.dropout.autoBuy = 0; localStats.dropout.updatehud(1)'> Off </td>"
  405. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='apy' onclick='localStats.dropout.autoBuy = 1; localStats.dropout.updatehud(1)'> On </td>"
  406. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='drip0' onclick='localStats.dropout.autoDrip = 0; localStats.dropout.updatehud(4)'> Never </td>"
  407. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='drip1' onclick='localStats.dropout.autoDrip = 1; localStats.dropout.updatehud(4)'> At <br /> Limit </td>"
  408. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='drip2' onclick='localStats.dropout.autoDrip = 2; localStats.dropout.updatehud(4)'> For <br /> Costs </td>"
  409. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='acn' onclick='localStats.dropout.autoClick = 0; localStats.dropout.updatehud(2)'> Off </td>"
  410. +"<td style='width:6%; border: 2px solid black; border-top: 1px solid black' class='acy' onclick='localStats.dropout.autoClick = 1; localStats.dropout.updatehud(2)'> On </td>"
  411. +"<td style='width:15%; border: 2px solid black; border-right:1px solid black'> Auto Click <div id='multm'></div></td>"
  412. +"<td style='width:5%; border-top: 2px solid black; border-bottom: 2px solid black; background-color: #AFA' onclick='localStats.dropout.cupmultm = Math.min(localStats.dropout.cupmultm + 1, 20); localStats.dropout.updatehud(32)'> + </td>"
  413. +"<td style='width:5%; border: 2px solid black; border-left: 1px solid black; background-color: #FAA' onclick='localStats.dropout.cupmultm = Math.max(localStats.dropout.cupmultm - 1, localStats.dropout.cupmultl); localStats.dropout.updatehud(32)'> - </td></tr>"
  414. +"<tr><td style='height:35px; border: 2px solid black; border-right: none'> Average Click Rate - Last 10s: </td>"
  415. +"<td style='border: 2px solid black; border-left: none'><strong><div id='click-rate-10'></div></strong></td>"
  416. +"<td colspan=2 style='border: 2px solid black; border-right: none'> Last 60s: </td>"
  417. +"<td style='border: 2px solid black; border-left: none'><strong><div id='click-rate-60'></div></strong></td>"
  418. +"<td colspan=4 style='border: 2px solid black; border-right: none' class='cry crn' onclick='localStats.dropout.clickRate = 1 - localStats.dropout.clickRate; localStats.dropout.updatehud(8)'> Take click rate into account? </td>"
  419. +"<td style='border: 2px solid black; border-left: 1px solid black; border-right: 1px solid black' class='cry' onclick='localStats.dropout.clickRate = 1; localStats.dropout.updatehud(8)'> Yes </td>"
  420. +"<td style='border: 2px solid black; border-left: none' class='crn' onclick='localStats.dropout.clickRate = 0; localStats.dropout.updatehud(8)'> No </td></tr></table>");
  421. $("#next-purchase-container").html("<div id='next-purchase-label'></div><div id='next-purchase-payback'></div><div id='next-purchase-time'></div><div id='max-space-label'></div>");
  422. $("head").append("<style id='tweaks'></style>");
  423. $("#tweaks").text('#upgrades .item {height: 50px}'
  424. +'#bpsChartContainer {padding-bottom: 2px}'
  425. +'#upgrades {height: 85px; line-height: 1.2}'
  426. +'#upgrades .upgcontainer {height: 85px; overflow-y: hidden}'
  427. +'#upgrades .upgROI {font-weight: bolder; text-align: center; color:#F00}'
  428. +'.storeItem {position: relative}'
  429. +'.storeItemName {font-size: 18px}'
  430. +'.storePriceRow {display: table}'
  431. +'.storeROI {display: table-cell; padding-left: 4px; font-size: 0.9em; font-weight: bolder; color: #F00}'
  432. +'.powerup-one {position: absolute; text-align: right; font-weight: bolder; font-size: 18px; top: 1px; right: 67px}'
  433. +'.powerup-all {position: absolute; text-align: right; font-weight: bolder; font-size: 18px; top: 26px; right: 70px; color: #BD511E}');
  434. localStats.dropout.updatehud(63);
  435. }
  436.  
  437. //Reimplementing these functions at the script level, because otherwise we lose "@grant none" and its scoping.
  438. //Code snippets courtesy of Anthony Lieuallen.
  439. const __GM_STORAGE_PREFIX = [
  440. '', GM_info.script.namespace, GM_info.script.name, ''].join('***');
  441.  
  442. function GM_getValue(aKey, aDefault) {
  443. 'use strict';
  444. let val = localStorage.getItem(__GM_STORAGE_PREFIX + aKey)
  445. if (null === val && 'undefined' != typeof aDefault) return aDefault;
  446. return val;
  447. }
  448.  
  449. function GM_setValue(aKey, aVal) {
  450. 'use strict';
  451. localStorage.setItem(__GM_STORAGE_PREFIX + aKey, aVal);
  452. }
  453.  
  454. setInterval(function(){loop();}, 1000);