NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
'use strict';
// ==UserScript==
// @name Timus Charts
// @namespace timus_charts
// @description Adds charts to Timus Online Judge profiles
// @copyright Alexander Borzunov, 2012-2013, 2015-2016
// @version 1.6
// @license MIT
// @icon http://acm.timus.ru/favicon.ico
// @downloadURL https://openuserjs.org/install/hx0/Timus_Charts.user.js
// @updateURL https://openuserjs.org/install/hx0/Timus_Charts.user.js
// @match http://acm.timus.ru/author.aspx*
// @match http://acm-judge.urfu.ru/author.aspx*
// @match http://timus.online/author.aspx*
// @match https://acm.timus.ru/author.aspx*
// @match https://acm-judge.urfu.ru/author.aspx*
// @match https://timus.online/author.aspx*
// @grant GM_getValue
// @grant GM_setValue
// @require http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.min.js
// @require http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/jquery.jqplot.min.js
// @require http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.dateAxisRenderer.min.js
// ==/UserScript==
var SCRIPT_VERSION = '1.6';
var CACHE_VERSION = 2;
"use strict";
var isGreasemonkey = typeof GM_getValue !== "undefined" && typeof GM_setValue !== "undefined";
var isChrome = typeof chrome !== "undefined";
function getValue(key) {
var value;
if (isGreasemonkey) value = GM_getValue(key);else value = localStorage[key];
if (value === undefined) throw new Error("Storage doesn't contain this key");
return value;
}
function setValue(key, value) {
try {
if (isGreasemonkey) GM_setValue(key, value);else localStorage[key] = value;
} catch (err) {}
}
'use strict';
// jquery.jqplot.min.css
/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com
jsDate | (c) 2010-2013 Chris Leonello */
var JQPLOT_STYLE = '.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em;}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px;}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);}';
var EXTENSION_STYLE = '#chart {\n width: 100%;\n}\n\n.chart_box {\n height: 255px;\n position: relative;\n}\n\n.chart_comment {\n color: #555;\n font-size: 15;\n}\n\n#chart_loading_error_judge_id {\n margin-top: 5px;\n}\n\n.chart_judge_id_input {\n height: 20px;\n width: 80px;\n}\n\n.chart_legend_box {\n font-size: 15;\n margin: -5px 7px 10px 25px;\n min-height: 20px;\n overflow: auto;\n}\n\n.chart_users_table {\n border-spacing: 0;\n font-size: 15;\n}\n\n.chart_users_table td {\n padding: 0 3px;\n}\n\n.chart_users_table td:first-child {\n padding-left: 2px;\n}\n\n.chart_users_table td:last-child {\n padding-right: 2px;\n}\n\n.chart_legend_open {\n float: right;\n}\n\n.chart_spin {\n position: relative;\n top: 130px;\n}\n\n#chart_error {\n clear: right;\n position: relative;\n top: 40%;\n}\n\n.chart_new_user {\n margin-top: 5px;\n}\n\n.chart_user_add {\n margin-left: 8px;\n}\n\n.chart_user_color {\n border: 1px solid black;\n float: left;\n height: 11px;\n width: 11px;\n}\n\n#chart_new_user_color {\n border-style: dashed;\n cursor: pointer;\n margin: 2px;\n margin-right: 7px;\n}\n\n.chart_user_judge_id {\n color: #707070;\n}\n\n.chart_user_problems_count {\n color: #707070;\n text-align: right;\n}\n\n.chart_legend {\n border: 1px solid #1a5cc8;\n float: right;\n margin-bottom: 10px;\n padding: 5px;\n text-align: left;\n}\n\n.chart_toggle {\n display: inline-block;\n margin-top: 15px;\n}\n\n.chart_user_remove {\n float: right;\n}\n\n.chart_version {\n float: right;\n}\n\n.chart_copyright {\n position: absolute;\n bottom: 10px;\n right: 0;\n}';
function addStyles(observer) {
observer.forEach('head', function () {
var _arr = [JQPLOT_STYLE, EXTENSION_STYLE];
for (var _i = 0; _i < _arr.length; _i++) {
var style = _arr[_i];
var elem = document.createElement('style');
elem.textContent = style;
document.head.appendChild(elem);
}
});
}
"use strict";
var LOCALES = {
"en": {
add: "Add",
addUsers: "Add users",
author: "Alexander Borzunov",
del: "Delete",
hideChart: "Hide chart",
judgeIDDoesntExist: "This user doesn't exist!",
judgeIDNotEnoughOfAccepted: "The user must have at least two solved problems!",
judgeIDIncorrectFormat: "Incorrect Judge ID format (there's no digits)!",
judgeIDIsAlreadyAdded: "This Judge ID has already been added!",
judgeIDLabel: "Judge ID or link:",
queryFailed: "An error occured on the request to the server.",
refreshPage: "Try to refresh the page.",
showChart: "Show chart",
version: "version",
wrongJudgeID: "There's no submits on this Judge ID",
highlightLastSolvedProblems: "Mark recent ACs",
notEnoughData: "Too little data for the chart"
},
"ru": {
add: "Добавить",
addUsers: "Добавить пользователей",
author: "Александр Борзунов",
del: "Удалить",
hideChart: "Скрыть график",
judgeIDDoesntExist: "Такого пользователя не существует!",
judgeIDNotEnoughOfAccepted: "Пользователь должен иметь не менее двух решённых задач!",
judgeIDIncorrectFormat: "Некорректный формат Judge ID (нет цифр)!",
judgeIDIsAlreadyAdded: "Этот Judge ID уже присутствует на графике!",
judgeIDLabel: "Judge ID или ссылка:",
queryFailed: "Произошла ошибка при запросе к серверу. ",
refreshPage: "Попробуйте обновить страницу.",
showChart: "Показать график",
version: "версия",
wrongJudgeID: "Не найдено посылок по этому Judge ID",
highlightLastSolvedProblems: "Выделять недавние AC",
notEnoughData: "Слишком мало данных для графика"
}
};
var locale = LOCALES.en;
function updateLocale(observer, callback) {
observer.forEachTextIn('.panel a[href="/news.aspx"]', function (newsLabel) {
locale = LOCALES[newsLabel.textContent === 'Site news' ? 'en' : 'ru'];
callback();
});
}
'use strict';
function substTemplateVariables(template, variables) {
for (var name in locale) {
template = template.replace(new RegExp('\{% locale.' + name + ' %\}', 'g'), locale[name]);
}for (var _name in variables) {
template = template.replace(new RegExp('\{% ' + _name + ' %\}', 'g'), variables[_name]);
}return template;
}
var COLOR_GREEN = '#4f4';
var COLOR_RED = '#f99';
var COLOR_BLUE = '#88f';
var TEMPLATE_TOGGLE_LINK = '<br /><a href="#" class="chart_toggle">{% label %}</a>';
var TEMPLATE_USER_BEGIN = '<tr id="{% row_id %}">\n<td><div class="chart_user_color" style="background: {% color %};"></div></td>\n<td class="chart_user_judge_id">{% judge_id %}</td>\n<td>{% name %}</td>';
var TEMPLATE_USER_SEVERAL_LINES = '<td class="chart_user_problems_count">{% problems_count %}</td>\n<td><a href="#" class="chart_user_remove">{% locale.del %}</a></td>';
var TEMPLATE_USER_END = '</tr>';
var TEMPLATE_CHART = '<div id="chart_place">\n<div id="chart_loading" class="chart_box">\n <div class="chart_comment chart_version">\n Timus Charts, {% locale.version %} ' + SCRIPT_VERSION + '\n </div>\n <div class="chart_comment chart_copyright">© {% locale.author %}</div>\n\n <div class="chart_spin"></div>\n <div id="chart_error" class="chart_comment" style="display: none;"></div>\n</div>\n<div id="chart" class="chart_box" style="display: none;"></div>\n<div class="chart_legend_box">\n <a href="#" class="chart_legend_open" style="display: none;">\n {% locale.addUsers %}\n </a>\n <div class="chart_legend" style="display: none;">\n <table class="chart_users_table"></table>\n <div class="chart_new_user">\n <div id="chart_new_user_color" class="chart_user_color" style="background: ' + COLOR_BLUE + ';"></div>\n {% locale.judgeIDLabel %} <input type="text" class="chart_judge_id_input" />\n <a href="#" class="chart_user_add">{% locale.add %}</a>\n <div id="chart_loading_error_judge_id" class="chart_comment" style="display: none;"></div>\n </div>\n </div>\n</div>\n</div>';
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ELEMENT_HANDLER_CLASS_PREFIX = 'tc__observer-element-';
var TEXT_HANDLER_CLASS_PREFIX = 'tc__observer-text-';
var ElementObserver = function () {
_createClass(ElementObserver, null, [{
key: '_invokeHandlers',
value: function _invokeHandlers(handlers, classPrefix, matchedElement, passedNode) {
handlers.forEach(function (_ref, i) {
var selector = _ref.selector,
handler = _ref.handler;
if (matchedElement.matches(selector) && !matchedElement.classList.contains(classPrefix + i)) handler(passedNode);
});
}
}]);
function ElementObserver() {
var _this = this;
_classCallCheck(this, ElementObserver);
this._elementHandlers = [];
this._textHandlers = [];
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
Array.from(mutation.addedNodes).forEach(function (node) {
if (node instanceof Element) ElementObserver._invokeHandlers(_this._elementHandlers, ELEMENT_HANDLER_CLASS_PREFIX, node, node);else if (node instanceof Text && node.parentElement !== null) ElementObserver._invokeHandlers(_this._textHandlers, TEXT_HANDLER_CLASS_PREFIX, node.parentElement, node);
});
});
}).observe(document.documentElement, {
childList: true,
subtree: true
});
}
_createClass(ElementObserver, [{
key: 'forEach',
value: function forEach(selector, handler) {
var handlerId = this._elementHandlers.length;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Array.from(document.querySelectorAll(selector))[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var el = _step.value;
handler(el);
el.classList.add(ELEMENT_HANDLER_CLASS_PREFIX + handlerId);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
this._elementHandlers.push({ selector: selector, handler: handler });
}
}, {
key: 'forEachTextIn',
value: function forEachTextIn(selector, handler) {
var handlerId = this._textHandlers.length;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = Array.from(document.querySelectorAll(selector))[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var el = _step2.value;
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = el.childNodes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var node = _step3.value;
if (node instanceof Text) handler(node);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
el.classList.add(TEXT_HANDLER_CLASS_PREFIX + handlerId);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
this._textHandlers.push({ selector: selector, handler: handler });
}
}]);
return ElementObserver;
}();
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Submit = function () {
function Submit() {
_classCallCheck(this, Submit);
}
_createClass(Submit, [{
key: 'getProblemID',
value: function getProblemID() {
return this.space + ',' + this.problemNo;
}
}, {
key: 'getCacheKey',
value: function getCacheKey() {
return 'problem' + this.space + '_' + this.problemNo;
}
}, {
key: 'isConsidered',
value: function isConsidered() {
if (this.verdict !== 'Accepted') return false;
if (this.space == 1) return true;
// Check whether the online-contest problem is
// copied to the main archive
var problemID = this.getProblemID();
var archiveNo;
if (problemID in Submit.problemsFromContests) {
archiveNo = Submit.problemsFromContests[problemID];
} else {
try {
archiveNo = getValue(this.getCacheKey());
Submit.problemsFromContests[problemID] = archiveNo;
} catch (err) {}
}
if (archiveNo !== undefined) {
if (archiveNo == "null") return false;
this.space = 1;
this.problemNo = archiveNo;
return true;
}
return null;
}
}, {
key: 'queryWhetherConsidered',
value: function queryWhetherConsidered(resultCallback, failCallback) {
var _this = this;
var address = document.location.origin + '/problem.aspx?space=' + this.space + '&num=' + this.problemNo;
$.get(address, function (data) {
var problemID = _this.getProblemID();
var cacheKey = _this.getCacheKey();
var match = /<A HREF="problem\.aspx\?space=1(&|&)num=(\d{4})"><nobr>\d{4}. .*?<\/nobr><\/A>/i.exec(data);
if (match !== null) {
var archiveNo = match[2];
Submit.problemsFromContests[problemID] = archiveNo;
setValue(cacheKey, archiveNo);
_this.space = 1;
_this.problemNo = archiveNo;
resultCallback(true);
} else {
Submit.problemsFromContests[problemID] = "null";
setValue(cacheKey, "null");
resultCallback(false);
}
}).fail(failCallback);
}
}]);
return Submit;
}();
// This dictionary duplicates some "problem*_*" records of local storage
// because it can be full or inaccessible
Submit.problemsFromContests = {};
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var MSEC_PER_SEC = 1e3;
var Author = function () {
function Author(judgeID) {
_classCallCheck(this, Author);
this.judgeID = judgeID;
this.acceptedProblems = {};
this.acceptedProblemsCount = 0;
this.submitsQuery = '?author=' + judgeID + '&status=accepted';
this.lastSubmitID = null;
this.noMorePages = false;
this.hasDeletedProblems = false;
}
_createClass(Author, [{
key: 'getCacheKeyPrefix',
value: function getCacheKeyPrefix() {
return 'author' + this.judgeID;
}
}, {
key: 'saveToCache',
value: function saveToCache() {
var keyPrefix = this.getCacheKeyPrefix();
setValue(keyPrefix + '_cacheVer', CACHE_VERSION);
setValue(keyPrefix + '_acceptedProblems', JSON.stringify(this.acceptedProblems));
setValue(keyPrefix + '_acceptedProblemsCount', this.acceptedProblemsCount);
setValue(keyPrefix + '_lastKnownSubmitID', this.lastSubmitID);
}
}, {
key: 'loadFromCache',
value: function loadFromCache() {
var keyPrefix = this.getCacheKeyPrefix();
try {
var cacheVersion = parseInt(getValue(keyPrefix + '_cacheVer'));
if (cacheVersion !== CACHE_VERSION) throw new Error('Incompatible cache version');
this.acceptedProblems = JSON.parse(getValue(keyPrefix + '_acceptedProblems'));
this.cachedAcceptedProblemsCount = parseInt(getValue(keyPrefix + '_acceptedProblemsCount'));
this.cachedLastSubmitID = parseInt(getValue(keyPrefix + '_lastKnownSubmitID'));
this.cacheAvailable = true;
} catch (err) {
this.cacheAvailable = false;
}
}
}, {
key: 'retrieve',
value: function retrieve(expectedAcProblems, resultCallback, failCallback) {
this.loadFromCache();
if (this.cacheAvailable && this.cachedAcceptedProblemsCount == expectedAcProblems) {
this.acceptedProblemsCount = this.cachedAcceptedProblemsCount;
this.lastSubmitID = this.cachedLastSubmitID;
if (resultCallback !== undefined) resultCallback();
return;
}
this.retrieveCallback = resultCallback;
this.failCallback = failCallback;
this.parseSubmitsPage(null);
}
}, {
key: 'getSubmitsPage',
value: function getSubmitsPage(query, resultCallback, failCallback) {
var _this = this;
var url = document.location.origin + '/textstatus.aspx' + query;
if (!this.hasDeletedProblems) {
$.get(url, function (data) {
var expr = /<HTML>/i;
if (expr.test(data)) {
_this.hasDeletedProblems = true;
_this.getSubmitsPage(query, resultCallback, failCallback);
return;
}
resultCallback(data);
}).fail(failCallback);
return;
}
// Timus API used to throw an exception if the author have submits on
// deleted problems (e.g. in private contests). If we got an exception,
// just skip additional problem spaces.
$.get(url + '&space=1').then(resultCallback, failCallback);
}
}, {
key: 'parseSubmitsPage',
value: function parseSubmitsPage(fromSubmitID) {
var _this2 = this;
var submitsQueried = this.cacheAvailable ? 200 : 1000;
var query = this.submitsQuery + '&count=' + submitsQueried;
if (fromSubmitID !== null) query += '&from=' + fromSubmitID;
var author = this;
this.getSubmitsPage(query, function (data) {
var lines = data.split('\n').filter(function (line) {
return line !== '';
});
if (!lines.length || !lines[0].startsWith('submit')) {
_this2.failCallback();
return;
}
lines = lines.slice(1);
if (lines.length < submitsQueried) _this2.noMorePages = true;
try {
_this2.submits = lines.map(function (line) {
var fields = line.split('\t');
var submit = new Submit();
submit.id = parseInt(fields[0]);
submit.space = parseInt(fields[3]);
submit.problemNo = parseInt(fields[4]);
var elems = fields[1].replace(/-/g, ' ').replace(/:/g, ' ').split(' ');
submit.time = new Date(elems[0], elems[1] - 1, elems[2], elems[3], elems[4], elems[5]).getTime();
submit.verdict = fields[6];
if (isNaN(submit.id) || isNaN(submit.space) || isNaN(submit.problemNo) || isNaN(submit.time)) throw new Error("Failed to parse information about submit");
return submit;
});
} catch (err) {
_this2.failCallback();
return;
}
_this2.processSubmitsFrom(0);
}, this.failCallback);
}
}, {
key: 'considerSubmit',
value: function considerSubmit(submit) {
var seconds = Math.floor(submit.time / MSEC_PER_SEC);
var alreadyAccepted = submit.problemNo in this.acceptedProblems;
if (!alreadyAccepted) this.acceptedProblemsCount++;
if (!alreadyAccepted || seconds < this.acceptedProblems[submit.problemNo]) this.acceptedProblems[submit.problemNo] = seconds;
}
}, {
key: 'processSubmitsFrom',
value: function processSubmitsFrom(index) {
while (index < this.submits.length) {
var submit = this.submits[index];
if (this.lastSubmitID === null) this.lastSubmitID = submit.id;
if (this.cacheAvailable && submit.id <= this.cachedLastSubmitID) {
this.acceptedProblemsCount += this.cachedAcceptedProblemsCount;
this.noMorePages = true;
break;
}
var isConsidered = submit.isConsidered();
if (isConsidered === null) {
this.queryAndProcessSubmitsFrom(index);
return;
}
if (isConsidered === true) this.considerSubmit(submit);
index++;
}
if (this.noMorePages) {
this.saveToCache();
if (this.retrieveCallback !== undefined) this.retrieveCallback();
} else this.parseSubmitsPage(this.submits[this.submits.length - 1].id - 1);
}
}, {
key: 'queryAndProcessSubmitsFrom',
value: function queryAndProcessSubmitsFrom(index) {
var _this3 = this;
var submit = this.submits[index];
submit.queryWhetherConsidered(function (result) {
if (result) _this3.considerSubmit(submit);
_this3.processSubmitsFrom(index + 1);
}, this.failCallback);
}
}]);
return Author;
}();
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PageParser = function () {
function PageParser() {
_classCallCheck(this, PageParser);
this.parsed = false;
var match = /id=(\d+)/i.exec(location.href);
var id = match !== null ? match[1] : null;
match = /compareto=(\d+)/i.exec(location.href);
var compareto = match !== null ? match[1] : null;
if (compareto === null) {
this.ourId = id;
this.rivalId = null;
} else {
this.ourId = compareto;
this.rivalId = id;
}
}
_createClass(PageParser, [{
key: 'parse',
value: function parse() {
if (this.parsed) return;
this.parsed = true;
var link = $('h2.author_name a');
var profileName = link.length ? link.html() : $('h2.author_name').contents().get(0).nodeValue;
if (this.rivalId !== null) {
var bothCount = $('td.both').length - 1;
this.ourCount = $('td.accepted').length + bothCount - 1;
this.rivalCount = $('td.cmpac').length + bothCount - 1;
this.ourName = $('.author_comparison_legend .padright:first').html();
this.rivalName = profileName;
} else {
this.ourCount = $('td.accepted').length;
this.ourName = profileName;
}
}
}]);
return PageParser;
}();
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var DataRetriever = function () {
function DataRetriever(pageParser) {
_classCallCheck(this, DataRetriever);
this._pageParser = pageParser;
this._authorStates = {};
}
_createClass(DataRetriever, [{
key: '_getExpectedAcProblems',
value: function _getExpectedAcProblems(judgeID) {
switch (judgeID) {
case this._pageParser.ourId:
return this._pageParser.ourCount;
case this._pageParser.rivalId:
return this._pageParser.rivalCount;
default:
return null;
}
}
}, {
key: '_startRetrieval',
value: function _startRetrieval(judgeID, resultCb, failCb) {
var _this = this;
var resultCallbacks = [];
var failCallbacks = [];
var author = new Author(judgeID);
var state = {
status: 'process',
resultCallbacks: resultCallbacks,
failCallbacks: failCallbacks,
author: author
};
DataRetriever._pushCallbacks(state, resultCb, failCb);
this._authorStates[judgeID] = state;
author.retrieve(this._getExpectedAcProblems(judgeID), function () {
_this._authorStates[judgeID] = {
status: 'success',
author: author
};
resultCallbacks.forEach(function (cb) {
return cb(author);
});
}, function () {
_this._authorStates[judgeID] = {
status: 'fail',
author: author
};
failCallbacks.forEach(function (cb) {
return cb(author);
});
});
}
}, {
key: 'retrieve',
value: function retrieve(judgeID, resultCb, failCb) {
var state = this._authorStates[judgeID];
if (state === undefined) {
this._startRetrieval(judgeID, resultCb, failCb);
return;
}
switch (state.status) {
case 'process':
DataRetriever._pushCallbacks(state, resultCb, failCb);
break;
case 'success':
resultCb(state.author);
break;
case 'fail':
failCb(state.author);
break;
default:
throw new Error("Unknown retrieval state " + state.status);
}
}
}], [{
key: '_pushCallbacks',
value: function _pushCallbacks(state, resultCb, failCb) {
if (resultCb !== undefined) state.resultCallbacks.push(resultCb);
if (failCb !== undefined) state.failCallbacks.push(failCb);
}
}]);
return DataRetriever;
}();
"use strict";
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Line = function () {
function Line(author, name, color) {
_classCallCheck(this, Line);
this.author = author;
this.name = name;
this.color = color;
}
_createClass(Line, [{
key: "make",
value: function make() {
var _this = this;
this.points = Object.keys(this.author.acceptedProblems).map(function (key) {
return _this.author.acceptedProblems[key] * MSEC_PER_SEC;
}).sort(function (a, b) {
return a - b;
}).map(function (date, i) {
return [new Date(date), i + 1];
});
}
}]);
return Line;
}();
'use strict';
/**
* Copyright (c) 2011-2014 Felix Gnass
* Licensed under the MIT license
* http://spin.js.org/
*
* Modified 2016 Alexander Borzunov - Make a public factory function
*
* Example:
var opts = {
lines: 12 // The number of lines to draw
, length: 7 // The length of each line
, width: 5 // The line thickness
, radius: 10 // The radius of the inner circle
, scale: 1.0 // Scales overall size of the spinner
, corners: 1 // Roundness (0..1)
, color: '#000' // #rgb or #rrggbb
, opacity: 1/4 // Opacity of the lines
, rotate: 0 // Rotation offset
, direction: 1 // 1: clockwise, -1: counterclockwise
, speed: 1 // Rounds per second
, trail: 100 // Afterglow percentage
, fps: 20 // Frames per second when using setTimeout()
, zIndex: 2e9 // Use a high z-index by default
, className: 'spinner' // CSS class to assign to the element
, top: '50%' // center vertically
, left: '50%' // center horizontally
, shadow: false // Whether to render a shadow
, hwaccel: false // Whether to use hardware acceleration (might be buggy)
, position: 'absolute' // Element positioning
}
var target = document.getElementById('foo')
var spinner = new Spinner(opts).spin(target)
*/
function makeSpinner() {
"use strict";
var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */
,
animations = {} /* Animation rules keyed by their name */
,
useCssAnimations /* Whether to use CSS animations or setTimeout */
,
sheet; /* A stylesheet to hold the @keyframe or VML rules. */
/**
* Utility function to create elements. If no tag name is given,
* a DIV is created. Optionally properties can be passed.
*/
function createEl(tag, prop) {
var el = document.createElement(tag || 'div'),
n;
for (n in prop) {
el[n] = prop[n];
}return el;
}
/**
* Appends children and returns the parent.
*/
function ins(parent /* child1, child2, ...*/) {
for (var i = 1, n = arguments.length; i < n; i++) {
parent.appendChild(arguments[i]);
}
return parent;
}
/**
* Creates an opacity keyframe animation rule and returns its name.
* Since most mobile Webkits have timing issues with animation-delay,
* we create separate rules for each line/segment.
*/
function addAnimation(alpha, trail, i, lines) {
var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-'),
start = 0.01 + i / lines * 100,
z = Math.max(1 - (1 - alpha) / trail * (100 - start), alpha),
prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase(),
pre = prefix && '-' + prefix + '-' || '';
if (!animations[name]) {
sheet.insertRule('@' + pre + 'keyframes ' + name + '{' + '0%{opacity:' + z + '}' + start + '%{opacity:' + alpha + '}' + (start + 0.01) + '%{opacity:1}' + (start + trail) % 100 + '%{opacity:' + alpha + '}' + '100%{opacity:' + z + '}' + '}', sheet.cssRules.length);
animations[name] = 1;
}
return name;
}
/**
* Tries various vendor prefixes and returns the first supported property.
*/
function vendor(el, prop) {
var s = el.style,
pp,
i;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
if (s[prop] !== undefined) return prop;
for (i = 0; i < prefixes.length; i++) {
pp = prefixes[i] + prop;
if (s[pp] !== undefined) return pp;
}
}
/**
* Sets multiple style properties at once.
*/
function css(el, prop) {
for (var n in prop) {
el.style[vendor(el, n) || n] = prop[n];
}
return el;
}
/**
* Fills in default values.
*/
function merge(obj) {
for (var i = 1; i < arguments.length; i++) {
var def = arguments[i];
for (var n in def) {
if (obj[n] === undefined) obj[n] = def[n];
}
}
return obj;
}
/**
* Returns the line color from the given string or array.
*/
function getColor(color, idx) {
return typeof color == 'string' ? color : color[idx % color.length];
}
// Built-in defaults
var defaults = {
lines: 12 // The number of lines to draw
, length: 7 // The length of each line
, width: 5 // The line thickness
, radius: 10 // The radius of the inner circle
, scale: 1.0 // Scales overall size of the spinner
, corners: 1 // Roundness (0..1)
, color: '#000' // #rgb or #rrggbb
, opacity: 1 / 4 // Opacity of the lines
, rotate: 0 // Rotation offset
, direction: 1 // 1: clockwise, -1: counterclockwise
, speed: 1 // Rounds per second
, trail: 100 // Afterglow percentage
, fps: 20 // Frames per second when using setTimeout()
, zIndex: 2e9 // Use a high z-index by default
, className: 'spinner' // CSS class to assign to the element
, top: '50%' // center vertically
, left: '50%' // center horizontally
, shadow: false // Whether to render a shadow
, hwaccel: false // Whether to use hardware acceleration (might be buggy)
, position: 'absolute' // Element positioning
/** The constructor */
};function Spinner(o) {
this.opts = merge(o || {}, Spinner.defaults, defaults);
}
// Global defaults that override the built-ins:
Spinner.defaults = {};
merge(Spinner.prototype, {
/**
* Adds the spinner to the given target element. If this instance is already
* spinning, it is automatically removed from its previous target b calling
* stop() internally.
*/
spin: function spin(target) {
this.stop();
var self = this,
o = self.opts,
el = self.el = createEl(null, { className: o.className });
css(el, {
position: o.position,
width: 0,
zIndex: o.zIndex,
left: o.left,
top: o.top
});
if (target) {
target.insertBefore(el, target.firstChild || null);
}
el.setAttribute('role', 'progressbar');
self.lines(el, self.opts);
if (!useCssAnimations) {
// No CSS animation support, use setTimeout() instead
var i = 0,
start = (o.lines - 1) * (1 - o.direction) / 2,
alpha,
fps = o.fps,
f = fps / o.speed,
ostep = (1 - o.opacity) / (f * o.trail / 100),
astep = f / o.lines;(function anim() {
i++;
for (var j = 0; j < o.lines; j++) {
alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity);
self.opacity(el, j * o.direction + start, alpha, o);
}
self.timeout = self.el && setTimeout(anim, ~~(1000 / fps));
})();
}
return self;
}
/**
* Stops and removes the Spinner.
*/
, stop: function stop() {
var el = this.el;
if (el) {
clearTimeout(this.timeout);
if (el.parentNode) el.parentNode.removeChild(el);
this.el = undefined;
}
return this;
}
/**
* Internal method that draws the individual lines. Will be overwritten
* in VML fallback mode below.
*/
, lines: function lines(el, o) {
var i = 0,
start = (o.lines - 1) * (1 - o.direction) / 2,
seg;
function fill(color, shadow) {
return css(createEl(), {
position: 'absolute',
width: o.scale * (o.length + o.width) + 'px',
height: o.scale * o.width + 'px',
background: color,
boxShadow: shadow,
transformOrigin: 'left',
transform: 'rotate(' + ~~(360 / o.lines * i + o.rotate) + 'deg) translate(' + o.scale * o.radius + 'px' + ',0)',
borderRadius: (o.corners * o.scale * o.width >> 1) + 'px'
});
}
for (; i < o.lines; i++) {
seg = css(createEl(), {
position: 'absolute',
top: 1 + ~(o.scale * o.width / 2) + 'px',
transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
opacity: o.opacity,
animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1 / o.speed + 's linear infinite'
});
if (o.shadow) ins(seg, css(fill('#000', '0 0 4px #000'), { top: '2px' }));
ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)')));
}
return el;
}
/**
* Internal method that adjusts the opacity of a single line.
* Will be overwritten in VML fallback mode below.
*/
, opacity: function opacity(el, i, val) {
if (i < el.childNodes.length) el.childNodes[i].style.opacity = val;
}
});
function initVML() {
/* Utility function to create a VML tag */
function vml(tag, attr) {
return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr);
}
// No CSS transforms but VML support, add a CSS rule for VML elements:
sheet.addRule('.spin-vml', 'behavior:url(#default#VML)');
Spinner.prototype.lines = function (el, o) {
var r = o.scale * (o.length + o.width),
s = o.scale * 2 * r;
function grp() {
return css(vml('group', {
coordsize: s + ' ' + s,
coordorigin: -r + ' ' + -r
}), { width: s, height: s });
}
var margin = -(o.width + o.length) * o.scale * 2 + 'px',
g = css(grp(), { position: 'absolute', top: margin, left: margin }),
i;
function seg(i, dx, filter) {
ins(g, ins(css(grp(), { rotation: 360 / o.lines * i + 'deg', left: ~~dx }), ins(css(vml('roundrect', { arcsize: o.corners }), { width: r,
height: o.scale * o.width,
left: o.scale * o.radius,
top: -o.scale * o.width >> 1,
filter: filter
}), vml('fill', { color: getColor(o.color, i), opacity: o.opacity }), vml('stroke', { opacity: 0 }) // transparent stroke to fix color bleeding upon opacity change
)));
}
if (o.shadow) for (i = 1; i <= o.lines; i++) {
seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)');
}
for (i = 1; i <= o.lines; i++) {
seg(i);
}return ins(el, g);
};
Spinner.prototype.opacity = function (el, i, val, o) {
var c = el.firstChild;
o = o.shadow && o.lines || 0;
if (c && i + o < c.childNodes.length) {
c = c.childNodes[i + o];c = c && c.firstChild;c = c && c.firstChild;
if (c) c.opacity = val;
}
};
}
if (typeof document !== 'undefined') {
sheet = function () {
var el = createEl('style', { type: 'text/css' });
ins(document.getElementsByTagName('head')[0], el);
return el.sheet || el.styleSheet;
}();
var probe = css(createEl('group'), { behavior: 'url(#default#VML)' });
if (!vendor(probe, 'transform') && probe.adj) initVML();else useCssAnimations = vendor(probe, 'animation');
}
return Spinner;
}
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function zfill(str, width) {
while (str.length < width) {
str = '0' + str;
}return str;
}
function randomColor() {
return '#' + zfill(Math.floor(Math.random() * 0x1000).toString(16), 3);
}
var YAXIS_SMALLEST_MAX = 10;
var XAXIS_CRITICAL_DIFF = 1000 * 60 * 60 * 24 * 3;
var MIN_PROBLEMS_TO_SHOW_USER = 2;
var Chart = function () {
function Chart(observer, pageParser, dataRetriever) {
_classCallCheck(this, Chart);
this.observer = observer;
this.pageParser = pageParser;
this.dataRetriever = dataRetriever;
this.ready = false;
this.visible = false;
this.lines = [];
this.linesExpected = 0;
this.loadingState = false;
this.errorShown = false;
}
_createClass(Chart, [{
key: 'loading',
value: function loading(state) {
if (state === false) {
this.spinner.stop();
$('#chart_loading').hide();
$('#chart').show();
this.loadingState = false;
return;
}
if (state === true) {
this.loadingState = true;
$('#chart').hide();
$('#chart_loading').show();
this.spinner.spin($('.chart_spin')[0]);
return;
}
return this.loadingState;
}
}, {
key: 'showError',
value: function showError(html) {
this.errorShown = true;
this.loading(false);
$('.chart_legend_open').hide();
$('.chart_legend').hide();
$('#chart').hide();
$('#chart_loading').show();
$('#chart_error').html(html);
$('#chart_error').show();
}
}, {
key: 'showQueryError',
value: function showQueryError() {
this.showError(locale.queryFailed + '<br />' + locale.refreshPage);
}
}, {
key: 'redrawLegend',
value: function redrawLegend() {
var _this = this;
var severalLines = this.lines.length > 1;
var code = '';
this.lines.forEach(function (line) {
code += substTemplateVariables(TEMPLATE_USER_BEGIN, {
row_id: Chart.getLegendRowID(line),
color: line.color,
judge_id: line.author.judgeID,
name: line.name
});
if (severalLines) code += substTemplateVariables(TEMPLATE_USER_SEVERAL_LINES, {
problems_count: line.author.acceptedProblemsCount
});
code += TEMPLATE_USER_END;
});
$('.chart_users_table').html(code);
if (!severalLines) return;
this.lines.forEach(function (line) {
$('#' + Chart.getLegendRowID(line) + ' .chart_user_remove').click(function (event) {
_this.removeUser(line.author.judgeID);
event.preventDefault();
});
});
}
}, {
key: 'fixPlot',
value: function fixPlot(plot) {
var needReplot = false;
// Fix non-integer ticks on X axis when maximal value is small
if (plot.axes.yaxis.max < YAXIS_SMALLEST_MAX) {
plot.axes.yaxis.reset();
plot.axes.yaxis.max = YAXIS_SMALLEST_MAX;
needReplot = true;
}
// Fix inadequate behavior of ticks when Y axis dates range is small
if (plot.axes.xaxis.max - plot.axes.xaxis.min <= XAXIS_CRITICAL_DIFF) {
plot.axes.xaxis.numberTicks = 5;
plot.axes.xaxis.tickOptions.formatString += ', %H:%M';
needReplot = true;
}
if (needReplot) plot.replot();
}
}, {
key: 'redraw',
value: function redraw() {
this.lines.sort(function (a, b) {
return b.author.acceptedProblemsCount - a.author.acceptedProblemsCount;
});
this.redrawLegend();
var points = this.lines.map(function (line) {
return line.points;
}).reverse();
var colors = this.lines.map(function (line) {
return line.color;
}).reverse();
if (!$('.chart_legend').is(':visible')) $('.chart_legend_open').show();
$('#chart').html('');
this.loading(false);
var plot = $.jqplot('chart', points, {
gridPadding: {
bottom: 50
},
grid: {
shadow: false
},
axes: {
xaxis: {
renderer: $.jqplot.DateAxisRenderer,
tickOptions: { formatString: '%#d %b %Y' }
},
yaxis: {
min: 0,
tickOptions: { formatString: '%d' }
}
},
seriesDefaults: {
shadow: false,
showMarker: false,
lineWidth: 2
},
seriesColors: colors
});
this.fixPlot(plot);
}
}, {
key: 'showJudgeIDError',
value: function showJudgeIDError(message) {
this.loading(false);
$('#chart_loading_error_judge_id').html(message).show();
}
}, {
key: 'expectUsers',
value: function expectUsers(count) {
this.linesExpected += count;
}
}, {
key: 'addUser',
value: function addUser(judgeID, name, color, isCritical, callback) {
var _this2 = this;
this.dataRetriever.retrieve(judgeID, function (author) {
var line = new Line(author, name, color);
line.make();
if (line.points.length < MIN_PROBLEMS_TO_SHOW_USER) {
if (isCritical) _this2.showQueryError();else _this2.showJudgeIDError(locale.judgeIDNotEnoughOfAccepted);
_this2.linesExpected--;
return;
}
_this2.lines.push(line);
if (_this2.lines.length === _this2.linesExpected) {
_this2.redraw();
if (callback !== undefined) callback();
}
}, function () {
if (isCritical) _this2.showQueryError();else _this2.showJudgeIDError(locale.queryFailed);
_this2.linesExpected--;
});
}
}, {
key: 'removeUser',
value: function removeUser(judgeID) {
var index = this.lines.findIndex(function (line) {
return line.author.judgeID == judgeID;
});
if (index == -1) return;
this.lines.splice(index, 1);
this.linesExpected--;
this.redraw();
}
}, {
key: 'loadJudgeID',
value: function loadJudgeID() {
var _this3 = this;
if (this.loading()) return;
this.loading(true);
$('#chart_loading_error_judge_id').hide();
var judgeID = $('.chart_judge_id_input').val();
var match = /(\d+)[^\d]*$/.exec(judgeID);
if (match === null) {
this.showJudgeIDError(locale.judgeIDIncorrectFormat);
return;
}
judgeID = match[1];
if (this.lines.some(function (line) {
return line.author.judgeID == judgeID;
})) {
this.showJudgeIDError(locale.judgeIDIsAlreadyAdded);
return;
}
var address = document.location.origin + '/author.aspx?id=' + judgeID;
$.get(address, function (data) {
var match = /<H2 CLASS="author_name">(<A HREF=".*?" TARGET="_blank">)?(.+?)(<\/A>)?<\/H2>/i.exec(data);
if (match === null) {
_this3.showJudgeIDError(locale.judgeIDDoesntExist);
return;
}
var name = match[2];
var color = $('#chart_new_user_color').css('background-color');
_this3.expectUsers(1);
_this3.addUser(judgeID, name, color, false, function () {
$('.chart_judge_id_input').val('');
$('#chart_new_user_color').css('background-color', randomColor());
});
}).fail(function () {
return _this3.showJudgeIDError(locale.queryFailed);
});
}
}, {
key: 'showLegend',
value: function showLegend() {
$('.chart_legend_open').hide();
$('.chart_legend').show();
$('.chart_judge_id_input').focus();
}
}, {
key: 'areEnoughDataPresent',
value: function areEnoughDataPresent() {
return this.pageParser.ourCount >= MIN_PROBLEMS_TO_SHOW_USER || this.pageParser.rivalId !== null && this.pageParser.rivalCount >= MIN_PROBLEMS_TO_SHOW_USER;
}
}, {
key: 'createToggleLink',
value: function createToggleLink(authorLinksElem, expectedVisibility) {
var _this4 = this;
var label = expectedVisibility ? locale.hideChart : locale.showChart;
$(authorLinksElem).append(substTemplateVariables(TEMPLATE_TOGGLE_LINK, {
label: label
}));
$('.chart_toggle').click(function (event) {
if (_this4.visible) _this4.hide();else _this4.show();
event.preventDefault();
});
}
}, {
key: 'createChartPlace',
value: function createChartPlace() {
var _this5 = this;
$('.author_links').after(substTemplateVariables(TEMPLATE_CHART, {}));
$('#chart_new_user_color').click(function () {
$(this).css('background-color', randomColor());
});
$('.chart_legend_open').click(function (event) {
_this5.showLegend();
event.preventDefault();
});
$('.chart_judge_id_input').keypress(function (event) {
if (event.which === 13) {
_this5.loadJudgeID();
event.preventDefault();
}
});
$('.chart_user_add').click(function (event) {
_this5.loadJudgeID();
event.preventDefault();
});
var Spinner = makeSpinner();
this.spinner = new Spinner();
}
}, {
key: 'loadInitialData',
value: function loadInitialData() {
var showUs = this.pageParser.ourCount >= MIN_PROBLEMS_TO_SHOW_USER;
var showRival = this.pageParser.rivalId !== null && this.pageParser.rivalCount >= MIN_PROBLEMS_TO_SHOW_USER;
this.expectUsers(showUs + showRival);
if (showUs) this.addUser(this.pageParser.ourId, this.pageParser.ourName, COLOR_GREEN, true);
if (showRival) this.addUser(this.pageParser.rivalId, this.pageParser.rivalName, COLOR_RED, true);
}
}, {
key: 'hide',
value: function hide() {
if (!this.visible) return;
this.visible = false;
setValue('chart_visible', '0');
$('.chart_toggle').html(locale.showChart);
$('#chart_place').hide();
}
}, {
key: 'show',
value: function show() {
var _this6 = this;
if (this.visible) return;
this.visible = true;
setValue('chart_visible', '1');
$('.chart_toggle').html(locale.hideChart);
if (!this.ready) {
this.createChartPlace();
this.loading(true);
$(function () {
_this6.pageParser.parse();
if (_this6.areEnoughDataPresent()) _this6.loadInitialData();else _this6.showError(locale.notEnoughData);
});
this.ready = true;
} else {
$('#chart_place').show();
if (!this.loadingState) {
// If the last redrawing happened when the chart was hidden,
// jqPlot wouldn't accomplish it correctly,
// so we need run to redraw the chart again
this.redraw();
}
}
}
}, {
key: 'getDefaultVisibility',
value: function getDefaultVisibility() {
try {
if (getValue('chart_visible') === '0') return false;
} catch (err) {}
return true;
}
}, {
key: 'arrange',
value: function arrange() {
var _this7 = this;
this.observer.forEach('.author_links', function (elem) {
var visible = _this7.getDefaultVisibility();
_this7.createToggleLink(elem, visible);
if (visible) _this7.show();
});
}
}], [{
key: 'getLegendRowID',
value: function getLegendRowID(line) {
return 'chart_user_' + line.author.judgeID;
}
}]);
return Chart;
}();
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var SECS_PER_DAY = 60 * 60 * 24;
var SECS_TO_HIGHLIGHT = 60 * SECS_PER_DAY;
var LastACHighlighter = function () {
function LastACHighlighter(observer, pageParser, dataRetriever) {
_classCallCheck(this, LastACHighlighter);
this.observer = observer;
this.pageParser = pageParser;
this.dataRetriever = dataRetriever;
}
_createClass(LastACHighlighter, [{
key: 'show',
value: function show() {
this.pageParser.parse();
var curTime = Date.now() / MSEC_PER_SEC;
this.dataRetriever.retrieve(this.pageParser.ourId, function (author) {
var acTimes = author.acceptedProblems;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(acTimes).sort(function (a, b) {
return acTimes[b] - acTimes[a];
})[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var problem = _step.value;
var acTime = acTimes[problem];
if (curTime - acTime > SECS_TO_HIGHLIGHT) break;
var ratio = (curTime - acTime) / SECS_TO_HIGHLIGHT;
var td = $('.attempt_list td.accepted:contains("' + problem + '")');
var hue = 120 + (1 - ratio) * 60;
td.css('background-color', 'hsl(' + hue + ', 100%, 78%)');
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
});
}
}, {
key: 'hide',
value: function hide() {
$('.attempt_list td.accepted').css('background-color', 'hsl(120, 100%, 78%)');
}
}, {
key: 'createToggler',
value: function createToggler(prevCell) {
var _this = this;
var checkbox = $('<input type="checkbox">');
var label = $('<label>').append(checkbox).append(document.createTextNode(locale.highlightLastSolvedProblems));
var td = $('<td align="right">').append(label);
$(prevCell).after(td);
checkbox.prop('checked', this.visible);
checkbox.change(function () {
return _this.setVisibility(checkbox.is(':checked'));
});
}
}, {
key: 'getDefaultVisibility',
value: function getDefaultVisibility() {
try {
if (getValue('highlight_last_solved_problems') === '0') return false;
} catch (err) {}
return true;
}
}, {
key: 'setVisibility',
value: function setVisibility(visibility) {
setValue('highlight_last_solved_problems', visibility ? '1' : '0');
this.visible = visibility;
if (visibility) this.show();else this.hide();
}
}, {
key: 'arrange',
value: function arrange() {
var _this2 = this;
if (this.pageParser.rivalId !== null) return;
this.observer.forEach('.solved_map_links td:first-child', function (elem) {
_this2.visible = _this2.getDefaultVisibility();
_this2.createToggler(elem);
});
$(function () {
if (_this2.visible) _this2.show();
});
}
}]);
return LastACHighlighter;
}();
"use strict";
var observer = new ElementObserver();
var pageParser = new PageParser();
var dataRetriever = new DataRetriever(pageParser);
addStyles(observer);
updateLocale(observer, function () {
new Chart(observer, pageParser, dataRetriever).arrange();
new LastACHighlighter(observer, pageParser, dataRetriever).arrange();
});