Project Euler Problem Translator

Provides translations in Romanian, Russian, Korean and German for Project Euler problems

  1. /*******************************************************************************
  2. * Copyright (c) 2012 - 2016 Radu Murzea. All rights reserved.
  3. *
  4. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  6. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  7. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  8. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  9. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  10. * THE SOFTWARE.
  11. *
  12. *******************************************************************************/
  13. /*******************************************************************************
  14. * DESCRIPTION:
  15. *
  16. * This script is intended for use only on ProjectEuler.net and it was build to be used together
  17. * with Firefox's GreaseMonkey extension.
  18. *
  19. * It places 5 flags (British, Romanian, Russian, Korean and German) on top of every problem's page.
  20. * By clicking on the flag, the corresponding translation of a problem is retrieved.
  21. *
  22. * Obviously, not at all problems are available in the above mentioned languages. In this case, clicking on the flag will do nothing.
  23. *
  24. * Notes about implementation:
  25. *
  26. * - The technique used for implementing this is **JSONP** (JSON with padding), since AJAX wouldn't work (see Same Origin Policy).
  27. * - The processing function (only 2 - 3 lines of code) is found in the **processtranslation.js** file. That function will be executed when the response comes back.
  28. * - The 5 flag images are stored inside the script in Base64 format, to avoid additional HTTP requests.
  29. *
  30. * LIMITATIONS:
  31. *
  32. * - does not work on HTTPS version of ProjectEuler (Firefox 23+), unless you disable Mixed Active Content blocker
  33. * - for some unknown reason, it needs at least Firefox 9+ to work.
  34. *
  35. * The translations are parsed from the corresponding translations websites:
  36. *
  37. * - http://projecteuler.radumurzea.net/ for Romanian
  38. * - http://euler.jakumo.org/ for Russian,
  39. * - http://euler.synap.co.kr/ for Korean and
  40. * - http://projekteuler.de for German
  41. *
  42. * You can see a demo on how the script works in the video on this page: http://projecteuler.radumurzea.net/greasemonkey.php
  43. *
  44. * The script is also hosted here, for easier installation:
  45. *
  46. * - https://greasyfork.org/en/scripts/4899-project-euler-problem-translator
  47. * - https://openuserjs.org/scripts/SoboLAN/Project_Euler_Problem_Translator
  48. *
  49. *
  50. *******************************************************************************/
  51. /***************************************************
  52. *
  53. * Version 1.7 (24 September 2016)
  54. * - The domain name where the scripts and romanian translations live has been changed, so this new version updates them.
  55. * _______________________________
  56. *
  57. * Version 1.6 (15 June 2014)
  58. * - Since Firefox introduced the Mixed Active Content blocker in Firefox 23, this script will
  59. * only run when viewing problems in HTTP mode and it will fail in HTTPS. So it's now
  60. * disabled on HTTPS.
  61. * @see https://blog.mozilla.org/tanvi/2013/04/10/mixed-content-blocking-enabled-in-firefox-23/
  62. * A solution would be to buy a HTTPS certificate for my domain, but atm the costs are not justified.
  63. * _______________________________
  64. *
  65. * Version 1.5 (15 June 2014)
  66. * - Added translations in German.
  67. *_______________________________
  68. *
  69. * Version 1.4 (24 May 2014)
  70. * - Due to significant and frequent accessibility issues, support for Spanish translations is now
  71. * dropped.
  72. * _______________________________
  73. *
  74. * Version 1.3 (18 March 2013)
  75. * - support for Korean added. At this date, 110 problems are translated in this language.
  76. * _______________________________
  77. *
  78. * Version 1.2.5 (13 January 2013)
  79. * - the flags will no longer appear on the page exactly after
  80. * you enter a (correct or incorrect) answer. This issue existed because the URL remains
  81. * the same.
  82. * - a few minor changes
  83. * _______________________________
  84. *
  85. * Version 1.2 (28 December 2012)
  86. * - translations are now offered in Russian and Spanish as well. These translations are parsed from
  87. * euler.jakumo.org and euleres.tk, respectively. Because of this, additional roundtrips must be made to
  88. * retrieve these translations, which is why it will feel slower... sometimes very slow.
  89. * - some small changes here and there.
  90. * - the backend part has been changed from "read.php" to "getjsontranslation.php". Although the old version
  91. * is still functional, it is highly recommended to switch to the new one (spanish and russian are accessible
  92. * only in the new one). Please note that the old version will be taken out of rotation on the 20th of January.
  93. *
  94. * WARNING: I have no control over how many problems are accessible in the 2 new languages and the quality
  95. * of these translations. Any problem regarding these 2 languages (Russian and Spanish) should be directed
  96. * to their authors.
  97. *
  98. * WARNING: In my tests, the Spanish version would sometimes fail for some problems and then work again
  99. * a few minutes later. Apparently, this issue has something to do
  100. * with network connection timeouts (low quality hosting ?), so this is not a bug in the script
  101. * itself. Please do not report this as a bug.
  102. * _______________________________
  103. *
  104. * Version 1.0.2 (17 December 2012)
  105. * - script functionality was broken by some changes in
  106. * the HTML code on projecteuler.net that occured on 16 December 2012. This version
  107. * fixes this issue.
  108. * _______________________________
  109. *
  110. * Version 1.0.1 (22 September 2012)
  111. * - added some extra safety by checking that the parsing of
  112. * the problem's ID did not return NaN
  113. * _______________________________
  114. *
  115. * Version 1.0 (18 September 2012)
  116. * - initial release
  117. *
  118. ****************************************************/
  119.  
  120.  
  121. // ==UserScript==
  122. // @name Project Euler Problem Translator
  123. // @description Provides translations in Romanian, Russian, Korean and German for Project Euler problems
  124. // @author Radu Murzea
  125. // @version 1.7
  126. // @icon http://projecteuler.radumurzea.net/favicon.ico
  127. // @include http://projecteuler.net/problem=*
  128. // @grant none
  129. // @namespace https://greasyfork.org/users/5099
  130. // ==/UserScript==
  131.  
  132.  
  133.  
  134. function setNewTranslation(problem, lang)
  135. {
  136. var script = document.createElement('script');
  137. script.setAttribute('src', 'http://projecteuler.radumurzea.net/getjsontranslation.php?problem=' + problem + '&lang=' + lang);
  138. document.getElementsByTagName('head')[0].appendChild(script);
  139. }
  140.  
  141. function getProblemID()
  142. {
  143. var h3Nodes = document.getElementsByTagName('h3');
  144. for (var nodeIndex = 0; nodeIndex < h3Nodes.length; nodeIndex++) {
  145. var nodePieces = h3Nodes[nodeIndex].innerHTML.split(" ");
  146. if (nodePieces[0] === "Problem") {
  147. var problemID = parseInt(nodePieces[1]);
  148. return problemID;
  149. }
  150. }
  151. return -1;
  152. }
  153.  
  154. function getROFlag()
  155. {
  156. var RO = document.createElement("img");
  157. RO.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAALCAIAAAD5gJpuAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHd" +
  158. "hcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGBSURBVHjaYmTQPs7w6Q8DCDAxMLC8P2DOwcbA8I/hHxix/GD4pw3kIRBAALEwvPtT3aQIV" +
  159. "P7vH+O//0yc0hWsrD8ZGP78//8HRH75/T/mz//fv///AZFfNm0CCCAWBhYGhv8MT17//vvv/99/TP/+PWJg+P7//28o+vP7/+1f/3/9Aqp" +
  160. "mlJUF2gAQQCwgs/8zAFX/+QtCQIP///8FJn+DGP+Aqn9DNDD8/g3UABBALAx//oFV//vzhwGs4RfCeBAbRQPQdIAAYmH49Q+o7vef/zANv" +
  161. "5H0gBm/oE5i+PMHaANAAIE0/AUZ//8XUM9fBiQNYBLJSYxgJwEEEEjD778Mv/6A9Pz+wwB1BpoNYOOBbgAGHEAAsTD8BNL/gJqBrvr9lxF" +
  162. "JA8QGsIY/QA1/Gf7+BfoBIICAofQHqFRShBXkjb/MTEzSDAzfGBmB/gMa95uB5Q+D0h+QUjACOgkggBgZGLYyMPwCS4Nc+HxvMAsLw78/4" +
  163. "HgFkh8Y/oVD4xgCAAIMACetb51Fz+5FAAAAAElFTkSuQmCC";
  164. RO.alt = "Romania";
  165. RO.title = "Romanian";
  166. RO.style.cursor = "pointer";
  167. RO.onclick = function() {
  168. var problemID = getProblemID();
  169. if (! isNaN(problemID) && problemID !== -1) {
  170. setNewTranslation(problemID, "ro");
  171. }
  172. };
  173.  
  174. return RO;
  175. }
  176.  
  177. function getDEFlag()
  178. {
  179. var DE = document.createElement("img");
  180. DE.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAALCAIAAAD5gJpuAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHd" +
  181. "hcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGzSURBVHjaYvTxcWb4+53h3z8GZpZff/79+v3n/7/fDAz/GHAAgABi+f37e3FxOZD1Dwz+/" +
  182. "v3z9y+E/AMFv3//+Qumfv9et241QACxMDExAVWfOHkJJAEW/gUEP0EQDn78+AHE/gFOQJUAAcQiy8Ag8O+fLFj1n1+/QDp+/gQioK7fP37" +
  183. "8+vkDqOH39x9A/RJ/gE5lAAhAYhzcAACCQBDkgRXRjP034R0IaDTZTFZn0DItot37S94KLOINerEcI7aKHAHE8v/3r/9//zIA1f36/R+o4" +
  184. "tevf1ANYNVA9P07RD9IJQMDQACxADHD3z8Ig4GMHz+AqqHagKp//fwLVA0U//v7LwMDQACx/LZiYFD7/5/53/+///79BqK/EMZ/UPACSYa" +
  185. "/v/8DyX9A0oTxx2EGgABi+a/H8F/m339BoCoQ+g8kgRaCQvgPJJiBYmAuw39hxn+uDAABxMLwi+E/0PusRkwMvxhBGoDkH4b/v/+D2EDyz" +
  186. "///QB1/QLb8+sP0lQEggFh+vGXYM2/SP6A2Zoaf30Ex/J+PgekHwz9gQDAz/P0FYrAyMfz7wcDAzPDtFwNAgAEAd3SIyRitX1gAAAAASUV" +
  187. "ORK5CYII=";
  188. DE.alt = "Germany";
  189. DE.title = "German";
  190. DE.style.cursor = "pointer";
  191. DE.onclick = function() {
  192. var problemID = getProblemID();
  193. if (! isNaN(problemID) && problemID !== -1) {
  194. setNewTranslation(problemID, "de");
  195. }
  196. };
  197.  
  198. return DE;
  199. }
  200.  
  201. function getKRFlag()
  202. {
  203. var KR = document.createElement("img");
  204. KR.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAALCAIAAAD5gJpuAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHd" +
  205. "hcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHDSURBVHjaYjSs/f/lBwME/Pn379cfIMnw6xfDrz9A9r/fIA4SYmMACCDGgzf/q4iBlf///" +
  206. "5+B4d9/KPMfCIMY/xn+//sH4f4/duMLQAAxfmRgZO/v+/fiFcNfkJkMLEz/v3wB6fn95//fPyDy9+9/f37///WbSUry+ZzZAAHEApRifPW" +
  207. "KiYmBOSiEUV6e8efPX6tX/9m9m+HXb4bfv0Do129GoBN//2b49YOJgQEggJj+AZ3x9y+zv/+/W7f+P7j/a8cO5qCg/2xs/379AqK/P3/9/" +
  208. "QVCf4Dc30DdDAABBNLA8Ocvg6gIk77+z1Wrmays/vPwMIiI/P8N0gB0z3+wTiD5/8+fPwwMAAHEBHIu0K0vXv7evIklIODP9u0M37//e/7" +
  209. "838+fIEU/f0JVg20AKgYIIKAfGBiBdi1ZwpaY+F9SgkVN7Wdt7f83bxjBZgOdDvEA0HgmIGJgAAggFqAt/3h4/j169K29AxRQwOD78pWBi" +
  210. "+s/K+s/sDpwKAFj588/QUFghAEEEMups9+1pFlAgQ0Nc0iog6MCLAQR/weSY9hx6jVAADEyx3/9+wEWkcB4BRryC4kLj+l/QDYDAx8DQIA" +
  211. "BAA2EWORnICKSAAAAAElFTkSuQmCC";
  212. KR.alt = "Korea";
  213. KR.title = "Korean";
  214. KR.style.cursor = "pointer";
  215. KR.onclick = function() {
  216. var problemID = getProblemID();
  217. if (! isNaN(problemID) && problemID !== -1) {
  218. setNewTranslation(problemID, "kr");
  219. }
  220. };
  221. return KR;
  222. }
  223.  
  224. function getRUFlag()
  225. {
  226. var RU = document.createElement("img");
  227. RU.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAALCAIAAAD5gJpuAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHd" +
  228. "hcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAE2SURBVHjaYvz69T8DAvz79w9CQVj/0MCffwwAAcQClObiAin6/x+okxHMgPCAbOb//5n+I" +
  229. "4EXL74ABBALxGSwagTjPzbAyMgItAQggBg9Pf9nZPx//x7kjL9////9C2QAyf9//qCQQCQkxFhY+BEggFi2b/+nq8v46BEDSPQ3w+8//3/" +
  230. "/BqFfv9BJeXmQEwACCOSkP38YgHy4Bog0RN0vIOMXVOTPH6Cv/gEEEEgDxFKgHEgDXCmGDUAE1AAQQCybGZg1f/d8//XsH0jTn3+///z79" +
  231. "RtE/v4NZfz68xfI/vOX+4/0ZoZFAAHE4gYMvD+3/v2+h91wCANo9Z+/jH9VxBkYAAKIBRg9TL//MEhKAuWAogxgZzGC2CCfgUggAoYdGAE" +
  232. "VAwQQ41egu5AQAyoXTQoIAAIMAD+JZR7YOGEWAAAAAElFTkSuQmCC";
  233. RU.alt = "Russia";
  234. RU.title = "Russian";
  235. RU.style.cursor = "pointer";
  236. RU.onclick = function() {
  237. var problemID = getProblemID();
  238. if (! isNaN(problemID) && problemID !== -1) {
  239. setNewTranslation(problemID, "ru");
  240. }
  241. };
  242. return RU;
  243. }
  244.  
  245. function getUKFlag()
  246. {
  247. var UK = document.createElement("img");
  248. UK.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAALCAIAAAD5gJpuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJ" +
  249. "lYWR5ccllPAAAAflJREFUeNpinDRzn5qN3uFDt16+YWBg+Pv339+KGN0rbVP+//2rW5tf0Hfy/2+mr99+yKpyOl3Ydt8njEWIn8f9zj639" +
  250. "NC7j78eP//8739GVUUhNUNuhl8//ysKeZrJ/v7z10Zb2PTQTIY1XZO2Xmfad+f7XgkXxuUrVB6cjPVXef78JyMjA8PFuwyX7gAZj97+T2e" +
  251. "9o3d4BWNp84K1NzubTjAB3fH0+fv6N3qP/ir9bW6ozNQCijB8/8zw/TuQ7r4/ndvN5mZgkpPXiis3Pv34+ZPh5t23//79Rwehof/9/NDEg" +
  252. "MrOXHvJcrllgpoRN8PFOwy/fzP8+gUlgZI/f/5xcPj/69e/37//AUX+/mXRkN555gsOG2xt/5hZQMwF4r9///75++f3nz8nr75gSms82jf" +
  253. "vQnT6zqvXPjC8e/srJQHo9P9fvwNtAHmG4f8zZ6dDc3bIyM2LTNlsbtfM9OPHH3FhtqUz3eXX9H+cOy9ZMB2o6t/Pn0DHMPz/b+2wXGTvP" +
  254. "lPGFxdcD+mZyjP8+8MUE6sa7a/xo6Pykn1s4zdzIZ6///8zMGpKM2pKAB0jqy4UE7/msKat6Jw5mafrsxNtWZ6/fjvNLW29qv25pQd///n" +
  255. "+5+/fxDDVbcc//P/zx/36m5Ub9zL8+7t66yEROcHK7q5bldMBAgwADcRBCuVLfoEAAAAASUVORK5CYII=";
  256. UK.alt = "United Kingdom";
  257. UK.title = "British English";
  258. UK.style.cursor = "pointer";
  259. UK.onclick = function() {
  260. var problemID = getProblemID();
  261. if (! isNaN(problemID) && problemID !== -1) {
  262. setNewTranslation(problemID, "en");
  263. }
  264. };
  265. return UK;
  266. }
  267.  
  268. function insertFlags()
  269. {
  270. var UK = getUKFlag(); //UK
  271. var RO = getROFlag(); //Romania
  272. var RU = getRUFlag(); //Russia
  273. var KR = getKRFlag(); //Korea
  274. var DE = getDEFlag(); //Germany
  275. var flagsParagraph = document.createElement("p");
  276. UK.style.marginRight = "12px";
  277. RO.style.marginRight = "12px";
  278. RU.style.marginRight = "12px";
  279. KR.style.marginRight = "12px";
  280. flagsParagraph.appendChild(UK);
  281. flagsParagraph.appendChild(RO);
  282. flagsParagraph.appendChild(RU);
  283. flagsParagraph.appendChild(KR);
  284. flagsParagraph.appendChild(DE);
  285. flagsParagraph.style.display = "block";
  286. flagsParagraph.style.marginLeft = "auto";
  287. flagsParagraph.style.marginRight = "auto";
  288. flagsParagraph.style.textAlign = "center";
  289. // reference node
  290. var refNode = document.getElementById("content");
  291. // insert before
  292. refNode.parentNode.insertBefore(flagsParagraph, refNode);
  293. }
  294.  
  295. function insertTranslationProcessing()
  296. {
  297. var pscript = document.createElement('script');
  298. pscript.setAttribute('type', 'text/javascript');
  299. pscript.setAttribute('src', 'https://raw.githubusercontent.com/SoboLAN/projecteuler-translation-script/master/processtranslation.js');
  300. var bodyElement = document.getElementsByTagName('body')[0];
  301. bodyElement.insertBefore(pscript, bodyElement.firstChild);
  302. }
  303.  
  304. var problemID = getProblemID();
  305.  
  306. if (! isNaN(problemID) && problemID !== -1) {
  307. insertFlags();
  308. insertTranslationProcessing();
  309. }