Advertisement
Guest User

Leech Trainer Update

a guest
Jun 22nd, 2018
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         WaniKani Leech Trainer
  3. // @version      1.0.3
  4. // @description  Study and quiz yourself on your leeches!
  5. // @require      https://greasyfork.org/scripts/19781-wanakana/code/WanaKana.js?version=126349
  6. // @author       hitechbunny
  7. // @include      https://www.wanikani.com/
  8. // @include      https://www.wanikani.com/dashboard
  9. // @run-at       document-end
  10. // @grant        none
  11. // @namespace https://greasyfork.org/users/149329
  12. // ==/UserScript==
  13.  
  14. (function() {
  15.     'use strict';
  16.  
  17.     // Hook into App Store
  18.     try { $('.app-store-menu-item').remove(); $('<li class="app-store-menu-item"><a href="https://community.wanikani.com/t/there-are-so-many-user-scripts-now-that-discovering-them-is-hard/20709">App Store</a></li>').insertBefore($('.navbar .dropdown-menu .nav-header:contains("Account")')); window.appStoreRegistry = window.appStoreRegistry || {}; window.appStoreRegistry[GM_info.script.uuid] = GM_info; localStorage.appStoreRegistry = JSON.stringify(appStoreRegistry); } catch (e) {}
  19.  
  20.     var css =
  21.         '.noselect {-webkit-touch-callout:none; -webkit-user-select:none; -khtml-user-select:none; -moz-user-select: none;'+
  22.         '-ms-user-select:none; user-select: none;}'+
  23.  
  24.         '.selfstudy {margin-left:20px; margin-bottom:10px; position:relative;}'+
  25.         '.selfstudy label {display:inline; vertical-align:middle; padding-right:4px; color:#999; font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif; text-shadow:0 1px 0 #fff;}'+
  26.         '.selfstudy button.enable {width:55px;}'+
  27.         '.ss_active .selfstudy button.enable.on {background-color:#b3e6b3; background-image:linear-gradient(to bottom, #ecf9ec, #b3e6b3);}'+
  28.         '.selfstudy select.config {width:300px;}'+
  29.  
  30.         '.selfstudy .center {display:block; position:relative; top:50%; left:50%; transform:translate(-50%,-50%);}'+
  31.  
  32.         'section[id^="level-"].ss_active.ss_hidechar .character-item a span:not(.dummy) {opacity:0; transition:opacity ease-in-out 0.15s}'+
  33.         'section[id^="level-"].ss_active.ss_hideread .character-item a li[lang="ja"] {opacity:0; transition:opacity ease-in-out 0.15s}'+
  34.         'section[id^="level-"].ss_active.ss_hidemean .character-item a li:not([lang="ja"]) {opacity:0; transition:opacity ease-in-out 0.15s}'+
  35.         'section[id^="level-"].ss_active.ss_hideburned .character-item.burned {display:none;}'+
  36.         'section[id^="level-"].ss_active.ss_hidelocked .character-item.locked {display:none;}'+
  37.         'section[id^="level-"].ss_active.ss_hideunburned .character-item:not(.burned) {display:none;}'+
  38.         'section[id^="level-"].ss_active.ss_hideunlocked .character-item:not(.locked) {display:none;}'+
  39.  
  40.         'section.ss_active .character-item:hover a span {opacity: initial !important; transition:opacity ease-in-out 0.05s !important;}'+
  41.         'section.ss_active .character-item:hover a li {opacity: initial !important; transition:opacity ease-in-out 0.05s !important;}'+
  42.  
  43.         '#ss_config {position:absolute; z-index:1029; width:573px; background-color:rgba(0,0,0,0.9); border-radius:8px; padding:8px;}'+
  44.  
  45.         '#ss_config select.configs {width:475px;}'+
  46.         '#ss_config label {color:#ccc; text-shadow:initial; text-align:right; vertical-align:baseline;}'+
  47.         '#ss_config .btns {display:inline-block; float:left; vertical-align:top; margin-right:8px;}'+
  48.         '#ss_config .btns .btn {display:block; margin-bottom:5px;}'+
  49.         '#ss_config .btn {width:70px;}'+
  50.  
  51.         '#ss_config .list {overflow-x:auto;}'+
  52.         '#ss_config .list select.configs {width:100%; height:135px;}'+
  53.  
  54.         '#ss_config .section {border-top:1px solid #ccc; padding:0 0 8px 0;}'+
  55.         '#ss_config .section > label {display:block; text-align:left; color:#ffc; font-size:1.2em; font-weight:bold; padding-left:4px; margin-bottom:4px; background-color:#2e2e2e; background-image:linear-gradient(to bottom, #3c3c3c, #1a1a1a); background-repeat:repeat-x;}'+
  56.  
  57.         '#ss_config .txtline label {display:inline-block; float:left; margin-right:8px; width:100px; line-height:30px; clear:both;}'+
  58.         '#ss_config .txtline .expand {overflow-x:auto;}'+
  59.         '#ss_config .txtline input {box-sizing:border-box; width:100%; height:30px;}'+
  60.  
  61.         '#ss_config .cbbox {display:inline-block; width:49%; vertical-align:top;}'+
  62.         '#ss_config .cbbox label {display:inline-block; float:left; margin:0 8px 0 0; width:190px; line-height:20px;}'+
  63.         '#ss_config .cbbox input {position:relative; overflow-x:auto; height:20px; margin:0; top:1px;}'+
  64.  
  65.         '#ss_config [class*="icon-"] {color:#fff;}'+
  66.  
  67.         '#ss_config .dlg_close {text-align:center; margin-top:16px; margin-bottom:8px;}'+
  68.  
  69.         '#ss_quiz [lang="ja"] {font-family: "Meiryo","Yu Gothic","Hiragino Kaku Gothic Pro","TakaoPGothic","Yu Gothic","ヒラギノ角ゴ Pro W3","メイリオ","Osaka","MS PGothic","MS Pゴシック",sans-serif;}'+
  70.         '#ss_quiz {position:absolute; z-index:1028; width:573px; background-color:rgba(0,0,0,0.85); border-radius:8px; border:8px solid rgba(0,0,0,0.85); font-size:2em;}'+
  71.         '#ss_quiz * {text-align:center;}'+
  72.         '#ss_quiz .qwrap {height:8em; position:relative; clear:both;}'+
  73.  
  74.         '#ss_quiz.radicals .qwrap, #ss_quiz.radicals .summary .que {background-color:#0af;}'+
  75.         '#ss_quiz.kanji .qwrap, #ss_quiz.kanji .summary .que {background-color:#f0a;}'+
  76.         '#ss_quiz.vocabulary .qwrap, #ss_quiz.vocabulary .summary .que {background-color:#a0f;}'+
  77.  
  78.         '#ss_quiz .prev, #ss_quiz .next {display:inline-block; width:80px; color:#fff; line-height:8em; cursor:pointer;}'+
  79.         '#ss_quiz .prev:hover {background-image:linear-gradient(to left, rgba(0,0,0,0), rgba(0,0,0,0.2));}'+
  80.         '#ss_quiz .next:hover {background-image:linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.2));}'+
  81.         '#ss_quiz .prev {float:left;}'+
  82.         '#ss_quiz .next {float:right;}'+
  83.  
  84.         '#ss_quiz .topbar {font-size:0.5em; line-height:1em; color: rgba(255,255,255,0.5);}'+
  85.  
  86.         '#ss_quiz .settings {float:left; padding:6px 8px; text-align:left; line-height:1.5em;}'+
  87.         '#ss_quiz .settings span[class*="icon-"] {font-size:1.3em; padding:0 2px;}'+
  88.         '#ss_quiz .settings .ss_audio {padding-left:0; padding-right:4px;}'+
  89.         '#ss_quiz .settings .ss_typo {padding-left:0px;}'+
  90.         '#ss_quiz .settings .ss_done {font-size:1.25em;}'+
  91.         '#ss_quiz .settings .ss_pair {font-weight:bold;}'+
  92.         '#ss_quiz .settings span {cursor:pointer;}'+
  93.         '#ss_quiz .settings span:hover {color:rgba(255,255,204,0.8);}'+
  94.         '#ss_quiz .settings span.active {color:#ffc;}'+
  95.         '#ss_quiz.help .settings .ss_help {color:#ffc;}'+
  96.  
  97.         '#ss_quiz .stats_labels {text-align:right; font-family:monospace;}'+
  98.         '#ss_quiz .stats {float:right; text-align:right; color:rgba(255,255,255,0.8); font-family:monospace; padding:0 5px;}'+
  99.  
  100.         '#ss_quiz .round {display:none; font-weight:bold; position:absolute; box-sizing:border-box; width:60%; height:75%; border-radius:24px; border:2px solid #000; background-color:#fff;}'+
  101.         '#ss_quiz.round .round {display:block;}'+
  102.  
  103.         '#ss_quiz .question {'+
  104.         '  overflow-x:auto; overflow-y:hidden; position:relative; top:50%; transform:translateY(-50%);'+
  105.         '  color:#fff; text-align:center; line-height:1.1em; font-size:1em; font-weight:bold; cursor:default;'+
  106.         '}'+
  107.         '#ss_quiz .question[data-type="char"] {font-size:2em;}'+
  108.         '#ss_quiz .icon-audio:before {content:"\\f028";}'+
  109.         '#ss_quiz .question .icon-audio {font-size:2.5em; cursor:pointer;}'+
  110.         '#ss_quiz.summary .question {display:none;}'+
  111.  
  112.         '#ss_quiz .qtype {line-height:2em; cursor:default; text-transform:capitalize;}'+
  113.         '#ss_quiz .qtype.reading {color:#fff; text-shadow:-1px -1px 0 #000; border-top:1px solid #555; border-bottom:1px solid #000; background-color:#2e2e2e; background-image:linear-gradient(to bottom, #3c3c3c, #1a1a1a); background-repeat:repeat-x;}'+
  114.         '#ss_quiz .qtype.meaning {color:#555; text-shadow:-1px -1px 0 rgba(255,255,255,0.1); border-top:1px solid #d5d5d5; border-bottom:1px solid #c8c8c8; background-color:#e9e9e9; background-image:linear-gradient(to bottom, #eee, #e1e1e1); background-repeat:repeat-x;}'+
  115.  
  116.         '#ss_quiz .help {display:none;'+
  117.         '  position:absolute; top:3%; left:13%; width:74%; box-sizing:border-box; border:2px solid #000; border-radius:15px; padding:4px;'+
  118.         '  color:#555; text-shadow:2px 2px 0 rgba(0,0,0,0.2); background-color:rgba(255,255,255,0.9); font-size:0.8em; line-height:1.2em;'+
  119.         '}'+
  120.         '#ss_quiz.help .help {display:inherit;}'+
  121.  
  122.         '#ss_quiz .answer {background-color:#ddd; padding:8px;}'+
  123.         '#ss_quiz .answer input {'+
  124.         '  width:100%; background-color:#fff; height:2em; margin:0; border:2px solid #000; padding:0;'+
  125.         '  box-sizing:border-box; border-radius:0; font-size:1em;'+
  126.         '}'+
  127.         '#ss_quiz .answer input.correct {color:#fff; background-color:#8c8; text-shadow:2px 2px 0 rgba(0,0,0,0.2);}'+
  128.         '#ss_quiz .answer input.incorrect {color:#fff; background-color:#f03; text-shadow:2px 2px 0 rgba(0,0,0,0.2);}'+
  129.  
  130.         '#ss_quiz.loading .qwrap, #ss_quiz.loading .answer {display:none;}'+
  131.  
  132.         '#ss_quiz .summary {display:none; position:absolute; width:74%; height:100%; background-color:rgba(0,0,0,0.7); color:#fff; font-weight:bold;}'+
  133.         '#ss_quiz.summary .summary {display:block;}'+
  134.         '#ss_quiz .summary h3 {'+
  135.         '  background-image:linear-gradient(to bottom, #3c3c3c, #1a1a1a); background-repeat:repeat-x;'+
  136.         '  border-top:1px solid #777; border-bottom:1px solid #000; margin:0; box-sizing:border-box;'+
  137.         '  text-shadow:2px 2px 0 rgba(0,0,0,0.5); color:#fff; font-size:0.8em; font-weight:bold; line-height:40px;'+
  138.         '}'+
  139.         '#ss_quiz .summary .errors {position:absolute; top:40px; bottom:0px; width:100%; margin:0; overflow-y:auto; list-style-type:none;}'+
  140.         '#ss_quiz .summary li {margin:4px 0 0 0; font-size:0.6em; font-weight:bold; line-height:1.4em;}'+
  141.  
  142.         '#ss_quiz .summary .errors span {display:inline-block; padding:2px 4px 0px 4px; border-radius:4px; line-height:1.1em; max-width:50%; vertical-align:middle; cursor:pointer;}'+
  143.         '#ss_quiz .summary .ans {background-color:#fff; color:#000;}'+
  144.         '#ss_quiz .summary .wrong {color:#f22;}'+
  145.  
  146.         '#ss_quiz .btn.requiz {position:absolute; top:6px; right:6px; padding-left:6px; padding-right:6px;}'+
  147.  
  148.         '#ss_quiz_container {position:absolute; top:0; left:0; width:100%}'+
  149.  
  150.         '#ss_quiz {position: fixed;    margin-left: auto;    margin-right: auto;    left: 0;    right: 0;    top: 6em;}'+
  151.  
  152.         '.leech-badge {cursor: pointer;}'+
  153.         '.leech-badge div.popover {display: none !important;}'+
  154.  
  155.         '#ss_quiz .quiz-progress {margin-bottom: 8px; height: 8px; background-color: gray;}'+
  156.  
  157.         '#ss_quiz .quiz-progress .quiz-progress-bar {height: 8px; background-color: white;}'+
  158.  
  159.         '#ss_quiz .quiz-progress .quiz-progress-bar.pulse { animation: pulse 1.5s ease-in-out infinite alternate; }'+
  160.         '@keyframes pulse { 0% { box-shadow: 0px 0px 5px white; } 25% { box-shadow: 0px 0px 20px white; } 75% { box-shadow: 0px 0px 20px white; } 100% { box-shadow: 0px 0px 5px white; } }'+
  161.  
  162.         '#ss_quiz_abort { position: fixed; top: 0; left: 0; bottom: 0; right: 0; z-index: 999; }'+
  163.  
  164.         '';
  165.  
  166.     var quiz_html =
  167.         '<div id="ss_quiz" class="kanji reading">'+
  168.         '  <div class="quiz-progress"><div class="quiz-progress-bar"></div></div>'+
  169.         '  <div class="qwrap">'+
  170. //        '    <div class="prev" title="Previous question (Ctrl-Left)"><i class="icon-chevron-left"></i></div>'+
  171. //        '    <div class="next"><i class="icon-chevron-right"></i></div>'+
  172.         '    <div class="question"></div>'+
  173.         '    <div class="help"></div>'+
  174.         '    <div class="summary center">'+
  175.         '      <h3>Summary - <span class="percent">100%</span> Correct <button class="btn requiz" title="Re-quiz wrong items">Re-quiz</button></h3>'+
  176.         '      <ul class="errors"></ul>'+
  177.         '    </div>'+
  178.         '    <div class="round center"><span class="center">Round 1</span></div>'+
  179.         '  </div>'+
  180.         '  <div class="qtype"></div>'+
  181.         '  <div class="answer"><input type="text" value=""></div>'+
  182.         '</div>';
  183.  
  184.     $('head').append('<style type="text/css">'+css+'</style>');
  185.  
  186.     var api_key;
  187.     var quiz;
  188.     var dialog;
  189.     var correct = [];
  190.     var incorrect = [];
  191.     var wanakana_isbound;
  192.     var quizInProgress = false;
  193.  
  194.     function clear() {
  195.         $('.leech-badge').remove();
  196.         $('<li class="reviews leech-badge"><a><span>&nbsp;</span>Leeches</a></li>').insertAfter('.reviews');
  197.     }
  198.  
  199.     function query() {
  200.         clear();
  201.         if (localStorage.leech_train_cache) {
  202.             render(JSON.parse(localStorage.leech_train_cache));
  203.         }
  204.         get_api_key().then(function() {
  205.             ajax_retry('https://wanikanitools-golang.curiousattemptbunny.com/leeches/lesson?api_key='+api_key.replace(/-/g, ""), {timeout: 0}).then(function(json) {
  206.                 clear();
  207.                 render(json);
  208.             });
  209.         });
  210.     }
  211.  
  212.     function render(json) {
  213.         localStorage.leech_train_cache = JSON.stringify(json);
  214.         $('.leech-badge a span').html(json.leeches_available);
  215.         if (quizInProgress) {
  216.             return;
  217.         }
  218.         quiz = json.leech_lesson_items;
  219.         $('.leech-badge').click(startQuiz);
  220.     }
  221.  
  222.     function startQuiz() {
  223.         if (quiz.length === 0) return;
  224.         quizInProgress = true;
  225.  
  226.         for(var i=0; i<3; i++) {
  227.             shuffle(quiz);
  228.             var last = null;
  229.             var duplicate = false;
  230.             quiz.forEach(function(leech) {
  231.                 var key = leech.type + "/" + leech.name;
  232.                 if (key == last) {
  233.                     duplicate = true;
  234.                 }
  235.                 last = key;
  236.             });
  237.             if (!duplicate) break;
  238.         }
  239.  
  240.         correct = [];
  241.         incorrect = [];
  242.  
  243.         $('#ss_quiz, #ss_quiz_abort').remove();
  244.         $('body').append(quiz_html).append('<div id="ss_quiz_abort"/>');
  245.         $('.navbar, #search, .dashboard, footer').css('filter', 'blur(20px)');
  246.         wanakana_isbound = false;
  247.  
  248.         dialog = $('#ss_quiz');
  249.  
  250.         $('.quiz-progress-bar').css('width', (correct.length*100.0 / (quiz.length))+'%');
  251.  
  252.         dialog.find('.answer input').on('keypress', onKeyPress);
  253.  
  254.         $('#ss_quiz_abort').click(function() {
  255.             $('.navbar, #search, .dashboard, footer').css('filter', 'none');
  256.             $('#ss_quiz, #ss_quiz_abort').remove();
  257.             quizInProgress = false;
  258.             query();
  259.         });
  260.  
  261.         show_next();
  262.     }
  263.  
  264.     function onKeyPress(e) {
  265.         var code = e.originalEvent.code || String.fromCharCode(e.charCode);
  266.         if (code === 'Enter') {
  267.             var answerGiven = $('#ss_quiz .answer input').val().trim();
  268.             if (e.ctrlKey) answerGiven = quiz[0].correct_answers[0];
  269.             if (answerGiven.length === 0) return;
  270.             if (quiz[0].train_type == 'reading') {
  271.                 answerGiven = wanakana.toHiragana(answerGiven).trim();
  272.                 if (answerGiven.indexOf("n") == answerGiven.length-1) {
  273.                     answerGiven = answerGiven.substring(0,answerGiven.length-1)+"ん";
  274.                 }
  275.             }
  276.             $('#ss_quiz .answer input').val(answerGiven);
  277.             var correctAnswers = quiz[0].correct_answers;
  278.             var tryAgainAnswers = quiz[0].try_again_answers;
  279.  
  280.             var matches = function(answer) {
  281.                 if (quiz[0].train_type == 'reading') {
  282.                     return answer == answerGiven;
  283.                 } else {
  284.                     return jw_distance(answer.toLowerCase(), answerGiven.toLowerCase()) > 0.9;
  285.                 }
  286.             };
  287.             if (correctAnswers.filter(matches).length > 0) {
  288.                 $('#ss_quiz .answer input').addClass('correct').blur();
  289.                 correct.push(quiz[0].leech);
  290.                 quiz = quiz.slice(1);
  291.                 if (e.ctrlKey) {
  292.                     show_next();
  293.                 } else {
  294.                     setTimeout(show_next, 750);
  295.                 }
  296.             } else if (tryAgainAnswers.filter(matches).length > 0) {
  297.                 shake($('#ss_quiz .answer input'));
  298.             } else {
  299.                 shake($('#ss_quiz .answer input'));
  300.                 $('#ss_quiz .answer input').select();
  301.                 dialog.find('.help').html('<a href="/'+quiz[0].type+'/'+quiz[0].name+'" target="_blank">'+quiz[0].correct_answers[0]+'</a>').attr('lang','ja').show();
  302.  
  303.                 incorrect.push(quiz[0].leech);
  304.             }
  305.         } else {
  306.             dialog.find('.help').hide();
  307.         }
  308.         $('.quiz-progress-bar').animate({width: (correct.length*100.0 / (correct.length+quiz.length))+'%'}, 250);
  309.     }
  310.  
  311.     function shake(elem) {
  312.         var dist = '25px';
  313.         var speed = 75;
  314.         var right = {padding:'0 '+dist+' 0 0'}, left = {padding:'0 0 0 '+dist}, center = {padding:"0 0 0 0"};
  315.  
  316.         elem.animate(left,speed/2).animate(right,speed)
  317.             .animate(left,speed).animate(right,speed)
  318.             .animate(left,speed).animate(center,speed/2);
  319.     }
  320.  
  321.     function show_next() {
  322.         if (quiz.length === 0) {
  323.             $('.quiz-progress-bar').addClass('pulse');
  324.             $('#ss_quiz_abort').css('z-index', 1031);
  325.  
  326.             var trainedLeeches = [];
  327.             correct.forEach(function(leech) {
  328.                 if (!trainedLeeches.find(function(l) { return l.key == leech.key; }) && !incorrect.find(function(l) { return l.key == leech.key; })) {
  329.                     trainedLeeches.push(leech);
  330.                 }
  331.             });
  332. //            console.log("CORRECT", correct);
  333. //            console.log("WRONG", incorrect);
  334. //            console.log("TRAINED", trainedLeeches);
  335.             var msg = (trainedLeeches.length === 0 ? "Sorry. No leeches trained." : trainedLeeches.length+" leech"+(trainedLeeches > 1 ? "es" : "")+" trained!");
  336.             dialog.find('.help').html(msg).attr('lang','en').show();
  337.  
  338.             var extras = JSON.parse(window.localStorage['leeches-trained'] || '{}');
  339.             Object.keys(extras).forEach(function(key) {
  340.                 if (!trainedLeeches.find(function(l) { return l.key == key; }) && !incorrect.find(function(l) { return l.key == key; })) {
  341.                     trainedLeeches.push({key: key, worst_incorrect: extras[key]});
  342.                 }
  343.             });
  344.             console.log(trainedLeeches);
  345.             ajax_retry('https://wanikanitools-golang.curiousattemptbunny.com/leeches/trained?api_key='+api_key.replace(/-/g, ""), {data: JSON.stringify(trainedLeeches), method: 'POST', timeout: 0}).then(function(json) {
  346.                 console.log(json);
  347.                 delete window.localStorage['leeches-trained'];
  348.             });
  349.  
  350.             delete localStorage.leech_train_cache;
  351.             clear();
  352.             return;
  353.         }
  354.  
  355.         var item = quiz[0];
  356.         var qtype = 'char';
  357.         var qlang = 'ja';
  358.         var qtext = item.name;
  359.         var atype = item.train_type;
  360.         var alang = 'ja';
  361.         var itype = item.type;
  362.  
  363.         //console.log(item.readings);
  364.  
  365.         dialog.find('.question').attr('data-type', qtype).attr('lang',qlang).html(qtext);
  366.         var type_text = itype + ' <strong>'+atype+'</strong>';
  367.         dialog.find('.qtype').removeClass('reading meaning').addClass(atype).html(type_text);
  368.         dialog.removeClass('kanji vocabulary').addClass(itype);
  369.  
  370.         $('#ss_quiz .answer input').attr('lang',alang).removeClass('correct').val('').focus().select();
  371.  
  372.         if (atype === 'reading') {
  373.             if (!wanakana_isbound) {
  374.                 wanakana.bind($('#ss_quiz .answer input')[0]);
  375.                 wanakana_isbound = true;
  376.             }
  377.         } else {
  378.             if (wanakana_isbound) {
  379.                 wanakana.unbind($('#ss_quiz .answer input')[0]);
  380.                 wanakana_isbound = false;
  381.             }
  382.         }
  383.     }
  384.  
  385.     query();
  386.  
  387.     function shuffle(array) {
  388.         var i = array.length, j, temp;
  389.         if (i===0) return array;
  390.         while (--i) {
  391.             j = Math.floor(Math.random()*(i+1));
  392.             temp = array[i]; array[i] = array[j]; array[j] = temp;
  393.         }
  394.         return array;
  395.     }
  396.  
  397.     // Jaro-Winkler Distance
  398.     function jw_distance(a, c) {
  399.         var h, b, d, k, e, g, f, l, n, m, p;
  400.         if (a.length > c.length) {
  401.             c = [c, a];
  402.             a = c[0];
  403.             c = c[1];
  404.         }
  405.         k = ~~Math.max(0, c.length / 2 - 1);
  406.         e = [];
  407.         g = [];
  408.         b = n = 0;
  409.         for (p = a.length; n < p; b = ++n) {
  410.             for (h = a[b], l = Math.max(0, b - k), f = Math.min(b + k + 1, c.length), d = m = l; l <= f ? m < f : m > f; d = l <= f ? ++m : --m) {
  411.                 if (g[d] === undefined && h === c[d]) {
  412.                     e[b] = h;
  413.                     g[d] = c[d];
  414.                     break;
  415.                 }
  416.             }
  417.         }
  418.         e = e.join("");
  419.         g = g.join("");
  420.         d = e.length;
  421.         if (d) {
  422.             b = f = k = 0;
  423.             for (l = e.length; f < l; b = ++f) {
  424.                 h = e[b];
  425.                 if (h !== g[b]) k++;
  426.             }
  427.             b = g = e = 0;
  428.             for (f = a.length; g < f; b = ++g) {
  429.                 if (h = a[b], h === c[b])
  430.                     e++;
  431.                 else
  432.                     break;
  433.             }
  434.             a = (d/a.length + d/c.length + (d - ~~(k/2))/d)/3;
  435.             a += 0.1 * Math.min(e, 4) * (1 - a);
  436.         } else {
  437.             a = 0;
  438.         }
  439.         return a;
  440.     }
  441.  
  442.     //-------------------------------------------------------------------
  443.     // Fetch a document from the server.
  444.     //-------------------------------------------------------------------
  445.     function ajax_retry(url, options) {
  446.         //console.log('url:' + url, 'retries: ' + retries, 'timeout: ' + timeout);
  447.         options = options || {};
  448.         var retries = options.retries || 3;
  449.         var timeout = options.timeout || 3000;
  450.         var headers = options.headers || {};
  451.         var method = options.method || 'GET';
  452.         var data = options.data || undefined;
  453.         var cache = options.cache || false;
  454.  
  455.         function action(resolve, reject) {
  456.             $.ajax({
  457.                 url: url,
  458.                 method: method,
  459.                 timeout: timeout,
  460.                 headers: headers,
  461.                 data: data,
  462.                 cache: cache
  463.             })
  464.             .done(function(data, status){
  465.                 //console.log(status, data);
  466.                 if (status === 'success') {
  467.                     resolve(data);
  468.                 } else {
  469.                     //console.log("done (reject)", status, data);
  470.                     reject();
  471.                 }
  472.             })
  473.             .fail(function(xhr, status, error){
  474.                 //console.log(status, error);
  475.                 if ((status === 'error' || status === 'timeout') && --retries > 0) {
  476.                     //console.log("fail", status, error);
  477.                     action(resolve, reject);
  478.                 } else {
  479.                     reject();
  480.                 }
  481.             });
  482.         }
  483.         return new Promise(action);
  484.     }
  485.  
  486.     function get_api_key() {
  487.         return new Promise(function(resolve, reject) {
  488.             api_key = localStorage.getItem('apiKey_v2');
  489.             if (typeof api_key === 'string' && api_key.length == 36) return resolve();
  490.  
  491.             // status_div.html('Fetching API key...');
  492.             ajax_retry('/settings/account').then(function(page) {
  493.  
  494.                 // --[ SUCCESS ]----------------------
  495.                 // Make sure what we got is a web page.
  496.                 if (typeof page !== 'string') {return reject();}
  497.  
  498.                 // Extract the user name.
  499.                 page = $(page);
  500.  
  501.                 // Extract the API key.
  502.                 api_key = page.find('#user_api_key_v2').attr('value');
  503.                 if (typeof api_key !== 'string' || api_key.length !== 36) {
  504.                     return reject(new Error('generate_apikey'));
  505.                 }
  506.  
  507.                 localStorage.setItem('apiKey_v2', api_key);
  508.                 resolve();
  509.  
  510.             },function(result) {
  511.                 // --[ FAIL ]-------------------------
  512.                 reject(new Error('Failed to fetch API key!'));
  513.  
  514.             });
  515.         });
  516.     }
  517. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement