Sorryops

Collect and reuse ORIOKS test answers

当前为 2024-05-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Sorryops
  3. // @name:ru Сориупс
  4. // @namespace https://git.disroot.org/electromagneticcyclone/sorryops
  5. // @version 20240502.3
  6. // @description Collect and reuse ORIOKS test answers
  7. // @description:ru Скрипт для сбора и переиспользования ответов на тесты ОРИОКС
  8. // @icon https://orioks.miet.ru/favicon.ico
  9. // @author electromagneticcyclone & angelbeautifull
  10. // @license GPL-3.0-or-later
  11. // @supportURL https://git.disroot.org/electromagneticcyclone/sorryops
  12. // @match https://orioks.miet.ru/student/student/test*
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_addStyle
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_setClipboard
  18. // @grant GM_xmlhttpRequest
  19. // @grant GM_openInTab
  20. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  21. // @connect sorryops.ru
  22. // @run-at document-start
  23. // ==/UserScript==
  24.  
  25. /* Version */
  26. const VERSION = "20240502.3";
  27. /* End Version */
  28.  
  29. /* Charset */
  30. const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  31. /* End Charset */
  32.  
  33. /* Labels */
  34.  
  35. const all_labels = {
  36. en: {
  37. l: "English",
  38. settings_title: "Settings",
  39. script_language: "Language",
  40. show_user_id: "Show user ID",
  41. user_id: "User ID (keep private)",
  42. server: "Sync answers with server (leave blank to disable)",
  43. wait_server_response: "Wait server response",
  44. auto_answer: "Auto answer",
  45. auto_answer_no: "No",
  46. auto_answer_first: "First",
  47. auto_answer_random: "Random",
  48. auto_answer_not_greedy: "Choose a known answer if there are more wrong answers than that number",
  49. auto_answer_greed_level: "Number of randomly answered questions",
  50. display_values: "Answers variant",
  51. display_values_ori: "ORIOKS",
  52. display_values_sorry: "Sorry",
  53. display_values_both: "Both",
  54. display_answer: "Display answer near variant",
  55. stop_timer: "Freeze and hide timer",
  56. register_keyboard_keys: "Register hotkeys",
  57. copy_answers: "Copy results to the clipboard",
  58. append_question_number: "Show question numbers in the final report",
  59. accumulator_enable: "Accumulate test results in one field",
  60. auto_continue: "Auto continue (DANGEROUS!!! Will be disabled after an hour. Press `d` to disable)",
  61. auto_restart: "Auto restart (DANGEROUS!!! Will be disabled after an hour. Press `d` to disable. Make sure you have infinite attempts)",
  62. },
  63. ru: {
  64. l: "Русский",
  65. settings_title: "Настройки",
  66. script_language: "Язык",
  67. show_user_id: "Показать индетификатор пользователя",
  68. user_id: "Индетификатор (держать в секрете)",
  69. server: "Синхронизировать ответы с сервером (оставить пустым для отключения)",
  70. wait_server_response: "Ждать ответа сервера",
  71. auto_answer: "Автовыбор ответа",
  72. auto_answer_no: "Нет",
  73. auto_answer_first: "Первый",
  74. auto_answer_random: "Случайный",
  75. auto_answer_not_greedy: "Выбирать известный ответ, если неправильных больше этого числа",
  76. auto_answer_greed_level: "Количество вопросов, на которые будет случайный ответ",
  77. display_values: "Вариант отображения ответов",
  78. display_values_ori: "ОРИОКС",
  79. display_values_sorry: "Сори",
  80. display_values_both: "Оба",
  81. display_answer: "Отображать ответ рядом с вариантом",
  82. stop_timer: "Заморозить и скрыть таймер",
  83. register_keyboard_keys: "Горячие клавиши",
  84. copy_answers: "Копировать результаты в буфер обмена",
  85. append_question_number: "Отображать номер вопроса в финальном отчёте",
  86. accumulator_enable: "Собирать отчёты в одно поле",
  87. auto_continue: "Автопродолжение (ОПАСНО!!! Отключается через час. Нажмите `d`, чтобы остановить)",
  88. auto_restart: "Автоперезапуск (ОПАСНО!!! Отключается через час. Нажмите `d`, чтобы остановить. Убедитесь, что количество попыток неограничено)",
  89. },
  90. };
  91.  
  92. var labels = all_labels[(() => {
  93. var lang = GM_getValue('language', "-");
  94. if (!lang || (lang == "-")) {
  95. lang = navigator.language || navigator.userLanguage;
  96. }
  97. for (var l in all_labels) {
  98. if (lang.includes(l)) {
  99. return l;
  100. }
  101. }
  102. })()];
  103. if (labels == undefined) {
  104. labels = all_labels.ru;
  105. }
  106.  
  107. /* End Labels */
  108.  
  109. /* Config */
  110.  
  111. var config = new GM_config({
  112. id: 'config',
  113. title: labels.settings_title,
  114. fields: {
  115. script_language: {
  116. label: labels.script_language,
  117. type: 'select',
  118. options: [
  119. '-',
  120. all_labels.en.l,
  121. all_labels.ru.l,
  122. ],
  123. default: '-',
  124. },
  125. show_user_id: {
  126. label: labels.show_user_id,
  127. type: 'checkbox',
  128. default: false,
  129. },
  130. user_id: {
  131. label: labels.user_id + (GM_getValue("show_user_id", false) ? "" : "<input readonly value='******'>"),
  132. type: GM_getValue("show_user_id", false) ? 'text' : 'hidden',
  133. save: false,
  134. default: '',
  135. },
  136. valid_user_id: {
  137. type: 'hidden',
  138. default: '',
  139. },
  140. server: {
  141. label: labels.server,
  142. type: 'text',
  143. default: '',
  144. },
  145. wait_server_response: {
  146. label: labels.wait_server_response,
  147. type: 'checkbox',
  148. default: true,
  149. },
  150. auto_answer: {
  151. label: labels.auto_answer,
  152. type: 'select',
  153. options: [
  154. labels.auto_answer_no,
  155. labels.auto_answer_first,
  156. labels.auto_answer_random,
  157. ],
  158. default: labels.auto_answer_no,
  159. },
  160. auto_answer_not_greedy: {
  161. label: labels.auto_answer_not_greedy,
  162. type: 'number',
  163. default: -1,
  164. },
  165. auto_answer_greed_level: {
  166. label: labels.auto_answer_greed_level,
  167. type: 'number',
  168. default: -1,
  169. },
  170. display_values: {
  171. label: labels.display_values,
  172. type: 'select',
  173. options: [
  174. labels.display_values_ori,
  175. labels.display_values_sorry,
  176. labels.display_values_both,
  177. ],
  178. default: labels.display_values_ori,
  179. },
  180. display_answer: {
  181. label: labels.display_answer,
  182. type: 'checkbox',
  183. default: true,
  184. },
  185. stop_timer: {
  186. label: labels.stop_timer,
  187. type: 'checkbox',
  188. default: false,
  189. },
  190. register_keyboard_keys: {
  191. label: labels.register_keyboard_keys,
  192. type: 'checkbox',
  193. default: true,
  194. },
  195. copy_answers: {
  196. label: labels.copy_answers,
  197. type: 'checkbox',
  198. default: false,
  199. },
  200. append_question_number: {
  201. label: labels.append_question_number,
  202. type: 'checkbox',
  203. default: true,
  204. },
  205. accumulator_enable: {
  206. label: labels.accumulator_enable,
  207. type: 'checkbox',
  208. default: false,
  209. },
  210. auto_continue: {
  211. label: labels.auto_continue,
  212. type: 'checkbox',
  213. default: false,
  214. },
  215. auto_continue_time: {
  216. type: 'hidden',
  217. default: 0,
  218. },
  219. auto_restart: {
  220. label: labels.auto_restart,
  221. type: 'checkbox',
  222. default: false,
  223. },
  224. auto_restart_time: {
  225. type: 'hidden',
  226. default: 0,
  227. },
  228. },
  229. events: {
  230. init: function() {
  231. var valid_user_id = this.get('valid_user_id');
  232. if (!validate_user_id(valid_user_id)) {
  233. valid_user_id = generate_user_id();
  234. }
  235. this.set('user_id', valid_user_id);
  236. this.set('valid_user_id', valid_user_id);
  237. GM_setValue('show_user_id', this.get('show_user_id'));
  238. GM_setValue('stop_timer', this.get('stop_timer'));
  239. if (this.get('auto_continue') && (this.get('auto_answer') == "No")) {
  240. this.set('auto_continue', false);
  241. }
  242. if (this.get('accumulator_enable') == false) {
  243. GM_setValue('accumulated_answers', "");
  244. }
  245. switch (this.get('script_language')) {
  246. case all_labels.en.l:
  247. GM_setValue('language', "en");
  248. break;
  249. case all_labels.ru.l:
  250. GM_setValue('language', "ru");
  251. break;
  252. default:
  253. GM_setValue('language', "-");
  254. break;
  255. }
  256. },
  257. save: function(forgotten) {
  258. this.set('auto_continue_time', Date.now());
  259. this.set('auto_restart_time', Date.now());
  260. if (this.isOpen && this.get('auto_continue') && (this.get('auto_answer') == "No")) {
  261. this.set('auto_continue', false);
  262. alert("Can't automatically continue without answer.");
  263. }
  264. if (!validate_user_id(forgotten['user_id'])) {
  265. this.set('user_id', this.get('valid_user_id'))
  266. alert('User ID is invalid!');
  267. } else {
  268. this.set('valid_user_id', forgotten['user_id'])
  269. }
  270. this.init();
  271. },
  272. },
  273. });
  274.  
  275. GM_registerMenuCommand(labels.settings_title, () => {
  276. config.open();
  277. });
  278.  
  279. /* End Config */
  280.  
  281. /* Server */
  282.  
  283. function send_to_server(results) {
  284. var server = config.get('server');
  285. if (server != '') {
  286. GM_xmlhttpRequest({
  287. method: 'POST',
  288. url: 'https://' + server,
  289. headers: {
  290. 'Content-Type': 'application/json',
  291. },
  292. data: JSON.stringify(results),
  293. });
  294. }
  295. }
  296.  
  297. function fetch_from_server(path, func) {
  298. var server = config.get('server');
  299. var fetched_data = GM_getValue('fetched_data');
  300. if (fetched_data == undefined) {
  301. fetched_data = {};
  302. }
  303. if ((server != '') && (Object.keys(fetched_data).length == 0)) {
  304. GM_xmlhttpRequest({
  305. method: 'GET',
  306. url: 'https://' + server + '/' + path + '?uid=' + config.get('user_id'),
  307. timeout: 1000,
  308. onload: function (response) {
  309. var text = response.responseText;
  310. if (response.status == 404) {
  311. fetched_data = {version: VERSION};
  312. GM_setValue('fetched_data', fetched_data);
  313. func(fetched_data);
  314. } else if (!text.includes("{")) {
  315. func({});
  316. } else {
  317. fetched_data = JSON.parse(text);
  318. GM_setValue('fetched_data', fetched_data);
  319. func(fetched_data);
  320. }
  321. },
  322. onerror: function (e) {
  323. console.log(e);
  324. func({});
  325. },
  326. onabort: function (e) {
  327. func({});
  328. },
  329. ontimeout: function (e) {
  330. func({});
  331. }
  332. });
  333. } else {
  334. func(fetched_data);
  335. }
  336. }
  337.  
  338. /* End Server */
  339.  
  340. /* Stop timer */
  341.  
  342. if (GM_getValue('stop_timer', true)) {
  343. var i, pbox;
  344. var pboxes = document.getElementsByTagName('p');
  345. for (i = 0; i < pboxes.length; i++) {
  346. pbox = pboxes[i];
  347. if (pbox.textContent.includes("Осталось:")) {
  348. pbox.parentNode.remove();
  349. document.getElementsByTagName('hr')[0].remove();
  350. var injectFakeTimer = function(window) {
  351. window.setInterval = (f, t, its_me = false) => {
  352. return window.setInterval(f, its_me ? t : 10^999);
  353. };
  354. }
  355. var scriptFakeTimer = document.createElement('script');
  356. scriptFakeTimer.setAttribute("type", "application/javascript");
  357. scriptFakeTimer.textContent = '(' + injectFakeTimer + ')(window);';
  358. document.body.appendChild(scriptFakeTimer);
  359. break;
  360. }
  361. }
  362. }
  363.  
  364. /* End Stop timer */
  365.  
  366. /* Events */
  367.  
  368. window.addEventListener('load', main);
  369. window.onkeydown = (e) => {
  370. if ((e.key == "Enter") && config.get('register_keyboard_keys')) {
  371. press_continue_btn();
  372. }
  373. if (e.key == "d") {
  374. config.set('auto_continue', false);
  375. config.set('auto_restart', false);
  376. config.save();
  377. }
  378. };
  379.  
  380. /* End Events */
  381.  
  382. /* Page properties */
  383.  
  384. // const success = -1487162948;
  385. var answers = [];
  386. var sorted_objects_value = [];
  387. var variant, hash, type, correct, incorrect, version;
  388. var prev_new_answer_f = false;
  389. var new_answer_f = false;
  390. var testID = (() => {
  391. var url = document.URL;
  392. url = url.slice(url.indexOf("idKM=") + 5);
  393. url = url.slice(0, url.indexOf("&"));
  394. return url;
  395. })();
  396.  
  397. /* End properties */
  398.  
  399. /* Functions */
  400.  
  401. function comb(s, blacklist = []) {
  402. var result = [];
  403. for (var i = 1; i < (1 << s.length); i++) {
  404. var temp = '';
  405. for (var j = 0; j < s.length; j++) {
  406. if (i & Math.pow(2, j)) {
  407. temp += s[j];
  408. }
  409. }
  410. temp = "{" + temp + "}";
  411. if (!blacklist.includes(temp)) {
  412. result.push(temp);
  413. }
  414. }
  415. return result;
  416. }
  417.  
  418. // https://github.com/ajayyy/maze-utils/blob/036086403f675b8fea0e22065f26ba534e351562/src/setup.ts
  419. function generate_user_id(length = 36) {
  420. var i;
  421. var result = "";
  422. const cryptoFuncs = typeof window === "undefined" ? crypto : window.crypto;
  423. if (cryptoFuncs && cryptoFuncs.getRandomValues) {
  424. const values = new Uint32Array(length);
  425. cryptoFuncs.getRandomValues(values);
  426. for (i = 0; i < length; i++) {
  427. result += charset[values[i] % charset.length];
  428. }
  429. } else {
  430. for (i = 0; i < length; i++) {
  431. result += charset[Math.floor(Math.random() * charset.length)];
  432. }
  433. }
  434. return result;
  435. }
  436.  
  437. function validate_user_id(uid, length = 36) {
  438. var i;
  439. if (uid.length != length) {
  440. return false;
  441. }
  442. for (i = 0; i < length; i++) {
  443. if (!charset.includes(uid[i])) {
  444. return false;
  445. }
  446. }
  447. return true;
  448. }
  449.  
  450. // https://stackoverflow.com/a/15710692
  451. function hashCode(s, return_num = false) {
  452. var result = "";
  453. var h = s.split("").reduce(function(a, b) {
  454. a = ((a << 5) - a) + b.charCodeAt(0);
  455. return a & a;
  456. }, 0);
  457. if (return_num) {
  458. return h;
  459. }
  460. while (h != 0) {
  461. result += charset[((h % charset.length) + charset.length) % charset.length];
  462. h = Math.floor(Math.abs(h) / charset.length) * (h / Math.abs(h));
  463. }
  464. return result;
  465. }
  466.  
  467. function set_to_clear(id, exec_if_not_cleared) {
  468. var clear = GM_getValue('clear_tests', new Object());
  469. if (!clear[id]) {
  470. exec_if_not_cleared();
  471. }
  472. clear[id] = true;
  473. GM_setValue('clear_tests', clear);
  474. }
  475.  
  476. function DB_cleaner() {
  477. var clear = GM_getValue('clear_tests', new Object());
  478. var tests = GM_getValue('tests', new Object());
  479. for (var test in clear) {
  480. delete tests[test];
  481. }
  482. GM_setValue('tests', tests);
  483. GM_setValue('clear_tests', new Object());
  484. }
  485.  
  486. function press_continue_btn() {
  487. var i;
  488. var buttons = document.getElementsByTagName('button');
  489. var button = undefined;
  490. for (i = 0; i < buttons.length; i++) {
  491. var btn = buttons[i];
  492. if (btn.textContent.includes("Пройти") || btn.textContent.includes("Продолжить")) {
  493. button = btn;
  494. break;
  495. }
  496. }
  497. if (button === undefined) {
  498. return;
  499. }
  500. if (button.textContent.includes("Пройти")) {
  501. window.location.replace(button.parentNode.href);
  502. } else if (button.textContent.includes("Продолжить")) {
  503. button.click();
  504. }
  505. }
  506.  
  507. function calculate_variant_hash() {
  508. variant = document.getElementById('w0').parentNode.textContent;
  509. variant = variant.slice(variant.indexOf("Вопрос:"));
  510. hash = hashCode(variant);
  511. }
  512.  
  513. function update_variant() {
  514. var i, pbox;
  515. var status = "Неизвестен";
  516. var chosen_answer = "";
  517. switch (type) {
  518. case 'checkbox':
  519. case 'radio': {
  520. for (i = 0; i < answers.length; i++) {
  521. chosen_answer += answers[i].checked ? answers[i].sorry_value : "";
  522. }
  523. chosen_answer = chosen_answer.split('').sort().join('');
  524. if (type == 'checkbox') {
  525. chosen_answer = "{" + chosen_answer + "}";
  526. }
  527. } break;
  528. case 'text': {
  529. for (i = 0; i < answers.length; i++) {
  530. chosen_answer += "[" + answers[i].value + "]";
  531. }
  532. }
  533. }
  534. new_answer_f = true;
  535. if ((version != VERSION) && (version !== undefined)) {
  536. status = "<span style='color: red;'>Скрипт устарел</span>";
  537. GM_setValue('fetched_data', {});
  538. } else if (version === undefined) {
  539. if (config.get('wait_server_response')) {
  540. status = "<span style='color: blue;'>Ожидание ответа</span>";
  541. } else {
  542. status = "<span style='color: red;'>Нет соединения</span>";
  543. }
  544. } else if (chosen_answer == correct) {
  545. status = "<span style='color: green;'>Верно</span>";
  546. new_answer_f = false;
  547. } else if (incorrect.includes(chosen_answer)) {
  548. status = "<span style='color: red;'>Неверно</span>";
  549. new_answer_f = false;
  550. }
  551. GM_setValue('new_answer_f', prev_new_answer_f || new_answer_f);
  552. var pboxes = document.getElementsByTagName('p');
  553. const display_answer = config.get('display_answer');
  554. for (i = 0; i < pboxes.length; i++) {
  555. pbox = pboxes[i];
  556. if (pbox.textContent.includes("Вопрос:")) {
  557. pbox.innerHTML = "<i>(Вариант <input onfocus='this.select();' id='variant' value='" + hash + (display_answer == true ? (" " + chosen_answer) : "") + "' readonly>)</i>";
  558. if (config.get('server') != '') {
  559. pbox.innerHTML += "<br>Статус: " + status;
  560. }
  561. pbox.innerHTML += "<br>Вопрос:";
  562. break;
  563. }
  564. }
  565. var question_num = undefined;
  566. for (i = 0; i < pboxes.length; i++) {
  567. pbox = pboxes[i];
  568. if (pbox.textContent.includes("Текущий вопрос: ")) {
  569. question_num = pbox.textContent.slice(variant.indexOf("Текущий вопрос: ") + 16).trim();
  570. break;
  571. }
  572. }
  573. if (hash !== undefined) {
  574. var tests = GM_getValue('tests', new Object());
  575. if (tests[testID] === undefined) {
  576. tests[testID] = new Object();
  577. }
  578. tests[testID][hash] = [question_num, chosen_answer, answers.length];
  579. GM_setValue('tests', tests);
  580. }
  581. }
  582.  
  583. function color_answers() {
  584. var answer, correct_element, incorrect_element, sorry_val;
  585. switch (type) {
  586. case 'radio': {
  587. for (answer in answers) {
  588. if (answers[answer].sorry_value == correct) {
  589. if (!answers[answer].sorry_colored && (version !== undefined)) {
  590. correct_element = answers[answer].parentNode;
  591. sorry_val = answers[answer].sorry_value;
  592. correct_element.innerHTML = "<span style='color: green;'>" + correct_element.innerHTML + "</span>";
  593. answers[answer] = correct_element.getElementsByTagName('input')[0];
  594. answers[answer].sorry_value = sorry_val;
  595. answers[answer].sorry_colored = true;
  596. }
  597. }
  598. if (incorrect.includes(answers[answer].sorry_value)) {
  599. if (!answers[answer].sorry_colored && (version !== undefined)) {
  600. incorrect_element = answers[answer].parentNode;
  601. sorry_val = answers[answer].sorry_value;
  602. incorrect_element.innerHTML = "<span style='color: red;'>" + incorrect_element.innerHTML + "</span>";
  603. answers[answer] = incorrect_element.getElementsByTagName('input')[0];
  604. answers[answer].sorry_value = sorry_val;
  605. answers[answer].sorry_colored = true;
  606. }
  607. }
  608. }
  609. } break;
  610. case 'checkbox': {
  611. for (answer in answers) {
  612. if (correct != undefined) {
  613. if (correct.includes(answers[answer].sorry_value)) {
  614. if (!answers[answer].sorry_colored && (version !== undefined)) {
  615. correct_element = answers[answer].parentNode;
  616. sorry_val = answers[answer].sorry_value;
  617. correct_element.innerHTML = "<span style='color: green;'>" + correct_element.innerHTML + "</span>";
  618. answers[answer] = correct_element.getElementsByTagName('input')[0];
  619. answers[answer].sorry_value = sorry_val;
  620. answers[answer].sorry_colored = true;
  621. }
  622. }
  623. }
  624. }
  625. } break;
  626. }
  627. }
  628.  
  629. function auto_answer() {
  630. var answer, chosen_answer, sorry_val, correct_element, incorrect_element;
  631. const auto_answer = config.get('auto_answer');
  632. function pick_answer(picked) {
  633. switch (type) {
  634. case 'radio': {
  635. for (answer in answers) {
  636. if (answers[answer].sorry_value == picked) {
  637. answers[answer].click();
  638. }
  639. }
  640. } break;
  641. case 'checkbox': {
  642. for (answer in answers) {
  643. if (picked.includes(answers[answer].sorry_value)) {
  644. answers[answer].click();
  645. }
  646. }
  647. } break;
  648. case 'text': {
  649. var corr = picked.slice(1, picked.length - 1).split('][');
  650. for (i = 0; (i < answers.leght) && (i < corr.length); i++) {
  651. answers[i].placeholder = corr[i];
  652. }
  653. } break;
  654. }
  655. }
  656. var greed = GM_getValue('greed');
  657. if (greed === undefined) {
  658. greed = 99999;
  659. }
  660. if (correct != undefined) {
  661. pick_answer(correct);
  662. } else if (auto_answer == labels.auto_answer_random) {
  663. if ((incorrect.length >= Math.max(config.get('auto_answer_not_greedy'), 1)) &&
  664. ((config.get('auto_answer_not_greedy') > 0) || (greed <= 0))) {
  665. chosen_answer = Math.floor(Math.random() * incorrect.length);
  666. pick_answer(incorrect[chosen_answer]);
  667. } else {
  668. GM_setValue('greed', greed - 1);
  669. switch (type) {
  670. case 'radio': {
  671. var possible_answers = [];
  672. for (answer in answers) {
  673. if (incorrect.includes(answers[answer].sorry_value) == false) {
  674. possible_answers.push(answer);
  675. }
  676. }
  677. chosen_answer = Math.floor(Math.random() * possible_answers.length);
  678. answers[possible_answers[chosen_answer]].click();
  679. } break;
  680. case 'checkbox': {
  681. var combs = comb(charset.slice(0, answers.length), incorrect);
  682. var pick = combs[Math.floor(Math.random() * combs.length)];
  683. for (i = 0; i < answers.length; i++) {
  684. if(pick.includes(answers[i].sorry_value)) {
  685. answers[i].click();
  686. }
  687. }
  688. } break;
  689. }
  690. }
  691. } else if (auto_answer == labels.auto_answer_first) {
  692. Object.values(sorted_objects_value)[0].click();
  693. }
  694. }
  695.  
  696. function parse_server_data(server_data) {
  697. version = server_data.version;
  698. if ((version !== VERSION) && (version !== undefined)) {
  699. console.warn("Sorryops is outdated");
  700. server_data = {};
  701. GM_openInTab("https://greasyfork.org/en/scripts/481036-sorryops");
  702. config.set('auto_continue', false);
  703. }
  704. if (server_data.hasOwnProperty('correct')) {
  705. correct = server_data.correct;
  706. if (correct === undefined) {
  707. correct = undefined;
  708. } else if (correct.hasOwnProperty(hash)) {
  709. correct = correct[hash];
  710. } else {
  711. correct = undefined;
  712. }
  713. } else {
  714. correct = undefined;
  715. }
  716. if (server_data.hasOwnProperty('incorrect')) {
  717. incorrect = server_data.incorrect;
  718. if (incorrect === undefined) {
  719. incorrect = [];
  720. } else if (incorrect.hasOwnProperty(hash)) {
  721. incorrect = incorrect[hash];
  722. } else {
  723. incorrect = [];
  724. }
  725. } else {
  726. incorrect = [];
  727. }
  728. }
  729.  
  730. function auto_continue() {
  731. var old_time, cur_time;
  732. if (config.get('auto_continue')) {
  733. old_time = config.get('auto_continue_time');
  734. cur_time = Date.now();
  735. if (cur_time - old_time > 60 * 60 * 1000) {
  736. config.set('auto_continue', false);
  737. } else {
  738. press_continue_btn();
  739. }
  740. }
  741. }
  742.  
  743. function auto_restart() {
  744. var old_time, cur_time;
  745. if (config.get('auto_restart')) {
  746. old_time = config.get('auto_restart_time');
  747. cur_time = Date.now();
  748. if (cur_time - old_time > 60 * 60 * 1000) {
  749. config.set('auto_restart', false);
  750. } else {
  751. press_continue_btn();
  752. }
  753. }
  754. }
  755.  
  756. /* End Functions */
  757.  
  758. /* Handlers */
  759.  
  760. function test_form_handler(server_response) {
  761. var i, key, answer, sorry_val;
  762. var complicated_hash_f = false;
  763. var boxes = [];
  764. var sorted_objects;
  765. var objects_hash = new Object();
  766. var objects_value = new Object();
  767. var form = document.getElementById('testform-answer');
  768. var manual_form = document.getElementById('testform-answer-0');
  769. if (form != null) {
  770. boxes = form.getElementsByTagName('input');
  771. } else if (manual_form != null) {
  772. i = 1;
  773. while (manual_form != null) {
  774. boxes.push(manual_form);
  775. manual_form = document.getElementById('testform-answer-' + i++);
  776. }
  777. }
  778. type = boxes[0].type;
  779. for (i = 0; i < boxes.length; i++) {
  780. if (boxes[i].parentNode.innerHTML.includes("<img")) {
  781. complicated_hash_f = true;
  782. break;
  783. }
  784. }
  785. switch (type) {
  786. case 'checkbox':
  787. case 'radio': {
  788. for (i = 0; i < boxes.length; i++) {
  789. boxes[i].hash = hashCode(complicated_hash_f ? boxes[i].parentNode.innerHTML : boxes[i].parentNode.innerText, true);
  790. objects_hash[boxes[i].hash] = boxes[i];
  791. objects_value[boxes[i].value] = boxes[i];
  792. }
  793. const sorted_objects_hash = Object.keys(objects_hash).sort().reduce(
  794. (obj, key) => {
  795. obj[key] = objects_hash[key];
  796. return obj;
  797. }, {}
  798. );
  799. sorted_objects_value = Object.keys(objects_value).sort().reduce(
  800. (obj, key) => {
  801. obj[key] = objects_value[key];
  802. return obj;
  803. }, {}
  804. );
  805. i = 0;
  806. sorted_objects = sorted_objects_hash;
  807. for (key in sorted_objects) {
  808. sorted_objects[key].parentNode.remove();
  809. form.appendChild(sorted_objects[key].parentNode);
  810. }
  811. calculate_variant_hash();
  812. parse_server_data(server_response);
  813. for (key in sorted_objects) {
  814. sorted_objects[key].sorry_value = charset[i++];
  815. var span = document.createElement('span');
  816. var disp_val;
  817. switch (config.get('display_values')) {
  818. case labels.display_values_ori:
  819. disp_val = sorted_objects[key].value;
  820. break;
  821. case labels.display_values_sorry:
  822. disp_val = sorted_objects[key].sorry_value;
  823. break;
  824. case labels.display_values_both:
  825. disp_val = sorted_objects[key].value + ":" + sorted_objects[key].sorry_value;
  826. break;
  827. }
  828. span.innerHTML = disp_val + ") ";
  829. sorted_objects[key].parentNode.insertBefore(span, sorted_objects[key]);
  830. answers.push(sorted_objects[key]);
  831. }
  832. if (config.get('display_values') == labels.display_values_ori) {
  833. for (key in sorted_objects_value) {
  834. sorted_objects_value[key].parentNode.remove();
  835. form.appendChild(sorted_objects_value[key].parentNode);
  836. }
  837. }
  838. } break;
  839. case 'text': {
  840. answers = boxes;
  841. calculate_variant_hash();
  842. } break;
  843. }
  844. color_answers();
  845. auto_answer();
  846. update_variant();
  847. for (i = 0; i < answers.length; i++) {
  848. answers[i].addEventListener('change', update_variant);
  849. }
  850. }
  851.  
  852. function result_page_handler() {
  853. var i;
  854. var correct_num = variant.slice(variant.indexOf("Число верных ответов: ") + 22);
  855. var all_num = variant.slice(variant.indexOf("Число неверных ответов: ") + 24);
  856. correct_num = correct_num.slice(0, correct_num.indexOf("\n")).trim();
  857. all_num = all_num.slice(0, all_num.indexOf("\n")).trim();
  858. all_num = (parseInt(all_num) + parseInt(correct_num)).toString();
  859. var test = GM_getValue('tests', new Object())[testID];
  860. if (test === undefined) {
  861. return;
  862. }
  863. var printer = "";
  864. var sorted_test = [];
  865. for (var hash in test) {
  866. sorted_test.push([hash].concat(test[hash]));
  867. }
  868. sorted_test.sort((a, b) => {return a[1] - b[1]});
  869. for (i = 0; i < sorted_test.length; i++) {
  870. printer += (config.get('append_question_number') ? (sorted_test[i][1] + ") ") : "") + sorted_test[i][0] + " " + sorted_test[i][2] + "\n";
  871. }
  872. printer += correct_num;
  873. if (config.get('copy_answers')) {
  874. GM_setClipboard(printer);
  875. }
  876. if (config.get('accumulator_enable')) {
  877. var acc = GM_getValue('accumulated_answers', "");
  878. if (acc != "") {
  879. acc += "\n\n";
  880. }
  881. var prefix = testID;
  882. if (prefix != "") {
  883. acc += prefix + "\n";
  884. }
  885. acc += printer;
  886. GM_setValue('accumulated_answers', acc);
  887. printer = acc;
  888. }
  889. printer = "<textarea readonly style='resize:none; width:fit-content; height:fit-content' rows='" + String(Object.keys(test).length + 1) + "' cols='50' onfocus='this.select();' id='answers'>" + printer + "</textarea>";
  890. var pboxes = document.getElementsByTagName('p');
  891. for (i = 0; i < pboxes.length; i++) {
  892. var pbox = pboxes[i];
  893. if (pbox.textContent.includes("Попытка ")) {
  894. pbox.outerHTML += printer;
  895. break;
  896. }
  897. }
  898. set_to_clear(testID, () => {
  899. if (GM_getValue('new_answer_f')) {
  900. send_to_server({
  901. type: "test_results",
  902. uid: config.get('user_id'),
  903. id: testID,
  904. answers: sorted_test,
  905. correct: correct_num,
  906. all: all_num,
  907. });
  908. }
  909. GM_setValue('fetched_data', {});
  910. GM_setValue('new_answer_f', false);
  911. var greed = config.get('auto_answer_not_greedy');
  912. if (greed < 0) {
  913. greed = 99999;
  914. }
  915. GM_setValue('greed', greed);
  916. });
  917. }
  918.  
  919. /* End Handlers */
  920.  
  921. function main() {
  922. variant = document.getElementById('w0').parentNode.textContent;
  923. prev_new_answer_f = !!GM_getValue('new_answer_f');
  924. if (variant.includes("Вопрос:")) {
  925. fetch_from_server(testID, (server_response) => {
  926. DB_cleaner();
  927. test_form_handler(server_response);
  928. if (config.get('wait_server_response') && (version === undefined)) {
  929. window.setInterval(() => {fetch_from_server(testID, (server_response) => {
  930. if (version === undefined) {
  931. parse_server_data(server_response);
  932. color_answers();
  933. if (config.get('auto_continue')) {
  934. auto_answer();
  935. }
  936. update_variant();
  937. if (version === VERSION) {
  938. auto_continue();
  939. }
  940. }
  941. })}, 1000, true);
  942. } else {
  943. auto_continue();
  944. }
  945. });
  946. } else if (variant.includes("Результат прохождения теста:")) {
  947. result_page_handler();
  948. auto_restart();
  949. }
  950. }