diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1380c2e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules +.next \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..e312149 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:prettier/recommended" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "quotes": [ + 2, + "double" + ], + "camelcase": "off" + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8cc2b41..4f76999 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ packets/* img/* .htaccess + +node_modules diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..48dde77 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +package-lock.json +.next +node_modules/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c5f7c9e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.autoIndent": "keep", + "javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false, + "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false, + "javascript.format.enable": false +} \ No newline at end of file diff --git a/css/main.css b/css/main.css index 814c0ae..90f68a8 100644 --- a/css/main.css +++ b/css/main.css @@ -583,6 +583,7 @@ img { z-index: 2; cursor: pointer; color: lightgray; + overflow: auto; } #review-overlay { diff --git a/index.html b/index.html index 2cd50d4..058edbd 100644 --- a/index.html +++ b/index.html @@ -109,7 +109,7 @@ - + diff --git a/js/helpers.js b/js/helpers.js new file mode 100644 index 0000000..815f108 --- /dev/null +++ b/js/helpers.js @@ -0,0 +1,18 @@ +/** + * Function to randomise an array order + * @param {array} array + */ +export function shuffleArray(array) { + var currentIndex = array.length, temporaryValue, randomIndex; + // While there remain elements to shuffle... + while (0 !== currentIndex) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + return array; +} diff --git a/js/main.js b/js/main.js index 8c5055d..b577d6d 100644 --- a/js/main.js +++ b/js/main.js @@ -1,70 +1,98 @@ -//cid = null; -var cid = 1234; -var eid = 5678; +import * as helper from "./helpers.js"; -var exam_mode = false; +// cid = null; +window.cid = 1234; +window.eid = 5678; -var packet_list = []; +window.exam_mode = false; -//var questions = null -var question_order = []; -var number_of_questions = null; -var question_type = null; -var loaded_question = null; -var review = false; +window.packet_list = []; -var allow_self_marking = true; +// var questions = null +window.question_order = []; +window.number_of_questions = null; +window.question_type = null; +window.loaded_question = null; +window.review = false; -var dfile = null; +window.allow_self_marking = true; -var a = null; -var b = null; +window.dfile = null; -loadPacketList(); -function loadPacketList() { - var jqxhr = $.getJSON("packets/", function (data) { - packet_list = data.packets; - packet_list.forEach(function (packet) { - $("#packet-list").append($("
" + packet + "
").click(function () { - loadPacketFromAjax("packets/" + packet); - })); - }) - $("#options-panel").show(); +retrievePacketList(); + +/** + * Retrieves a list of available packets via JSON ajax requests + * Will initially try /packets/ (for example if index.php generates the list) + * and then fallback to packets.json + */ +function retrievePacketList() { + $.getJSON("packets/", function(data) { + loadPacketList(data); }) - .done(function () { - }) - .fail(function () { - console.log("No packet list available"); - showLoginDialog(); - }) - .always(function () { - }); + .done(function() { + }) + .fail(function() { + $.getJSON("packets/packets.json", function(data) { + loadPacketList(data); + }) + .fail(function() { + console.log("No packet list available"); + showLoginDialog(); + }); + }) + .always(function() { + }); - //setUpPacket(questions); + // setUpPacket(questions); } +/** + * Generate a list of the packets that are available to be loaded + * + * @param {JSON} data - json containing available packets + */ +function loadPacketList(data) { + window.packet_list = data.packets; + window.packet_list.forEach(function(packet) { + $("#packet-list").append( + $("
" + packet + "
").click(function() { + loadPacketFromAjax("packets/" + packet); + })); + }); + $("#options-panel").show(); +} + +/** + * Loads the requisite packet into the quiz system + * @param {string} path - relative path to the packet json file + */ function loadPacketFromAjax(path) { - console.log("loading packet from " + path) - var jqxhr = $.getJSON(path, function (data) { + console.log("loading packet from " + path); + $.getJSON(path, function(data) { setUpPacket(data); $("#options-panel").hide(); }) - .done(function () { - }) - .fail(function () { - console.log("Unable to load packet at: " + path); - }) + .done(function() { + }) + .fail(function() { + console.log("Unable to load packet at: " + path); + }); } +/** + * Build the currently loaded quiz + */ function setUpQuestions() { - - if (questions == undefined) { return } + if (questions == undefined) { + return; + } // Set an order for the questions - question_order = []; - Object.keys(questions).forEach(function (e) { - question_order.push(e); + window.question_order = []; + Object.keys(questions).forEach(function(e) { + window.question_order.push(e); // Make sure answers are arrays if (!Array.isArray(questions[e]["answers"])) { @@ -72,15 +100,17 @@ function setUpQuestions() { } }); - question_order = shuffleArray(question_order); - number_of_questions = Object.keys(questions).length; - review = false; - console.log(question_order) + console.log("pre", window.question_order); + window.question_order = helper.shuffleArray(window.question_order); + console.log("post", window.question_order); + window.number_of_questions = Object.keys(questions).length; + window.review = false; + console.log(window.question_order); // Horrible way to get type of questions // We assume they are all of the same type.... - if (question_type == null) { - question_type = questions[Object.keys(questions)[0]].type; + if (window.question_type == null) { + window.question_type = questions[Object.keys(questions)[0]].type; } if (window.exam_mode) { @@ -90,59 +120,43 @@ function setUpQuestions() { } loadQuestion(0, 1, true); - createReviewPanel(); -} - -// randomise order -function shuffleArray(array) { - var currentIndex = array.length, - temporaryValue, - randomIndex; - - // While there remain elements to shuffle... - while (0 !== currentIndex) { - // Pick a remaining element... - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex -= 1; - - // And swap it with the current element. - temporaryValue = array[currentIndex]; - array[currentIndex] = array[randomIndex]; - array[randomIndex] = temporaryValue; - } - - return array; + createQuestionListPanel(); } // Set up cornerstone (the dicom viewer) cornerstoneBase64ImageLoader.external.cornerstone = cornerstone; cornerstoneWebImageLoader.external.cornerstone = cornerstone; -//cornerstoneWebImageLoader.configure({ +// cornerstoneWebImageLoader.configure({ // beforeSend: function(xhr) { // // Add custom headers here (e.g. auth tokens) // //xhr.setRequestHeader('x-auth-token', 'my auth token'); // } -//}); +// }); cornerstoneWADOImageLoader.external.cornerstone = cornerstone; -//cornerstoneWADOImageLoader.configure({ +// cornerstoneWADOImageLoader.configure({ // beforeSend: function(xhr) { // // Add custom headers here (e.g. auth tokens) // //xhr.setRequestHeader('APIKEY', 'my auth token'); // } -//}); +// }); cornerstoneTools.init(); -//Set up database -var db = new Dexie("answers_database"); +// Set up database +const db = new Dexie("answers_database"); db.version(1).stores({ answers: "[cid+eid+qid+qidn], [cid+eid], ans", flags: "[cid+eid+qid+qidn], [cid+eid]", - user_answers: "qid, ans" + user_answers: "qid, ans", }); +/** + * Parse the packet and extract metadata (if it exists) + * Will then call setUpQuestions() to load the packet + * @param {JSON} data + */ function setUpPacket(data) { if (data.hasOwnProperty("exam_name")) { $(".exam-name").text("Exam: " + data.exam_name); @@ -170,22 +184,30 @@ function setUpPacket(data) { } +/** + * Loads a specific question + * @param {number} n - Question number to load + * @param {number} section - Question section to focus + * @param {boolean} force_reload - Force question to be reloaded if already loaded + */ function loadQuestion(n, section = 1, force_reload = false) { // Make sure we have an integer n = parseInt(n); + console.log(n); - qid = question_order[n]; - current_question = questions[qid]; + const qid = window.question_order[n]; + console.log("qid", qid); + const current_question = questions[qid]; console.log("N=", n, section, current_question); - if (n == loaded_question && force_reload == false) { + if (n == window.loaded_question && force_reload == false) { // Question already loaded setFocus(section); return; } - loaded_question = n; + window.loaded_question = n; // Set up question navigation $(".navigation[value='next']").off(); @@ -194,44 +216,44 @@ function loadQuestion(n, section = 1, force_reload = false) { $(".navigation[value='previous']").attr("disabled", "disabled"); } else { $(".navigation[value='previous']") - .removeAttr("disabled") - .click(function () { - loadQuestion(n - 1); - }); + .removeAttr("disabled") + .click(function() { + loadQuestion(n - 1); + }); } - if (n == number_of_questions - 1) { + if (n == window.number_of_questions - 1) { $(".navigation[value='next']").attr("disabled", "disabled"); } else { $(".navigation[value='next']") - .removeAttr("disabled") - .click(function () { - loadQuestion(n + 1); - }); + .removeAttr("disabled") + .click(function() { + loadQuestion(n + 1); + }); } - display_n = n + 1; + const display_n = n + 1; if (current_question.title) { $(".question .title").get(0).innerHTML = - '' + + "" + display_n + " " + current_question.title; } else { $(".question .title").get(0).innerHTML = - '' + display_n + ""; + "" + display_n + ""; } // Close any open figures - el = document.getElementById("dicom-image"); + let el = document.getElementById("dicom-image"); if (el != undefined) { cornerstone.disable(el); $(".canvas-panel").remove(); } // Set up thumbnails - thumbnails = $(".thumbs"); + const thumbnails = $(".thumbs"); // Why are we checking this? if (thumbnails) { thumbnails.empty(); @@ -245,25 +267,25 @@ function loadQuestion(n, section = 1, force_reload = false) { } thumbnails.append( - '
...
' + "\">
...
", ); - thumbnail = $(".figure .thumbnail").get(id); - //cornerstone.enable(thumbnail) - //based_img = current_question.images[id]; - based_img = image; + // const thumbnail = $(".figure .thumbnail").get(id); + // cornerstone.enable(thumbnail) + // based_img = current_question.images[id]; + const based_img = image; // based (image) data url, just load the image directly if (based_img.startsWith("data:image/")) { - img = $("", { + const img = $("", { src: based_img, id: "thumb-" + id, class: "thumbnail", title: "Click on the thumbnail to view and manipulate the image.", draggable: "false", - style: "height: 100px;" + style: "height: 100px;", }); $("#figure-" + id).append(img); @@ -271,15 +293,15 @@ function loadQuestion(n, section = 1, force_reload = false) { // otherwise try to load it as a dicom } else { // convert the data url to a file - urltoFile(based_img, "dicom", "application/dicom").then(function ( - dfile + urltoFile(based_img, "dicom", "application/dicom").then(function( + dfile, ) { // load the file using cornerstoneWADO file loader const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add( - dfile + dfile, ); - cornerstone.loadAndCacheImage(imageId).then(function (image) { - img = $("
").get(0); + cornerstone.loadAndCacheImage(imageId).then(function(image) { + const img = $("
").get(0); img.id = "thumb-" + id; img.class = "thumbnail"; img.title = @@ -292,23 +314,28 @@ function loadQuestion(n, section = 1, force_reload = false) { cornerstone.enable(element); cornerstone.displayImage(element, image); cornerstone.resize(element); - }); //.catch( function(error) { + }); // .catch( function(error) { }); } }); } $(".thumbs .figure").each(function handleThumbnailClicks(id, thumbnail) { - thumbnail.onclick = function (event) { + thumbnail.onclick = function(event) { view(event, this); }; }); + /** + * View cornstone image + * @param {*} t + * @param {*} source + */ function view(t, source) { if (current_question) { // Check if the figure is already loaded (or if another one is) - open_figure = $("#dicom-image").data("figure"); - figure_to_load = source.id; + const open_figure = $("#dicom-image").data("figure"); + const figure_to_load = source.id; if (open_figure != undefined) { // No full size figure / dicom loaded yet @@ -324,19 +351,19 @@ function loadQuestion(n, section = 1, force_reload = false) { } $(".figure-open") - .removeClass("figure-open") - .addClass("figure"); + .removeClass("figure-open") + .addClass("figure"); source.className = "figure-open"; $(".question").append( - '
' + "\">
", ); - images = current_question.images[figure_to_load.split("-")[1]]; - //images = current_question.images + let images = current_question.images[figure_to_load.split("-")[1]]; + // images = current_question.images // Make sure we have an array if (!Array.isArray(images)) { @@ -345,63 +372,67 @@ function loadQuestion(n, section = 1, force_reload = false) { load(images); + /** + * Load image + * @param {*} images - list of images + */ async function load(images) { - imageIds = []; - for (i = 0; i < images.length; i++) { - data_url = images[i]; + const imageIds = []; + for (let i = 0; i < images.length; i++) { + const data_url = images[i]; // check stack type if (data_url.startsWith("data:image")) { - imageId = "base64://" + data_url.split(",")[1]; + const imageId = "base64://" + data_url.split(",")[1]; imageIds.push(imageId); } else if (data_url.startsWith("data:application/dicom")) { - //stack = stack.split(";")[1]; + // stack = stack.split(";")[1]; dfile = await urltoFile(data_url, "dicom", "application/dicom"); const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add( - dfile + dfile, ); imageIds.push(imageId); - //cornerstone.loadImage(imageId).then(function(image) { + // cornerstone.loadImage(imageId).then(function(image) { // tempFunction(image); - //}); + // }); } } const stack = { currentImageIdIndex: 0, - imageIds + imageIds, }; - //cornerstone.loadAndCacheImage(imageIds[0]).then(function(image) { - cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) { + // cornerstone.loadAndCacheImage(imageIds[0]).then(function(image) { + cornerstone.loadAndCacheImage(imageIds[0]).then(function(image) { loadMainImage(image, stack); }); } } } - //Answer setup - ap = $(".answer-panel"); + // Answer setup + const ap = $(".answer-panel"); ap.empty(); switch (current_question.type) { case "rapid": { ap.append( - '

' + + "

" + display_n + - '.1Case normal/abnormal

' + "\" data-qidn=1 style=\"margin-right:0\">⚐

", ); ap.append( - '", ); // Handle changing display of optional answer fields and saving of data - $("#rapid-option").change(function (evt) { + $("#rapid-option").change(function(evt) { if (evt.target.value == "Abnormal") { $("#rapid-text").css("display", "block"); } else { @@ -412,338 +443,355 @@ function loadQuestion(n, section = 1, force_reload = false) { eid: eid, qid: qid, qidn: "1", - ans: evt.target.value + ans: evt.target.value, }); - updateReviewPanel(); + updateQuestionListPanel(); }); // Save long answers on textchange - $(".long-answer").change(function (evt) { + $(".long-answer").change(function(evt) { // ignore blank text and delete any stored value if (evt.target.value.length < 1) { db.answers.delete([cid, eid, qid, "2"]); $( - "#question-list-item-" + question_order.indexOf(qid) + "-2" + "#question-list-item-" + window.question_order.indexOf(qid) + "-2", ).removeClass("question-saved-localdb"); return; } - //db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); + // db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); db.answers.put({ cid: cid, eid: eid, qid: qid, qidn: "2", - ans: evt.target.value + ans: evt.target.value, }); - $("#question-list-item-" + question_order.indexOf(qid) + "-2").addClass( - "question-saved-localdb" + $("#question-list-item-" + window.question_order.indexOf(qid) + "-2").addClass( + "question-saved-localdb", ); - updateReviewPanel(); + updateQuestionListPanel(); }); // We chain our db requests as we can only check answers once // they have been loaded (should probably use then or after) db.answers - .get({ cid: cid, eid: eid, qid: qid, qidn: "1" }) - .then(function (answer) { - if (answer != undefined) { - $("#rapid-option option:contains(" + answer.ans + ")").prop( - "selected", - true - ); - // For some reason a change event is not fired... - if (answer.ans == "Abnormal") { - $("#rapid-text").css("display", "block"); - } - $("#rapid-option-not-answered").remove(); - } - }) - .catch(function (error) { - console.log("error-", error); - }) - .then( - db.answers - .get({ cid: cid, eid: eid, qid: qid, qidn: "2" }) - .then(function (answer) { - if (answer != undefined) { - console.log(answer); - $(".long-answer").text(answer.ans); + .get({cid: cid, eid: eid, qid: qid, qidn: "1"}) + .then(function(answer) { + if (answer != undefined) { + $("#rapid-option option:contains(" + answer.ans + ")").prop( + "selected", + true, + ); + // For some reason a change event is not fired... + if (answer.ans == "Abnormal") { + $("#rapid-text").css("display", "block"); } - markAnswer(qid, "rapid"); - }) - .catch(function (error) { - console.log("error-", error); - }) - ); + $("#rapid-option-not-answered").remove(); + } + }) + .catch(function(error) { + console.log("error-", error); + }) + .then( + db.answers + .get({cid: cid, eid: eid, qid: qid, qidn: "2"}) + .then(function(answer) { + if (answer != undefined) { + console.log(answer); + $(".long-answer").text(answer.ans); + } + markAnswer(qid, "rapid"); + }) + .catch(function(error) { + console.log("error-", error); + }), + ); addFlagEvents(); - loadFlagsFromDb("1"); - loadFlagsFromDb("2"); + loadFlagsFromDb(qid, "1"); + loadFlagsFromDb(qid, "2"); break; } case "anatomy": { ap.append( - '

' + + "

" + display_n + - '.1' + + ".1" + current_question.question + - '

' + "\" data-qidn=1 style=\"margin-right:0\">⚐

", ); - $(".long-answer").change(function (evt) { + $(".long-answer").change(function(evt) { // ignore blank text and delete any stored value if (evt.target.value.length < 1) { db.answers.delete([cid, eid, qid, "1"]); $( - "#question-list-item-" + question_order.indexOf(qid) + "-1" + "#question-list-item-" + window.question_order.indexOf(qid) + "-1", ).removeClass("question-saved-localdb"); return; } - //db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); + // db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); db.answers.put({ cid: cid, eid: eid, qid: qid, qidn: "1", - ans: evt.target.value + ans: evt.target.value, }); - $("#question-list-item-" + question_order.indexOf(qid) + "-1").addClass( - "question-saved-localdb" + $("#question-list-item-" + window.question_order.indexOf(qid) + "-1").addClass( + "question-saved-localdb", ); - updateReviewPanel(); + updateQuestionListPanel(); }); db.answers - .get({ cid: cid, eid: eid, qid: qid, qidn: "1" }) - .then(function (answer) { - if (answer != undefined) { - $(".long-answer").text(answer.ans); - } - markAnswer(qid, "anatomy"); - }) - .catch(function (error) { - console.log(error); - }); + .get({cid: cid, eid: eid, qid: qid, qidn: "1"}) + .then(function(answer) { + if (answer != undefined) { + $(".long-answer").text(answer.ans); + } + markAnswer(qid, "anatomy"); + }) + .catch(function(error) { + console.log(error); + }); addFlagEvents(); - loadFlagsFromDb("1"); + loadFlagsFromDb(qid, "1"); break; } case "long": { ap.append( - '

' + + "

" + display_n + - '.1Observations

' + "\" data-qidn=1 style=\"margin-right:0\">⚐

", ); ap.append( - '

' + + "

" + display_n + - '.2Interpretation

' + "\" data-qidn=2 style=\"margin-right:0\">⚐

", ); ap.append( - '

' + + "

" + display_n + - '.3Principle Diagnosis

' + "\" data-qidn=3 style=\"margin-right:0\">⚐

", ); ap.append( - '

' + + "

" + display_n + - '.4Differential Diagnosis

' + "\" data-qidn=4 style=\"margin-right:0\">⚐

", ); ap.append( - '

' + + "

" + display_n + - '.5Management (if appropriate)

' + "\" data-qidn=5 style=\"margin-right:0\">⚐

", ); // Save long answers on textchange - $(".long-answer").change(function (evt) { - qidn = evt.target.dataset.qidn.toString(); + $(".long-answer").change(function(evt) { + const qidn = evt.target.dataset.qidn.toString(); // ignore blank text and delete any stored value if (evt.target.value.length < 1) { db.answers.delete([cid, eid, qid, qidn]); $( - "#question-list-item-" + question_order.indexOf(qid) + "-" + qidn + "#question-list-item-" + window.question_order.indexOf(qid) + "-" + qidn, ).removeClass("question-saved-localdb"); return; } - //db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); + // db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value}); db.answers.put({ cid: cid, eid: eid, qid: qid, qidn: qidn, - ans: evt.target.value + ans: evt.target.value, }); console.log("SAVE", qid, qidn, evt.target.value); $( - "#question-list-item-" + question_order.indexOf(qid) + "-" + qidn + "#question-list-item-" + window.question_order.indexOf(qid) + "-" + qidn, ).addClass("question-saved-localdb"); - updateReviewPanel(); + updateQuestionListPanel(); }); // Loop through the 5 text areas and retrieve from db // could all be retrieved at once with an addition key index // - for (var qidn_count = 1; qidn_count < 6; qidn_count++) { + for (let qidn_count = 1; qidn_count < 6; qidn_count++) { db.answers - .get({ cid: cid, eid: eid, qid: qid, qidn: qidn_count.toString() }) - .then(function (answer) { - if (answer != undefined) { - $(".long-answer") - .eq(parseInt(answer.qidn) - 1) - .text(answer.ans); - } - //markAnswer(qid, "anatomy"); - }) - .catch(function (error) { - console.log(error); - }); + .get({cid: cid, eid: eid, qid: qid, qidn: qidn_count.toString()}) + .then(function(answer) { + if (answer != undefined) { + $(".long-answer") + .eq(parseInt(answer.qidn) - 1) + .text(answer.ans); + } + // markAnswer(qid, "anatomy"); + }) + .catch(function(error) { + console.log(error); + }); } addFlagEvents(); - loadFlagsFromDb("1"); - loadFlagsFromDb("2"); - loadFlagsFromDb("3"); - loadFlagsFromDb("4"); - loadFlagsFromDb("5"); + loadFlagsFromDb(qid, "1"); + loadFlagsFromDb(qid, "2"); + loadFlagsFromDb(qid, "3"); + loadFlagsFromDb(qid, "4"); + loadFlagsFromDb(qid, "5"); break; } } - updateReviewPanel(); + updateQuestionListPanel(); setFocus(section); } +/** + * Sets the focus to the required question answer section + * @param {number} section - section to focus + */ function setFocus(section) { // Horrible (but it works) - setTimeout(function () { + setTimeout(function() { // In pratique it selects the end of a textarea but I'm not sure if I can be bothered... $("*[data-answer-section-qidn=" + section + "]").focus(); }, 200); } -// Test with just a global update (may need to do these individually if it gets slow...) -function updateReviewPanel() { +/** + * Updates the question list panel + * Test with just a global update (may need to do these individually + * if it gets slow...) + */ +function updateQuestionListPanel() { console.log("UP"); // Reset all classes db.answers - .where({ cid: cid, eid: eid }) - .toArray() - .then(function (answers) { - $(".question-list-panel div") - .slice(1) - .attr("class", "question-list-item"); - answers.forEach(function (answer, n) { - $( - "#question-list-item-" + - question_order.indexOf(answer.qid) + + .where({cid: cid, eid: eid}) + .toArray() + .then(function(answers) { + $(".question-list-panel div") + .slice(1) + .attr("class", "question-list-item"); + answers.forEach(function(answer, n) { + $( + "#question-list-item-" + + window.question_order.indexOf(answer.qid) + "-" + - answer.qidn - ).addClass("question-saved-localdb"); + answer.qidn, + ).addClass("question-saved-localdb"); - if (question_type == "rapid" && answer.qidn == "1") { - if (answer.ans == "Abnormal") { - $( - "#question-list-item-" + question_order.indexOf(answer.qid) + "-2" - ).css("display", "block"); - } else { - $( - "#question-list-item-" + question_order.indexOf(answer.qid) + "-2" - ).css("display", "none"); + if (window.question_type == "rapid" && answer.qidn == "1") { + if (answer.ans == "Abnormal") { + $( + "#question-list-item-" + window.question_order.indexOf(answer.qid) + "-2", + ).css("display", "block"); + } else { + $( + "#question-list-item-" + window.question_order.indexOf(answer.qid) + "-2", + ).css("display", "none"); + } } - } + }); + // $(".long-answer").text(answer.ans); + }) + .catch(function(error) { + console.log("error - ", error); }); - //$(".long-answer").text(answer.ans); - }) - .catch(function (error) { - console.log("error - ", error); - }); db.flags - .where({ cid: cid, eid: eid }) - .toArray() - .then(function (answers) { - answers.forEach(function (answer, n) { - $( - "#question-list-item-" + - question_order.indexOf(answer.qid) + + .where({cid: cid, eid: eid}) + .toArray() + .then(function(answers) { + answers.forEach(function(answer, n) { + $( + "#question-list-item-" + + window.question_order.indexOf(answer.qid) + "-" + answer.qidn + - " span" - ).css("visibility", "visible"); + " span", + ).css("visibility", "visible"); + }); + // $(".long-answer").text(answer.ans); + }) + .catch(function(error) { + console.log("error - ", error); }); - //$(".long-answer").text(answer.ans); - }) - .catch(function (error) { - console.log("error - ", error); - }); } -function createReviewPanel() { +/** + * Builds the QuestionListPanel + */ +function createQuestionListPanel() { $(".question-list-panel").empty(); $(".question-list-panel").append( - '
Questions
' + "
Questions
", ); + /** + * Appends QuestionList item + * @param {number} n - question number + * @param {number} qidn - question section number + * @return {*} el - element that has been created + */ function appendReviewItem(n, qidn) { - qn = n - 1; - el = $( - '
' + + "\" class=\"question-list-item\">" + n + "." + qidn + - '
' + "", ); $(".question-list-panel").append(el); // return the new element so it can be hidden if necessary return el; } - if (question_type == "rapid") { + if (window.question_type == "rapid") { // Loop through all questions and append list items - for (let n = 1; n < number_of_questions + 1; n++) { + for (let n = 1; n < window.number_of_questions + 1; n++) { appendReviewItem(n, "1"); appendReviewItem(n, "2").hide(); } - } else if (question_type == "anatomy") { - for (let n = 1; n < number_of_questions + 1; n++) { + } else if (window.question_type == "anatomy") { + for (let n = 1; n < window.number_of_questions + 1; n++) { appendReviewItem(n, "1"); } - } else if (question_type == "long") { - for (let n = 1; n < number_of_questions + 1; n++) { + } else if (window.question_type == "long") { + for (let n = 1; n < window.number_of_questions + 1; n++) { appendReviewItem(n, "1"); appendReviewItem(n, "2"); appendReviewItem(n, "3"); @@ -752,13 +800,19 @@ function createReviewPanel() { } } - $(".question-list-item").click(function (evt) { + $(".question-list-item").click(function(evt) { loadQuestion($(this).attr("data-qid"), $(this).attr("data-qidn")); }); } +/** + * Finds a select options but its text value + * @param {*} select - select element + * @param {*} text - text value + * @return {number} - number of found option or 'undefined' + */ function find_option(select, text) { - for (var i = 0; i < select.length; ++i) { + for (let i = 0; i < select.length; ++i) { if (select.options[i].value == text) { return i; } @@ -766,15 +820,19 @@ function find_option(select, text) { return undefined; } -// We use the same key bindings +/** + * Handle key button events + * These are the same as in the RCR pratique implementation + * @param {*} event - KeyEvent + */ function keydown_handler(event) { - var target_element = event.target.tagName; + const target_element = event.target.tagName; // Catch all keypresses unless user is typing if (target_element == "INPUT" || target_element == "TEXTAREA") { return; } - var sel = $(".control-overlay").get(0); + const sel = $(".control-overlay").get(0); switch (event.code) { case "KeyP": sel.selectedIndex = find_option(sel, "pan"); @@ -814,7 +872,7 @@ function keydown_handler(event) { break; case "KeyE": sel.selectedIndex = find_option(sel, "reset"); - //$("#dicom-image").get(0).scrollIntoView(false); + // $("#dicom-image").get(0).scrollIntoView(false); changeControlSelection(); break; // Escape and C do the same @@ -835,7 +893,7 @@ function keydown_handler(event) { manualPanDicom(0, -1); break; case "zoom": - //_this.current_dicom.current_view.pre_scale_at(1.01, 1.01, _this.current_dicom.cols / 2, _this.current_dicom.rows / 2); + // _this.current_dicom.current_view.pre_scale_at(1.01, 1.01, _this.current_dicom.cols / 2, _this.current_dicom.rows / 2); manualZoomDicom(1); break; case "rotate": @@ -914,41 +972,44 @@ function keydown_handler(event) { event.preventDefault(); } -function changeControlSelection(event) { - //We also duplicate the sel that are available - var sel = $(".control-overlay").get(0); +/** + * Registers the selected dicom tool + */ +function changeControlSelection() { + // We also duplicate the sel that are available + const sel = $(".control-overlay").get(0); - old = sel.oldSelectedIndex; + const old = sel.oldSelectedIndex; sel.oldSelectedIndex = sel.selectedIndex; console.log(event); - dicom_element = document.getElementById("dicom-image"); + const dicom_element = document.getElementById("dicom-image"); switch (sel.options[sel.selectedIndex].value) { case "pan": { - cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Pan", {mouseButtonMask: 1}); break; } case "zoom": { - cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Zoom", {mouseButtonMask: 1}); break; } case "rotate": { - cornerstoneTools.setToolActive("Rotate", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Rotate", {mouseButtonMask: 1}); break; } case "scroll": { - cornerstoneTools.setToolActive("StackScroll", { mouseButtonMask: 1 }); - //_this.left.onstart = _this.scroll_start; - //_this.selected_control = t.selectedIndex; + cornerstoneTools.setToolActive("StackScroll", {mouseButtonMask: 1}); + // _this.left.onstart = _this.scroll_start; + // _this.selected_control = t.selectedIndex; break; } case "window": { - cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Wwwc", {mouseButtonMask: 1}); break; } case "abdomen": { - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.voi.windowCenter = 150; viewport.voi.windowWidth = 500; cornerstone.setViewport(dicom_element, viewport); @@ -957,7 +1018,7 @@ function changeControlSelection(event) { break; } case "pulmonary": { - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.voi.windowCenter = -500; viewport.voi.windowWidth = 1500; cornerstone.setViewport(dicom_element, viewport); @@ -966,7 +1027,7 @@ function changeControlSelection(event) { break; } case "brain": { - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.voi.windowCenter = 50; viewport.voi.windowWidth = 80; cornerstone.setViewport(dicom_element, viewport); @@ -975,7 +1036,7 @@ function changeControlSelection(event) { break; } case "bone": { - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.voi.windowCenter = 570; viewport.voi.windowWidth = 3000; cornerstone.setViewport(dicom_element, viewport); @@ -999,8 +1060,8 @@ function changeControlSelection(event) { cornerstone.disable(dicom_element); $(".canvas-panel").remove(); $(".figure-open") - .removeClass("figure-open") - .addClass("figure"); + .removeClass("figure-open") + .addClass("figure"); $(dicom_element).remove(); } break; @@ -1012,11 +1073,15 @@ function changeControlSelection(event) { } } +/** + * Called when a dicom image is rendered + * @param {*} e - Event + */ function onImageRendered(e) { const eventData = e.detail; // Update ww/wl - sel = $(".control-overlay").get(0); + const sel = $(".control-overlay").get(0); sel.options[find_option(sel, "window")].firstChild.textContent = "window (" + Math.round(eventData.viewport.voi.windowCenter) + @@ -1025,16 +1090,16 @@ function onImageRendered(e) { ")"; // update stack data - stack = eventData.enabledElement.toolStateManager.toolState.stack.data[0]; + const stack = eventData.enabledElement.toolStateManager.toolState.stack.data[0]; if (stack.imageIds.length > 1) { $("option[value=scroll").prop("disabled", false); $("option[value=scroll").prop("hidden", false); $("option[value=scroll").text( - "scroll (" + + "scroll (" + (stack.currentImageIdIndex + 1) + "/" + stack.imageIds.length + - ")" + ")", ); // Temp way to enable CT window presets @@ -1050,15 +1115,19 @@ function onImageRendered(e) { } } +/** + * Disables fullscreen mode + * @param {*} dicom_element - + */ function disableFullscreen(dicom_element) { // TODO: rescale the image to stop it getting zoomed in $(".canvas-panel-fullscreen").toggleClass( - "canvas-panel canvas-panel-fullscreen" + "canvas-panel canvas-panel-fullscreen", ); $(".question").append($(".canvas-panel")); $(".canvas-panel") - .get(0) - .scrollIntoView(); + .get(0) + .scrollIntoView(); setDicomCanvasNonFullscreen(dicom_element); } @@ -1066,65 +1135,77 @@ function disableFullscreen(dicom_element) { // Register Key Event Listener window.addEventListener("keydown", keydown_handler); -$("#submit-button").click(function (evt) { +$("#submit-button").click(function(evt) { submitAnswers(); }); -$("#review-button").click(function (evt) { +$("#review-button").click(function(evt) { $(".question-list-panel").toggle(); }); -$("#options-button").click(function (evt) { +$("#options-button").click(function(evt) { $("#options-panel").toggle(); }); -$("#review-overlay-button").click(function (evt) { - if (review == true) { +$("#review-overlay-button").click(function(evt) { + if (window.review == true) { reviewQuestions(); } else { $("#finish-dialog").modal(); } }); -$("#finish-exam").click(function (evt) { - review = true; +$("#finish-exam").click(function(evt) { + window.review = true; reviewQuestions(); $.modal.close(); }); -$("#finish-cancel").click(function (evt) { +$("#finish-cancel").click(function(evt) { $.modal.close(); }); -$("#overlay-close").click(function (evt) { +$("#overlay-close").click(function(evt) { $("#options-panel").hide(); }); -$("#review-overlay-close").click(function (evt) { +$("#review-overlay-close").click(function(evt) { $("#review-overlay").hide(); }); +/** + * Gets a json representation of answers + * @return {JSON} - answers + */ function getJsonAnswers() { - return db.answers.where({ cid: cid, eid: eid }).toArray(); + return db.answers.where({cid: cid, eid: eid}).toArray(); // .then(function(ans) { // console.log(ans); // submitAnswers(ans); // }); } +/** + * Posts answers to url + * @param {*} ans - json representation of answers + */ function postAnswers(ans) { console.log(ans); - //ans = {"test" : 1} + // ans = {"test" : 1} $.post("http://localhost:8000/submit_answers", JSON.stringify(ans)).done( - data => { - console.log(data); - } + (data) => { + console.log(data); + }, ); - //$.post( "http://localhost:8000/submit_answers", JSON.stringify(ans)); + // $.post( "http://localhost:8000/submit_answers", JSON.stringify(ans)); } +/** + * Loads a local question set (from a file) + * This is defined in index.html + */ function loadLocalQuestionSet() { - var input, file, fr; + let input; let file; let fr; if (typeof window.FileReader !== "function") { alert("The file API isn't supported on this browser yet."); @@ -1136,7 +1217,7 @@ function loadLocalQuestionSet() { alert("No fileinput element."); } else if (!input.files) { alert( - "This browser doesn't seem to support the `files` property of file inputs." + "This browser doesn't seem to support the `files` property of file inputs.", ); } else if (!input.files[0]) { alert("Please select a file before clicking 'Load'"); @@ -1147,22 +1228,31 @@ function loadLocalQuestionSet() { fr.readAsText(file); } + /** + * Reads text from event and loads the packet + * @param {*} e - event + */ function receivedText(e) { - let lines = e.target.result; + const lines = e.target.result; j = JSON.parse(lines); setUpPacket(j); } } +/** + * Submits answers + */ function submitAnswers() { console.log( - getJsonAnswers().then(a => { - postAnswers(a); - }) + getJsonAnswers().then((a) => { + postAnswers(a); + }), ); } -// Displays the review question panel with a summary of marks +/** + * Displays the review question panel with a summary of marks + */ function reviewQuestions() { $("#review-overlay").show(); $("#review-answer-list").empty(); @@ -1170,171 +1260,182 @@ function reviewQuestions() { loadQuestion(0); db.answers - .where({ cid: cid, eid: eid }) - .toArray() - .then(function (answers) { - current_answers = {}; - answers.forEach(function (arr, n) { - answer = arr["ans"]; - if (answer == undefined) { - answer = "Not answered"; - } + .where({cid: cid, eid: eid}) + .toArray() + .then(function(answers) { + current_answers = {}; + answers.forEach(function(arr, n) { + answer = arr["ans"]; + if (answer == undefined) { + answer = "Not answered"; + } - current_answers[[arr["qid"], arr["qidn"]]] = answer; - }); + current_answers[[arr["qid"], arr["qidn"]]] = answer; + }); - correct_count = 0; - question_order.forEach(function (qid, n) { - $("#review-answer-list").append( - "
  • Question " + (n + 1) + - ": Not answered
  • " - ); - $("#review-answer-list a").click(function (evt) { - loadQuestion(this.dataset.qid); - $("#review-overlay").hide(); - }); - db.user_answers - .get({ qid: qid }) - .then(function (answers) { - question_answers = questions[qid]["answers"]; - if (answers == undefined) { - } else { - question_answers = question_answers.concat(answers.ans); - } + ": Not answered", + ); + $("#review-answer-list a").click(function(evt) { + loadQuestion(this.dataset.qid); + $("#review-overlay").hide(); + }); + db.user_answers + .get({qid: qid}) + .then(function(answers) { + question_answers = questions[qid]["answers"]; + if (answers == undefined) { + } else { + question_answers = question_answers.concat(answers.ans); + } - section_1_answer = current_answers[[qid, "1"]]; - section_2_answer = current_answers[[qid, "2"]]; + section_1_answer = current_answers[[qid, "1"]]; + section_2_answer = current_answers[[qid, "2"]]; - if (section_1_answer == undefined) { - section_1_answer = "Not Answered"; - } - if (section_2_answer == undefined) { - if (section_1_answer == "Normal") { - section_2_answer = "Normal"; - } else { - section_2_answer = "Not Answered"; - } - } + if (section_1_answer == undefined) { + section_1_answer = "Not Answered"; + } + if (section_2_answer == undefined) { + if (section_1_answer == "Normal") { + section_2_answer = "Normal"; + } else { + section_2_answer = "Not Answered"; + } + } - el = $("#review-answer-" + qid + " span"); + el = $("#review-answer-" + qid + " span"); - // Helper function to define how review items are displayed - // Yes it is a bit shit - function setReviewAnswer( - el, - c, - user_answer, - normal, - question_answers - ) { - if (normal) { - el.html( - "Answer: " + user_answer + - " (Normal)" - ); - } else { - el.html( - "Answer: " + user_answer + " (Abnormal: " + question_answers.join(", ") + - ")" - ); - } - } - - if (question_type == "rapid") { - // First check normal vs abnormal - if (questions[qid]["normal"] == true) { - if (section_1_answer == "Normal") { - setReviewAnswer( - el, - "correct", - section_1_answer, - true, - question_answers - ); - correct_count++; - } else { - setReviewAnswer( - el, - "incorrect", - section_1_answer, - true, - question_answers - ); + ")
    ", + ); + } } - } else { - if (answerInArray(question_answers, section_2_answer)) { - correct_count++; - setReviewAnswer( - el, - "correct", - section_2_answer, - false, - question_answers - ); - } else { - setReviewAnswer( - el, - "incorrect", - section_2_answer, - false, - question_answers - ); - } - } - } else if (question_type == "anatomy") { - // Anatomy answers are either correct or incorrect - if (answerInArray(question_answers, section_1_answer)) { - correct_count++; - setReviewAnswer( - el, - "correct", - section_1_answer, - false, - question_answers - ); - } else { - setReviewAnswer( - el, - "incorrect", - section_1_answer, - false, - question_answers - ); - } - } - $("#review-score").text( - "Score: " + correct_count + " out of " + question_order.length - ); - }) - .catch(function (error) { - console.log("error-", error); - }); + if (window.question_type == "rapid") { + // First check normal vs abnormal + if (questions[qid]["normal"] == true) { + if (section_1_answer == "Normal") { + setReviewAnswer( + el, + "correct", + section_1_answer, + true, + question_answers, + ); + correct_count++; + } else { + setReviewAnswer( + el, + "incorrect", + section_1_answer, + true, + question_answers, + ); + } + } else { + if (answerInArray(question_answers, section_2_answer)) { + correct_count++; + setReviewAnswer( + el, + "correct", + section_2_answer, + false, + question_answers, + ); + } else { + setReviewAnswer( + el, + "incorrect", + section_2_answer, + false, + question_answers, + ); + } + } + } else if (window.question_type == "anatomy") { + // Anatomy answers are either correct or incorrect + if (answerInArray(question_answers, section_1_answer)) { + correct_count++; + setReviewAnswer( + el, + "correct", + section_1_answer, + false, + question_answers, + ); + } else { + setReviewAnswer( + el, + "incorrect", + section_1_answer, + false, + question_answers, + ); + } + } + + $("#review-score").text( + "Score: " + correct_count + " out of " + window.question_order.length, + ); + }) + .catch(function(error) { + console.log("error-", error); + }); + }); + }) + .catch(function(error) { + console.log("error - ", error); }); - }) - .catch(function (error) { - console.log("error - ", error); - }); } -// Marks the loaded question and updates display +/** + * Marks the loaded question and updates display + * @param {*} qid - + * @param {*} type - + */ function markAnswer(qid, type) { console.log("mark", qid); - if (review == true) { + if (window.review == true) { // Disable all possible answer elements $("#rapid-option,.long-answer").attr("disabled", "true"); @@ -1342,7 +1443,7 @@ function markAnswer(qid, type) { option = document.getElementById("rapid-option"); if (current_question.normal == true) { $(".answer-panel").append( - "
    This is normal
    " + "
    This is normal
    ", ); if (option.value == "Normal") { option.classList.add("correct"); @@ -1350,12 +1451,12 @@ function markAnswer(qid, type) { option.classList.add("incorrect"); } // If answer is normal we have nothing else to add. - return addFeedback(); + addFeedback(); } } $(".answer-panel").append( - "
    Correct answer(s):
    " + "
    Correct answer(s):
    ", ); ul = $("#answer-list"); @@ -1365,46 +1466,46 @@ function markAnswer(qid, type) { user_answer = textarea.val(); db.user_answers - .get({ qid: qid }) - .then(function (answers) { - if (answers != undefined) { - answers.ans.forEach(function (answer, n) { + .get({qid: qid}) + .then(function(answers) { + if (answers != undefined) { + answers.ans.forEach(function(answer, n) { + ul.append("
  • " + answer + "
  • "); + if (compareString(answer, user_answer)) { + textarea.removeClass("incorrect").addClass("correct"); + } + }); + } + + current_question.answers.forEach(function(answer, n) { ul.append("
  • " + answer + "
  • "); if (compareString(answer, user_answer)) { textarea.removeClass("incorrect").addClass("correct"); } }); - } - current_question.answers.forEach(function (answer, n) { - ul.append("
  • " + answer + "
  • "); - if (compareString(answer, user_answer)) { - textarea.removeClass("incorrect").addClass("correct"); - } - }); - - if (type == "rapid" && option.value != "Abnormal") { - option.classList.add("incorrect"); - } else { - if ( - textarea.hasClass("incorrect") == true && + if (type == "rapid" && option.value != "Abnormal") { + option.classList.add("incorrect"); + } else { + if ( + textarea.hasClass("incorrect") == true && user_answer.replace(/\s/g, "") != "" - ) { - if (allow_self_marking) { - $(".answer-panel").append( - $("").click( - function () { - markCorrect(qid, user_answer); - } - ) - ); + ) { + if (window.allow_self_marking) { + $(".answer-panel").append( + $("").click( + function() { + markCorrect(qid, user_answer); + }, + ), + ); + } } } - } - }) - .catch(function (error) { - console.log("error-", error); - }); + }) + .catch(function(error) { + console.log("error-", error); + }); addFeedback(); } } @@ -1415,11 +1516,11 @@ function addFeedback() { current_question.feedback.length > 0 ) { $(".answer-panel").append( - $( - "

    Feedback

    " + + $( + "

    Feedback

    " + current_question.feedback + - "
    " - ) + "
    ", + ), ); } } @@ -1430,22 +1531,22 @@ function markCorrect(qid, user_answer) { } db.user_answers - .get({ qid: qid }) - .then(function (answers) { - if (answers == undefined) { - new_answers = []; - } else { - new_answers = answers.ans; - } + .get({qid: qid}) + .then(function(answers) { + if (answers == undefined) { + new_answers = []; + } else { + new_answers = answers.ans; + } - new_answers.push(user_answer); - db.user_answers.put({ qid: qid, ans: new_answers }); - }) - .catch(function (error) { - console.log("error-", error); - }); + new_answers.push(user_answer); + db.user_answers.put({qid: qid, ans: new_answers}); + }) + .catch(function(error) { + console.log("error-", error); + }); - if (allow_self_marking) { + if (window.allow_self_marking) { $("#mark-correct").remove(); } @@ -1461,61 +1562,62 @@ function compareString(a, b) { function answerInArray(arr, ans) { return ( arr - .map(v => v.toLowerCase().replace(/\s/g, "")) - .includes(ans.toLowerCase().replace(/\s/g, "")) == true + .map((v) => v.toLowerCase().replace(/\s/g, "")) + .includes(ans.toLowerCase().replace(/\s/g, "")) == true ); } function addFlagEvents() { // Bind flag change events - $("button.flag").click(function (event) { + $("button.flag").click(function(event) { el = $(this); nqid = el.attr("data-qid"); - qid = question_order[nqid]; + qid = window.question_order[nqid]; qidn = el.attr("data-qidn"); el.toggleClass("flag flag-selected"); if (el.hasClass("flag")) { $("#question-list-item-" + nqid + "-" + qidn + " span").css( - "visibility", - "hidden" + "visibility", + "hidden", ); db.flags.delete([cid, eid, qid, qidn]); } else { $("#question-list-item-" + nqid + "-" + qidn + " span").css( - "visibility", - "visible" + "visibility", + "visible", ); - db.flags.put({ cid: cid, eid: eid, qid: qid, qidn: qidn }); + db.flags.put({cid: cid, eid: eid, qid: qid, qidn: qidn}); } - updateReviewPanel(); + updateQuestionListPanel(); }); } -function loadFlagsFromDb(n) { +function loadFlagsFromDb(qid, n) { + console.log("loadFlagsFromDb", cid, eid, qid, n); db.flags - .get({ cid: cid, eid: eid, qid: qid, qidn: n }) - .then(function (answer) { - if (answer != undefined) { - $("button.flag, button.flag-selected") - .eq(parseInt(answer.qidn) - 1) - .toggleClass("flag flag-selected"); - } - }) - .catch(function (error) { - console.log(error); - }); + .get({cid: cid, eid: eid, qid: qid, qidn: n}) + .then(function(answer) { + if (answer != undefined) { + $("button.flag, button.flag-selected") + .eq(parseInt(answer.qidn) - 1) + .toggleClass("flag flag-selected"); + } + }) + .catch(function(error) { + console.log(error); + }); } function urltoFile(url, filename, mimeType) { return fetch(url) - .then(function (res) { - return res.arrayBuffer(); - }) - .then(function (buf) { - return new File([buf], filename, { type: mimeType }); - }); + .then(function(res) { + return res.arrayBuffer(); + }) + .then(function(buf) { + return new File([buf], filename, {type: mimeType}); + }); } function loadMainImage(image, stack) { @@ -1539,16 +1641,16 @@ function loadMainImage(image, stack) { cornerstoneTools.addTool(RotateTool); cornerstoneTools.addTool(StackScrollTool); - cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Pan", {mouseButtonMask: 1}); element.addEventListener("cornerstoneimagerendered", onImageRendered); setDicomCanvasNonFullscreen(element); cornerstone.reset(element); element.scrollIntoView(false); - //element.scrollTo(0); + // element.scrollTo(0); - $(element).dblclick(function () { + $(element).dblclick(function() { if ($(".canvas-panel").length == 0) { // already fullscreen (disable it) disableFullscreen(this); @@ -1557,8 +1659,8 @@ function loadMainImage(image, stack) { $(".canvas-panel").toggleClass("canvas-panel canvas-panel-fullscreen"); $("#dicom-image").attr("height", "100%"); $("#dicom-image").height("100%"); - //$(".cornerstone-canvas").attr("height", "100%"); - //$(".cornerstone-canvas").height("100%"); + // $(".cornerstone-canvas").attr("height", "100%"); + // $(".cornerstone-canvas").height("100%"); cornerstone.resize(this, true); } }); @@ -1567,20 +1669,20 @@ function loadMainImage(image, stack) { // Add tool selector $(".canvas-panel").append( - '' + "", ); $(".control-overlay") - .get(0) - .addEventListener("change", changeControlSelection); + .get(0) + .addEventListener("change", function() {changeControlSelection();}); } function setDicomCanvasNonFullscreen(element) { - h = window.innerHeight - $(".nav-bar").height() - 4; + const h = window.innerHeight - $(".nav-bar").height() - 4; $("#dicom-image").attr("height", h); $("#dicom-image").height(h); - //$("#dicom-image.cornerstone-canvas").attr("height", h); - //$("#dicom-image.cornerstone-canvas").height(h); + // $("#dicom-image.cornerstone-canvas").attr("height", h); + // $("#dicom-image.cornerstone-canvas").height(h); $("#dicom-image .cornerstone-canvas").attr("width", "100%"); @@ -1591,7 +1693,7 @@ function showLoginDialog() { $("#login-dialog").modal(); } -$("#start-exam-button").click(function (evt) { +$("#start-exam-button").click(function(evt) { cid = parseInt($("#candidate-number").val()); $.modal.close(); }); @@ -1599,7 +1701,7 @@ $("#start-exam-button").click(function (evt) { function manualPanDicom(x, y) { dicom_element = document.getElementById("dicom-image"); - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.translation.x += x; viewport.translation.y += y; @@ -1609,7 +1711,7 @@ function manualPanDicom(x, y) { function manualZoomDicom(delta) { dicom_element = document.getElementById("dicom-image"); - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.scale += delta / 100; @@ -1618,7 +1720,7 @@ function manualZoomDicom(delta) { function manualRotateDicom(delta) { dicom_element = document.getElementById("dicom-image"); - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); viewport.rotation += delta; @@ -1649,15 +1751,15 @@ function manualScrollDicom(n) { c.toolStateManager.toolState.stack.data[0].currentImageIdIndex = new_index; id = c.toolStateManager.toolState.stack.data[0].imageIds[new_index]; - cornerstone.loadImage(id).then(b => { + cornerstone.loadImage(id).then((b) => { cornerstone.displayImage(dicom_element, b); }); - //c = cornerstone.getEnabledElement(dicom_element) + // c = cornerstone.getEnabledElement(dicom_element) } function manualWindowDicom(wl, ww) { dicom_element = document.getElementById("dicom-image"); - let viewport = cornerstone.getViewport(dicom_element); + const viewport = cornerstone.getViewport(dicom_element); // For reference // brightness ~= wl diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..609ff23 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1101 @@ +{ + "name": "rts", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-google": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "dev": true + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..eece1b0 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "rts", + "version": "1.0.0", + "description": "RTS is a quick and dirty clone of the RCR radiology test system that supports the full set of RCR exam types (Anatomy / Rapid / Longs).", + "main": "index.js", + "directories": { + "lib": "lib" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/xkjq/rts.git" + }, + "author": "", + "license": "GPL", + "bugs": { + "url": "https://github.com/xkjq/rts/issues" + }, + "homepage": "https://github.com/xkjq/rts#readme", + "devDependencies": { + "eslint": "^6.8.0", + "eslint-config-google": "^0.14.0" + }, + "lint": "eslint --fix . && echo 'Lint complete.'" +} \ No newline at end of file