X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=www%2Fjs%2Fremoteglot.js;h=beaf63f74f1bfcba4437c3e4a6ca94aa30a91736;hb=eb0119aedb0a2c93b5020c10e0e8006ee0c4b0c1;hp=b72f4c426119082512ba43af50bec53fe68a3019;hpb=f71f5c94d093acda1b39d23cf7a71a21c6a3122b;p=remoteglot diff --git a/www/js/remoteglot.js b/www/js/remoteglot.js index b72f4c4..beaf63f 100644 --- a/www/js/remoteglot.js +++ b/www/js/remoteglot.js @@ -104,7 +104,7 @@ var highlight_from = undefined; var highlight_to = undefined; /** The HTML object of the move currently being highlighted (in red). - * @type {?jQuery} + * @type {?Element} * @private */ var highlighted_move = null; @@ -127,6 +127,9 @@ var unique = null; /** @type {boolean} @private */ var enable_sound = false; +/** @type {!number} @private */ +var delay_ms = 0; + /** * Our best estimate of how many milliseconds we need to add to * new Date() to get the true UTC time. Calibrated against the @@ -190,7 +193,7 @@ var current_display_move = null; * The current backend request to get main analysis (not history), if any, * so that we can abort it. * - * @type {?jqXHR} + * @type {?AbortController} * @private */ var current_analysis_xhr = null; @@ -207,7 +210,7 @@ var current_analysis_request_timer = null; /** * The current backend request to get historic data, if any. * - * @type {?jqXHR} + * @type {?AbortController} * @private */ var current_historic_xhr = null; @@ -215,7 +218,7 @@ var current_historic_xhr = null; /** * The current backend request to get hash probes, if any, so that we can abort it. * - * @type {?jqXHR} + * @type {?AbortController} * @private */ var current_hash_xhr = null; @@ -254,62 +257,88 @@ var get_unique = function() { var request_update = function() { current_analysis_request_timer = null; - current_analysis_xhr = $.ajax({ - url: backend_url + "?ims=" + ims + "&unique=" + unique - }).done(function(data, textstatus, xhr) { - sync_server_clock(xhr.getResponseHeader('Date')); - ims = xhr.getResponseHeader('X-RGLM'); - var num_viewers = xhr.getResponseHeader('X-RGNV'); - var new_data; - if (Array.isArray(data)) { - new_data = JSON.parse(JSON.stringify(current_analysis_data)); - JSON_delta.patch(new_data, data); - } else { - new_data = data; - } + let handle_err = () => { + // Backend error or similar. Wait ten seconds, then try again. + current_analysis_request_timer = setTimeout(function() { request_update(); }, 10000); + }; - var minimum_version = xhr.getResponseHeader('X-RGMV'); - if (minimum_version && minimum_version > SCRIPT_VERSION) { - // Upgrade to latest version with a force-reload. - location.reload(true); - } + current_analysis_xhr = new AbortController(); + const signal = current_analysis_xhr.signal; + fetch(backend_url + "?ims=" + ims + "&unique=" + unique, { signal }) + .then((response) => response.json().then(data => ({ok: response.ok, headers: response.headers, json: data}))) // ick + .then((obj) => { + if (!obj.ok) { + handle_err(); + return; + } - // Verify that the PV makes sense. - var valid = true; - if (new_data['pv']) { - var hiddenboard = new Chess(new_data['position']['fen']); - for (var i = 0; i < new_data['pv'].length; ++i) { - if (hiddenboard.move(new_data['pv'][i]) === null) { - valid = false; - break; - } + if (delay_ms === 0) { + process_update_response(obj.json, obj.headers); + } else { + setTimeout(function() { process_update_response(obj.json, obj.headers); }, delay_ms); } - } - var timeout = 100; - if (valid) { - possibly_play_sound(current_analysis_data, new_data); - current_analysis_data = new_data; - update_board(); - update_num_viewers(num_viewers); - } else { - console.log("Received invalid update, waiting five seconds and trying again."); - setTimeout(function() { location.reload(true); }, 5000); - } + // Next update. + if (!backend_url.match(/history/)) { + var timeout = 100; + current_analysis_request_timer = setTimeout(function() { request_update(); }, timeout); + } + }) + .catch((err) => { + if (err.name === 'AbortError') { + // Aborted because we are switching backends. Abandon and don't retry, + // because another one is already started for us. + } else { + console.log(err); + handle_err(err); + } + }) + .finally(() => { + // Display. + document.body.style.opacity = null; + }) - // Next update. - if (!backend_url.match(/history/)) { - current_analysis_request_timer = setTimeout(function() { request_update(); }, timeout); - } - }).fail(function(jqXHR, textStatus, errorThrown) { - if (textStatus === "abort") { - // Aborted because we are switching backends. Abandon and don't retry, - // because another one is already started for us. - } else { - // Backend error or similar. Wait ten seconds, then try again. - current_analysis_request_timer = setTimeout(function() { request_update(); }, 10000); +} + +var process_update_response = function(data, headers) { + sync_server_clock(headers.get('Date')); + ims = headers.get('X-RGLM'); + var num_viewers = headers.get('X-RGNV'); + var new_data; + if (Array.isArray(data)) { + new_data = JSON.parse(JSON.stringify(current_analysis_data)); + JSON_delta.patch(new_data, data); + } else { + new_data = data; + } + + var minimum_version = headers.get('X-RGMV'); + if (minimum_version && minimum_version > SCRIPT_VERSION) { + // Upgrade to latest version with a force-reload. + location.reload(true); + } + + // Verify that the PV makes sense. + var valid = true; + if (new_data['pv']) { + var hiddenboard = new Chess(new_data['position']['fen']); + for (var i = 0; i < new_data['pv'].length; ++i) { + if (hiddenboard.move(new_data['pv'][i]) === null) { + valid = false; + break; + } } - }); + } + + if (valid) { + possibly_play_sound(current_analysis_data, new_data); + current_analysis_data = new_data; + update_board(); + update_num_viewers(num_viewers); + } else { + console.log("Received invalid update, waiting five seconds and trying again."); + setTimeout(function() { location.reload(true); }, 5000); + } } var possibly_play_sound = function(old_data, new_data) { @@ -476,20 +505,18 @@ var position_arrow = function(arrow) { return; } - var zoom_factor = $("#board").width() / 400.0; + var zoom_factor = document.getElementById("board").getBoundingClientRect().width / 400.0; var line_width = arrow.line_width * zoom_factor; var arrow_size = arrow.arrow_size * zoom_factor; - var square_width = $(".square-a8").width(); - var pos, from_y, to_y, from_x, to_x; + var square_width = document.querySelector(".square-a8").getBoundingClientRect().width; + var from_y, to_y, from_x, to_x; if (board.orientation() === 'black') { - pos = $(".square-h1").position(); from_y = (arrow.from_row + 0.5)*square_width; to_y = (arrow.to_row + 0.5)*square_width; from_x = (7 - arrow.from_col + 0.5)*square_width; to_x = (7 - arrow.to_col + 0.5)*square_width; } else { - pos = $(".square-a8").position(); from_y = (7 - arrow.from_row + 0.5)*square_width; to_y = (7 - arrow.to_row + 0.5)*square_width; from_x = (arrow.from_col + 0.5)*square_width; @@ -499,8 +526,8 @@ var position_arrow = function(arrow) { var SVG_NS = "http://www.w3.org/2000/svg"; var XHTML_NS = "http://www.w3.org/1999/xhtml"; var svg = document.createElementNS(SVG_NS, "svg"); - svg.setAttribute("width", /** @type{number} */ ($("#board").width())); - svg.setAttribute("height", /** @type{number} */ ($("#board").height())); + svg.setAttribute("width", /** @type{number} */ (document.getElementById("board").getBoundingClientRect().width)); + svg.setAttribute("height", /** @type{number} */ (document.getElementById("board").getBoundingClientRect().height)); svg.setAttribute("style", "position: absolute"); svg.setAttribute("position", "absolute"); svg.setAttribute("version", "1.1"); @@ -543,8 +570,10 @@ var position_arrow = function(arrow) { head.setAttribute("fill", arrow.fg_color); svg.appendChild(head); - $(svg).css({ top: pos.top, left: pos.left, 'pointer-events': 'none' }); - document.body.appendChild(svg); + svg.style.top = '2px'; /* Border for .board-b72b1. */ + svg.style.left = '2px'; + svg.style.pointerEvents = 'none'; + document.getElementById('board').appendChild(svg); arrow.svg = svg; } @@ -764,23 +793,23 @@ var print_pv = function(line_num, splicepos, opt_limit, opt_showlast) { * Based on the global "highlight_from" and "highlight_to" variables. */ var update_board_highlight = function() { - $("#board").find('.square-55d63').removeClass('nonuglyhighlight'); + document.getElementById("board").querySelector('.square-55d63').classList.remove('nonuglyhighlight'); if ((current_display_line === null || current_display_line_is_history) && highlight_from !== undefined && highlight_to !== undefined) { - $("#board").find('.square-' + highlight_from).addClass('nonuglyhighlight'); - $("#board").find('.square-' + highlight_to).addClass('nonuglyhighlight'); + document.getElementById("board").querySelector('.square-' + highlight_from).classList.add('nonuglyhighlight'); + document.getElementById("board").querySelector('.square-' + highlight_to).classList.add('nonuglyhighlight'); } } var update_history = function() { if (display_lines[0] === null || display_lines[0].pv.length == 0) { - $("#history").html("No history"); + document.getElementById("history").innerHTML = "No history"; } else if (truncate_display_history) { - $("#history").html(print_pv(0, null, 8, true)); + document.getElementById("history").innerHTML = print_pv(0, null, 8, true); } else { - $("#history").html( + document.getElementById("history").innerHTML = '(collapse) ' + - print_pv(0, null)); + print_pv(0, null); } } @@ -805,8 +834,8 @@ var update_refutation_lines = function() { // Truncate so that only the history and PV is left. display_lines = [ display_lines[0], display_lines[1] ]; } - var tbl = $("#refutationlines"); - tbl.empty(); + var tbl = document.getElementById("refutationlines"); + tbl.replaceChildren(); if (display_lines.length < 2) { return; @@ -839,55 +868,55 @@ var update_refutation_lines = function() { var move_td = document.createElement("td"); tr.appendChild(move_td); - $(move_td).addClass("move"); + move_td.classList.add("move"); var scores = base_scores.concat([{ first_move: start_display_move_num, score: line['score'] }]); if (line['pv'].length == 0) { // Not found, so just make a one-move PV. var move = "" + line['move'] + ""; - $(move_td).html(move); + move_td.innerHTML = move; var score_td = document.createElement("td"); - $(score_td).addClass("score"); - $(score_td).text("—"); + score_td.classList.add("score"); + score_td.textContent = "—"; tr.appendChild(score_td); var depth_td = document.createElement("td"); tr.appendChild(depth_td); - $(depth_td).addClass("depth"); - $(depth_td).text("—"); + depth_td.classList.add("depth"); + depth_td.textContent = "—"; var pv_td = document.createElement("td"); tr.appendChild(pv_td); - $(pv_td).addClass("pv"); - $(pv_td).html(add_pv(base_fen, base_line.concat([ line['move'] ]), move_num, toplay, scores, start_display_move_num)); + pv_td.classList.add("pv"); + pv_td.innerHTML = add_pv(base_fen, base_line.concat([ line['move'] ]), move_num, toplay, scores, start_display_move_num); tbl.append(tr); continue; } var move = "" + line['move'] + ""; - $(move_td).html(move); + move_td.innerHTML = move; var score_td = document.createElement("td"); tr.appendChild(score_td); - $(score_td).addClass("score"); - $(score_td).text(format_short_score(line['score'])); + score_td.classList.add("score"); + score_td.textContent = format_short_score(line['score']); var depth_td = document.createElement("td"); tr.appendChild(depth_td); - $(depth_td).addClass("depth"); + depth_td.classList.add("depth"); if (line['depth'] && line['depth'] >= 0) { - $(depth_td).text("d" + line['depth']); + depth_td.textContent = "d" + line['depth']; } else { - $(depth_td).text("—"); + depth_td.textContent = "—"; } var pv_td = document.createElement("td"); tr.appendChild(pv_td); - $(pv_td).addClass("pv"); - $(pv_td).html(add_pv(base_fen, base_line.concat(line['pv']), move_num, toplay, scores, start_display_move_num, 10)); + pv_td.classList.add("pv"); + pv_td.innerHTML = add_pv(base_fen, base_line.concat(line['pv']), move_num, toplay, scores, start_display_move_num, 10); tbl.append(tr); } @@ -922,7 +951,7 @@ var chess_from = function(fen, moves, last_move) { } var update_game_list = function(games) { - $("#games").text(""); + document.getElementById("games").textContent = ""; if (games === null) { return; } @@ -1028,6 +1057,8 @@ var patch_move = function(move) { /** Update all the HTML on the page, based on current global state. */ var update_board = function() { + document.body.style.opacity = null; + var data = displayed_analysis_data || current_analysis_data; var current_data = current_analysis_data; // Convenience alias. @@ -1068,33 +1099,33 @@ var update_board = function() { // when e.g. viewing history, so if any of these changed during the game, // use the current one still. if (current_data['using_lomonosov']) { - $("#lomonosov").show(); + document.getElementById("lomonosov").style.display = null; } else { - $("#lomonosov").hide(); + document.getElementById("lomonosov").style.display = 'none'; } // Credits: The engine name/version. if (current_data['engine'] && current_data['engine']['name'] !== null) { - $("#engineid").text(current_data['engine']['name']); + document.getElementById("engineid").textContent = current_data['engine']['name']; } // Credits: The engine URL. if (current_data['engine'] && current_data['engine']['url']) { - $("#engineid").attr("href", current_data['engine']['url']); + document.getElementById("engineid").setAttribute("href", current_data['engine']['url']); } else { - $("#engineid").removeAttr("href"); + document.getElementById("engineid").removeAttribute("href"); } // Credits: Engine details. if (current_data['engine'] && current_data['engine']['details']) { - $("#enginedetails").text(" (" + current_data['engine']['details'] + ")"); + document.getElementById("enginedetails").textContent = " (" + current_data['engine']['details'] + ")"; } else { - $("#enginedetails").text(""); + document.getElementById("enginedetails").textContent = ""; } // Credits: Move source, possibly with URL. if (current_data['move_source'] && current_data['move_source_url']) { - $("#movesource").text("Moves provided by "); + document.getElementById("movesource").textContent = "Moves provided by "; var movesource_a = document.createElement("a"); movesource_a.setAttribute("href", current_data['move_source_url']); var movesource_text = document.createTextNode(current_data['move_source']); @@ -1103,9 +1134,9 @@ var update_board = function() { document.getElementById("movesource").appendChild(movesource_a); document.getElementById("movesource").appendChild(movesource_period); } else if (current_data['move_source']) { - $("#movesource").text("Moves provided by " + current_data['move_source'] + "."); + document.getElementById("movesource").textContent = "Moves provided by " + current_data['move_source'] + "."; } else { - $("#movesource").text(""); + document.getElementById("movesource").textContent = ""; } var last_move; @@ -1137,7 +1168,7 @@ var update_board = function() { } else { last_move = null; } - $("#headline").text(headline); + document.getElementById("headline").textContent = headline; // The contains a very brief headline. var title_elems = []; @@ -1176,13 +1207,13 @@ var update_board = function() { update_board_highlight(); if (data['failed']) { - $("#score").text("No analysis for this move"); - $("#pvtitle").text("PV:"); - $("#pv").empty(); - $("#searchstats").html(" "); - $("#refutationlines").empty(); - $("#whiteclock").empty(); - $("#blackclock").empty(); + document.getElementById("score").textContent = "No analysis for this move"; + document.getElementById("pvtitle").textContent = "PV:"; + document.getElementById("pv").replaceChildren(); + document.getElementById("searchstats").innerHTML = " "; + document.getElementById("refutationlines").replaceChildren(); + document.getElementById("whiteclock").replaceChildren(); + document.getElementById("blackclock").replaceChildren(); refutation_lines = []; update_refutation_lines(); clear_arrows(); @@ -1205,37 +1236,19 @@ var update_board = function() { } } if (score) { - $("#score").text(format_long_score(score)); + document.getElementById("score").textContent = format_long_score(score); } else { - $("#score").text("No score for this line"); + document.getElementById("score").textContent = "No score for this line"; } } else if (data['score']) { - $("#score").text(format_long_score(data['score'])); + document.getElementById("score").textContent = format_long_score(data['score']); } - // Low depth. - var lowdepth = ''; - if (data['lowdepth']) { - lowdepth = 'Quick look: '; - var lds = []; - Object.keys(data['lowdepth']).forEach(function(depth) { - lds.push([parseInt(depth), format_short_score(data['lowdepth'][depth])]); - }); - lds.sort(function(a, b) { return a[0] - b[0]; }); - for (var i = 0; i < lds.length; ++i) { - lowdepth += '<span class="depth">d' + lds[i][0] + ':</span> ' + lds[i][1]; - if (i != lds.length - 1) { - lowdepth += ', '; - } - } - } - $("#lowdepth").html(lowdepth); - // The search stats. if (data['searchstats']) { - $("#searchstats").html(data['searchstats']); + document.getElementById("searchstats").innerHTML = data['searchstats']; } else if (data['tablebase'] == 1) { - $("#searchstats").text("Tablebase result"); + document.getElementById("searchstats").textContent = "Tablebase result"; } else if (data['nodes'] && data['nps'] && data['depth']) { var stats = thousands(data['nodes']) + ' nodes, ' + thousands(data['nps']) + ' nodes/sec, depth ' + data['depth'] + ' ply'; if (data['seldepth']) { @@ -1249,9 +1262,9 @@ var update_board = function() { } } - $("#searchstats").text(stats); + document.getElementById("searchstats").textContent = stats; } else { - $("#searchstats").text(""); + document.getElementById("searchstats").textContent = ""; } // Update the board itself. @@ -1259,10 +1272,10 @@ var update_board = function() { update_displayed_line(); // Print the PV. - $("#pvtitle").text("PV:"); + document.getElementById("pvtitle").textContent = "PV:"; var scores = [{ first_move: -1, score: data['score'] }]; - $("#pv").html(add_pv(data['position']['fen'], data['pv'], data['position']['move_num'], data['position']['toplay'], scores, 0)); + document.getElementById("pv").innerHTML = add_pv(data['position']['fen'], data['pv'], data['position']['move_num'], data['position']['toplay'], scores, 0); // Update the PV arrow. clear_arrows(); @@ -1348,6 +1361,8 @@ var update_board = function() { } var update_sparkline = function(data) { + let scorespark = document.getElementById('scoresparkcontainer'); + scorespark.textContent = ''; if (data && data['score_history']) { var first_move_num = undefined; for (var halfmove_num in data['score_history']) { @@ -1363,17 +1378,13 @@ var update_sparkline = function(data) { } // Possibly truncate some moves if we don't have enough width. - // FIXME: Sometimes width() for #scorecontainer (and by extent, - // #scoresparkcontainer) on Chrome for mobile seems to start off - // at something very small, and then suddenly snap back into place. - // Figure out why. - var max_moves = Math.floor($("#scoresparkcontainer").width() / 5) - 5; + var max_moves = Math.floor(scorespark.getBoundingClientRect().width / 5) - 3; if (last_move_num - first_move_num > max_moves) { first_move_num = last_move_num - max_moves; } - var min_score = -100; - var max_score = 100; + var min_score = -1; + var max_score = 1; var last_score = null; var scores = []; for (var halfmove_num = first_move_num; halfmove_num <= last_move_num; ++halfmove_num) { @@ -1388,36 +1399,77 @@ var update_sparkline = function(data) { if (data['score']) { scores.push(compute_plot_score(data['score'])); } - // FIXME: at some widths, calling sparkline() seems to push - // #scorecontainer under the board. - $('#scorespark').unbind('sparklineClick'); - $("#scorespark").sparkline(scores, { - type: 'bar', - zeroColor: 'gray', - chartRangeMin: min_score, - chartRangeMax: max_score, - tooltipFormatter: function(sparkline, options, fields) { - // score_history contains the Nth _position_, but format_tooltip - // wants to format the Nth _move_; thus the -1. - return format_tooltip(data, fields[0].offset + first_move_num - 1); + + const h = scorespark.getBoundingClientRect().height; + + let base_y = h - h * min_score / (min_score - max_score); + for (let i = 0; i < scores.length; ++i) { + let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + //rect.setAttributeNS(null, 'stroke', "#000000"); + rect.setAttributeNS(null, 'x', i * 5) + rect.setAttributeNS(null, 'width', 4); + let extent = scores[i] * h / (max_score - min_score); + if (extent > 0 && extent < 1) { + extent = 1; + } else if (extent < 0 && extent > -1) { + extent = -1; + } + + let color; + if (scores[i] === 0) { + color = [0.5, 0.5, 0.5]; + rect.setAttributeNS(null, 'y', base_y - 1); + rect.setAttributeNS(null, 'height', 1); + } else if (scores[i] > 0) { + color = [0.2, 0.4, 0.8]; + rect.setAttributeNS(null, 'y', base_y - extent); + rect.setAttributeNS(null, 'height', extent); + } else { + color = [1.0, 0.267, 0.267]; + rect.setAttributeNS(null, 'y', base_y); + rect.setAttributeNS(null, 'height', -extent); } - }); - $('#scorespark').unbind('sparklineClick'); - $('#scorespark').bind('sparklineClick', function(event) { - var sparkline = event.sparklines[0]; - var region = sparkline.getCurrentRegionFields(); - if (region[0].offset !== undefined) { - show_line(0, first_move_num + region[0].offset - 1); + let hlcolor = [color[0], color[1], color[2]]; + if (scores[i] !== 0) { + hlcolor[0] = Math.min(hlcolor[0] * 1.4, 1.0); + hlcolor[1] = Math.min(hlcolor[1] * 1.4, 1.0); + hlcolor[2] = Math.min(hlcolor[2] * 1.4, 1.0); } - }); - } else { - $("#scorespark").text(""); + rect.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + + // score_history contains the Nth _position_, but format_tooltip + // wants to format the Nth _move_; thus the -1. + const tooltip = format_tooltip(data, i + first_move_num - 1); + rect.addEventListener('mouseenter', (e) => draw_hover(e, hlcolor, tooltip)); + rect.addEventListener('mousemove', (e) => draw_hover(e, hlcolor, tooltip)); + rect.addEventListener('mouseleave', (e) => hide_hover(e, color)); + rect.addEventListener('click', (e) => show_line(0, i + first_move_num - 1)); + scorespark.appendChild(rect); + } } - } else { - $("#scorespark").text(""); } } +var draw_hover = function(e, color, tooltip) { + e.target.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + + let hover = document.getElementById('sparklinehover'); + hover.textContent = tooltip; + hover.style.display = 'initial'; + + let left = Math.max(e.pageX + 10, window.pageXOffset); + let top = Math.max(e.pageY - hover.getBoundingClientRect().height, window.pageYOffset); + left = Math.min(left, window.pageXOffset + document.documentElement.clientWidth - hover.getBoundingClientRect().width); + + hover.style.left = left + 'px'; + hover.style.top = top + 'px'; + +} +var hide_hover = function(e, color) { + e.target.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + document.getElementById('sparklinehover').style.display = 'none'; +} + /** * @param {number} num_viewers */ @@ -1437,7 +1489,7 @@ var update_num_viewers = function(num_viewers) { text += " | 50-move rule: " + counter; } } - $("#numviewers").text(text); + document.getElementById("numviewers").textContent = text; } var update_clock = function() { @@ -1449,24 +1501,24 @@ var update_clock = function() { if (data['position']) { var result = data['position']['result']; if (result === '1-0') { - $("#whiteclock").text("1"); - $("#blackclock").text("0"); - $("#whiteclock").removeClass("running-clock"); - $("#blackclock").removeClass("running-clock"); + document.getElementById("whiteclock").textContent = "1"; + document.getElementById("blackclock").textContent = "0"; + document.getElementById("whiteclock").classList.remove("running-clock"); + document.getElementById("blackclock").classList.remove("running-clock"); return; } if (result === '1/2-1/2') { - $("#whiteclock").text("1/2"); - $("#blackclock").text("1/2"); - $("#whiteclock").removeClass("running-clock"); - $("#blackclock").removeClass("running-clock"); + document.getElementById("whiteclock").textContent = "1/2"; + document.getElementById("blackclock").textContent = "1/2"; + document.getElementById("whiteclock").classList.remove("running-clock"); + document.getElementById("blackclock").classList.remove("running-clock"); return; } if (result === '0-1') { - $("#whiteclock").text("0"); - $("#blackclock").text("1"); - $("#whiteclock").removeClass("running-clock"); - $("#blackclock").removeClass("running-clock"); + document.getElementById("whiteclock").textContent = "0"; + document.getElementById("blackclock").textContent = "1"; + document.getElementById("whiteclock").classList.remove("running-clock"); + document.getElementById("blackclock").classList.remove("running-clock"); return; } } @@ -1486,15 +1538,15 @@ var update_clock = function() { var color; if (data['position']['white_clock_target']) { color = "white"; - $("#whiteclock").addClass("running-clock"); - $("#blackclock").removeClass("running-clock"); + document.getElementById("whiteclock").classList.add("running-clock"); + document.getElementById("blackclock").classList.remove("running-clock"); } else if (data['position']['black_clock_target']) { color = "black"; - $("#whiteclock").removeClass("running-clock"); - $("#blackclock").addClass("running-clock"); + document.getElementById("whiteclock").classList.remove("running-clock"); + document.getElementById("blackclock").classList.add("running-clock"); } else { - $("#whiteclock").removeClass("running-clock"); - $("#blackclock").removeClass("running-clock"); + document.getElementById("whiteclock").classList.remove("running-clock"); + document.getElementById("blackclock").classList.remove("running-clock"); } var remaining_ms; if (color) { @@ -1508,8 +1560,8 @@ var update_clock = function() { } if (white_clock_ms === null || black_clock_ms === null) { - $("#whiteclock").empty(); - $("#blackclock").empty(); + document.getElementById("whiteclock").replaceChildren(); + document.getElementById("blackclock").replaceChildren(); return; } @@ -1528,8 +1580,8 @@ var update_clock = function() { clock_timer = setTimeout(update_clock, next_update_ms); } - $("#whiteclock").text(format_clock(white_clock_ms, show_seconds)); - $("#blackclock").text(format_clock(black_clock_ms, show_seconds)); + document.getElementById("whiteclock").textContent = format_clock(white_clock_ms, show_seconds); + document.getElementById("blackclock").textContent = format_clock(black_clock_ms, show_seconds); } /** @@ -1661,7 +1713,7 @@ var show_line = function(line_num, move_num) { update_board(); return; } else { - current_display_line = jQuery.extend({}, display_lines[line_num]); // Shallow clone. + current_display_line = {...display_lines[line_num]}; // Shallow clone. current_display_move = move_num + current_display_line.start_display_move_num; } current_display_line_is_history = (line_num == 0); @@ -1728,20 +1780,32 @@ var update_historic_analysis = function() { var filename = "/history/move" + (current_display_move + 1) + "-" + hiddenboard.fen().replace(/ /g, '_').replace(/\//g, '-') + ".json"; - current_historic_xhr = $.ajax({ - url: filename - }).done(function(data, textstatus, xhr) { - displayed_analysis_data = data; + let handle_err = () => { + displayed_analysis_data = {'failed': true}; update_board(); - }).fail(function(jqXHR, textStatus, errorThrown) { - if (textStatus === "abort") { - // Aborted because we are switching backends. Don't do anything; - // we will already have been cleared. - } else { - displayed_analysis_data = {'failed': true}; + }; + + current_historic_xhr = new AbortController(); + const signal = current_analysis_xhr.signal; + fetch(filename, { signal }) + .then((response) => response.json().then(data => ({ok: response.ok, json: data}))) // ick + .then((obj) => { + if (!obj.ok) { + handle_err(); + return; + } + displayed_analysis_data = obj.json; update_board(); - } - }); + }) + .catch((err) => { + if (err.name === 'AbortError') { + // Aborted because we are switching backends. Abandon and don't retry, + // because another one is already started for us. + } else { + console.log(err); + handle_err(); + } + }); } /** @@ -1769,14 +1833,16 @@ var update_imbalance = function(fen) { var black_imbalance = ''; for (var piece in imbalance) { for (var i = 0; i < imbalance[piece]; ++i) { - white_imbalance += '<img src="img/chesspieces/wikipedia/w' + piece.toUpperCase() + '.png" alt="" style="width: 15px;height: 15px;">'; + white_imbalance += '<img src="' + svg_pieces['w' + piece.toUpperCase()] + '" alt="" style="width: 15px;height: 15px;" class="imbalance-piece">'; + white_imbalance += '<img src="' + svg_pieces['b' + piece.toUpperCase()] + '" alt="" style="width: 15px;height: 15px;" class="imbalance-inverted-piece">'; } for (var i = 0; i < -imbalance[piece]; ++i) { - black_imbalance += '<img src="img/chesspieces/wikipedia/b' + piece.toUpperCase() + '.png" alt="" style="width: 15px;height: 15px;">'; + black_imbalance += '<img src="' + svg_pieces['b' + piece.toUpperCase()] + '" alt="" style="width: 15px;height: 15px;" class="imbalance-piece">'; + black_imbalance += '<img src="' + svg_pieces['w' + piece.toUpperCase()] + '" alt="" style="width: 15px;height: 15px;" class="imbalance-inverted-piece">'; } } - $('#whiteimbalance').html(white_imbalance); - $('#blackimbalance').html(black_imbalance); + document.getElementById('whiteimbalance').innerHTML = white_imbalance; + document.getElementById('blackimbalance').innerHTML = black_imbalance; } /** Mark the currently selected move in red. @@ -1785,24 +1851,26 @@ var update_imbalance = function(fen) { */ var update_move_highlight = function() { if (highlighted_move !== null) { - highlighted_move.removeClass('highlight'); + highlighted_move.classList.remove('highlight'); } if (current_display_line) { var display_line_num = find_display_line_matching_num(); if (display_line_num === null) { // Replace the PV with the (complete) line. - $("#pvtitle").text("Exploring:"); + document.getElementById("pvtitle").textContent = "Exploring:"; current_display_line.start_display_move_num = 0; display_lines.push(current_display_line); - $("#pv").html(print_pv(display_lines.length - 1, null)); // FIXME + document.getElementById("pv").innerHTML = print_pv(display_lines.length - 1, null); // FIXME display_line_num = display_lines.length - 1; // Clear out the PV, so it's not selected by anything later. display_lines[1].pv = []; } - highlighted_move = $("#automove" + display_line_num + "-" + (current_display_move - current_display_line.start_display_move_num)); - highlighted_move.addClass('highlight'); + highlighted_move = document.getElementById("automove" + display_line_num + "-" + (current_display_move - current_display_line.start_display_move_num)); + if (highlighted_move !== null) { + highlighted_move.classList.add('highlight'); + } } } @@ -1840,26 +1908,26 @@ var find_display_line_matching_num = function() { */ var update_displayed_line = function() { if (current_display_line === null) { - $("#linenav").hide(); - $("#linemsg").show(); + document.getElementById("linenav").style.display = 'none'; + document.getElementById("linemsg").style.display = 'revert'; display_fen = base_fen; set_board_position(base_fen); update_imbalance(base_fen); return; } - $("#linenav").show(); - $("#linemsg").hide(); + document.getElementById("linenav").style.display = 'revert'; + document.getElementById("linemsg").style.display = 'none'; if (current_display_move <= 0) { - $("#prevmove").html("Previous"); + document.getElementById("prevmove").innerHTML = "Previous"; } else { - $("#prevmove").html("<a href=\"javascript:prev_move();\">Previous</a></span>"); + document.getElementById("prevmove").innerHTML = "<a href=\"javascript:prev_move();\">Previous</a></span>"; } if (current_display_move == current_display_line.pv.length - 1) { - $("#nextmove").html("Next"); + document.getElementById("nextmove").innerHTML = "Next"; } else { - $("#nextmove").html("<a href=\"javascript:next_move();\">Next</a></span>"); + document.getElementById("nextmove").innerHTML = "<a href=\"javascript:next_move();\">Next</a></span>"; } var hiddenboard = chess_from(current_display_line.start_fen, current_display_line.pv, current_display_move); @@ -1888,8 +1956,8 @@ var set_board_position = function(new_fen) { var set_sound = function(param_enable_sound) { enable_sound = param_enable_sound; if (enable_sound) { - $("#soundon").html("<strong>On</strong>"); - $("#soundoff").html("<a href=\"javascript:set_sound(false)\">Off</a>"); + document.getElementById("soundon").innerHTML = "<strong>On</strong>"; + document.getElementById("soundoff").innerHTML = "<a href=\"javascript:set_sound(false)\">Off</a>"; // Seemingly at least Firefox prefers MP3 over Opus; tell it otherwise, // and also preload the file since the user has selected audio. @@ -1899,8 +1967,8 @@ var set_sound = function(param_enable_sound) { ding.load(); } } else { - $("#soundon").html("<a href=\"javascript:set_sound(true)\">On</a>"); - $("#soundoff").html("<strong>Off</strong>"); + document.getElementById("soundon").innerHTML = "<a href=\"javascript:set_sound(true)\">On</a>"; + document.getElementById("soundoff").innerHTML = "<strong>Off</strong>"; } if (supports_html5_storage()) { localStorage['enable_sound'] = enable_sound ? 1 : 0; @@ -1920,12 +1988,13 @@ var explore_hash = function(fen) { clearTimeout(current_hash_display_timer); current_hash_display_timer = null; } - $("#refutationlines").empty(); - current_hash_xhr = $.ajax({ - url: backend_hash_url + "?fen=" + fen - }).done(function(data, textstatus, xhr) { - show_explore_hash_results(data, fen); - }); + document.getElementById("refutationlines").replaceChildren(); + + current_hash_xhr = new AbortController(); + const signal = current_analysis_xhr.signal; + fetch(backend_hash_url + "?fen=" + fen, { signal }) + .then((response) => response.json()) + .then((data) => { show_explore_hash_results(data, fen); }); } /** Process the JSON response from a hash probe request. @@ -1955,15 +2024,19 @@ var onDragStart = function(source, piece, position, orientation) { recommended_move = get_best_move(pseudogame, source, null, pseudogame.turn() === 'b'); if (recommended_move) { - var squareEl = $('#board .square-' + recommended_move.to); - squareEl.addClass('highlight1-32417'); + var squareEl = document.querySelector('#board .square-' + recommended_move.to); + squareEl.classList.add('highlight1-32417'); } return true; } var mousedownSquare = function(e) { + if (!e.target || !e.target.matches('.square-55d63')) { + return; + } + reverse_dragging_from = null; - var square = $(this).attr('data-square'); + var square = e.target.getAttribute('data-square'); var pseudogame = new Chess(display_fen); if (pseudogame.game_over() === true) { @@ -1979,25 +2052,30 @@ var mousedownSquare = function(e) { reverse_dragging_from = square; recommended_move = get_best_move(pseudogame, null, square, pseudogame.turn() === 'b'); if (recommended_move) { - var squareEl = $('#board .square-' + recommended_move.from); - squareEl.addClass('highlight1-32417'); - squareEl = $('#board .square-' + recommended_move.to); - squareEl.addClass('highlight1-32417'); + var squareEl = document.querySelector('#board .square-' + recommended_move.from); + squareEl.classList.add('highlight1-32417'); + squareEl = document.querySelector('#board .square-' + recommended_move.to); + squareEl.classList.add('highlight1-32417'); } } } var mouseupSquare = function(e) { + if (!e.target || !e.target.matches('.square-55d63')) { + return; + } if (reverse_dragging_from === null) { return; } - var source = $(this).attr('data-square'); + var source = e.target.getAttribute('data-square'); var target = reverse_dragging_from; reverse_dragging_from = null; if (onDrop(source, target) !== 'snapback') { onSnapEnd(source, target); } - $("#board").find('.square-55d63').removeClass('highlight1-32417'); + document.getElementById("board").querySelectorAll('.square-55d63.highlight1-32417').forEach((square) => { + square.classList.remove('highlight1-32417'); + }); } var get_best_move = function(game, source, target, invert) { @@ -2307,6 +2385,30 @@ var switch_backend = function(game) { window['switch_backend'] = switch_backend; window['flip'] = function() { board.flip(); redraw_arrows(); }; +window['set_delay_ms'] = function(ms) { delay_ms = ms; console.log('Delay is now ' + ms + ' ms.'); }; + +// Mostly from Wikipedia's chess set as of October 2022, but some pieces are from +// the 2013 version, as I like those better (and it matches the 2014 PNGs; nobody +// really likes change, do they?). That is wK, bK, bQ. wQ is also slightly different, +// but not enough to notice. +const svg_pieces = { + 'wK': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPGcgc3R5bGU9ImZpbGw6bm9uZTsgZmlsbC1vcGFjaXR5OjE7IGZpbGwtcnVsZTpldmVub2RkOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjEuNTsgc3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7IHN0cm9rZS1kYXNoYXJyYXk6bm9uZTsgc3Ryb2tlLW9wYWNpdHk6MTsiPgogICAgPHBhdGgKICAgICAgZD0iTSAyMi41LDExLjYzIEwgMjIuNSw2IgogICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLWxpbmVqb2luOm1pdGVyOyIgLz4KICAgIDxwYXRoCiAgICAgIGQ9Ik0gMjAsOCBMIDI1LDgiCiAgICAgIHN0eWxlPSJmaWxsOm5vbmU7IHN0cm9rZTojMDAwMDAwOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAyMi41LDI1IEMgMjIuNSwyNSAyNywxNy41IDI1LjUsMTQuNSBDIDI1LjUsMTQuNSAyNC41LDEyIDIyLjUsMTIgQyAyMC41LDEyIDE5LjUsMTQuNSAxOS41LDE0LjUgQyAxOCwxNy41IDIyLjUsMjUgMjIuNSwyNSIKICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS1saW5lY2FwOmJ1dHQ7IHN0cm9rZS1saW5lam9pbjptaXRlcjsiIC8+CiAgICA8cGF0aAogICAgICBkPSJNIDExLjUsMzcgQyAxNyw0MC41IDI3LDQwLjUgMzIuNSwzNyBMIDMyLjUsMzAgQyAzMi41LDMwIDQxLjUsMjUuNSAzOC41LDE5LjUgQyAzNC41LDEzIDI1LDE2IDIyLjUsMjMuNSBMIDIyLjUsMjcgTCAyMi41LDIzLjUgQyAxOSwxNiA5LjUsMTMgNi41LDE5LjUgQyAzLjUsMjUuNSAxMS41LDI5LjUgMTEuNSwyOS41IEwgMTEuNSwzNyB6ICIKICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMS41LDMwIEMgMTcsMjcgMjcsMjcgMzIuNSwzMCIKICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiMwMDAwMDA7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMS41LDMzLjUgQyAxNywzMC41IDI3LDMwLjUgMzIuNSwzMy41IgogICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IzAwMDAwMDsiIC8+CiAgICA8cGF0aAogICAgICBkPSJNIDExLjUsMzcgQyAxNywzNCAyNywzNCAzMi41LDM3IgogICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IzAwMDAwMDsiIC8+CiAgPC9nPgo8L3N2Zz4K', + 'wQ': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPGcgc3R5bGU9ImZpbGw6I2ZmZmZmZjtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS41O3N0cm9rZS1saW5lam9pbjpyb3VuZCI+CiAgICA8cGF0aCBkPSJNIDksMjYgQyAxNy41LDI0LjUgMzAsMjQuNSAzNiwyNiBMIDM4LjUsMTMuNSBMIDMxLDI1IEwgMzAuNywxMC45IEwgMjUuNSwyNC41IEwgMjIuNSwxMCBMIDE5LjUsMjQuNSBMIDE0LjMsMTAuOSBMIDE0LDI1IEwgNi41LDEzLjUgTCA5LDI2IHoiLz4KICAgIDxwYXRoIGQ9Ik0gOSwyNiBDIDksMjggMTAuNSwyOCAxMS41LDMwIEMgMTIuNSwzMS41IDEyLjUsMzEgMTIsMzMuNSBDIDEwLjUsMzQuNSAxMSwzNiAxMSwzNiBDIDkuNSwzNy41IDExLDM4LjUgMTEsMzguNSBDIDE3LjUsMzkuNSAyNy41LDM5LjUgMzQsMzguNSBDIDM0LDM4LjUgMzUuNSwzNy41IDM0LDM2IEMgMzQsMzYgMzQuNSwzNC41IDMzLDMzLjUgQyAzMi41LDMxIDMyLjUsMzEuNSAzMy41LDMwIEMgMzQuNSwyOCAzNiwyOCAzNiwyNiBDIDI3LjUsMjQuNSAxNy41LDI0LjUgOSwyNiB6Ii8+CiAgICA8cGF0aCBkPSJNIDExLjUsMzAgQyAxNSwyOSAzMCwyOSAzMy41LDMwIiBzdHlsZT0iZmlsbDpub25lIi8+CiAgICA8cGF0aCBkPSJNIDEyLDMzLjUgQyAxOCwzMi41IDI3LDMyLjUgMzMsMzMuNSIgc3R5bGU9ImZpbGw6bm9uZSIvPgogICAgPGNpcmNsZSBjeD0iNiIgY3k9IjEyIiByPSIyIiAvPgogICAgPGNpcmNsZSBjeD0iMTQiIGN5PSI5IiByPSIyIiAvPgogICAgPGNpcmNsZSBjeD0iMjIuNSIgY3k9IjgiIHI9IjIiIC8+CiAgICA8Y2lyY2xlIGN4PSIzMSIgY3k9IjkiIHI9IjIiIC8+CiAgICA8Y2lyY2xlIGN4PSIzOSIgY3k9IjEyIiByPSIyIiAvPgogIDwvZz4KPC9zdmc+Cg==', + 'wR': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjQ1IiBoZWlnaHQ9IjQ1Ij4NCiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDojZmZmZmZmOyBmaWxsLW9wYWNpdHk6MTsgZmlsbC1ydWxlOmV2ZW5vZGQ7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDsgc3Ryb2tlLWRhc2hhcnJheTpub25lOyBzdHJva2Utb3BhY2l0eToxOyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwLjMpIj4NCiAgICA8cGF0aA0KICAgICAgZD0iTSA5LDM5IEwgMzYsMzkgTCAzNiwzNiBMIDksMzYgTCA5LDM5IHogIg0KICAgICAgc3R5bGU9InN0cm9rZS1saW5lY2FwOmJ1dHQ7IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDEyLDM2IEwgMTIsMzIgTCAzMywzMiBMIDMzLDM2IEwgMTIsMzYgeiAiDQogICAgICBzdHlsZT0ic3Ryb2tlLWxpbmVjYXA6YnV0dDsiIC8+DQogICAgPHBhdGgNCiAgICAgIGQ9Ik0gMTEsMTQgTCAxMSw5IEwgMTUsOSBMIDE1LDExIEwgMjAsMTEgTCAyMCw5IEwgMjUsOSBMIDI1LDExIEwgMzAsMTEgTCAzMCw5IEwgMzQsOSBMIDM0LDE0Ig0KICAgICAgc3R5bGU9InN0cm9rZS1saW5lY2FwOmJ1dHQ7IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDM0LDE0IEwgMzEsMTcgTCAxNCwxNyBMIDExLDE0IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDMxLDE3IEwgMzEsMjkuNSBMIDE0LDI5LjUgTCAxNCwxNyINCiAgICAgIHN0eWxlPSJzdHJva2UtbGluZWNhcDpidXR0OyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDMxLDI5LjUgTCAzMi41LDMyIEwgMTIuNSwzMiBMIDE0LDI5LjUiIC8+DQogICAgPHBhdGgNCiAgICAgIGQ9Ik0gMTEsMTQgTCAzNCwxNCINCiAgICAgIHN0eWxlPSJmaWxsOm5vbmU7IHN0cm9rZTojMDAwMDAwOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPg0KICA8L2c+DQo8L3N2Zz4NCg==', + 'wB': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjQ1IiBoZWlnaHQ9IjQ1Ij4NCiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDpub25lOyBmaWxsLXJ1bGU6ZXZlbm9kZDsgZmlsbC1vcGFjaXR5OjE7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDsgc3Ryb2tlLWxpbmVqb2luOnJvdW5kOyBzdHJva2UtbWl0ZXJsaW1pdDo0OyBzdHJva2UtZGFzaGFycmF5Om5vbmU7IHN0cm9rZS1vcGFjaXR5OjE7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDAuNikiPg0KICAgIDxnIHN0eWxlPSJmaWxsOiNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJva2UtbGluZWNhcDpidXR0OyI+DQogICAgICA8cGF0aCBkPSJNIDksMzYgQyAxMi4zOSwzNS4wMyAxOS4xMSwzNi40MyAyMi41LDM0IEMgMjUuODksMzYuNDMgMzIuNjEsMzUuMDMgMzYsMzYgQyAzNiwzNiAzNy42NSwzNi41NCAzOSwzOCBDIDM4LjMyLDM4Ljk3IDM3LjM1LDM4Ljk5IDM2LDM4LjUgQyAzMi42MSwzNy41MyAyNS44OSwzOC45NiAyMi41LDM3LjUgQyAxOS4xMSwzOC45NiAxMi4zOSwzNy41MyA5LDM4LjUgQyA3LjY1LDM4Ljk5IDYuNjgsMzguOTcgNiwzOCBDIDcuMzUsMzYuNTQgOSwzNiA5LDM2IHoiLz4NCiAgICAgIDxwYXRoIGQ9Ik0gMTUsMzIgQyAxNy41LDM0LjUgMjcuNSwzNC41IDMwLDMyIEMgMzAuNSwzMC41IDMwLDMwIDMwLDMwIEMgMzAsMjcuNSAyNy41LDI2IDI3LjUsMjYgQyAzMywyNC41IDMzLjUsMTQuNSAyMi41LDEwLjUgQyAxMS41LDE0LjUgMTIsMjQuNSAxNy41LDI2IEMgMTcuNSwyNiAxNSwyNy41IDE1LDMwIEMgMTUsMzAgMTQuNSwzMC41IDE1LDMyIHoiLz4NCiAgICAgIDxwYXRoIGQ9Ik0gMjUgOCBBIDIuNSAyLjUgMCAxIDEgIDIwLDggQSAyLjUgMi41IDAgMSAxICAyNSA4IHoiLz4NCiAgICA8L2c+DQogICAgPHBhdGggZD0iTSAxNy41LDI2IEwgMjcuNSwyNiBNIDE1LDMwIEwgMzAsMzAgTSAyMi41LDE1LjUgTCAyMi41LDIwLjUgTSAyMCwxOCBMIDI1LDE4IiBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLWxpbmVqb2luOm1pdGVyOyIvPg0KICA8L2c+DQo8L3N2Zz4NCg==', + 'wN': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjQ1IiBoZWlnaHQ9IjQ1Ij4NCiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDpub25lOyBmaWxsLW9wYWNpdHk6MTsgZmlsbC1ydWxlOmV2ZW5vZGQ7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDsgc3Ryb2tlLWRhc2hhcnJheTpub25lOyBzdHJva2Utb3BhY2l0eToxOyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwLjMpIj4NCiAgICA8cGF0aA0KICAgICAgZD0iTSAyMiwxMCBDIDMyLjUsMTEgMzguNSwxOCAzOCwzOSBMIDE1LDM5IEMgMTUsMzAgMjUsMzIuNSAyMywxOCINCiAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyIgLz4NCiAgICA8cGF0aA0KICAgICAgZD0iTSAyNCwxOCBDIDI0LjM4LDIwLjkxIDE4LjQ1LDI1LjM3IDE2LDI3IEMgMTMsMjkgMTMuMTgsMzEuMzQgMTEsMzEgQyA5Ljk1OCwzMC4wNiAxMi40MSwyNy45NiAxMSwyOCBDIDEwLDI4IDExLjE5LDI5LjIzIDEwLDMwIEMgOSwzMCA1Ljk5NywzMSA2LDI2IEMgNiwyNCAxMiwxNCAxMiwxNCBDIDEyLDE0IDEzLjg5LDEyLjEgMTQsMTAuNSBDIDEzLjI3LDkuNTA2IDEzLjUsOC41IDEzLjUsNy41IEMgMTQuNSw2LjUgMTYuNSwxMCAxNi41LDEwIEwgMTguNSwxMCBDIDE4LjUsMTAgMTkuMjgsOC4wMDggMjEsNyBDIDIyLDcgMjIsMTAgMjIsMTAiDQogICAgICBzdHlsZT0iZmlsbDojZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsiIC8+DQogICAgPHBhdGgNCiAgICAgIGQ9Ik0gOS41IDI1LjUgQSAwLjUgMC41IDAgMSAxIDguNSwyNS41IEEgMC41IDAuNSAwIDEgMSA5LjUgMjUuNSB6Ig0KICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDsgc3Ryb2tlOiMwMDAwMDA7IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDE1IDE1LjUgQSAwLjUgMS41IDAgMSAxICAxNCwxNS41IEEgMC41IDEuNSAwIDEgMSAgMTUgMTUuNSB6Ig0KICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44NjYsMC41LC0wLjUsMC44NjYsOS42OTMsLTUuMTczKSINCiAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7IHN0cm9rZTojMDAwMDAwOyIgLz4NCiAgPC9nPg0KPC9zdmc+DQo=', + 'wP': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPHBhdGggZD0ibSAyMi41LDkgYyAtMi4yMSwwIC00LDEuNzkgLTQsNCAwLDAuODkgMC4yOSwxLjcxIDAuNzgsMi4zOCBDIDE3LjMzLDE2LjUgMTYsMTguNTkgMTYsMjEgYyAwLDIuMDMgMC45NCwzLjg0IDIuNDEsNS4wMyBDIDE1LjQxLDI3LjA5IDExLDMxLjU4IDExLDM5LjUgSCAzNCBDIDM0LDMxLjU4IDI5LjU5LDI3LjA5IDI2LjU5LDI2LjAzIDI4LjA2LDI0Ljg0IDI5LDIzLjAzIDI5LDIxIDI5LDE4LjU5IDI3LjY3LDE2LjUgMjUuNzIsMTUuMzggMjYuMjEsMTQuNzEgMjYuNSwxMy44OSAyNi41LDEzIGMgMCwtMi4yMSAtMS43OSwtNCAtNCwtNCB6IiBzdHlsZT0ib3BhY2l0eToxOyBmaWxsOiNmZmZmZmY7IGZpbGwtb3BhY2l0eToxOyBmaWxsLXJ1bGU6bm9uemVybzsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDoxLjU7IHN0cm9rZS1saW5lY2FwOnJvdW5kOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IHN0cm9rZS1taXRlcmxpbWl0OjQ7IHN0cm9rZS1kYXNoYXJyYXk6bm9uZTsgc3Ryb2tlLW9wYWNpdHk6MTsiLz4KPC9zdmc+Cg==', + 'bK': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPGcgc3R5bGU9ImZpbGw6bm9uZTsgZmlsbC1vcGFjaXR5OjE7IGZpbGwtcnVsZTpldmVub2RkOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjEuNTsgc3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7IHN0cm9rZS1kYXNoYXJyYXk6bm9uZTsgc3Ryb2tlLW9wYWNpdHk6MTsiPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMjIuNSwxMS42MyBMIDIyLjUsNiIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7IHN0cm9rZTojMDAwMDAwOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IgogICAgICAgaWQ9InBhdGg2NTcwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMjIuNSwyNSBDIDIyLjUsMjUgMjcsMTcuNSAyNS41LDE0LjUgQyAyNS41LDE0LjUgMjQuNSwxMiAyMi41LDEyIEMgMjAuNSwxMiAxOS41LDE0LjUgMTkuNSwxNC41IEMgMTgsMTcuNSAyMi41LDI1IDIyLjUsMjUiCiAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxOyBzdHJva2UtbGluZWNhcDpidXR0OyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMTEuNSwzNyBDIDE3LDQwLjUgMjcsNDAuNSAzMi41LDM3IEwgMzIuNSwzMCBDIDMyLjUsMzAgNDEuNSwyNS41IDM4LjUsMTkuNSBDIDM0LjUsMTMgMjUsMTYgMjIuNSwyMy41IEwgMjIuNSwyNyBMIDIyLjUsMjMuNSBDIDE5LDE2IDkuNSwxMyA2LjUsMTkuNSBDIDMuNSwyNS41IDExLjUsMjkuNSAxMS41LDI5LjUgTCAxMS41LDM3IHogIgogICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDsgc3Ryb2tlOiMwMDAwMDA7IiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMjAsOCBMIDI1LDgiCiAgICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLWxpbmVqb2luOm1pdGVyOyIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJNIDMyLDI5LjUgQyAzMiwyOS41IDQwLjUsMjUuNSAzOC4wMywxOS44NSBDIDM0LjE1LDE0IDI1LDE4IDIyLjUsMjQuNSBMIDIyLjUxLDI2LjYgTCAyMi41LDI0LjUgQyAyMCwxOCA5LjkwNiwxNCA2Ljk5NywxOS44NSBDIDQuNSwyNS41IDExLjg1LDI4Ljg1IDExLjg1LDI4Ljg1IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiNmZmZmZmY7IiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMTEuNSwzMCBDIDE3LDI3IDI3LDI3IDMyLjUsMzAgTSAxMS41LDMzLjUgQyAxNywzMC41IDI3LDMwLjUgMzIuNSwzMy41IE0gMTEuNSwzNyBDIDE3LDM0IDI3LDM0IDMyLjUsMzciCiAgICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6I2ZmZmZmZjsiIC8+CiAgPC9nPgo8L3N2Zz4K', + 'bQ': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB2ZXJzaW9uPSIxLjEiCiAgIHdpZHRoPSI0NSIKICAgaGVpZ2h0PSI0NSIKICAgaWQ9InN2ZzMxMjgiPgogIDxkZWZzIC8+CiAgPGcKICAgICBpZD0ibGF5ZXIxIj4KICAgIDxwYXRoCiAgICAgICBkPSJNIDggMTIgQSAyIDIgMCAxIDEgIDQsMTIgQSAyIDIgMCAxIDEgIDggMTIgeiIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGg1NTcxIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gOSAxMyBBIDIgMiAwIDEgMSAgNSwxMyBBIDIgMiAwIDEgMSAgOSAxMyB6IgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTUuNSwtNS41KSIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGg1NTczIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gOSAxMyBBIDIgMiAwIDEgMSAgNSwxMyBBIDIgMiAwIDEgMSAgOSAxMyB6IgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzIsLTEpIgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDU1NzUiIC8+CiAgICA8cGF0aAogICAgICAgZD0iTSA5IDEzIEEgMiAyIDAgMSAxICA1LDEzIEEgMiAyIDAgMSAxICA5IDEzIHoiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3LC00LjUpIgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDU1NzciIC8+CiAgICA8cGF0aAogICAgICAgZD0iTSA5IDEzIEEgMiAyIDAgMSAxICA1LDEzIEEgMiAyIDAgMSAxICA5IDEzIHoiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNCwtNCkiCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTU3OSIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJNIDksMjYgQyAxNy41LDI0LjUgMzAsMjQuNSAzNiwyNiBMIDM4LDE0IEwgMzEsMjUgTCAzMSwxMSBMIDI1LjUsMjQuNSBMIDIyLjUsOS41IEwgMTkuNSwyNC41IEwgMTQsMTAuNSBMIDE0LDI1IEwgNywxNCBMIDksMjYgeiAiCiAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTU4MSIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJNIDksMjYgQyA5LDI4IDEwLjUsMjggMTEuNSwzMCBDIDEyLjUsMzEuNSAxMi41LDMxIDEyLDMzLjUgQyAxMC41LDM0LjUgMTAuNSwzNiAxMC41LDM2IEMgOSwzNy41IDExLDM4LjUgMTEsMzguNSBDIDE3LjUsMzkuNSAyNy41LDM5LjUgMzQsMzguNSBDIDM0LDM4LjUgMzUuNSwzNy41IDM0LDM2IEMgMzQsMzYgMzQuNSwzNC41IDMzLDMzLjUgQyAzMi41LDMxIDMyLjUsMzEuNSAzMy41LDMwIEMgMzQuNSwyOCAzNiwyOCAzNiwyNiBDIDI3LjUsMjQuNSAxNy41LDI0LjUgOSwyNiB6ICIKICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGg1NTgzIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Ik0gMTEuNSwzMCBDIDE1LDI5IDMwLDI5IDMzLjUsMzAiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eTowLjc1O2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoxcHg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDU1ODUiIC8+CiAgICA8cGF0aAogICAgICAgZD0iTSAxMiwzMy41IEMgMTgsMzIuNSAyNywzMi41IDMzLDMzLjUiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eTowLjc1O2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoxcHg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0icGF0aDU1ODciIC8+CiAgICA8cGF0aAogICAgICAgZD0iTSAxMC41LDM2IEMgMTUuNSwzNSAyOSwzNSAzNCwzNiIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjAuNzU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTU4OSIgLz4KICA8L2c+Cjwvc3ZnPgo=', + 'bR': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDojMDAwMDAwOyBmaWxsLW9wYWNpdHk6MTsgZmlsbC1ydWxlOmV2ZW5vZGQ7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDsgc3Ryb2tlLWRhc2hhcnJheTpub25lOyBzdHJva2Utb3BhY2l0eToxOyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwLjMpIj4KICAgIDxwYXRoCiAgICAgIGQ9Ik0gOSwzOSBMIDM2LDM5IEwgMzYsMzYgTCA5LDM2IEwgOSwzOSB6ICIKICAgICAgc3R5bGU9InN0cm9rZS1saW5lY2FwOmJ1dHQ7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMi41LDMyIEwgMTQsMjkuNSBMIDMxLDI5LjUgTCAzMi41LDMyIEwgMTIuNSwzMiB6ICIKICAgICAgc3R5bGU9InN0cm9rZS1saW5lY2FwOmJ1dHQ7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMiwzNiBMIDEyLDMyIEwgMzMsMzIgTCAzMywzNiBMIDEyLDM2IHogIgogICAgICBzdHlsZT0ic3Ryb2tlLWxpbmVjYXA6YnV0dDsiIC8+CiAgICA8cGF0aAogICAgICBkPSJNIDE0LDI5LjUgTCAxNCwxNi41IEwgMzEsMTYuNSBMIDMxLDI5LjUgTCAxNCwyOS41IHogIgogICAgICBzdHlsZT0ic3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxNCwxNi41IEwgMTEsMTQgTCAzNCwxNCBMIDMxLDE2LjUgTCAxNCwxNi41IHogIgogICAgICBzdHlsZT0ic3Ryb2tlLWxpbmVjYXA6YnV0dDsiIC8+CiAgICA8cGF0aAogICAgICBkPSJNIDExLDE0IEwgMTEsOSBMIDE1LDkgTCAxNSwxMSBMIDIwLDExIEwgMjAsOSBMIDI1LDkgTCAyNSwxMSBMIDMwLDExIEwgMzAsOSBMIDM0LDkgTCAzNCwxNCBMIDExLDE0IHogIgogICAgICBzdHlsZT0ic3Ryb2tlLWxpbmVjYXA6YnV0dDsiIC8+CiAgICA8cGF0aAogICAgICBkPSJNIDEyLDM1LjUgTCAzMywzNS41IEwgMzMsMzUuNSIKICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiNmZmZmZmY7IHN0cm9rZS13aWR0aDoxOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMywzMS41IEwgMzIsMzEuNSIKICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiNmZmZmZmY7IHN0cm9rZS13aWR0aDoxOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxNCwyOS41IEwgMzEsMjkuNSIKICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiNmZmZmZmY7IHN0cm9rZS13aWR0aDoxOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxNCwxNi41IEwgMzEsMTYuNSIKICAgICAgc3R5bGU9ImZpbGw6bm9uZTsgc3Ryb2tlOiNmZmZmZmY7IHN0cm9rZS13aWR0aDoxOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IiAvPgogICAgPHBhdGgKICAgICAgZD0iTSAxMSwxNCBMIDM0LDE0IgogICAgICBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6I2ZmZmZmZjsgc3Ryb2tlLXdpZHRoOjE7IHN0cm9rZS1saW5lam9pbjptaXRlcjsiIC8+CiAgPC9nPgo8L3N2Zz4K', + 'bB': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjQ1IiBoZWlnaHQ9IjQ1Ij4NCiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDpub25lOyBmaWxsLXJ1bGU6ZXZlbm9kZDsgZmlsbC1vcGFjaXR5OjE7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDsgc3Ryb2tlLWxpbmVqb2luOnJvdW5kOyBzdHJva2UtbWl0ZXJsaW1pdDo0OyBzdHJva2UtZGFzaGFycmF5Om5vbmU7IHN0cm9rZS1vcGFjaXR5OjE7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDAuNikiPg0KICAgIDxnIHN0eWxlPSJmaWxsOiMwMDAwMDA7IHN0cm9rZTojMDAwMDAwOyBzdHJva2UtbGluZWNhcDpidXR0OyI+DQogICAgICA8cGF0aCBkPSJNIDksMzYgQyAxMi4zOSwzNS4wMyAxOS4xMSwzNi40MyAyMi41LDM0IEMgMjUuODksMzYuNDMgMzIuNjEsMzUuMDMgMzYsMzYgQyAzNiwzNiAzNy42NSwzNi41NCAzOSwzOCBDIDM4LjMyLDM4Ljk3IDM3LjM1LDM4Ljk5IDM2LDM4LjUgQyAzMi42MSwzNy41MyAyNS44OSwzOC45NiAyMi41LDM3LjUgQyAxOS4xMSwzOC45NiAxMi4zOSwzNy41MyA5LDM4LjUgQyA3LjY1LDM4Ljk5IDYuNjgsMzguOTcgNiwzOCBDIDcuMzUsMzYuNTQgOSwzNiA5LDM2IHoiLz4NCiAgICAgIDxwYXRoIGQ9Ik0gMTUsMzIgQyAxNy41LDM0LjUgMjcuNSwzNC41IDMwLDMyIEMgMzAuNSwzMC41IDMwLDMwIDMwLDMwIEMgMzAsMjcuNSAyNy41LDI2IDI3LjUsMjYgQyAzMywyNC41IDMzLjUsMTQuNSAyMi41LDEwLjUgQyAxMS41LDE0LjUgMTIsMjQuNSAxNy41LDI2IEMgMTcuNSwyNiAxNSwyNy41IDE1LDMwIEMgMTUsMzAgMTQuNSwzMC41IDE1LDMyIHoiLz4NCiAgICAgIDxwYXRoIGQ9Ik0gMjUgOCBBIDIuNSAyLjUgMCAxIDEgIDIwLDggQSAyLjUgMi41IDAgMSAxICAyNSA4IHoiLz4NCiAgICA8L2c+DQogICAgPHBhdGggZD0iTSAxNy41LDI2IEwgMjcuNSwyNiBNIDE1LDMwIEwgMzAsMzAgTSAyMi41LDE1LjUgTCAyMi41LDIwLjUgTSAyMCwxOCBMIDI1LDE4IiBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6I2ZmZmZmZjsgc3Ryb2tlLWxpbmVqb2luOm1pdGVyOyIvPg0KICA8L2c+DQo8L3N2Zz4NCg==', + 'bN': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjQ1IiBoZWlnaHQ9IjQ1Ij4NCiAgPGcgc3R5bGU9Im9wYWNpdHk6MTsgZmlsbDpub25lOyBmaWxsLW9wYWNpdHk6MTsgZmlsbC1ydWxlOmV2ZW5vZGQ7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MS41OyBzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDsgc3Ryb2tlLWRhc2hhcnJheTpub25lOyBzdHJva2Utb3BhY2l0eToxOyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwwLjMpIj4NCiAgICA8cGF0aA0KICAgICAgZD0iTSAyMiwxMCBDIDMyLjUsMTEgMzguNSwxOCAzOCwzOSBMIDE1LDM5IEMgMTUsMzAgMjUsMzIuNSAyMywxOCINCiAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7IHN0cm9rZTojMDAwMDAwOyIgLz4NCiAgICA8cGF0aA0KICAgICAgZD0iTSAyNCwxOCBDIDI0LjM4LDIwLjkxIDE4LjQ1LDI1LjM3IDE2LDI3IEMgMTMsMjkgMTMuMTgsMzEuMzQgMTEsMzEgQyA5Ljk1OCwzMC4wNiAxMi40MSwyNy45NiAxMSwyOCBDIDEwLDI4IDExLjE5LDI5LjIzIDEwLDMwIEMgOSwzMCA1Ljk5NywzMSA2LDI2IEMgNiwyNCAxMiwxNCAxMiwxNCBDIDEyLDE0IDEzLjg5LDEyLjEgMTQsMTAuNSBDIDEzLjI3LDkuNTA2IDEzLjUsOC41IDEzLjUsNy41IEMgMTQuNSw2LjUgMTYuNSwxMCAxNi41LDEwIEwgMTguNSwxMCBDIDE4LjUsMTAgMTkuMjgsOC4wMDggMjEsNyBDIDIyLDcgMjIsMTAgMjIsMTAiDQogICAgICBzdHlsZT0iZmlsbDojMDAwMDAwOyBzdHJva2U6IzAwMDAwMDsiIC8+DQogICAgPHBhdGgNCiAgICAgIGQ9Ik0gOS41IDI1LjUgQSAwLjUgMC41IDAgMSAxIDguNSwyNS41IEEgMC41IDAuNSAwIDEgMSA5LjUgMjUuNSB6Ig0KICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjsgc3Ryb2tlOiNmZmZmZmY7IiAvPg0KICAgIDxwYXRoDQogICAgICBkPSJNIDE1IDE1LjUgQSAwLjUgMS41IDAgMSAxICAxNCwxNS41IEEgMC41IDEuNSAwIDEgMSAgMTUgMTUuNSB6Ig0KICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44NjYsMC41LC0wLjUsMC44NjYsOS42OTMsLTUuMTczKSINCiAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7IHN0cm9rZTojZmZmZmZmOyIgLz4NCiAgICA8cGF0aA0KICAgICAgZD0iTSAyNC41NSwxMC40IEwgMjQuMSwxMS44NSBMIDI0LjYsMTIgQyAyNy43NSwxMyAzMC4yNSwxNC40OSAzMi41LDE4Ljc1IEMgMzQuNzUsMjMuMDEgMzUuNzUsMjkuMDYgMzUuMjUsMzkgTCAzNS4yLDM5LjUgTCAzNy40NSwzOS41IEwgMzcuNSwzOSBDIDM4LDI4Ljk0IDM2LjYyLDIyLjE1IDM0LjI1LDE3LjY2IEMgMzEuODgsMTMuMTcgMjguNDYsMTEuMDIgMjUuMDYsMTAuNSBMIDI0LjU1LDEwLjQgeiAiDQogICAgICBzdHlsZT0iZmlsbDojZmZmZmZmOyBzdHJva2U6bm9uZTsiIC8+DQogIDwvZz4NCjwvc3ZnPg0K', + 'bP': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+CiAgPHBhdGggZD0ibSAyMi41LDkgYyAtMi4yMSwwIC00LDEuNzkgLTQsNCAwLDAuODkgMC4yOSwxLjcxIDAuNzgsMi4zOCBDIDE3LjMzLDE2LjUgMTYsMTguNTkgMTYsMjEgYyAwLDIuMDMgMC45NCwzLjg0IDIuNDEsNS4wMyBDIDE1LjQxLDI3LjA5IDExLDMxLjU4IDExLDM5LjUgSCAzNCBDIDM0LDMxLjU4IDI5LjU5LDI3LjA5IDI2LjU5LDI2LjAzIDI4LjA2LDI0Ljg0IDI5LDIzLjAzIDI5LDIxIDI5LDE4LjU5IDI3LjY3LDE2LjUgMjUuNzIsMTUuMzggMjYuMjEsMTQuNzEgMjYuNSwxMy44OSAyNi41LDEzIGMgMCwtMi4yMSAtMS43OSwtNCAtNCwtNCB6IiBzdHlsZT0ib3BhY2l0eToxOyBmaWxsOiMwMDAwMDA7IGZpbGwtb3BhY2l0eToxOyBmaWxsLXJ1bGU6bm9uemVybzsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDoxLjU7IHN0cm9rZS1saW5lY2FwOnJvdW5kOyBzdHJva2UtbGluZWpvaW46bWl0ZXI7IHN0cm9rZS1taXRlcmxpbWl0OjQ7IHN0cm9rZS1kYXNoYXJyYXk6bm9uZTsgc3Ryb2tlLW9wYWNpdHk6MTsiLz4KPC9zdmc+Cg==', +}; + +var svg_piece_theme = function(piece) { + return svg_pieces[piece]; +} var init = function() { unique = get_unique(); @@ -2323,21 +2425,22 @@ var init = function() { onMoveEnd: function() { board_is_animating = false; }, draggable: true, + pieceTheme: svg_piece_theme, onDragStart: onDragStart, onDrop: onDrop, onSnapEnd: onSnapEnd }); - $("#board").on('mousedown', '.square-55d63', mousedownSquare); - $("#board").on('mouseup', '.square-55d63', mouseupSquare); + document.getElementById("board").addEventListener('mousedown', mousedownSquare); + document.getElementById("board").addEventListener('mouseup', mouseupSquare); request_update(); - $(window).resize(function() { + window.addEventListener('resize', function() { board.resize(); update_sparkline(displayed_analysis_data || current_analysis_data); update_board_highlight(); redraw_arrows(); }); - $(window).keyup(function(event) { + window.addEventListener('keyup', function(event) { if (event.which == 39) { // Left arrow. next_move(); } else if (event.which == 37) { // Right arrow. @@ -2354,6 +2457,6 @@ var init = function() { window.addEventListener('hashchange', possibly_switch_game_from_hash, false); possibly_switch_game_from_hash(); }; -$(document).ready(init); +document.addEventListener('DOMContentLoaded', init); })();