From f6fdbfaf7f23b280bd2c4c6b361ffb11a4f4e993 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 Feb 2021 21:05:49 +0000 Subject: [PATCH] . --- anatomy/static/css/anatomy.css | 13 +- anatomy/static/js/anatomy.js | 390 +++++++++++--------- longs/forms.py | 16 + longs/migrations/0002_auto_20210204_1032.py | 75 ++++ longs/migrations/0003_auto_20210204_2105.py | 23 ++ longs/models.py | 4 +- longs/templates/longs/longseries_form.html | 317 ++++++++++++++++ longs/urls.py | 1 + longs/views.py | 37 +- temp.png | Bin 446 -> 0 bytes templates/base.html | 2 +- 11 files changed, 687 insertions(+), 191 deletions(-) create mode 100644 longs/migrations/0002_auto_20210204_1032.py create mode 100644 longs/migrations/0003_auto_20210204_2105.py create mode 100755 longs/templates/longs/longseries_form.html delete mode 100644 temp.png diff --git a/anatomy/static/css/anatomy.css b/anatomy/static/css/anatomy.css index 6a206cfb..afe6e8e6 100644 --- a/anatomy/static/css/anatomy.css +++ b/anatomy/static/css/anatomy.css @@ -158,6 +158,11 @@ button a { height: 600px; } +.dicom-viewer { + width: 100%; + height: 600px; +} + .marking-dicom { position: fixed; right: 0px; @@ -208,10 +213,6 @@ button a { } .drop-target { - border: 1px dashed white; -} - -#drop-container { width: 100%; width: 100vw; height: 100px; @@ -225,6 +226,10 @@ button a { margin-right: -50vw; } +#drop-container { + border: 1px dashed white; +} + .submit-button { position: sticky; bottom: 0; diff --git a/anatomy/static/js/anatomy.js b/anatomy/static/js/anatomy.js index 4337b5f8..e3bca40c 100644 --- a/anatomy/static/js/anatomy.js +++ b/anatomy/static/js/anatomy.js @@ -1,233 +1,259 @@ import * as dicomViewer from "./dicomViewer.js" window.marked_answers = { - "correct": [], - "half-correct": [], - "incorrect": [], + "correct": [], + "half-correct": [], + "incorrect": [], } window.control_pressed = false; $(document).ready(function () { - $(".answer-list li").each(function (index, element) { - $(element).append($("G")); + $(".answer-list li").each(function (index, element) { + $(element).append($("G")); + }); + + $(".answer-list span.answer").each(function (index, element) { + console.log(element); + + $(element).click(function (e) { + + var classes = ['answer correct', 'answer half-correct', 'answer incorrect']; + $(element).each(function () { + this.className = classes[($.inArray(this.className, classes) + 1) % classes.length]; + }); + + prepAnswerData(); + + + + }); + }); + prepAnswerData(); + + if ($(".post-form").length > 0) { + $(".post-form").get(0).addEventListener("submit", function (e) { + if ($(".not-marked").length > 0 && e.submitter.name != "skip") { + e.preventDefault(); // before the code + alert("Ensure all answers are marked first"); + } + + }); + } + + let dicom_images = document.getElementsByClassName("dicom-image"); + if (dicom_images.length) { + + for (let element of dicom_images) { + setUpDicom(element) + } + + } + + + loadDicomViewer(); + + if ($("#question-mark-list").length) { + $(".show-all-button").click(() => { + $("#question-mark-list li").show(); + }); + $(".show-unmarked-button").click(() => { + console.log("TESTIG"); + $("#question-mark-list li").each((n, el) => { + console.log(el); + if (el.dataset.markcount < 1) { $(el).hide(); } + }) }); - $(".answer-list span.answer").each(function (index, element) { - console.log(element); + } - $(element).click(function (e) { + $(document).keydown(keyDownHandler); + $(document).keyup(keyUpHandler); - var classes = ['answer correct', 'answer half-correct', 'answer incorrect']; - $(element).each(function () { - this.className = classes[($.inArray(this.className, classes) + 1) % classes.length]; - }); - - prepAnswerData(); - - - - }); - }); - prepAnswerData(); - - if ($(".post-form").length > 0) { - $(".post-form").get(0).addEventListener("submit", function (e) { - if ($(".not-marked").length > 0 && e.submitter.name != "skip") { - e.preventDefault(); // before the code - alert("Ensure all answers are marked first"); - } - - }); - } - - let dicom_images = document.getElementsByClassName("dicom-image"); - if (dicom_images.length) { - - for (let element of dicom_images) { - setUpDicom(element) - } - - } - - let single_dicom = document.getElementById("single-dicom-viewer"); - if (single_dicom) { - - let images = single_dicom.dataset.images; - if (images.indexOf(",") > 0) { - images = images.split(","); - } - - let annotations = single_dicom.dataset.annotations; - if (annotations != undefined && annotations.indexOf(",") > 0) { - annotations = annotations; - } - - dicomViewer.loadCornerstone($(single_dicom), null, images, annotations); - } - - if ($("#question-mark-list").length) { - $(".show-all-button").click(() => { - $("#question-mark-list li").show(); - }); - $(".show-unmarked-button").click(() => { - console.log("TESTIG"); - $("#question-mark-list li").each((n, el) => { - console.log(el); - if (el.dataset.markcount < 1) { $(el).hide(); } - }) - }); - - } - - $(document).keydown(keyDownHandler); - $(document).keyup(keyUpHandler); }); -function prepAnswerData() { - //$("#id_correct").val($("li.correct").map(function() { - // ans = $(this).text(); - // window.marked_answers["correct"].push(ans); - // return ans - //}).get().join('--//--')); - //$("#id_half_correct").val($("li.half-correct").map(function() { - // ans = $(this).text(); - // window.marked_answers["half-correct"].push(ans); - // return ans; - //}).get().join('--//--')); - //$("#id_incorrect").val($("li.incorrect").map(function() { - // ans = $(this).text(); - // window.marked_answers["incorrect"].push(ans); - // return ans; - //}).get().join('--//--')); +window.loadDicomViewerEvent = new Event('loadDicomViewer'); +window.addEventListener('loadDicomViewer', function (e) { + console.log("listen", e.detail) + let images = []; + console.log($("#images img")); + $("#images img").each((n, el) => { + images.push($(el).attr("src")); + } ); + console.log("listen2", images) + loadDicomViewer(images); }, false); - window.marked_answers["correct"] = []; - window.marked_answers["half-correct"] = []; - window.marked_answers["incorrect"] = []; - $("li span.correct").map(function () { - let ans = $(this).text(); - window.marked_answers["correct"].push(ans); - }) - $("li span.half-correct").map(function () { - let ans = $(this).text(); - window.marked_answers["half-correct"].push(ans); - }) - $("li span.incorrect").map(function () { - let ans = $(this).text(); - window.marked_answers["incorrect"].push(ans); - }) - $("#id_marked_answers").val(JSON.stringify(window.marked_answers)); +function loadDicomViewer(images_to_load) { + console.log("loadDicomViewer", images_to_load); + let single_dicom = document.getElementById("single-dicom-viewer"); + if (single_dicom) { + + let images = single_dicom.dataset.images; + + if (images_to_load != undefined) { + images = images_to_load; + console.log("i1", images) + } else if (images.indexOf(",") > 0) { + images = images.split(","); + } + + console.log(images); + + let annotations = single_dicom.dataset.annotations; + if (annotations != undefined && annotations.indexOf(",") > 0) { + annotations = annotations; + } + + if (images) { + dicomViewer.loadCornerstone($(single_dicom), null, images, annotations, true); + } + } +} + +function prepAnswerData() { + //$("#id_correct").val($("li.correct").map(function() { + // ans = $(this).text(); + // window.marked_answers["correct"].push(ans); + // return ans + //}).get().join('--//--')); + //$("#id_half_correct").val($("li.half-correct").map(function() { + // ans = $(this).text(); + // window.marked_answers["half-correct"].push(ans); + // return ans; + //}).get().join('--//--')); + //$("#id_incorrect").val($("li.incorrect").map(function() { + // ans = $(this).text(); + // window.marked_answers["incorrect"].push(ans); + // return ans; + //}).get().join('--//--')); + + window.marked_answers["correct"] = []; + window.marked_answers["half-correct"] = []; + window.marked_answers["incorrect"] = []; + $("li span.correct").map(function () { + let ans = $(this).text(); + window.marked_answers["correct"].push(ans); + }) + $("li span.half-correct").map(function () { + let ans = $(this).text(); + window.marked_answers["half-correct"].push(ans); + }) + $("li span.incorrect").map(function () { + let ans = $(this).text(); + window.marked_answers["incorrect"].push(ans); + }) + $("#id_marked_answers").val(JSON.stringify(window.marked_answers)); } function loadJsonToolStateOnCurrentImage(json) { - let el = document.getElementById("dicom-image"); + let el = document.getElementById("dicom-image"); - const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager; + const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager; - const c = cornerstone.getEnabledElement(el); + const c = cornerstone.getEnabledElement(el); - let image_id = c.image.imageId; + let image_id = c.image.imageId; - let tool_state_no_id = JSON.parse(json); + let tool_state_no_id = JSON.parse(json); - let tool_state = {}; - tool_state[image_id] = tool_state_no_id; + let tool_state = {}; + tool_state[image_id] = tool_state_no_id; - toolStateManager.restoreToolState(tool_state); + toolStateManager.restoreToolState(tool_state); - cornerstone.reset(el); + cornerstone.reset(el); - return tool_state; + return tool_state; } function setUpDicom(element) { - console.log("Dicom element found ", $(element)); + console.log("Dicom element found ", $(element)); - $(element).bind('contextmenu', function (e) { - return false; - }); + $(element).bind('contextmenu', function (e) { + return false; + }); - $(element).dblclick((evt) => { - element.requestFullscreen(); - }) + $(element).dblclick((evt) => { + element.requestFullscreen(); + }) - cornerstoneBase64ImageLoader.external.cornerstone = cornerstone; - cornerstoneWebImageLoader.external.cornerstone = cornerstone; - cornerstoneWADOImageLoader.external.cornerstone = cornerstone; + cornerstoneBase64ImageLoader.external.cornerstone = cornerstone; + cornerstoneWebImageLoader.external.cornerstone = cornerstone; + cornerstoneWADOImageLoader.external.cornerstone = cornerstone; - cornerstoneTools.init(); - const PanTool = cornerstoneTools.PanTool; - const ZoomTool = cornerstoneTools.ZoomTool; - const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool; - const WwwcTool = cornerstoneTools.WwwcTool; - const WwwcRegionTool = cornerstoneTools.WwwcRegionTool; - const RotateTool = cornerstoneTools.RotateTool; - const StackScrollTool = cornerstoneTools.StackScrollTool; - const MagnifyTool = cornerstoneTools.MagnifyTool; - const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool; + cornerstoneTools.init(); + const PanTool = cornerstoneTools.PanTool; + const ZoomTool = cornerstoneTools.ZoomTool; + const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool; + const WwwcTool = cornerstoneTools.WwwcTool; + const WwwcRegionTool = cornerstoneTools.WwwcRegionTool; + const RotateTool = cornerstoneTools.RotateTool; + const StackScrollTool = cornerstoneTools.StackScrollTool; + const MagnifyTool = cornerstoneTools.MagnifyTool; + const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool; - const imageIds = element.dataset.url.split(","); + const imageIds = element.dataset.url.split(","); - console.log("Dicom - load imageId: ", imageIds); + console.log("Dicom - load imageId: ", imageIds); - cornerstone.enable(element); - cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) { - cornerstone.displayImage(element, image); + cornerstone.enable(element); + cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) { + cornerstone.displayImage(element, image); - cornerstoneTools.addTool(PanTool); - cornerstoneTools.addTool(ZoomTool); - cornerstoneTools.addTool(ZoomMouseWheelTool); - cornerstoneTools.addTool(WwwcTool); - cornerstoneTools.addTool(WwwcRegionTool); - cornerstoneTools.addTool(RotateTool); - cornerstoneTools.addTool(StackScrollTool); - cornerstoneTools.addTool(MagnifyTool); + cornerstoneTools.addTool(PanTool); + cornerstoneTools.addTool(ZoomTool); + cornerstoneTools.addTool(ZoomMouseWheelTool); + cornerstoneTools.addTool(WwwcTool); + cornerstoneTools.addTool(WwwcRegionTool); + cornerstoneTools.addTool(RotateTool); + cornerstoneTools.addTool(StackScrollTool); + cornerstoneTools.addTool(MagnifyTool); - cornerstoneTools.addTool(ArrowAnnotateTool, { - configuration: { - getTextCallback: () => { }, - changeTextCallback: () => { }, - allowEmptyLabel: true, - renderDashed: false, - drawHandles: false, - drawHandlesOnHover: true, - }, - }); + cornerstoneTools.addTool(ArrowAnnotateTool, { + configuration: { + getTextCallback: () => { }, + changeTextCallback: () => { }, + allowEmptyLabel: true, + renderDashed: false, + drawHandles: false, + drawHandlesOnHover: true, + }, + }); - // Enable our tools - // Avoid incorrect aspect ratio - cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); - cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 }); - cornerstoneTools.setToolActive("ZoomMouseWheel", { mouseButtonMask: 3 }); - cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 }); + // Enable our tools + // Avoid incorrect aspect ratio + cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); + cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 }); + cornerstoneTools.setToolActive("ZoomMouseWheel", { mouseButtonMask: 3 }); + cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 }); - if (element.dataset.edit_annotation == "true") { - cornerstoneTools.setToolActive("ArrowAnnotate", { mouseButtonMask: 2 }); - } else { - cornerstoneTools.setToolEnabled("ArrowAnnotate"); - } + if (element.dataset.edit_annotation == "true") { + cornerstoneTools.setToolActive("ArrowAnnotate", { mouseButtonMask: 2 }); + } else { + cornerstoneTools.setToolEnabled("ArrowAnnotate"); + } - if (element.dataset.annotations) { - loadJsonToolStateOnCurrentImage(element.dataset.annotations) - } + if (element.dataset.annotations) { + loadJsonToolStateOnCurrentImage(element.dataset.annotations) + } - cornerstone.resize(element); + cornerstone.resize(element); - }); + }); } function keyUpHandler(e) { - if(e.key == "Control") { + if (e.key == "Control") { dicomViewer.registerPrimaryDicomInterface(e); window.control_pressed = false; } @@ -236,16 +262,16 @@ function keyUpHandler(e) { function keyDownHandler(e) { // Ignore our custom keybindings if we are currently in a field that // accepts some kind of input - if($("*:focus:not(disabled)").is("textarea, input")) { + if ($("*:focus:not(disabled)").is("textarea, input")) { // unless a modifier key is pressed (not shift) - if(e.altKey ? true : false || e.ctrlKey ? true : false) { + if (e.altKey ? true : false || e.ctrlKey ? true : false) { } else { return; } } - if(e.key == "Control") { - if(window.control_pressed == false) { + if (e.key == "Control") { + if (window.control_pressed == false) { window.control_pressed = true; dicomViewer.registerAltDicomInterface(e); } @@ -255,23 +281,23 @@ function keyDownHandler(e) { console.log(e, charCode); function numberKeyPressed(e, x) { - if(e.altKey ? true : false) { + if (e.altKey ? true : false) { dicomViewer.selectThumb(x); e.preventDefault(); } else { } } - switch(charCode) { + switch (charCode) { case 13: // Return - if(e.shiftKey ? true : false) { + if (e.shiftKey ? true : false) { //$(".next-button:last").click(); } else { //$(".check-button:last").click(); } break; case 32: // Space - if(e.shiftKey ? true : false) { + if (e.shiftKey ? true : false) { //$(".previous-button:last").click(); } else { //$(".next-button:last").click(); diff --git a/longs/forms.py b/longs/forms.py index abbc7d2c..f126262a 100755 --- a/longs/forms.py +++ b/longs/forms.py @@ -55,6 +55,11 @@ class LongCreationDefaultForm(ModelForm): fields = ["site"] exclude = ["author"] +class LongSeriesForm(ModelForm): + class Meta: + model = LongSeries + exclude = [] + class LongForm(ModelForm): class Media: @@ -103,3 +108,14 @@ SeriesFormSet = inlineformset_factory( max_num=10, field_classes="testing", ) + + +LongSeriesImageFormSet = inlineformset_factory( + LongSeries, + LongSeriesImage, + exclude=[], + can_delete=True, + extra=4, + max_num=2000, + field_classes="testing", +) diff --git a/longs/migrations/0002_auto_20210204_1032.py b/longs/migrations/0002_auto_20210204_1032.py new file mode 100644 index 00000000..ab191a2d --- /dev/null +++ b/longs/migrations/0002_auto_20210204_1032.py @@ -0,0 +1,75 @@ +# Generated by Django 3.1.3 on 2021-02-04 10:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='ciduseranswer', + name='answer', + ), + migrations.RemoveField( + model_name='ciduseranswer', + name='answer_compare', + ), + migrations.RemoveField( + model_name='ciduseranswer', + name='normal', + ), + migrations.AddField( + model_name='ciduseranswer', + name='answer_differential_diagnosis', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='ciduseranswer', + name='answer_further_management', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='ciduseranswer', + name='answer_interpretation', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='ciduseranswer', + name='answer_observations', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='ciduseranswer', + name='answer_principle_diagnosis', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='long', + name='model_differential_diagnosis', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='long', + name='model_further_management', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='long', + name='model_interpretation', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='long', + name='model_observations', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='long', + name='model_principle_diagnosis', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/longs/migrations/0003_auto_20210204_2105.py b/longs/migrations/0003_auto_20210204_2105.py new file mode 100644 index 00000000..62a3be04 --- /dev/null +++ b/longs/migrations/0003_auto_20210204_2105.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.3 on 2021-02-04 21:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0002_auto_20210204_1032'), + ] + + operations = [ + migrations.RenameField( + model_name='long', + old_name='question', + new_name='history', + ), + migrations.AddField( + model_name='longseries', + name='description', + field=models.TextField(blank=True, help_text='Description of stack, for admin organisation'), + ), + ] diff --git a/longs/models.py b/longs/models.py index d9735469..641343a5 100644 --- a/longs/models.py +++ b/longs/models.py @@ -60,7 +60,8 @@ class Sign(tagulous.models.TagModel): class Long(models.Model): #author = models.ForeignKey('auth.User', on_delete=models.CASCADE) #image = models.ImageField() - question = models.TextField(null=True, blank=True) + history = models.TextField(null=True, blank=True) + feedback = models.TextField(null=True, blank=True) #condition = tagulous.models.TagField( @@ -157,6 +158,7 @@ class LongSeries(models.Model): examination = models.ForeignKey( Examination, help_text="Name of the examination", on_delete=models.SET_NULL, null=True) long = models.ForeignKey("Long", related_name="long", on_delete=models.SET_NULL, null=True) + description = models.TextField(blank=True, help_text="Description of stack, for admin organisation") #class LongImage(models.Model): # long = models.ForeignKey(Long, diff --git a/longs/templates/longs/longseries_form.html b/longs/templates/longs/longseries_form.html new file mode 100755 index 00000000..d99d8a72 --- /dev/null +++ b/longs/templates/longs/longseries_form.html @@ -0,0 +1,317 @@ +{% extends "longs/base.html" %} +{% load static from static %} + +{% block js %} + + + + +{{ form.media }} +{% endblock %} +{% block content %} +

Add Series

+Edit defaults +
+ {% csrf_token %} + + {{ form.as_table }} +
+ +

Images:

+ +
Drop images here (or use the buttons below) +
+
+
+
+ {% for form in image_formset %} +
    + {{form.non_field_errors}} + {{form.errors}} + {{ form.as_ul }} +
+ {% endfor %} +
+ {{ image_formset.management_form }} + +
+ +
+ +
+{% endblock %} \ No newline at end of file diff --git a/longs/urls.py b/longs/urls.py index 40dc3bd9..16fe72c5 100755 --- a/longs/urls.py +++ b/longs/urls.py @@ -35,6 +35,7 @@ urlpatterns = [ path("exam/json/", views.exam_json, name="exam_json"), path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), path("create/", views.LongCreate.as_view(), name="long_create"), + path("create/series", views.LongSeriesCreate.as_view(), name="long_series_create"), path("create/defaults", views.LongCreationDefaultView.as_view(), name="long_create_defaults"), diff --git a/longs/views.py b/longs/views.py index 267e598c..ba400e6b 100755 --- a/longs/views.py +++ b/longs/views.py @@ -20,13 +20,14 @@ from django.http import HttpResponseRedirect, HttpResponse from .forms import ( LongForm, + LongSeriesForm, LongSeriesImageFormSet, MarkLongQuestionForm, SeriesFormSet, NoteForm, ExaminationForm, ) from .models import ( - Long, + Long, LongSeries, Note, Examination, Exam, @@ -252,6 +253,38 @@ def long_clone(request, pk): return render(request, "longs/long_form.html", context) +class LongSeriesCreate(LoginRequiredMixin, CreateView): + model = LongSeries + form_class = LongSeriesForm + + def get_context_data(self, **kwargs): + context = super(LongSeriesCreate, self).get_context_data(**kwargs) + if self.request.POST: + context["image_formset"] = LongSeriesImageFormSet( + self.request.POST, self.request.FILES + ) + context["image_formset"].full_clean() + else: + context["image_formset"] = LongSeriesImageFormSet() + return context + + def form_valid(self, form): + + self.object = form.save(commit=False) + self.object.save() + + #form.instance.author.add(self.request.user.id) + + context = self.get_context_data(form=form) + series_formset = context["image_formset"] + if series_formset.is_valid(): + response = super().form_valid(form) + series_formset.instance = self.object + series_formset.save() + return response + + else: + return super().form_invalid(form) class LongCreateBase(LoginRequiredMixin, CreateView): model = Long @@ -294,8 +327,6 @@ class LongCreateBase(LoginRequiredMixin, CreateView): # @login_required class LongCreate(LongCreateBase): - - def get_initial(self): # There has to be a better way... try: diff --git a/temp.png b/temp.png deleted file mode 100644 index d71aeac42a10cdc4f96183c1439144a06e7892e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^E16Crc&9i47hODhfgZoEuYra#q)Pf+AlLLHL3r$?$ZWmlK)d$3Y^e}vk%pPvIl+N^;rCzDgZ6i-Wd zP3v%ovwFHVwUgt?W*d2VRd1I$r#?*Xxcn;dr%IFM>0o0iyG{>Yb0G2W&eR%#jdODS z_zznbI#^5G>twDu*<*1aGR=kQ(S~Qox-C|nTfe7c@vMbUTp>Xx8DG>eBQsA17>>o? k&k6XR30bcF(S@m=p^rb??fQeTo1lpCboFyt=akR{0NHxH00000 diff --git a/templates/base.html b/templates/base.html index 34a10aa0..a659b345 100644 --- a/templates/base.html +++ b/templates/base.html @@ -15,7 +15,7 @@ - +