From 5bcbd67b104ad61d1f6a6834c3a2df603b187a6a Mon Sep 17 00:00:00 2001 From: leangseu-edx <83240113+leangseu-edx@users.noreply.github.com> Date: Wed, 20 Sep 2023 14:45:54 -0400 Subject: [PATCH 01/27] feat: make legacy template (#2046) * chore: move template to legacy folder * chore: add lms+cms restart script to install-local-ora * chore: update test * chore: add top level block view --- Makefile | 2 + openassessment/templates/base.html | 3 + .../edit/oa_edit.html | 12 ++-- .../edit/oa_edit_assessment_steps.html | 2 +- .../edit/oa_edit_basic_settings_list.html | 0 .../edit/oa_edit_criterion.html | 2 +- .../edit/oa_edit_header_and_validation.html | 12 ++-- .../edit/oa_edit_option.html | 0 .../edit/oa_edit_peer_assessment.html | 0 .../oa_edit_peer_assessment_schedule.html | 0 .../edit/oa_edit_prompt.html | 0 .../edit/oa_edit_prompts.html | 4 +- .../edit/oa_edit_rubric.html | 8 +-- .../edit/oa_edit_schedule.html | 4 +- .../edit/oa_edit_self_assessment.html | 0 .../oa_edit_self_assessment_schedule.html | 0 .../edit/oa_edit_settings.html | 2 +- .../edit/oa_edit_staff_assessment.html | 0 .../edit/oa_edit_student_training.html | 6 +- .../edit/oa_rubric_reuse.html | 0 .../edit/oa_training_example.html | 2 +- .../edit/oa_training_example_criterion.html | 0 .../grade/oa_assessment_feedback.html | 0 .../grade/oa_assessment_title.html | 0 .../grade/oa_grade_cancelled.html | 0 .../grade/oa_grade_complete.html | 10 +-- .../grade/oa_grade_incomplete.html | 0 .../grade/oa_grade_not_started.html | 0 .../grade/oa_grade_waiting.html | 0 .../icons/warning_filled.html | 0 .../oa_grade_available_responses.html | 2 +- .../instructor_dashboard/oa_listing.html | 2 +- .../oa_waiting_step_details.html | 0 ...pen-response-assessment-summary.underscore | 0 .../leaderboard/oa_leaderboard_show.html | 4 +- .../leaderboard/oa_leaderboard_waiting.html | 0 .../message/oa_message_cancelled.html | 0 .../message/oa_message_closed.html | 0 .../message/oa_message_complete.html | 0 .../message/oa_message_incomplete.html | 0 .../message/oa_message_no_team.html | 0 .../message/oa_message_open.html | 0 .../message/oa_message_unavailable.html | 0 .../oa_base.html | 0 .../oa_error.html | 0 .../oa_latex_preview.html | 0 .../oa_rubric.html | 4 +- .../oa_submission_answer.html | 0 .../oa_team_uploaded_files.html | 0 .../oa_uploaded_file.html | 0 .../peer/oa_peer_assessment.html | 6 +- .../peer/oa_peer_cancelled.html | 2 +- .../peer/oa_peer_closed.html | 2 +- .../peer/oa_peer_complete.html | 2 +- .../peer/oa_peer_turbo_mode.html | 8 +-- .../peer/oa_peer_turbo_mode_waiting.html | 2 +- .../peer/oa_peer_unavailable.html | 2 +- .../peer/oa_peer_waiting.html | 2 +- .../response/oa_response.html | 8 +-- .../response/oa_response_cancelled.html | 2 +- .../response/oa_response_closed.html | 2 +- .../response/oa_response_graded.html | 8 +-- .../response/oa_response_studio_preview.html | 0 .../response/oa_response_submitted.html | 8 +-- .../oa_response_team_already_submitted.html | 2 +- .../response/oa_response_unavailable.html | 2 +- .../self/oa_self_assessment.html | 6 +- .../self/oa_self_cancelled.html | 2 +- .../self/oa_self_closed.html | 2 +- .../self/oa_self_complete.html | 2 +- .../self/oa_self_unavailable.html | 2 +- .../staff/oa_staff_grade.html | 0 .../staff_area/oa_staff_area.html | 2 +- .../staff_area/oa_staff_grade_learners.html | 2 +- .../oa_staff_grade_learners_assessment.html | 6 +- .../oa_staff_grade_learners_count.html | 0 .../oa_staff_override_assessment.html | 6 +- .../staff_area/oa_student_info.html | 14 ++-- .../oa_student_info_assessment_detail.html | 0 .../student_training/student_training.html | 2 +- .../student_training_cancelled.html | 2 +- .../student_training_closed.html | 2 +- .../student_training_complete.html | 2 +- .../student_training_error.html | 2 +- .../student_training_unavailable.html | 2 +- openassessment/xblock/grade_mixin.py | 10 +-- openassessment/xblock/leaderboard_mixin.py | 4 +- openassessment/xblock/message_mixin.py | 16 ++--- openassessment/xblock/openassessmentblock.py | 10 +-- openassessment/xblock/staff_area_mixin.py | 8 +-- .../xblock/static/js/fixtures/templates.json | 60 ++++++++--------- openassessment/xblock/studio_mixin.py | 2 +- .../test/data/student_training_mixin.json | 2 +- .../xblock/test/test_leaderboard.py | 4 +- openassessment/xblock/test/test_message.py | 66 +++++++++---------- openassessment/xblock/test/test_peer.py | 24 +++---- openassessment/xblock/test/test_self.py | 24 +++---- openassessment/xblock/test/test_staff.py | 2 +- openassessment/xblock/test/test_staff_area.py | 14 ++-- .../xblock/test/test_student_training.py | 12 ++-- openassessment/xblock/test/test_submission.py | 42 ++++++------ scripts/render_templates.py | 2 +- 102 files changed, 251 insertions(+), 246 deletions(-) create mode 100644 openassessment/templates/base.html rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit.html (62%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_assessment_steps.html (88%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_basic_settings_list.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_criterion.html (94%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_header_and_validation.html (85%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_option.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_peer_assessment.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_peer_assessment_schedule.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_prompt.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_prompts.html (74%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_rubric.html (80%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_schedule.html (97%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_self_assessment.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_self_assessment_schedule.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_settings.html (60%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_staff_assessment.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_edit_student_training.html (89%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_rubric_reuse.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_training_example.html (91%) rename openassessment/templates/{openassessmentblock => legacy}/edit/oa_training_example_criterion.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_assessment_feedback.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_assessment_title.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_grade_cancelled.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_grade_complete.html (95%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_grade_incomplete.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_grade_not_started.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/grade/oa_grade_waiting.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/icons/warning_filled.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/instructor_dashboard/oa_grade_available_responses.html (85%) rename openassessment/templates/{openassessmentblock => legacy}/instructor_dashboard/oa_listing.html (89%) rename openassessment/templates/{openassessmentblock => legacy}/instructor_dashboard/oa_waiting_step_details.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/instructor_dashboard/open-response-assessment-summary.underscore (100%) rename openassessment/templates/{openassessmentblock => legacy}/leaderboard/oa_leaderboard_show.html (80%) rename openassessment/templates/{openassessmentblock => legacy}/leaderboard/oa_leaderboard_waiting.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_cancelled.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_closed.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_complete.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_incomplete.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_no_team.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_open.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/message/oa_message_unavailable.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_base.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_error.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_latex_preview.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_rubric.html (95%) rename openassessment/templates/{openassessmentblock => legacy}/oa_submission_answer.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_team_uploaded_files.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/oa_uploaded_file.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_assessment.html (89%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_cancelled.html (90%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_closed.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_complete.html (97%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_turbo_mode.html (83%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_turbo_mode_waiting.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_unavailable.html (89%) rename openassessment/templates/{openassessmentblock => legacy}/peer/oa_peer_waiting.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_cancelled.html (97%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_closed.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_graded.html (65%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_studio_preview.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_submitted.html (80%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_team_already_submitted.html (96%) rename openassessment/templates/{openassessmentblock => legacy}/response/oa_response_unavailable.html (89%) rename openassessment/templates/{openassessmentblock => legacy}/self/oa_self_assessment.html (88%) rename openassessment/templates/{openassessmentblock => legacy}/self/oa_self_cancelled.html (91%) rename openassessment/templates/{openassessmentblock => legacy}/self/oa_self_closed.html (95%) rename openassessment/templates/{openassessmentblock => legacy}/self/oa_self_complete.html (91%) rename openassessment/templates/{openassessmentblock => legacy}/self/oa_self_unavailable.html (90%) rename openassessment/templates/{openassessmentblock => legacy}/staff/oa_staff_grade.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_staff_area.html (98%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_staff_grade_learners.html (76%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_staff_grade_learners_assessment.html (85%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_staff_grade_learners_count.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_staff_override_assessment.html (82%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_student_info.html (93%) rename openassessment/templates/{openassessmentblock => legacy}/staff_area/oa_student_info_assessment_detail.html (100%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training.html (98%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training_cancelled.html (88%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training_closed.html (94%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training_complete.html (88%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training_error.html (93%) rename openassessment/templates/{openassessmentblock => legacy}/student_training/student_training_unavailable.html (87%) diff --git a/Makefile b/Makefile index ca8769f672..07d19c2a41 100644 --- a/Makefile +++ b/Makefile @@ -155,6 +155,8 @@ install-osx-requirements: ## Install OSX specific requirements using Homebrew install-local-ora: ## installs your local ORA2 code into the LMS and Studio python virtualenvs docker exec -t edx.devstack.lms bash -c '. /edx/app/edxapp/venvs/edxapp/bin/activate && cd /edx/app/edxapp/edx-platform && pip uninstall -y ora2 && pip install -e /edx/src/edx-ora2 && pip freeze | grep ora2' docker exec -t edx.devstack.cms bash -c '. /edx/app/edxapp/venvs/edxapp/bin/activate && cd /edx/app/edxapp/edx-platform && pip uninstall -y ora2 && pip install -e /edx/src/edx-ora2 && pip freeze | grep ora2' + docker exec -t edx.devstack.lms bash -c 'kill $$(ps aux | egrep "manage.py ?\w* runserver" | egrep -v "while|grep" | awk "{print \$$2}")' + docker exec -t edx.devstack.cms bash -c 'kill $$(ps aux | egrep "manage.py ?\w* runserver" | egrep -v "while|grep" | awk "{print \$$2}")' install_transifex_client: ## Install the Transifex client # Instaling client will skip CHANGELOG and LICENSE files from git changes diff --git a/openassessment/templates/base.html b/openassessment/templates/base.html new file mode 100644 index 0000000000..355760ecf3 --- /dev/null +++ b/openassessment/templates/base.html @@ -0,0 +1,3 @@ +
+

Hello world

+
\ No newline at end of file diff --git a/openassessment/templates/openassessmentblock/edit/oa_edit.html b/openassessment/templates/legacy/edit/oa_edit.html similarity index 62% rename from openassessment/templates/openassessmentblock/edit/oa_edit.html rename to openassessment/templates/legacy/edit/oa_edit.html index 67290879dd..5c389d46b3 100644 --- a/openassessment/templates/openassessmentblock/edit/oa_edit.html +++ b/openassessment/templates/legacy/edit/oa_edit.html @@ -7,17 +7,17 @@ data-is-released="{{ is_released|lower }}" >
- {% include "openassessmentblock/edit/oa_edit_header_and_validation.html" %} + {% include "legacy/edit/oa_edit_header_and_validation.html" %} - {% include "openassessmentblock/edit/oa_edit_prompts.html" %} + {% include "legacy/edit/oa_edit_prompts.html" %} - {% include "openassessmentblock/edit/oa_edit_rubric.html" %} + {% include "legacy/edit/oa_edit_rubric.html" %} - {% include "openassessmentblock/edit/oa_edit_schedule.html" %} + {% include "legacy/edit/oa_edit_schedule.html" %} - {% include "openassessmentblock/edit/oa_edit_assessment_steps.html" %} + {% include "legacy/edit/oa_edit_assessment_steps.html" %} - {% include "openassessmentblock/edit/oa_edit_settings.html" %} + {% include "legacy/edit/oa_edit_settings.html" %}
diff --git a/openassessment/templates/openassessmentblock/edit/oa_edit_assessment_steps.html b/openassessment/templates/legacy/edit/oa_edit_assessment_steps.html similarity index 88% rename from openassessment/templates/openassessmentblock/edit/oa_edit_assessment_steps.html rename to openassessment/templates/legacy/edit/oa_edit_assessment_steps.html index b9c447441d..a019de8845 100644 --- a/openassessment/templates/openassessmentblock/edit/oa_edit_assessment_steps.html +++ b/openassessment/templates/legacy/edit/oa_edit_assessment_steps.html @@ -9,7 +9,7 @@
    {% for assessment in editor_assessments_order %} - {% with "openassessmentblock/edit/oa_edit_"|add:assessment|add:".html" as template %} + {% with "legacy/edit/oa_edit_"|add:assessment|add:".html" as template %} {% include template %} {% endwith %} {% endfor %} diff --git a/openassessment/templates/openassessmentblock/edit/oa_edit_basic_settings_list.html b/openassessment/templates/legacy/edit/oa_edit_basic_settings_list.html similarity index 100% rename from openassessment/templates/openassessmentblock/edit/oa_edit_basic_settings_list.html rename to openassessment/templates/legacy/edit/oa_edit_basic_settings_list.html diff --git a/openassessment/templates/openassessmentblock/edit/oa_edit_criterion.html b/openassessment/templates/legacy/edit/oa_edit_criterion.html similarity index 94% rename from openassessment/templates/openassessmentblock/edit/oa_edit_criterion.html rename to openassessment/templates/legacy/edit/oa_edit_criterion.html index e6ab7d3c17..120d088daf 100644 --- a/openassessment/templates/openassessmentblock/edit/oa_edit_criterion.html +++ b/openassessment/templates/legacy/edit/oa_edit_criterion.html @@ -35,7 +35,7 @@
    {% if criterion_options %} {% for option in criterion_options %} - {% include "openassessmentblock/edit/oa_edit_option.html" with criterion_name=criterion_name option_name=option.name option_label=option.label option_points=option.points option_explanation=option.explanation %} + {% include "legacy/edit/oa_edit_option.html" with criterion_name=criterion_name option_name=option.name option_label=option.label option_points=option.points option_explanation=option.explanation %} {% endfor %} {% endif %} diff --git a/openassessment/templates/openassessmentblock/edit/oa_edit_header_and_validation.html b/openassessment/templates/legacy/edit/oa_edit_header_and_validation.html similarity index 85% rename from openassessment/templates/openassessmentblock/edit/oa_edit_header_and_validation.html rename to openassessment/templates/legacy/edit/oa_edit_header_and_validation.html index ef24cf6b4c..fa1f5fc21f 100644 --- a/openassessment/templates/openassessmentblock/edit/oa_edit_header_and_validation.html +++ b/openassessment/templates/legacy/edit/oa_edit_header_and_validation.html @@ -4,21 +4,21 @@

    {% endwith %}
    {% trans "Your peer's response to the prompt above" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=topscore.submission.answer answer_text_label=translated_label %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=topscore.files class_prefix="submission__answer" including_template="leaderboard_show" xblock_id=xblock_id %} + {% include "legacy/oa_submission_answer.html" with answer=topscore.submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=topscore.files class_prefix="submission__answer" including_template="leaderboard_show" xblock_id=xblock_id %}
    {% endfor %} diff --git a/openassessment/templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html b/openassessment/templates/legacy/leaderboard/oa_leaderboard_waiting.html similarity index 100% rename from openassessment/templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html rename to openassessment/templates/legacy/leaderboard/oa_leaderboard_waiting.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_cancelled.html b/openassessment/templates/legacy/message/oa_message_cancelled.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_cancelled.html rename to openassessment/templates/legacy/message/oa_message_cancelled.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_closed.html b/openassessment/templates/legacy/message/oa_message_closed.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_closed.html rename to openassessment/templates/legacy/message/oa_message_closed.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_complete.html b/openassessment/templates/legacy/message/oa_message_complete.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_complete.html rename to openassessment/templates/legacy/message/oa_message_complete.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_incomplete.html b/openassessment/templates/legacy/message/oa_message_incomplete.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_incomplete.html rename to openassessment/templates/legacy/message/oa_message_incomplete.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_no_team.html b/openassessment/templates/legacy/message/oa_message_no_team.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_no_team.html rename to openassessment/templates/legacy/message/oa_message_no_team.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_open.html b/openassessment/templates/legacy/message/oa_message_open.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_open.html rename to openassessment/templates/legacy/message/oa_message_open.html diff --git a/openassessment/templates/openassessmentblock/message/oa_message_unavailable.html b/openassessment/templates/legacy/message/oa_message_unavailable.html similarity index 100% rename from openassessment/templates/openassessmentblock/message/oa_message_unavailable.html rename to openassessment/templates/legacy/message/oa_message_unavailable.html diff --git a/openassessment/templates/openassessmentblock/oa_base.html b/openassessment/templates/legacy/oa_base.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_base.html rename to openassessment/templates/legacy/oa_base.html diff --git a/openassessment/templates/openassessmentblock/oa_error.html b/openassessment/templates/legacy/oa_error.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_error.html rename to openassessment/templates/legacy/oa_error.html diff --git a/openassessment/templates/openassessmentblock/oa_latex_preview.html b/openassessment/templates/legacy/oa_latex_preview.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_latex_preview.html rename to openassessment/templates/legacy/oa_latex_preview.html diff --git a/openassessment/templates/openassessmentblock/oa_rubric.html b/openassessment/templates/legacy/oa_rubric.html similarity index 95% rename from openassessment/templates/openassessmentblock/oa_rubric.html rename to openassessment/templates/legacy/oa_rubric.html index f93341de71..1e21f19512 100644 --- a/openassessment/templates/openassessmentblock/oa_rubric.html +++ b/openassessment/templates/legacy/oa_rubric.html @@ -62,7 +62,7 @@ {% if criterion.feedback == 'required' %}required{% endif %} > - {% include "openassessmentblock/oa_latex_preview.html" with id="criteria__"|add:rubric_type|add:criterion.order_num elem="div" preview_name="criteria__" %} + {% include "legacy/oa_latex_preview.html" with id="criteria__"|add:rubric_type|add:criterion.order_num elem="div" preview_name="criteria__" %} {% endif %} @@ -86,7 +86,7 @@ maxlength="10000" > - {% include "openassessmentblock/oa_latex_preview.html" with id="feedback__"|add:rubric_type elem="div" preview_name="feedback" %} + {% include "legacy/oa_latex_preview.html" with id="feedback__"|add:rubric_type elem="div" preview_name="feedback" %} {% endif %} diff --git a/openassessment/templates/openassessmentblock/oa_submission_answer.html b/openassessment/templates/legacy/oa_submission_answer.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_submission_answer.html rename to openassessment/templates/legacy/oa_submission_answer.html diff --git a/openassessment/templates/openassessmentblock/oa_team_uploaded_files.html b/openassessment/templates/legacy/oa_team_uploaded_files.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_team_uploaded_files.html rename to openassessment/templates/legacy/oa_team_uploaded_files.html diff --git a/openassessment/templates/openassessmentblock/oa_uploaded_file.html b/openassessment/templates/legacy/oa_uploaded_file.html similarity index 100% rename from openassessment/templates/openassessmentblock/oa_uploaded_file.html rename to openassessment/templates/legacy/oa_uploaded_file.html diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_assessment.html b/openassessment/templates/legacy/peer/oa_peer_assessment.html similarity index 89% rename from openassessment/templates/openassessmentblock/peer/oa_peer_assessment.html rename to openassessment/templates/legacy/peer/oa_peer_assessment.html index c4352270a2..2054d9e065 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_assessment.html +++ b/openassessment/templates/legacy/peer/oa_peer_assessment.html @@ -72,14 +72,14 @@

    {% trans "Your peer's response to the prompt above" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=peer_submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=peer_submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=peer_file_urls header=translated_header class_prefix="peer-assessment" show_warning="true" including_template="peer_assessment" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=peer_file_urls header=translated_header class_prefix="peer-assessment" show_warning="true" including_template="peer_assessment" xblock_id=xblock_id %}
    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="peer" submission=peer_submission %} + {% include "legacy/oa_rubric.html" with rubric_type="peer" submission=peer_submission %}
    diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_cancelled.html b/openassessment/templates/legacy/peer/oa_peer_cancelled.html similarity index 90% rename from openassessment/templates/openassessmentblock/peer/oa_peer_cancelled.html rename to openassessment/templates/legacy/peer/oa_peer_cancelled.html index 653df6e5cd..89871f427a 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_cancelled.html +++ b/openassessment/templates/legacy/peer/oa_peer_cancelled.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% load tz %} diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_closed.html b/openassessment/templates/legacy/peer/oa_peer_closed.html similarity index 96% rename from openassessment/templates/openassessmentblock/peer/oa_peer_closed.html rename to openassessment/templates/legacy/peer/oa_peer_closed.html index b2550965d4..f7825b1b00 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_closed.html +++ b/openassessment/templates/legacy/peer/oa_peer_closed.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_complete.html b/openassessment/templates/legacy/peer/oa_peer_complete.html similarity index 97% rename from openassessment/templates/openassessmentblock/peer/oa_peer_complete.html rename to openassessment/templates/legacy/peer/oa_peer_complete.html index 71c31dba61..518dbbf361 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_complete.html +++ b/openassessment/templates/legacy/peer/oa_peer_complete.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode.html b/openassessment/templates/legacy/peer/oa_peer_turbo_mode.html similarity index 83% rename from openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode.html rename to openassessment/templates/legacy/peer/oa_peer_turbo_mode.html index 5b56ef3c50..0e93a07609 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode.html +++ b/openassessment/templates/legacy/peer/oa_peer_turbo_mode.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} @@ -51,14 +51,14 @@

    {% trans "Status" %}
    {% trans "Your peer's response to the prompt above" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=peer_submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=peer_submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=peer_file_urls header=translated_header class_prefix="peer-assessment" show_warning="true" including_template="peer_turbo_mode" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=peer_file_urls header=translated_header class_prefix="peer-assessment" show_warning="true" including_template="peer_turbo_mode" xblock_id=xblock_id %}
    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="peer" submission=peer_submission %} + {% include "legacy/oa_rubric.html" with rubric_type="peer" submission=peer_submission %}
    diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html b/openassessment/templates/legacy/peer/oa_peer_turbo_mode_waiting.html similarity index 96% rename from openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html rename to openassessment/templates/legacy/peer/oa_peer_turbo_mode_waiting.html index 5a29aeed30..c6f35b99e1 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html +++ b/openassessment/templates/legacy/peer/oa_peer_turbo_mode_waiting.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_unavailable.html b/openassessment/templates/legacy/peer/oa_peer_unavailable.html similarity index 89% rename from openassessment/templates/openassessmentblock/peer/oa_peer_unavailable.html rename to openassessment/templates/legacy/peer/oa_peer_unavailable.html index 854d3d1164..eb51ac32c6 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_unavailable.html +++ b/openassessment/templates/legacy/peer/oa_peer_unavailable.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/peer/oa_peer_waiting.html b/openassessment/templates/legacy/peer/oa_peer_waiting.html similarity index 96% rename from openassessment/templates/openassessmentblock/peer/oa_peer_waiting.html rename to openassessment/templates/legacy/peer/oa_peer_waiting.html index 19f78def78..b9eaa335f8 100644 --- a/openassessment/templates/openassessmentblock/peer/oa_peer_waiting.html +++ b/openassessment/templates/legacy/peer/oa_peer_waiting.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/peer/oa_peer_assessment.html" %} +{% extends "legacy/peer/oa_peer_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/response/oa_response.html b/openassessment/templates/legacy/response/oa_response.html similarity index 96% rename from openassessment/templates/openassessmentblock/response/oa_response.html rename to openassessment/templates/legacy/response/oa_response.html index ab49b7c48d..3ba0c66fbc 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response.html +++ b/openassessment/templates/legacy/response/oa_response.html @@ -121,7 +121,7 @@

    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="read_only" %} + {% include "legacy/oa_rubric.html" with rubric_type="read_only" %}
    @@ -199,7 +199,7 @@

    {% trans "The prompt for this >{{ part.text }} {% with forloop.counter|stringformat:"s" as submission_num %} - {% include "openassessmentblock/oa_latex_preview.html" with id="submission__"|add:xblock_id|add:submission_num elem="div" preview_name="submission__"|add:submission_num %} + {% include "legacy/oa_latex_preview.html" with id="submission__"|add:xblock_id|add:submission_num elem="div" preview_name="submission__"|add:submission_num %} {% endwith %} {% endif %} @@ -291,10 +291,10 @@
    {% trans "We could not delete files" %}
    {% endif %}
  1. - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls class_prefix="submission__answer" including_template="response" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls class_prefix="submission__answer" including_template="response" xblock_id=xblock_id %}
  2. - {% include "openassessmentblock/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls class_prefix="submission__team__answer" including_template="response" xblock_id=xblock_id %} + {% include "legacy/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls class_prefix="submission__team__answer" including_template="response" xblock_id=xblock_id %}
diff --git a/openassessment/templates/openassessmentblock/response/oa_response_cancelled.html b/openassessment/templates/legacy/response/oa_response_cancelled.html similarity index 97% rename from openassessment/templates/openassessmentblock/response/oa_response_cancelled.html rename to openassessment/templates/legacy/response/oa_response_cancelled.html index 3be6eada94..a546c1e8b8 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response_cancelled.html +++ b/openassessment/templates/legacy/response/oa_response_cancelled.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/response/oa_response.html" %} +{% extends "legacy/response/oa_response.html" %} {% load i18n %} {% load tz %} diff --git a/openassessment/templates/openassessmentblock/response/oa_response_closed.html b/openassessment/templates/legacy/response/oa_response_closed.html similarity index 96% rename from openassessment/templates/openassessmentblock/response/oa_response_closed.html rename to openassessment/templates/legacy/response/oa_response_closed.html index 4e86f9bc54..87394fa78f 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response_closed.html +++ b/openassessment/templates/legacy/response/oa_response_closed.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/response/oa_response.html" %} +{% extends "legacy/response/oa_response.html" %} {% load i18n %} {% block list_item %}
  • {% trans "Your response" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=student_submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=student_submission.answer answer_text_label=translated_label %} {% trans "Your Uploaded Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls header=translated_header class_prefix="submission__answer" including_template="response_graded" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls header=translated_header class_prefix="submission__answer" including_template="response_graded" xblock_id=xblock_id %} - {% include "openassessmentblock/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls class_prefix="submission__team__answer" including_template="response_graded" xblock_id=xblock_id %} + {% include "legacy/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls class_prefix="submission__team__answer" including_template="response_graded" xblock_id=xblock_id %}
    diff --git a/openassessment/templates/openassessmentblock/response/oa_response_studio_preview.html b/openassessment/templates/legacy/response/oa_response_studio_preview.html similarity index 100% rename from openassessment/templates/openassessmentblock/response/oa_response_studio_preview.html rename to openassessment/templates/legacy/response/oa_response_studio_preview.html diff --git a/openassessment/templates/openassessmentblock/response/oa_response_submitted.html b/openassessment/templates/legacy/response/oa_response_submitted.html similarity index 80% rename from openassessment/templates/openassessmentblock/response/oa_response_submitted.html rename to openassessment/templates/legacy/response/oa_response_submitted.html index 38dac4377d..e8fa2de3ad 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response_submitted.html +++ b/openassessment/templates/legacy/response/oa_response_submitted.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/response/oa_response.html" %} +{% extends "legacy/response/oa_response.html" %} {% load i18n %} {% block list_item %} @@ -49,12 +49,12 @@
    {% trans "Status" %}
    {% trans "Your response" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=student_submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=student_submission.answer answer_text_label=translated_label %} {% trans "Your Uploaded Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls header=translated_header class_prefix="submission__answer" including_template="response_submitted" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=file_urls header=translated_header class_prefix="submission__answer" including_template="response_submitted" xblock_id=xblock_id %} - {% include "openassessmentblock/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls header=translated_header class_prefix="submission__team__answer" including_template="response_submitted" xblock_id=xblock_id %} + {% include "legacy/oa_team_uploaded_files.html" with file_upload_type=file_upload_type team_file_urls=team_file_urls header=translated_header class_prefix="submission__team__answer" including_template="response_submitted" xblock_id=xblock_id %}
    diff --git a/openassessment/templates/openassessmentblock/response/oa_response_team_already_submitted.html b/openassessment/templates/legacy/response/oa_response_team_already_submitted.html similarity index 96% rename from openassessment/templates/openassessmentblock/response/oa_response_team_already_submitted.html rename to openassessment/templates/legacy/response/oa_response_team_already_submitted.html index 11654a3e44..2b9363b5f2 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response_team_already_submitted.html +++ b/openassessment/templates/legacy/response/oa_response_team_already_submitted.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/response/oa_response.html" %} +{% extends "legacy/response/oa_response.html" %} {% load i18n %} {% load tz %} diff --git a/openassessment/templates/openassessmentblock/response/oa_response_unavailable.html b/openassessment/templates/legacy/response/oa_response_unavailable.html similarity index 89% rename from openassessment/templates/openassessmentblock/response/oa_response_unavailable.html rename to openassessment/templates/legacy/response/oa_response_unavailable.html index da62660255..0d8d30f52f 100644 --- a/openassessment/templates/openassessmentblock/response/oa_response_unavailable.html +++ b/openassessment/templates/legacy/response/oa_response_unavailable.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/response/oa_response.html" %} +{% extends "legacy/response/oa_response.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/self/oa_self_assessment.html b/openassessment/templates/legacy/self/oa_self_assessment.html similarity index 88% rename from openassessment/templates/openassessmentblock/self/oa_self_assessment.html rename to openassessment/templates/legacy/self/oa_self_assessment.html index be274d3678..69427fdaa8 100644 --- a/openassessment/templates/openassessmentblock/self/oa_self_assessment.html +++ b/openassessment/templates/legacy/self/oa_self_assessment.html @@ -55,14 +55,14 @@

    {% trans "Your response" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=self_submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=self_submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=self_file_urls header=translated_header class_prefix="self-assessment" including_template="self_assessment" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=self_file_urls header=translated_header class_prefix="self-assessment" including_template="self_assessment" xblock_id=xblock_id %}
    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="self" submission=self_submission %} + {% include "legacy/oa_rubric.html" with rubric_type="self" submission=self_submission %}
    diff --git a/openassessment/templates/openassessmentblock/self/oa_self_cancelled.html b/openassessment/templates/legacy/self/oa_self_cancelled.html similarity index 91% rename from openassessment/templates/openassessmentblock/self/oa_self_cancelled.html rename to openassessment/templates/legacy/self/oa_self_cancelled.html index 9ba79d2d68..9105e8f06c 100644 --- a/openassessment/templates/openassessmentblock/self/oa_self_cancelled.html +++ b/openassessment/templates/legacy/self/oa_self_cancelled.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/self/oa_self_assessment.html" %} +{% extends "legacy/self/oa_self_assessment.html" %} {% load i18n %} {% load tz %} diff --git a/openassessment/templates/openassessmentblock/self/oa_self_closed.html b/openassessment/templates/legacy/self/oa_self_closed.html similarity index 95% rename from openassessment/templates/openassessmentblock/self/oa_self_closed.html rename to openassessment/templates/legacy/self/oa_self_closed.html index 97af67ec20..ad1d7bd0ee 100644 --- a/openassessment/templates/openassessmentblock/self/oa_self_closed.html +++ b/openassessment/templates/legacy/self/oa_self_closed.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/self/oa_self_assessment.html" %} +{% extends "legacy/self/oa_self_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/self/oa_self_complete.html b/openassessment/templates/legacy/self/oa_self_complete.html similarity index 91% rename from openassessment/templates/openassessmentblock/self/oa_self_complete.html rename to openassessment/templates/legacy/self/oa_self_complete.html index cff218e730..add9c3cf7a 100644 --- a/openassessment/templates/openassessmentblock/self/oa_self_complete.html +++ b/openassessment/templates/legacy/self/oa_self_complete.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/self/oa_self_assessment.html" %} +{% extends "legacy/self/oa_self_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/self/oa_self_unavailable.html b/openassessment/templates/legacy/self/oa_self_unavailable.html similarity index 90% rename from openassessment/templates/openassessmentblock/self/oa_self_unavailable.html rename to openassessment/templates/legacy/self/oa_self_unavailable.html index 3774807997..7ed4d33e13 100644 --- a/openassessment/templates/openassessmentblock/self/oa_self_unavailable.html +++ b/openassessment/templates/legacy/self/oa_self_unavailable.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/self/oa_self_assessment.html" %} +{% extends "legacy/self/oa_self_assessment.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/staff/oa_staff_grade.html b/openassessment/templates/legacy/staff/oa_staff_grade.html similarity index 100% rename from openassessment/templates/openassessmentblock/staff/oa_staff_grade.html rename to openassessment/templates/legacy/staff/oa_staff_grade.html diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_staff_area.html b/openassessment/templates/legacy/staff_area/oa_staff_area.html similarity index 98% rename from openassessment/templates/openassessmentblock/staff_area/oa_staff_area.html rename to openassessment/templates/legacy/staff_area/oa_staff_area.html index f5f98c1f19..ba8364190b 100644 --- a/openassessment/templates/openassessmentblock/staff_area/oa_staff_area.html +++ b/openassessment/templates/legacy/staff_area/oa_staff_area.html @@ -153,7 +153,7 @@

    - {% include "openassessmentblock/staff_area/oa_staff_grade_learners.html" with staff_assessment_ungraded=staff_assessment_ungraded %} + {% include "legacy/staff_area/oa_staff_grade_learners.html" with staff_assessment_ungraded=staff_assessment_ungraded %}
    diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners.html b/openassessment/templates/legacy/staff_area/oa_staff_grade_learners.html similarity index 76% rename from openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners.html rename to openassessment/templates/legacy/staff_area/oa_staff_grade_learners.html index 8ddeeca4de..5d10005643 100644 --- a/openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners.html +++ b/openassessment/templates/legacy/staff_area/oa_staff_grade_learners.html @@ -8,7 +8,7 @@

    - {% include "openassessmentblock/staff_area/oa_staff_grade_learners_count.html" with staff_assessment_ungraded=staff_assessment_ungraded staff_assessment_in_progress=staff_assessment_in_progress %} + {% include "legacy/staff_area/oa_staff_grade_learners_count.html" with staff_assessment_ungraded=staff_assessment_ungraded staff_assessment_in_progress=staff_assessment_in_progress %}
    diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html b/openassessment/templates/legacy/staff_area/oa_staff_grade_learners_assessment.html similarity index 85% rename from openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html rename to openassessment/templates/legacy/staff_area/oa_staff_grade_learners_assessment.html index bc1ff822d0..d27c60e477 100644 --- a/openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +++ b/openassessment/templates/legacy/staff_area/oa_staff_grade_learners_assessment.html @@ -40,14 +40,14 @@

    {% else %} {% trans "The learner's response to the prompt above" as translated_label %} {% endif %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="staff_grade_learners_assessment" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="staff_grade_learners_assessment" xblock_id=xblock_id %}

    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="staff-full-grade" %} + {% include "legacy/oa_rubric.html" with rubric_type="staff-full-grade" %}
    diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners_count.html b/openassessment/templates/legacy/staff_area/oa_staff_grade_learners_count.html similarity index 100% rename from openassessment/templates/openassessmentblock/staff_area/oa_staff_grade_learners_count.html rename to openassessment/templates/legacy/staff_area/oa_staff_grade_learners_count.html diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_staff_override_assessment.html b/openassessment/templates/legacy/staff_area/oa_staff_override_assessment.html similarity index 82% rename from openassessment/templates/openassessmentblock/staff_area/oa_staff_override_assessment.html rename to openassessment/templates/legacy/staff_area/oa_staff_override_assessment.html index a4eedde34d..ac22bed18d 100644 --- a/openassessment/templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +++ b/openassessment/templates/legacy/staff_area/oa_staff_override_assessment.html @@ -33,14 +33,14 @@

    {% else %} {% trans "The team's response to the prompt above" as translated_label %} {% endif %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="staff_override_assessment" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="staff_override_assessment" xblock_id=xblock_id %}
    - {% include "openassessmentblock/oa_rubric.html" with rubric_type="staff-override" %} + {% include "legacy/oa_rubric.html" with rubric_type="staff-override" %}
    diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_student_info.html b/openassessment/templates/legacy/staff_area/oa_student_info.html similarity index 93% rename from openassessment/templates/openassessmentblock/staff_area/oa_student_info.html rename to openassessment/templates/legacy/staff_area/oa_student_info.html index a50b0fbae3..dd63a1cc60 100644 --- a/openassessment/templates/openassessmentblock/staff_area/oa_student_info.html +++ b/openassessment/templates/legacy/staff_area/oa_student_info.html @@ -58,10 +58,10 @@

    {% else %} {% trans "The team's response to the prompt above" as translated_label %} {% endif %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %} {% trans "Associated Files" as translated_header %} - {% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="student_info" xblock_id=xblock_id %} + {% include "legacy/oa_uploaded_file.html" with file_upload_type=file_upload_type file_urls=staff_file_urls header=translated_header class_prefix="staff-assessment" show_warning="true" including_template="student_info" xblock_id=xblock_id %} {% endif %} @@ -69,17 +69,17 @@

    {% if peer_assessments %} {% trans "Peer Assessments for This Learner" as translated_title %} - {% include "openassessmentblock/staff_area/oa_student_info_assessment_detail.html" with class_type="peer" assessments=peer_assessments %} + {% include "legacy/staff_area/oa_student_info_assessment_detail.html" with class_type="peer" assessments=peer_assessments %} {% endif %} {% if submitted_assessments %} {% trans "Peer Assessments Completed by This Learner" as translated_title %} - {% include "openassessmentblock/staff_area/oa_student_info_assessment_detail.html" with class_type="submitted" assessments=submitted_assessments %} + {% include "legacy/staff_area/oa_student_info_assessment_detail.html" with class_type="submitted" assessments=submitted_assessments %} {% endif %} {% if self_assessment %} {% trans "Learner's Self Assessment" as translated_title %} - {% include "openassessmentblock/staff_area/oa_student_info_assessment_detail.html" with class_type="self" assessments=self_assessment %} + {% include "legacy/staff_area/oa_student_info_assessment_detail.html" with class_type="self" assessments=self_assessment %} {% endif %} {% if staff_assessment %} @@ -88,7 +88,7 @@

    {% else %} {% trans "Staff Assessment for this Team" as translated_title %} {% endif %} - {% include "openassessmentblock/staff_area/oa_student_info_assessment_detail.html" with class_type="staff" assessments=staff_assessment %} + {% include "legacy/staff_area/oa_student_info_assessment_detail.html" with class_type="staff" assessments=staff_assessment %} {% endif %}
    @@ -214,7 +214,7 @@
    {% trans "Unable to perform grade override" %}
    {% endif %}
    {% else %} - {% include "openassessmentblock/staff_area/oa_staff_override_assessment.html" %} + {% include "legacy/staff_area/oa_staff_override_assessment.html" %} {% endif %} diff --git a/openassessment/templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html b/openassessment/templates/legacy/staff_area/oa_student_info_assessment_detail.html similarity index 100% rename from openassessment/templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html rename to openassessment/templates/legacy/staff_area/oa_student_info_assessment_detail.html diff --git a/openassessment/templates/openassessmentblock/student_training/student_training.html b/openassessment/templates/legacy/student_training/student_training.html similarity index 98% rename from openassessment/templates/openassessmentblock/student_training/student_training.html rename to openassessment/templates/legacy/student_training/student_training.html index 2bd8666c28..f9e0a2d8f7 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training.html +++ b/openassessment/templates/legacy/student_training/student_training.html @@ -74,7 +74,7 @@

    {% trans "Learning to Assess Responses" %}
    {% trans "The response to the prompt above:" as translated_label %} - {% include "openassessmentblock/oa_submission_answer.html" with answer=training_essay.answer answer_text_label=translated_label %} + {% include "legacy/oa_submission_answer.html" with answer=training_essay.answer answer_text_label=translated_label %}
    diff --git a/openassessment/templates/openassessmentblock/student_training/student_training_cancelled.html b/openassessment/templates/legacy/student_training/student_training_cancelled.html similarity index 88% rename from openassessment/templates/openassessmentblock/student_training/student_training_cancelled.html rename to openassessment/templates/legacy/student_training/student_training_cancelled.html index d28efef3ed..c993c0806c 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training_cancelled.html +++ b/openassessment/templates/legacy/student_training/student_training_cancelled.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/student_training/student_training.html" %} +{% extends "legacy/student_training/student_training.html" %} {% load i18n %} {% load tz %} diff --git a/openassessment/templates/openassessmentblock/student_training/student_training_closed.html b/openassessment/templates/legacy/student_training/student_training_closed.html similarity index 94% rename from openassessment/templates/openassessmentblock/student_training/student_training_closed.html rename to openassessment/templates/legacy/student_training/student_training_closed.html index 4b72791a24..629c345971 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training_closed.html +++ b/openassessment/templates/legacy/student_training/student_training_closed.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/student_training/student_training.html" %} +{% extends "legacy/student_training/student_training.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/student_training/student_training_complete.html b/openassessment/templates/legacy/student_training/student_training_complete.html similarity index 88% rename from openassessment/templates/openassessmentblock/student_training/student_training_complete.html rename to openassessment/templates/legacy/student_training/student_training_complete.html index cbcd144bed..46d64f3d95 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training_complete.html +++ b/openassessment/templates/legacy/student_training/student_training_complete.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/student_training/student_training.html" %} +{% extends "legacy/student_training/student_training.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/student_training/student_training_error.html b/openassessment/templates/legacy/student_training/student_training_error.html similarity index 93% rename from openassessment/templates/openassessmentblock/student_training/student_training_error.html rename to openassessment/templates/legacy/student_training/student_training_error.html index 62fea5d578..08fd1c70c8 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training_error.html +++ b/openassessment/templates/legacy/student_training/student_training_error.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/student_training/student_training.html" %} +{% extends "legacy/student_training/student_training.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/templates/openassessmentblock/student_training/student_training_unavailable.html b/openassessment/templates/legacy/student_training/student_training_unavailable.html similarity index 87% rename from openassessment/templates/openassessmentblock/student_training/student_training_unavailable.html rename to openassessment/templates/legacy/student_training/student_training_unavailable.html index 329d0a0d09..2bf38c368b 100644 --- a/openassessment/templates/openassessmentblock/student_training/student_training_unavailable.html +++ b/openassessment/templates/legacy/student_training/student_training_unavailable.html @@ -1,4 +1,4 @@ -{% extends "openassessmentblock/student_training/student_training.html" %} +{% extends "legacy/student_training/student_training.html" %} {% load i18n %} {% block list_item %} diff --git a/openassessment/xblock/grade_mixin.py b/openassessment/xblock/grade_mixin.py index 1f3290be7f..04d1ad7752 100644 --- a/openassessment/xblock/grade_mixin.py +++ b/openassessment/xblock/grade_mixin.py @@ -55,7 +55,7 @@ def render_grade(self, data, suffix=''): # pylint: disable=unused-argument # Render the grading section based on the status of the workflow try: if status == "cancelled": - path = 'openassessmentblock/grade/oa_grade_cancelled.html' + path = 'legacy/grade/oa_grade_cancelled.html' context['score'] = workflow['score'] elif status == "done": path, context = self.render_grade_complete(workflow) @@ -68,9 +68,9 @@ def render_grade(self, data, suffix=''): # pylint: disable=unused-argument context['is_waiting_staff'] = "is--waiting--staff" context['score_explanation'] = self._get_score_explanation(workflow) - path = 'openassessmentblock/grade/oa_grade_waiting.html' + path = 'legacy/grade/oa_grade_waiting.html' elif status is None: - path = 'openassessmentblock/grade/oa_grade_not_started.html' + path = 'legacy/grade/oa_grade_not_started.html' else: # status is 'self' or 'peer', which implies that the workflow is incomplete path, context = self.render_grade_incomplete(workflow) except (sub_api.SubmissionError, PeerAssessmentError, SelfAssessmentError): @@ -159,7 +159,7 @@ def render_grade_complete(self, workflow): 'xblock_id': self.get_xblock_id() } - return ('openassessmentblock/grade/oa_grade_complete.html', context) + return ('legacy/grade/oa_grade_complete.html', context) def render_grade_incomplete(self, workflow): """ @@ -181,7 +181,7 @@ def _is_incomplete(step): incomplete_steps.append(self._("Self Assessment")) return ( - 'openassessmentblock/grade/oa_grade_incomplete.html', + 'legacy/grade/oa_grade_incomplete.html', { 'incomplete_steps': incomplete_steps, 'xblock_id': self.get_xblock_id(), diff --git a/openassessment/xblock/leaderboard_mixin.py b/openassessment/xblock/leaderboard_mixin.py index a56a0dbad7..9a57ef666c 100644 --- a/openassessment/xblock/leaderboard_mixin.py +++ b/openassessment/xblock/leaderboard_mixin.py @@ -118,7 +118,7 @@ def render_leaderboard_complete(self, student_item_dict): 'file_upload_type': self.file_upload_type, 'xblock_id': self.get_xblock_id()} - return 'openassessmentblock/leaderboard/oa_leaderboard_show.html', context + return 'legacy/leaderboard/oa_leaderboard_show.html', context def render_leaderboard_incomplete(self): """ @@ -127,7 +127,7 @@ def render_leaderboard_incomplete(self): Returns: template_path (string), tuple of context (dict) """ - return 'openassessmentblock/leaderboard/oa_leaderboard_waiting.html', {'xblock_id': self.get_xblock_id()} + return 'legacy/leaderboard/oa_leaderboard_waiting.html', {'xblock_id': self.get_xblock_id()} def _get_file_download_url(self, file_key): """ diff --git a/openassessment/xblock/message_mixin.py b/openassessment/xblock/message_mixin.py index 889e494551..67a9e1d8ab 100644 --- a/openassessment/xblock/message_mixin.py +++ b/openassessment/xblock/message_mixin.py @@ -52,7 +52,7 @@ def render_message(self, data, suffix=''): # pylint: disable=unused-argument if status is None: path, context = self.render_message_no_team() else: - path, context = 'openassessmentblock/message/oa_message_unavailable.html', {} + path, context = 'legacy/message/oa_message_unavailable.html', {} elif status in ("done", "waiting"): path, context = self.render_message_complete(status_details) elif problem_is_closed or active_step_deadline_info.get('is_closed'): @@ -66,7 +66,7 @@ def render_message(self, data, suffix=''): # pylint: disable=unused-argument else: # Default path leads to an "instruction-unavailable" block # Default context is empty - path, context = 'openassessmentblock/message/oa_message_unavailable.html', {} + path, context = 'legacy/message/oa_message_unavailable.html', {} context['xblock_id'] = self.get_xblock_id() return self.render_assessment(path, context) @@ -94,7 +94,7 @@ def render_message_incomplete(self, status, deadline_info): "peer_not_available": self.no_peers, } - return 'openassessmentblock/message/oa_message_incomplete.html', context + return 'legacy/message/oa_message_incomplete.html', context def render_message_complete(self, status_details): """ @@ -110,7 +110,7 @@ def render_message_complete(self, status_details): "waiting": self.get_waiting_details(status_details), } - return 'openassessmentblock/message/oa_message_complete.html', context + return 'legacy/message/oa_message_complete.html', context def render_message_closed(self, status_info): """ @@ -129,7 +129,7 @@ def render_message_closed(self, status_info): "not_yet_open": (reason == "start") } - return 'openassessmentblock/message/oa_message_closed.html', context + return 'legacy/message/oa_message_closed.html', context def render_message_open(self, deadline_info): """ @@ -148,7 +148,7 @@ def render_message_open(self, deadline_info): "approaching": submission_approaching } - return 'openassessmentblock/message/oa_message_open.html', context + return 'legacy/message/oa_message_open.html', context def render_message_cancelled(self): """ @@ -163,7 +163,7 @@ def render_message_cancelled(self): context = { "is_team_assignment": self.is_team_assignment() } - return 'openassessmentblock/message/oa_message_cancelled.html', context + return 'legacy/message/oa_message_cancelled.html', context def _get_deadline_info(self): """ @@ -265,4 +265,4 @@ def render_message_no_team(self): else: teamset_name = '' context = {'teamset_name': teamset_name} - return 'openassessmentblock/message/oa_message_no_team.html', context + return 'legacy/message/oa_message_no_team.html', context diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index 833fd4a3f8..13ec335178 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -553,7 +553,7 @@ def student_view(self, context=None): # pylint: disable=unused-argument "rubric_assessments": ui_models, "show_staff_area": self.is_course_staff and not self.in_studio_preview, } - template = get_template("openassessmentblock/oa_base.html") + template = get_template("legacy/oa_base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') def ora_blocks_listing_view(self, context=None): @@ -584,7 +584,7 @@ def ora_blocks_listing_view(self, context=None): "ora_item_view_enabled": ora_item_view_enabled } - template = get_template('openassessmentblock/instructor_dashboard/oa_listing.html') + template = get_template('legacy/instructor_dashboard/oa_listing.html') min_postfix = '.min' if settings.DEBUG else '' @@ -625,7 +625,7 @@ def grade_available_responses_view(self, context=None): # pylint: disable=unuse self.get_staff_assessment_statistics_context(student_item["course_id"], student_item["item_id"]) ) - template = get_template('openassessmentblock/instructor_dashboard/oa_grade_available_responses.html') + template = get_template('legacy/instructor_dashboard/oa_grade_available_responses.html') return self._create_fragment(template, context_dict, initialize_js_func='StaffAssessmentBlock') @@ -655,7 +655,7 @@ def waiting_step_details_view(self, context=None): # pylint: disable=unused-arg self, "waiting_step_data", ) - template = get_template('openassessmentblock/instructor_dashboard/oa_waiting_step_details.html') + template = get_template('legacy/instructor_dashboard/oa_waiting_step_details.html') return self._create_fragment( template, @@ -977,7 +977,7 @@ def render_error(self, error_msg): Response: A response object with an HTML body. """ context = {'error_msg': error_msg} - template = get_template('openassessmentblock/oa_error.html') + template = get_template('legacy/oa_error.html') return Response(template.render(context), content_type='application/html', charset='UTF-8') def is_closed(self, step=None, course_staff=None): diff --git a/openassessment/xblock/staff_area_mixin.py b/openassessment/xblock/staff_area_mixin.py index e5a65b3419..2fb599453b 100644 --- a/openassessment/xblock/staff_area_mixin.py +++ b/openassessment/xblock/staff_area_mixin.py @@ -103,7 +103,7 @@ def get_staff_path_and_context(self): Gets the path and context for the staff section of the ORA XBlock. """ context = {} - path = 'openassessmentblock/staff_area/oa_staff_area.html' + path = 'legacy/staff_area/oa_staff_area.html' student_item = self.get_student_item_dict() @@ -380,7 +380,7 @@ def render_staff_grade_form(self, data, suffix=''): # pylint: disable=W0613 self.add_team_submission_context( submission_context, individual_submission_uuid=submission['uuid'], transform_usernames=True ) - path = 'openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html' + path = 'legacy/staff_area/oa_staff_grade_learners_assessment.html' return self.render_assessment(path, submission_context) return self.render_error(self._("Error loading the checked out learner response.")) return self.render_error(self._("No other learner responses are available for grading at this time.")) @@ -402,7 +402,7 @@ def render_staff_grade_counts(self, data, suffix=''): # pylint: disable=W0613 student_item_dict.get('course_id'), student_item_dict.get('item_id') ) - path = 'openassessmentblock/staff_area/oa_staff_grade_learners_count.html' + path = 'legacy/staff_area/oa_staff_grade_learners_count.html' return self.render_assessment(path, context) except PeerAssessmentInternalError: @@ -514,7 +514,7 @@ def get_student_info_path_and_context(self, student_username): # A student outside of the course will not exist and is valid pass - path = 'openassessmentblock/staff_area/oa_student_info.html' + path = 'legacy/staff_area/oa_student_info.html' return path, context def add_submission_context(self, submission_uuid, context): diff --git a/openassessment/xblock/static/js/fixtures/templates.json b/openassessment/xblock/static/js/fixtures/templates.json index fc895f179b..38e661b8c7 100644 --- a/openassessment/xblock/static/js/fixtures/templates.json +++ b/openassessment/xblock/static/js/fixtures/templates.json @@ -1,6 +1,6 @@ [ { - "template": "openassessmentblock/oa_base.html", + "template": "legacy/oa_base.html", "context": { "show_staff_area": false, "title": "Test title", @@ -42,7 +42,7 @@ "output": "oa_base.html" }, { - "template": "openassessmentblock/oa_base.html", + "template": "legacy/oa_base.html", "context": { "show_staff_area": true, "title": "Test title", @@ -84,7 +84,7 @@ "output": "oa_base_course_staff.html" }, { - "template": "openassessmentblock/response/oa_response.html", + "template": "legacy/response/oa_response.html", "context": { "text_response": "required", "file_upload_response": "optional", @@ -106,7 +106,7 @@ "output": "oa_response.html" }, { - "template": "openassessmentblock/student_training/student_training.html", + "template": "legacy/student_training/student_training.html", "context": { "training_essay": { "answer": { @@ -196,7 +196,7 @@ "output": "oa_student_training.html" }, { - "template": "openassessmentblock/self/oa_self_assessment.html", + "template": "legacy/self/oa_self_assessment.html", "context": { "rubric_criteria": [ { @@ -273,7 +273,7 @@ "output": "oa_self_assessment.html" }, { - "template": "openassessmentblock/peer/oa_peer_assessment.html", + "template": "legacy/peer/oa_peer_assessment.html", "context": { "rubric_criteria": [ { @@ -350,12 +350,12 @@ "output": "oa_peer_assessment.html" }, { - "template": "openassessmentblock/peer/oa_peer_complete.html", + "template": "legacy/peer/oa_peer_complete.html", "context": {}, "output": "oa_peer_complete.html" }, { - "template": "openassessmentblock/grade/oa_grade_complete.html", + "template": "legacy/grade/oa_grade_complete.html", "context": { "score": "", "feedback_text": "", @@ -420,7 +420,7 @@ "output": "oa_grade_complete.html" }, { - "template": "openassessmentblock/edit/oa_edit.html", + "template": "legacy/edit/oa_edit.html", "context": { "prompts": [{ "description": "How much do you like waffles?" }, { "description": "How much do you like waffles 2?" }], "title": "The most important of all questions.", @@ -513,7 +513,7 @@ "output": "oa_edit.html" }, { - "template": "openassessmentblock/edit/oa_edit.html", + "template": "legacy/edit/oa_edit.html", "context": { "prompts": [{ "description": "How much do you like waffles?" }, { "description": "How much do you like waffles 2?" }], "title": "Test title", @@ -679,7 +679,7 @@ "output": "oa_edit_student_training.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "status_counts": { "self": 1, @@ -710,7 +710,7 @@ "output": "oa_staff_area.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "staff_assessment_required": true, "staff_assessment_ungraded": 10, @@ -744,7 +744,7 @@ "output": "oa_staff_area_full_grading.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "staff_assessment_required": true, "staff_assessment_ungraded": 5, @@ -778,7 +778,7 @@ "output": "oa_staff_area_full_grading_2.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "is_enhanced_staff_grader_enabled": false, "staff_assessment_required": true, @@ -813,7 +813,7 @@ "output": "oa_staff_area_full_grading_esg_disabled.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "is_enhanced_staff_grader_enabled": true, "staff_assessment_required": true, @@ -848,7 +848,7 @@ "output": "oa_staff_area_full_grading_esg_enabled.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_area.html", + "template": "legacy/staff_area/oa_staff_area.html", "context": { "status_counts": { "staff": 1, @@ -874,7 +874,7 @@ "output": "oa_staff_area_team_assignment.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_grade_learners_count.html", + "template": "legacy/staff_area/oa_staff_grade_learners_count.html", "context": { "staff_assessment_ungraded": 9, "staff_assessment_in_progress": 3 @@ -882,7 +882,7 @@ "output": "oa_staff_grade_learners_count_1.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_grade_learners_count.html", + "template": "legacy/staff_area/oa_staff_grade_learners_count.html", "context": { "staff_assessment_ungraded": 9, "staff_assessment_in_progress": 2 @@ -890,7 +890,7 @@ "output": "oa_staff_grade_learners_count_2.html" }, { - "template": "openassessmentblock/staff_area/oa_student_info.html", + "template": "legacy/staff_area/oa_student_info.html", "context": { "rubric_criteria": [ { @@ -1000,7 +1000,7 @@ "output": "oa_student_info.html" }, { - "template": "openassessmentblock/staff_area/oa_student_info.html", + "template": "legacy/staff_area/oa_student_info.html", "context": { "submission": { "image_url": "/test-url", @@ -1019,7 +1019,7 @@ "output": "oa_staff_cancelled_submission.html" }, { - "template": "openassessmentblock/staff_area/oa_student_info.html", + "template": "legacy/staff_area/oa_student_info.html", "context": { "rubric_criteria": [ { @@ -1080,7 +1080,7 @@ "output": "oa_staff_graded_submission.html" }, { - "template": "openassessmentblock/staff_area/oa_student_info.html", + "template": "legacy/staff_area/oa_student_info.html", "context": { "rubric_criteria": [ { @@ -1163,7 +1163,7 @@ "output": "oa_student_info_team.html" }, { - "template": "openassessmentblock/peer/oa_peer_assessment.html", + "template": "legacy/peer/oa_peer_assessment.html", "context": { "rubric_criteria": [ { @@ -1214,7 +1214,7 @@ "output": "oa_rubric.html" }, { - "template": "openassessmentblock/peer/oa_peer_turbo_mode.html", + "template": "legacy/peer/oa_peer_turbo_mode.html", "context": { "rubric_criteria": [ { @@ -1290,7 +1290,7 @@ "output": "oa_turbo_mode.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html", + "template": "legacy/staff_area/oa_staff_grade_learners_assessment.html", "context": { "rubric_criteria": [ { @@ -1347,7 +1347,7 @@ "output": "oa_staff_grade_learners_assessment.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html", + "template": "legacy/staff_area/oa_staff_grade_learners_assessment.html", "context": { "rubric_criteria": [ { @@ -1404,7 +1404,7 @@ "output": "oa_staff_grade_learners_assessment_2.html" }, { - "template": "openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html", + "template": "legacy/staff_area/oa_staff_grade_learners_assessment.html", "context": { "rubric_criteria": [ { @@ -1461,7 +1461,7 @@ "output": "oa_staff_grade_team_assessment.html" }, { - "template": "openassessmentblock/response/oa_response.html", + "template": "legacy/response/oa_response.html", "context": { "text_response": "required", "file_upload_response": "", @@ -1480,7 +1480,7 @@ "output": "oa_response_date.html" }, { - "template": "openassessmentblock/instructor_dashboard/oa_grade_available_responses.html", + "template": "legacy/instructor_dashboard/oa_grade_available_responses.html", "context": { "title": "Test ABC", "staff_assessment_required": true, @@ -1490,7 +1490,7 @@ "output": "oa_grade_available_responses_separate_view.html" }, { - "template": "openassessmentblock/instructor_dashboard/oa_listing.html", + "template": "legacy/instructor_dashboard/oa_listing.html", "context": { "ora_item_view_enabled": "1", "ora_items": "" diff --git a/openassessment/xblock/studio_mixin.py b/openassessment/xblock/studio_mixin.py index 34873e8c67..80d965e202 100644 --- a/openassessment/xblock/studio_mixin.py +++ b/openassessment/xblock/studio_mixin.py @@ -62,7 +62,7 @@ class StudioMixin: key: val.get('display_name', key) for key, val in AVAILABLE_EDITORS.items() } - STUDIO_EDITING_TEMPLATE = 'openassessmentblock/edit/oa_edit.html' + STUDIO_EDITING_TEMPLATE = 'legacy/edit/oa_edit.html' ORA_SETTINGS_DOCUMENT_URL = 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/open_response_assessments/CreateORAAssignment.html#specify-a-name-and-dates' # noqa: E501 pylint: disable=line-too-long diff --git a/openassessment/xblock/test/data/student_training_mixin.json b/openassessment/xblock/test/data/student_training_mixin.json index 7c1d4f8542..e68b559f35 100644 --- a/openassessment/xblock/test/data/student_training_mixin.json +++ b/openassessment/xblock/test/data/student_training_mixin.json @@ -1,6 +1,6 @@ { "simple": { - "expected_template": "openassessmentblock/student_training/student_training.html", + "expected_template": "legacy/student_training/student_training.html", "expected_context": { "training_num_completed": 0, "training_num_current": 1, diff --git a/openassessment/xblock/test/test_leaderboard.py b/openassessment/xblock/test/test_leaderboard.py index c1d2fbe11a..26af8bab0f 100644 --- a/openassessment/xblock/test/test_leaderboard.py +++ b/openassessment/xblock/test/test_leaderboard.py @@ -35,7 +35,7 @@ def test_unavailable(self, xblock): # Start date is in the future for this scenario self._assert_path_and_context( xblock, - 'openassessmentblock/leaderboard/oa_leaderboard_waiting.html', + 'legacy/leaderboard/oa_leaderboard_waiting.html', {'xblock_id': xblock.scope_ids.usage_id} ) self._assert_leaderboard_visible(xblock, True) @@ -286,7 +286,7 @@ def _assert_scores(self, xblock, scores): """ self._assert_path_and_context( xblock, - 'openassessmentblock/leaderboard/oa_leaderboard_show.html', + 'legacy/leaderboard/oa_leaderboard_show.html', { 'topscores': scores, 'allow_multiple_files': xblock.allow_multiple_files, diff --git a/openassessment/xblock/test/test_message.py b/openassessment/xblock/test/test_message.py index 9184ac00e2..b3277e7ee2 100644 --- a/openassessment/xblock/test/test_message.py +++ b/openassessment/xblock/test/test_message.py @@ -114,7 +114,7 @@ def test_submission(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_open.html' + expected_path = 'legacy/message/oa_message_open.html' expected_context = { "approaching": False, @@ -139,7 +139,7 @@ def test_submission_no_peer(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_open.html' + expected_path = 'legacy/message/oa_message_open.html' expected_context = { "approaching": False, @@ -165,7 +165,7 @@ def test_submission_approaching(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_open.html' + expected_path = 'legacy/message/oa_message_open.html' expected_context = { "approaching": True, @@ -190,7 +190,7 @@ def test_submission_no_self_approaching(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_open.html' + expected_path = 'legacy/message/oa_message_open.html' expected_context = { "approaching": True, @@ -216,7 +216,7 @@ def test_submission_not_yet_open(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": True, @@ -242,7 +242,7 @@ def test_submission_incomplete(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": False, @@ -269,7 +269,7 @@ def test_training(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "training": True, @@ -299,7 +299,7 @@ def test_training_approaching(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "training": True, @@ -329,7 +329,7 @@ def test_training_not_released(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": True, @@ -356,7 +356,7 @@ def test_training_closed(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": False, @@ -382,7 +382,7 @@ def test_peer(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "peer": True, @@ -410,7 +410,7 @@ def test_peer_no_self(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "peer": True, @@ -438,7 +438,7 @@ def test_peer_no_self_approaching(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "peer": True, @@ -467,7 +467,7 @@ def test_peer_not_released(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": True, @@ -493,7 +493,7 @@ def test_peer_incomplete(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": False, @@ -519,7 +519,7 @@ def test_peer_no_peers_to_assess(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "peer": True, @@ -548,7 +548,7 @@ def test_peer_no_peers_to_assess_approaching(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "peer": True, @@ -577,7 +577,7 @@ def test_peer_not_open_approaching(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": True, @@ -603,7 +603,7 @@ def test_self(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "self": True, @@ -631,7 +631,7 @@ def test_self_no_peer(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "self": True, @@ -659,7 +659,7 @@ def test_self_no_peer_approaching(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_incomplete.html' + expected_path = 'legacy/message/oa_message_incomplete.html' expected_context = { "self": True, @@ -688,7 +688,7 @@ def test_self_closed(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": True, @@ -713,7 +713,7 @@ def test_self_no_peer_incomplete(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_closed.html' + expected_path = 'legacy/message/oa_message_closed.html' expected_context = { "not_yet_open": False, @@ -741,7 +741,7 @@ def test_waiting_due(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_complete.html' + expected_path = 'legacy/message/oa_message_complete.html' expected_context = { "waiting": True, @@ -769,7 +769,7 @@ def test_waiting_not_due(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_complete.html' + expected_path = 'legacy/message/oa_message_complete.html' expected_context = { "waiting": True, @@ -803,7 +803,7 @@ def test_waiting_on_steps(self, xblock, step): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_complete.html' + expected_path = 'legacy/message/oa_message_complete.html' expected_context = { "waiting": True, @@ -829,7 +829,7 @@ def test_done_due(self, xblock): has_peers_to_grade = True - expected_path = 'openassessmentblock/message/oa_message_complete.html' + expected_path = 'legacy/message/oa_message_complete.html' expected_context = { "waiting": False, @@ -855,7 +855,7 @@ def test_done_not_due(self, xblock): has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_complete.html' + expected_path = 'legacy/message/oa_message_complete.html' expected_context = { "waiting": False, @@ -878,7 +878,7 @@ def test_cancelled(self, xblock): } has_peers_to_grade = False - expected_path = 'openassessmentblock/message/oa_message_cancelled.html' + expected_path = 'legacy/message/oa_message_cancelled.html' expected_context = { 'is_team_assignment': False, 'xblock_id': xblock.scope_ids.usage_id, @@ -901,7 +901,7 @@ def test_cancelled_team(self, xblock): self._enable_team_assignment(xblock) - expected_path = 'openassessmentblock/message/oa_message_cancelled.html' + expected_path = 'legacy/message/oa_message_cancelled.html' expected_context = { 'is_team_assignment': True, 'xblock_id': xblock.scope_ids.usage_id, @@ -927,7 +927,7 @@ def test_no_team(self, xblock, teamset_found): if not teamset_found: xblock.teamset_config = None - expected_path = 'openassessmentblock/message/oa_message_no_team.html' + expected_path = 'legacy/message/oa_message_no_team.html' expected_context = { 'teamset_name': 'Teamset Name' if teamset_found else '', 'xblock_id': xblock.scope_ids.usage_id, @@ -954,9 +954,9 @@ def test_no_team_with_prior_sumbission(self, xblock, has_prior_submbission): # Hide the message if the learner has already submitted if has_prior_submbission: - expected_path = 'openassessmentblock/message/oa_message_unavailable.html' + expected_path = 'legacy/message/oa_message_unavailable.html' else: - expected_path = 'openassessmentblock/message/oa_message_no_team.html' + expected_path = 'legacy/message/oa_message_no_team.html' expected_context['teamset_name'] = "Teamset Name" expected_context['xblock_id'] = xblock.scope_ids.usage_id diff --git a/openassessment/xblock/test/test_peer.py b/openassessment/xblock/test/test_peer.py index bd11c0acb5..d67f717fd3 100644 --- a/openassessment/xblock/test/test_peer.py +++ b/openassessment/xblock/test/test_peer.py @@ -331,7 +331,7 @@ def test_released_no_submission(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context + xblock, 'legacy/peer/oa_peer_unavailable.html', expected_context ) @scenario('data/peer_closed_scenario.xml', user_id='Bob') @@ -350,7 +350,7 @@ def test_closed_no_submission(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_closed.html', expected_context + xblock, 'legacy/peer/oa_peer_closed.html', expected_context ) @scenario('data/peer_future_scenario.xml', user_id='Bob') @@ -369,7 +369,7 @@ def test_before_release(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context + xblock, 'legacy/peer/oa_peer_unavailable.html', expected_context ) @scenario('data/peer_assessment_scenario.xml', user_id='Bob') @@ -391,7 +391,7 @@ def test_waiting_for_peers(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_waiting.html', + xblock, 'legacy/peer/oa_peer_waiting.html', expected_context, workflow_status='peer', graded_enough=False, @@ -425,7 +425,7 @@ def test_peer_assessment_available(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_assessment.html', + xblock, 'legacy/peer/oa_peer_assessment.html', expected_context, workflow_status='peer', ) @@ -449,7 +449,7 @@ def test_peer_cancelled_workflow(self, xblock): } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_cancelled.html', + xblock, 'legacy/peer/oa_peer_cancelled.html', expected_context, workflow_status='cancelled', graded_enough=True, @@ -475,7 +475,7 @@ def test_peer_closed_no_assessments_available(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_closed.html', + xblock, 'legacy/peer/oa_peer_closed.html', expected_context, workflow_status='peer', ) @@ -505,7 +505,7 @@ def test_peer_closed_assessments_available(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_closed.html', + xblock, 'legacy/peer/oa_peer_closed.html', expected_context, workflow_status='peer', ) @@ -534,7 +534,7 @@ def test_completed_and_past_due(self, xblock, workflow_status): } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_complete.html', + xblock, 'legacy/peer/oa_peer_complete.html', expected_context, workflow_status=workflow_status, graded_enough=True, @@ -563,7 +563,7 @@ def test_turbo_grade_past_due(self, xblock, workflow_status): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_turbo_mode_waiting.html', + xblock, 'legacy/peer/oa_peer_turbo_mode_waiting.html', expected_context, continue_grading=True, workflow_status=workflow_status, @@ -594,7 +594,7 @@ def test_turbo_grade_past_due(self, xblock, workflow_status): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_turbo_mode.html', + xblock, 'legacy/peer/oa_peer_turbo_mode.html', expected_context, continue_grading=True, workflow_status='done', @@ -619,7 +619,7 @@ def test_continued_grading_no_submission(self, xblock): 'user_language': 'en' } self._assert_path_and_context( - xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', + xblock, 'legacy/peer/oa_peer_unavailable.html', expected_context, continue_grading=True, ) diff --git a/openassessment/xblock/test/test_self.py b/openassessment/xblock/test/test_self.py index cab182c034..4fcdcd376b 100644 --- a/openassessment/xblock/test/test_self.py +++ b/openassessment/xblock/test/test_self.py @@ -167,7 +167,7 @@ def test_unavailable(self, xblock): # Start date is in the future for this scenario self._assert_path_and_context( xblock, - 'openassessmentblock/self/oa_self_unavailable.html', + 'legacy/self/oa_self_unavailable.html', { 'self_start': datetime.datetime(5999, 1, 1).replace(tzinfo=pytz.utc), 'allow_multiple_files': True, @@ -183,7 +183,7 @@ def test_closed(self, xblock): # Due date is in the past for this scenario self._assert_path_and_context( xblock, - 'openassessmentblock/self/oa_self_closed.html', + 'legacy/self/oa_self_closed.html', { 'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_multiple_files': True, @@ -198,7 +198,7 @@ def test_closed(self, xblock): def test_open_no_submission(self, xblock): # Without making a submission, this step should be unavailable self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_unavailable.html', + xblock, 'legacy/self/oa_self_unavailable.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -215,7 +215,7 @@ def test_open_in_peer_step(self, xblock): # Should still be able to access self-assessment because peer status can be skipped self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_assessment.html', { + xblock, 'legacy/self/oa_self_assessment.html', { 'file_upload_type': True, 'self_submission': True, 'prompts_type': True, @@ -235,7 +235,7 @@ def test_open_in_waiting_for_peer_step(self, xblock): # to be assessed), then the self step should display as completed. self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_complete.html', + xblock, 'legacy/self/oa_self_complete.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -257,7 +257,7 @@ def test_self_then_peer(self, xblock): # In the self --> peer configuration, self can be complete # if our status is "peer" self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_complete.html', + xblock, 'legacy/self/oa_self_complete.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -278,7 +278,7 @@ def test_open_done_status(self, xblock): # Simulate the workflow status being "done" self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_complete.html', + xblock, 'legacy/self/oa_self_complete.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -294,7 +294,7 @@ def test_open_cancelled_status(self, xblock): # Simulate the workflow status being "done" self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_cancelled.html', + xblock, 'legacy/self/oa_self_cancelled.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -310,7 +310,7 @@ def test_open_self_assessing(self, xblock): # Simulate the workflow being in the self assessment step submission = self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_assessment.html', + xblock, 'legacy/self/oa_self_assessment.html', { 'rubric_criteria': xblock.rubric_criteria, 'self_submission': submission, @@ -340,7 +340,7 @@ def test_open_completed_self_assessment(self, xblock): create_rubric_dict(xblock.prompts, xblock.rubric_criteria) ) self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_complete.html', + xblock, 'legacy/self/oa_self_complete.html', { 'allow_multiple_files': True, 'allow_latex': False, @@ -359,7 +359,7 @@ def test_started_and_past_due(self, xblock): submission = self.create_test_submission(xblock) self._assert_path_and_context( xblock, - 'openassessmentblock/self/oa_self_closed.html', + 'legacy/self/oa_self_closed.html', { 'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_multiple_files': True, @@ -392,7 +392,7 @@ def test_completed_and_past_due(self, xblock): # We're checking it anyway to be overly defensive: if the user has made a self-assessment, # we ALWAYS show complete, even if the workflow tells us we're still have status 'self'. self._assert_path_and_context( - xblock, 'openassessmentblock/self/oa_self_complete.html', + xblock, 'legacy/self/oa_self_complete.html', { 'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_multiple_files': True, diff --git a/openassessment/xblock/test/test_staff.py b/openassessment/xblock/test/test_staff.py index b53329df41..fd826a7569 100644 --- a/openassessment/xblock/test/test_staff.py +++ b/openassessment/xblock/test/test_staff.py @@ -37,7 +37,7 @@ def _assert_path_and_context(self, xblock, expected_context): """ Check Staff Assessment path and context correct. """ path, context = xblock.staff_path_and_context() - self.assertEqual('openassessmentblock/staff/oa_staff_grade.html', path) + self.assertEqual('legacy/staff/oa_staff_grade.html', path) self.assertCountEqual(expected_context, context) # Verify that we render without error diff --git a/openassessment/xblock/test/test_staff_area.py b/openassessment/xblock/test/test_staff_area.py index 5543a0de94..6a57b8c5fe 100644 --- a/openassessment/xblock/test/test_staff_area.py +++ b/openassessment/xblock/test/test_staff_area.py @@ -289,7 +289,7 @@ def test_staff_area_student_info_peer_only(self, xblock): self.assertIsNotNone(context['peer_assessments']) self.assertIsNone(context['self_assessment']) self.assertIsNone(context['staff_assessment']) - self.assertEqual("openassessmentblock/staff_area/oa_student_info.html", path) + self.assertEqual("legacy/staff_area/oa_student_info.html", path) # Bob still needs to assess other learners self.assertIsNone(context['grade_details']) @@ -323,7 +323,7 @@ def test_staff_area_student_info_self_only(self, xblock): self.assertIsNone(context['peer_assessments']) self.assertIsNotNone(context['self_assessment']) self.assertIsNone(context['staff_assessment']) - self.assertEqual("openassessmentblock/staff_area/oa_student_info.html", path) + self.assertEqual("legacy/staff_area/oa_student_info.html", path) grade_details = context['grade_details'] self.assertEqual(1, len(grade_details['criteria'][0]['assessments'])) @@ -392,7 +392,7 @@ def test_staff_area_student_info_staff_only(self, xblock): self.assertIsNone(context['peer_assessments']) self.assertIsNone(context['self_assessment']) self.assertIsNotNone(context['staff_assessment']) - self.assertEqual("openassessmentblock/staff_area/oa_student_info.html", path) + self.assertEqual("legacy/staff_area/oa_student_info.html", path) grade_details = context['grade_details'] self.assertEqual(1, len(grade_details['criteria'][0]['assessments'])) @@ -431,7 +431,7 @@ def test_staff_area_student_info_with_cancelled_submission(self, xblock): path, context = xblock.get_student_info_path_and_context("Bob") self.assertEqual("Bob Answer 1", context['submission']['answer']['parts'][0]['text']) self.assertIsNotNone(context['workflow_cancellation']) - self.assertEqual("openassessmentblock/staff_area/oa_student_info.html", path) + self.assertEqual("legacy/staff_area/oa_student_info.html", path) @scenario('data/basic_scenario.xml', user_id='Bob') def test_cancelled_submission_peer_assessment_render_path(self, xblock): @@ -463,7 +463,7 @@ def test_cancelled_submission_peer_assessment_render_path(self, xblock): xblock.submission_uuid = submission["uuid"] path, _ = xblock.peer_path_and_context(False) - self.assertEqual("openassessmentblock/peer/oa_peer_cancelled.html", path) + self.assertEqual("legacy/peer/oa_peer_cancelled.html", path) @scenario('data/self_only_scenario.xml', user_id='Bob') def test_staff_area_student_info_image_submission(self, xblock): @@ -1094,7 +1094,7 @@ def test_staff_area_student_upload_info_from_user_state(self, xblock, waffle_pat self._verify_staff_assessment_rendering( xblock, - 'openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html', + 'legacy/staff_area/oa_staff_grade_learners_assessment.html', context, FILE_URL, ) @@ -1411,7 +1411,7 @@ def test_staff_area_student_all_uploads(self, xblock, user_state_waffle, all_fil new_context['staff_file_urls'] = staff_urls self._verify_staff_assessment_rendering( xblock, - 'openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html', + 'legacy/staff_area/oa_staff_grade_learners_assessment.html', new_context, FILE_URL, ) diff --git a/openassessment/xblock/test/test_student_training.py b/openassessment/xblock/test/test_student_training.py index 0e130a63ae..9d5743170b 100644 --- a/openassessment/xblock/test/test_student_training.py +++ b/openassessment/xblock/test/test_student_training.py @@ -190,7 +190,7 @@ def test_updates_workflow(self, xblock, data): 'user_timezone': None, 'user_language': None } - expected_template = "openassessmentblock/student_training/student_training_complete.html" + expected_template = "legacy/student_training/student_training_complete.html" self.assert_path_and_context(xblock, expected_template, expected_context) @scenario('data/feedback_only_criterion_student_training.xml', user_id='Bob') @@ -321,8 +321,8 @@ def test_studio_preview(self, xblock): @scenario('data/student_training_due.xml', user_id="Plato") def test_past_due(self, xblock): - self.create_test_submission(xblock) - expected_template = "openassessmentblock/student_training/student_training_closed.html" + xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION) + expected_template = "legacy/student_training/student_training_closed.html" expected_context = { 'training_due': "2000-01-01T00:00:00+00:00", 'allow_multiple_files': True, @@ -340,7 +340,7 @@ def test_cancelled_submission(self, xblock): 'status': 'cancelled', 'submission_uuid': submission['uuid'] }) - expected_template = "openassessmentblock/student_training/student_training_cancelled.html" + expected_template = "legacy/student_training/student_training_cancelled.html" expected_context = { 'allow_multiple_files': True, 'allow_latex': False, @@ -360,8 +360,8 @@ def test_internal_error(self, xblock, mock_workflow): @scenario('data/student_training_future.xml', user_id="Plato") def test_before_start(self, xblock): - self.create_test_submission(xblock) - expected_template = "openassessmentblock/student_training/student_training_unavailable.html" + xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION) + expected_template = "legacy/student_training/student_training_unavailable.html" expected_context = { 'training_start': datetime.datetime(3000, 1, 1).replace(tzinfo=pytz.utc), 'allow_multiple_files': True, diff --git a/openassessment/xblock/test/test_submission.py b/openassessment/xblock/test/test_submission.py index a77d08ab82..4f6e9c98ec 100644 --- a/openassessment/xblock/test/test_submission.py +++ b/openassessment/xblock/test/test_submission.py @@ -696,7 +696,7 @@ class SubmissionRenderTest(SubmissionXBlockHandlerTestCase, SubmissionTestMixin) @scenario('data/submission_unavailable.xml', user_id="Bob") def test_unavailable(self, xblock): self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_unavailable.html', + xblock, 'legacy/response/oa_response_unavailable.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -724,7 +724,7 @@ def test_unavailable_submitted(self, xblock): # the submission. submission = self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_submitted.html', + xblock, 'legacy/response/oa_response_submitted.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -748,7 +748,7 @@ def test_unavailable_submitted(self, xblock): @scenario('data/submission_open.xml', user_id="Bob") def test_open_unanswered(self, xblock): self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -786,7 +786,7 @@ def test_team_open_unanswered(self, xblock): xblock.user_state_upload_data_enabled = Mock(return_value=True) xblock.is_team_assignment = Mock(return_value=True) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -907,7 +907,7 @@ def test_get_team_submission_context__staff_view(self, xblock): @scenario('data/submission_no_deadline.xml', user_id="Bob") def test_open_no_deadline(self, xblock): self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -947,7 +947,7 @@ def test_open_saved_response(self, xblock): del xblock.location # self.request() inserts dummy location self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1108,7 +1108,7 @@ def test_open_saved_response_misaligned_file_data(self, xblock): del xblock.location # self.request() inserts dummy location self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1259,7 +1259,7 @@ def test_open_saved_response_old_format(self, xblock): xblock.has_saved = True self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1308,7 +1308,7 @@ def test_team_open_submitted(self, xblock): def test_open_submitted(self, xblock): submission = self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_submitted.html', + xblock, 'legacy/response/oa_response_submitted.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1344,7 +1344,7 @@ def test_cancelled_submission(self, xblock): ) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_cancelled.html', + xblock, 'legacy/response/oa_response_cancelled.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1405,7 +1405,7 @@ def test_cancelled_team_submission(self, xblock): ) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_cancelled.html', + xblock, 'legacy/response/oa_response_cancelled.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1443,7 +1443,7 @@ def test_open_submitted_old_format(self, xblock, mock_get_user_submission): xblock.prompts = [{'description': 'One prompt.'}] self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_submitted.html', + xblock, 'legacy/response/oa_response_submitted.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1471,7 +1471,7 @@ def test_open_submitted_old_format(self, xblock, mock_get_user_submission): @scenario('data/submission_closed.xml', user_id="Bob") def test_closed_incomplete(self, xblock): self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_closed.html', + xblock, 'legacy/response/oa_response_closed.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1495,7 +1495,7 @@ def test_closed_incomplete(self, xblock): def test_closed_submitted(self, xblock): submission = self.create_test_submission(xblock) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_submitted.html', + xblock, 'legacy/response/oa_response_submitted.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1530,7 +1530,7 @@ def test_open_graded(self, xblock): }) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_graded.html', + xblock, 'legacy/response/oa_response_graded.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1563,7 +1563,7 @@ def test_closed_graded(self, xblock): }) self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_graded.html', + xblock, 'legacy/response/oa_response_graded.html', { 'allow_latex': False, 'allow_multiple_files': True, @@ -1663,7 +1663,7 @@ def test_change_team_with_submission(self, xblock): # Assert that the xblock will render Red Five's existing submission rather that # no submission (because TestTeam does not yet have a submission) path, context = xblock.submission_path_and_context() - self.assertEqual(path, 'openassessmentblock/response/oa_response_submitted.html') + self.assertEqual(path, 'legacy/response/oa_response_submitted.html') self.assertEqual(context['student_submission'], create_submission_dict(individual_submission, xblock.prompts)) @scenario('data/team_submission.xml', user_id="Red Five") @@ -1699,7 +1699,7 @@ def test_leave_team_with_submission(self, xblock): # Assert that the xblock will render Red Five's existing submission rather that no submission path, context = xblock.submission_path_and_context() - self.assertEqual(path, 'openassessmentblock/response/oa_response_submitted.html') + self.assertEqual(path, 'legacy/response/oa_response_submitted.html') self.assertEqual(context['student_submission'], create_submission_dict(individual_submission, xblock.prompts)) @scenario('data/team_submission.xml', user_id="Red Five") @@ -1719,7 +1719,7 @@ def test_get_submission_context_no_team(self, xblock): # Assert that the xblock renders an unavailable submission path, _ = xblock.submission_path_and_context() - self.assertEqual(path, 'openassessmentblock/response/oa_response_unavailable.html') + self.assertEqual(path, 'legacy/response/oa_response_unavailable.html') @scenario('data/team_submission.xml', user_id="Red Five") def test_team_has_already_submitted(self, xblock): @@ -1747,7 +1747,7 @@ def test_team_has_already_submitted(self, xblock): # Assert that we return the 'team already submitted' path self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response_team_already_submitted.html', + xblock, 'legacy/response/oa_response_team_already_submitted.html', { 'saved_response': create_submission_dict({ 'answer': prepare_submission_for_serialization( @@ -1785,7 +1785,7 @@ def test_load_file_extension_presets(self, xblock): the context. This allows us to show what files types are allowed for any upload configuration. """ self._assert_path_and_context( - xblock, 'openassessmentblock/response/oa_response.html', + xblock, 'legacy/response/oa_response.html', { 'allow_latex': False, 'allow_multiple_files': True, diff --git a/scripts/render_templates.py b/scripts/render_templates.py index 080068de5a..525916a750 100755 --- a/scripts/render_templates.py +++ b/scripts/render_templates.py @@ -9,7 +9,7 @@ where "templates.json" is a JSON file of the form: [ { - "template": "openassessmentblock/oa_base.html", + "template": "legacy/oa_base.html", "context": { "title": "Lorem", "question": "Ipsum?" From 1a37270261476ed185d221f21c20fc32b37d672b Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Mon, 25 Sep 2023 11:56:53 -0400 Subject: [PATCH 02/27] feat: ORA BFF Page Data (#2053) * refactor: UI and data providers * Moved data gathering pieces of mixins into xblock/apis * Created xblock/ui_mixins/legacy to replace existing view/handler behaviors from mixins, leveraging our new APIs. * Moved remaining non-core-xblock functionality from xblock to xblock/utils. Updated references to changed file locations. * Bump to version 5.4.0 * feat: add page context with placeholder submission Fetch top-level data for page context (both for submission and assessment views from BFF). This leaves the loading of responses (for drafting, viewing, or assessing) for a follow-up task. * refactor: allow peeking a peer assessment Allow us to see if there are peer assessments available without actually beginning a peer workflow. Enables checks on our BFF. * refactor: get submission ID on peer assessment API * feat: extend peer assessment API progress details * feat: add assessment steps to workflow API * feat: add grades data to workflow API * refactor: ORA config serializer to standalone file * chore: update translations --------- Co-authored-by: Jenkins --- openassessment/assessment/api/peer.py | 15 +- .../conf/locale/en/LC_MESSAGES/django.po | 947 +++++++++--------- .../conf/locale/en/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/eo/LC_MESSAGES/django.po | 922 +++++++++-------- .../conf/locale/eo/LC_MESSAGES/djangojs.po | 2 +- .../apis/assessments/peer_assessment_api.py | 32 +- openassessment/xblock/apis/grades_api.py | 83 ++ openassessment/xblock/apis/workflow_api.py | 5 + openassessment/xblock/openassessmentblock.py | 5 + .../xblock/test/test_student_training.py | 4 +- .../legacy/peer_assessments/views.py | 16 +- .../legacy/self_assessments/views.py | 10 +- .../legacy/staff_assessments/views.py | 2 +- .../legacy/student_training/views.py | 12 +- .../ui_mixins/legacy/submissions/views.py | 2 +- .../ui_mixins/mfe/assessment_serializers.py | 15 + openassessment/xblock/ui_mixins/mfe/mixin.py | 19 +- .../ui_mixins/mfe/ora_config_serializer.py | 223 +++++ .../ui_mixins/mfe/page_context_serializer.py | 219 ++++ .../xblock/ui_mixins/mfe/serializers.py | 4 +- .../ui_mixins/mfe/submission_serializers.py | 29 + .../xblock/ui_mixins/mfe/test_serializers.py | 2 +- 22 files changed, 1594 insertions(+), 976 deletions(-) create mode 100644 openassessment/xblock/apis/grades_api.py create mode 100644 openassessment/xblock/ui_mixins/mfe/assessment_serializers.py create mode 100644 openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py create mode 100644 openassessment/xblock/ui_mixins/mfe/page_context_serializer.py create mode 100644 openassessment/xblock/ui_mixins/mfe/submission_serializers.py diff --git a/openassessment/assessment/api/peer.py b/openassessment/assessment/api/peer.py index b555c4a2d7..c2af56bb6b 100644 --- a/openassessment/assessment/api/peer.py +++ b/openassessment/assessment/api/peer.py @@ -687,7 +687,7 @@ def get_submitted_assessments(submission_uuid, limit=None): raise PeerAssessmentInternalError(error_message) from ex -def get_submission_to_assess(submission_uuid, graded_by): +def get_submission_to_assess(submission_uuid, graded_by, peek=False): """Get a submission to peer evaluate. Retrieves a submission for assessment for the given student. This will @@ -705,6 +705,8 @@ def get_submission_to_assess(submission_uuid, graded_by): associated Peer Workflow. graded_by (int): The number of assessments a submission requires before it has completed the peer assessment process. + peek (bool): When True, will verify a submission is available, without + creating a workflow to begin grading. Returns: dict: A peer submission for assessment. This contains a 'student_item', @@ -754,14 +756,15 @@ def get_submission_to_assess(submission_uuid, graded_by): if peer_submission_uuid: try: submission_data = sub_api.get_submission(peer_submission_uuid) - PeerWorkflow.create_item(workflow, peer_submission_uuid) - _log_workflow(peer_submission_uuid, workflow) + if not peek: + PeerWorkflow.create_item(workflow, peer_submission_uuid) + _log_workflow(peer_submission_uuid, workflow) return submission_data except sub_api.SubmissionNotFoundError as ex: error_message = "Could not find a submission with the uuid %s for student %s in the peer workflow." - error_meesage_args = (peer_submission_uuid, workflow.student_id) - logger.exception(error_message, error_meesage_args[0], error_meesage_args[1]) - raise PeerAssessmentWorkflowError(error_message % error_meesage_args) from ex + error_message_args = (peer_submission_uuid, workflow.student_id) + logger.exception(error_message, error_message_args[0], error_message_args[1]) + raise PeerAssessmentWorkflowError(error_message % error_message_args) from ex else: logger.info( "No submission found for %s to assess (%s, %s)", diff --git a/openassessment/conf/locale/en/LC_MESSAGES/django.po b/openassessment/conf/locale/en/LC_MESSAGES/django.po index bf0b163f3e..6f3cced104 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-06 21:24+0000\n" +"POT-Creation-Date: 2023-09-25 15:05+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -102,7 +102,7 @@ msgid "Anonymous Scorer Id" msgstr "" #: data.py:916 -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html:59 +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html:59 msgid "Overall Feedback" msgstr "" @@ -142,378 +142,376 @@ msgstr "" msgid "No description provided." msgstr "" -#: templates/openassessmentblock/edit/oa_edit.html:28 +#: templates/legacy/edit/oa_edit.html:28 msgid "Save" msgstr "" -#: templates/openassessmentblock/edit/oa_edit.html:32 +#: templates/legacy/edit/oa_edit.html:32 msgid "Cancel" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_assessment_steps.html:6 +#: templates/legacy/edit/oa_edit_assessment_steps.html:6 msgid "" "Open Response Assessments allow you to configure single or multiple steps in " "a rubric based open response assessment sequence. The steps available below " "can be enabled, disable, and ordered for a flexible set of pedagogical needs." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:5 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:5 msgid "Display Name " msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:8 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:8 msgid "The display name for this component." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:12 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:12 msgid "Text Response" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:20 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:20 msgid "" "Specify whether learners must include a text based response to this " "problem's prompt." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:25 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:25 msgid "Response Editor" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:33 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:33 msgid "" "Select which editor learners will use to include a text based response to " "this problem's prompt." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:38 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:38 msgid "File Uploads Response" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:46 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:46 msgid "" "Specify whether learners are able to upload files as a part of their " "response." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:50 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:50 msgid "Allow Multiple Files" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:52 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:93 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:131 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:157 -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:45 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:52 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:93 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:131 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:157 +#: templates/legacy/edit/oa_edit_peer_assessment.html:45 msgid "False" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:53 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:94 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:132 -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:158 -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:46 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:53 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:94 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:132 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:158 +#: templates/legacy/edit/oa_edit_peer_assessment.html:46 msgid "True" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:56 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:56 msgid "" "Specify whether learners can upload more than one file. This has no effect " "if File Uploads Response is set to None. This is automatically set to True " "for Team Assignments. " msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:58 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:58 msgid "File Upload Types" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:60 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:60 msgid "PDF or Image Files" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:61 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:61 msgid "Image Files" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:62 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:62 msgid "Custom File Types" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:66 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:66 msgid "" "Specify whether learners can submit files along with their text responses." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:70 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:70 msgid "File Types" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:79 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:79 msgid "" "Enter the file extensions, separated by commas, that you want learners to be " "able to upload. For example: pdf,doc,docx." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:84 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:84 msgid "" "To add more file extensions, select Custom File Types and enter the full " "list of acceptable file extensions to be included." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:91 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:91 msgid "Allow LaTeX Responses" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:97 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:97 msgid "Specify whether learners can write LaTeX formatted strings" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:102 -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html:8 -#: templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html:10 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:102 +#: templates/legacy/leaderboard/oa_leaderboard_show.html:8 +#: templates/legacy/leaderboard/oa_leaderboard_waiting.html:10 msgid "Top Responses" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:104 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:104 msgid " (Disabled)" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:117 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:117 msgid "" "Specify the number of top scoring responses to display after the learner has " "submitted a response. Valid numbers are 0 to 99. If the number is 0, the Top " "Responses section does not appear to learners." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:122 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:122 msgid "When Teams Enabled is set to true, Top Responses will be disabled." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:129 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:129 msgid "Teams Enabled" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:136 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:136 msgid "Specify whether team submissions are allowed for this response." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:141 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:141 msgid "Select Team-Set" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:155 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:155 msgid "Show Rubric During Response" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html:162 +#: templates/legacy/edit/oa_edit_basic_settings_list.html:162 msgid "" "Specify whether learners can see the rubric while they are working on their " "response." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:6 -#: templates/openassessmentblock/staff_area/oa_student_info.html:122 -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html:25 +#: templates/legacy/edit/oa_edit_criterion.html:6 +#: templates/legacy/staff_area/oa_student_info.html:122 +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html:25 msgid "Criterion" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:7 +#: templates/legacy/edit/oa_edit_criterion.html:7 msgid "You cannot delete a criterion after the assignment has been released." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:9 -#: templates/openassessmentblock/edit/oa_edit_option.html:7 -#: templates/openassessmentblock/edit/oa_edit_prompt.html:10 -#: templates/openassessmentblock/edit/oa_training_example.html:10 +#: templates/legacy/edit/oa_edit_criterion.html:9 +#: templates/legacy/edit/oa_edit_option.html:7 +#: templates/legacy/edit/oa_edit_prompt.html:10 +#: templates/legacy/edit/oa_training_example.html:10 msgid "Remove" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:17 +#: templates/legacy/edit/oa_edit_criterion.html:17 msgid "Criterion Name" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:29 +#: templates/legacy/edit/oa_edit_criterion.html:29 msgid "Criterion Prompt" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:44 +#: templates/legacy/edit/oa_edit_criterion.html:44 msgid "Add Option" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:52 +#: templates/legacy/edit/oa_edit_criterion.html:52 msgid "Feedback for This Criterion" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:54 -#: xblock/studio_mixin.py:57 +#: templates/legacy/edit/oa_edit_criterion.html:54 xblock/studio_mixin.py:57 msgid "None" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:55 -#: xblock/studio_mixin.py:56 +#: templates/legacy/edit/oa_edit_criterion.html:55 xblock/studio_mixin.py:56 msgid "Optional" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:56 -#: templates/openassessmentblock/oa_rubric.html:13 -#: templates/openassessmentblock/student_training/student_training.html:93 +#: templates/legacy/edit/oa_edit_criterion.html:56 +#: templates/legacy/oa_rubric.html:13 +#: templates/legacy/student_training/student_training.html:93 #: xblock/studio_mixin.py:55 msgid "Required" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_criterion.html:61 +#: templates/legacy/edit/oa_edit_criterion.html:61 msgid "" "Select one of the options above. This describes whether or not the reviewer " "will have to provide criterion feedback." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:3 +#: templates/legacy/edit/oa_edit_header_and_validation.html:3 msgid "Open Response Assessment" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:8 -#: templates/openassessmentblock/edit/oa_edit_prompt.html:7 +#: templates/legacy/edit/oa_edit_header_and_validation.html:8 +#: templates/legacy/edit/oa_edit_prompt.html:7 msgid "Prompt" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:15 +#: templates/legacy/edit/oa_edit_header_and_validation.html:15 msgid "Rubric" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:22 +#: templates/legacy/edit/oa_edit_header_and_validation.html:22 msgid "Schedule" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:31 +#: templates/legacy/edit/oa_edit_header_and_validation.html:31 msgid "Assessment steps" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html:38 +#: templates/legacy/edit/oa_edit_header_and_validation.html:38 msgid "Settings" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_option.html:5 +#: templates/legacy/edit/oa_edit_option.html:5 msgid "Option" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_option.html:16 +#: templates/legacy/edit/oa_edit_option.html:16 msgid "Option Name" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_option.html:29 +#: templates/legacy/edit/oa_edit_option.html:29 msgid "Option Points" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_option.html:42 +#: templates/legacy/edit/oa_edit_option.html:42 msgid "Option Explanation" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:10 +#: templates/legacy/edit/oa_edit_peer_assessment.html:10 msgid "Step: Peer Assessment" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:15 +#: templates/legacy/edit/oa_edit_peer_assessment.html:15 msgid "" "Peer Assessment allows students to provide feedback to other students and " "also receive feedback from others in their final grade. Often, though not " "always, this step is preceded by Self Assessment or Learner Training steps." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:18 +#: templates/legacy/edit/oa_edit_peer_assessment.html:18 msgid "" "Configuration: For this step to be configured you must specify the number of " "peer reviews a student will be assessed with, and the number of peer a " "student must grade. Additional options can be specified." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:23 +#: templates/legacy/edit/oa_edit_peer_assessment.html:23 msgid "View Options & Configuration" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:29 +#: templates/legacy/edit/oa_edit_peer_assessment.html:29 msgid "Must Grade" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:32 +#: templates/legacy/edit/oa_edit_peer_assessment.html:32 msgid "" "Specify the number of peer assessments that each learner must complete. " "Valid numbers are 1 to 99." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:36 +#: templates/legacy/edit/oa_edit_peer_assessment.html:36 msgid "Graded By" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:39 +#: templates/legacy/edit/oa_edit_peer_assessment.html:39 msgid "" "Specify the number of learners that each response must be assessed by. Valid " "numbers are 1 to 99." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:43 +#: templates/legacy/edit/oa_edit_peer_assessment.html:43 msgid "Enable Flexible Peer Grade Averaging" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:49 +#: templates/legacy/edit/oa_edit_peer_assessment.html:49 #, python-format msgid "" "When enabled, learners who have received at least 30%% of the required \\" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html:53 +#: templates/legacy/edit/oa_edit_peer_assessment.html:53 msgid "" "This feature is being enabled by the course-level setting. It can be found " "under the Open Response Assessment Settings card on the Pages & Resources " "studio page." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:5 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:5 msgid "Peer Assessment Deadlines" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:10 -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:10 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:10 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:10 msgid "Start Date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:19 -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:19 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:19 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:19 msgid "Start Time" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:27 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:27 msgid "The date and time when learners can begin assessing peer responses." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:31 -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:31 -#: templates/openassessmentblock/staff_area/oa_staff_area.html:119 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:31 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:31 +#: templates/legacy/staff_area/oa_staff_area.html:119 msgid "Due Date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:40 -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:40 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:40 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:40 msgid "Due Time" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html:48 +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html:48 msgid "The date and time when all peer assessments must be complete." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_prompt.html:8 +#: templates/legacy/edit/oa_edit_prompt.html:8 msgid "You cannot delete a prompt after the assignment has been released." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_prompts.html:10 +#: templates/legacy/edit/oa_edit_prompts.html:10 msgid "" "Prompts. Replace the sample text with your own text. For more information, " "see the ORA documentation." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_prompts.html:22 +#: templates/legacy/edit/oa_edit_prompts.html:22 msgid "Add Prompt" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:14 +#: templates/legacy/edit/oa_edit_rubric.html:14 msgid "" "Rubrics are made up of criteria, which usually contain one or more options. " "Each option has a point value. This template contains two sample criteria " @@ -521,130 +519,130 @@ msgid "" "information, see the ORA documentation." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:29 +#: templates/legacy/edit/oa_edit_rubric.html:29 msgid "Add Criterion" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:35 +#: templates/legacy/edit/oa_edit_rubric.html:35 msgid "Feedback for This Response" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:40 +#: templates/legacy/edit/oa_edit_rubric.html:40 msgid "Feedback Instructions" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:44 +#: templates/legacy/edit/oa_edit_rubric.html:44 msgid "" "Encourage learners to provide feedback on the response they have graded. You " "can replace the sample text with your own." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:49 +#: templates/legacy/edit/oa_edit_rubric.html:49 msgid "Default Feedback Text" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_rubric.html:53 +#: templates/legacy/edit/oa_edit_rubric.html:53 msgid "" "Enter feedback text that learners will see before they enter their own " "feedback. Use this text to show learners a good example peer assessment." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:5 +#: templates/legacy/edit/oa_edit_schedule.html:5 msgid "Deadlines Configuration" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:9 +#: templates/legacy/edit/oa_edit_schedule.html:9 msgid "Select a deadline configuration option" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:13 +#: templates/legacy/edit/oa_edit_schedule.html:13 msgid " NEW" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:19 +#: templates/legacy/edit/oa_edit_schedule.html:19 msgid "Configure deadlines manually" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:23 +#: templates/legacy/edit/oa_edit_schedule.html:23 msgid "Match deadlines to the subsection due date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:27 +#: templates/legacy/edit/oa_edit_schedule.html:27 msgid "Match deadlines to the course end date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:30 +#: templates/legacy/edit/oa_edit_schedule.html:30 msgid "Learn more about open response date settings" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:40 +#: templates/legacy/edit/oa_edit_schedule.html:40 msgid "Response Start Date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:53 +#: templates/legacy/edit/oa_edit_schedule.html:53 msgid "Response Start Time" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:62 +#: templates/legacy/edit/oa_edit_schedule.html:62 msgid "The date and time when learners can begin submitting responses." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:70 +#: templates/legacy/edit/oa_edit_schedule.html:70 msgid "Response Due Date" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:83 +#: templates/legacy/edit/oa_edit_schedule.html:83 msgid "Response Due Time" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_schedule.html:92 +#: templates/legacy/edit/oa_edit_schedule.html:92 msgid "The date and time when learners can no longer submit responses." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_self_assessment.html:8 +#: templates/legacy/edit/oa_edit_self_assessment.html:8 msgid "Step: Self Assessment" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_self_assessment.html:12 +#: templates/legacy/edit/oa_edit_self_assessment.html:12 msgid "" "Self Assessment asks learners to grade their own submissions against the " "rubric." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:5 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:5 msgid "Self Assessment Deadlines" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:27 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:27 msgid "The date and time when learners can begin assessing their responses." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html:48 +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html:48 msgid "The date and time when all self assessments must be complete." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_staff_assessment.html:8 +#: templates/legacy/edit/oa_edit_staff_assessment.html:8 msgid "Step: Staff Assessment" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_staff_assessment.html:12 +#: templates/legacy/edit/oa_edit_staff_assessment.html:12 msgid "" "Staff Assessment gates sets the final grade for students if enabled with " "other steps, though it can also be used as a standalone step." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_student_training.html:9 +#: templates/legacy/edit/oa_edit_student_training.html:9 msgid "Step: Learner Training" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_student_training.html:14 +#: templates/legacy/edit/oa_edit_student_training.html:14 msgid "" "Learner Training is used to help students practice grading a simulated peer " "submission in order to train them on the rubric and ensure learner's " "understand the rubric for either Self or Peer Assessment steps." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_student_training.html:17 +#: templates/legacy/edit/oa_edit_student_training.html:17 msgid "" "Configuration: For this step to be fully configured you must provide one or " "more graded sample responses. Learners must then match this instructor score " @@ -652,19 +650,19 @@ msgid "" "sample response." msgstr "" -#: templates/openassessmentblock/edit/oa_edit_student_training.html:22 +#: templates/legacy/edit/oa_edit_student_training.html:22 msgid "View / Add Sample Responses" msgstr "" -#: templates/openassessmentblock/edit/oa_edit_student_training.html:32 +#: templates/legacy/edit/oa_edit_student_training.html:32 msgid "Add Sample Response" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:4 +#: templates/legacy/edit/oa_rubric_reuse.html:4 msgid "Clone Rubric" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:7 +#: templates/legacy/edit/oa_rubric_reuse.html:7 msgid "" "To clone a rubric from an existing published or unpublished draft, you can " "search by the Block ID. Note that cloning is one-way, meaning changes made " @@ -672,49 +670,49 @@ msgid "" "modify any rubric it was cloned from." msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:9 +#: templates/legacy/edit/oa_rubric_reuse.html:9 msgid "Block ID For this ORA:" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:19 +#: templates/legacy/edit/oa_rubric_reuse.html:19 msgid "Block ID" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:21 +#: templates/legacy/edit/oa_rubric_reuse.html:21 msgid "No other Open Response Assessments found in course" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:31 +#: templates/legacy/edit/oa_rubric_reuse.html:31 msgid "Clone" msgstr "" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html:37 +#: templates/legacy/edit/oa_rubric_reuse.html:37 msgid "Rubric Successfully Cloned from Block ID: " msgstr "" -#: templates/openassessmentblock/edit/oa_training_example.html:7 +#: templates/legacy/edit/oa_training_example.html:7 msgid "Scored Response" msgstr "" -#: templates/openassessmentblock/edit/oa_training_example.html:16 +#: templates/legacy/edit/oa_training_example.html:16 msgid "Response Score" msgstr "" -#: templates/openassessmentblock/edit/oa_training_example.html:27 +#: templates/legacy/edit/oa_training_example.html:27 msgid "Response" msgstr "" -#: templates/openassessmentblock/edit/oa_training_example_criterion.html:10 +#: templates/legacy/edit/oa_training_example_criterion.html:10 msgid "Not Selected" msgstr "" -#: templates/openassessmentblock/edit/oa_training_example_criterion.html:15 -#: templates/openassessmentblock/oa_rubric.html:43 -#: templates/openassessmentblock/student_training/student_training.html:128 +#: templates/legacy/edit/oa_training_example_criterion.html:15 +#: templates/legacy/oa_rubric.html:43 +#: templates/legacy/student_training/student_training.html:128 msgid "points" msgstr "" -#: templates/openassessmentblock/grade/oa_assessment_feedback.html:8 +#: templates/legacy/grade/oa_assessment_feedback.html:8 #, python-format msgid "" "\n" @@ -723,7 +721,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/grade/oa_assessment_title.html:7 +#: templates/legacy/grade/oa_assessment_title.html:7 #, python-format msgid "" "\n" @@ -736,21 +734,21 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: templates/openassessmentblock/grade/oa_assessment_title.html:24 +#: templates/legacy/grade/oa_assessment_title.html:24 #, python-format msgid "More information about %(name)s" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html:14 -#: templates/openassessmentblock/grade/oa_grade_complete.html:15 -#: templates/openassessmentblock/grade/oa_grade_complete.html:26 -#: templates/openassessmentblock/grade/oa_grade_incomplete.html:14 -#: templates/openassessmentblock/grade/oa_grade_not_started.html:14 -#: templates/openassessmentblock/grade/oa_grade_waiting.html:14 +#: templates/legacy/grade/oa_grade_cancelled.html:14 +#: templates/legacy/grade/oa_grade_complete.html:15 +#: templates/legacy/grade/oa_grade_complete.html:26 +#: templates/legacy/grade/oa_grade_incomplete.html:14 +#: templates/legacy/grade/oa_grade_not_started.html:14 +#: templates/legacy/grade/oa_grade_waiting.html:14 msgid "Your Grade" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html:19 +#: templates/legacy/grade/oa_grade_cancelled.html:19 #, python-format msgid "" "\n" @@ -759,11 +757,11 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html:38 +#: templates/legacy/grade/oa_grade_cancelled.html:38 msgid "Your submission has been cancelled." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:19 +#: templates/legacy/grade/oa_grade_complete.html:19 #, python-format msgid "" "\n" @@ -772,134 +770,134 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:38 -#: templates/openassessmentblock/response/oa_response.html:29 +#: templates/legacy/grade/oa_grade_complete.html:38 +#: templates/legacy/response/oa_response.html:29 msgid "Your Response" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:41 +#: templates/legacy/grade/oa_grade_complete.html:41 msgid "Your Upload" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:46 +#: templates/legacy/grade/oa_grade_complete.html:46 msgid "Assessments of Your Response" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:50 -#: templates/openassessmentblock/grade/oa_grade_complete.html:132 -#: templates/openassessmentblock/grade/oa_grade_incomplete.html:28 -#: templates/openassessmentblock/grade/oa_grade_waiting.html:28 -#: templates/openassessmentblock/message/oa_message_cancelled.html:4 -#: templates/openassessmentblock/message/oa_message_closed.html:4 -#: templates/openassessmentblock/message/oa_message_complete.html:4 -#: templates/openassessmentblock/message/oa_message_incomplete.html:4 -#: templates/openassessmentblock/peer/oa_peer_closed.html:33 -#: templates/openassessmentblock/peer/oa_peer_complete.html:30 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:40 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html:34 -#: templates/openassessmentblock/peer/oa_peer_waiting.html:34 -#: templates/openassessmentblock/response/oa_response_cancelled.html:31 -#: templates/openassessmentblock/response/oa_response_closed.html:29 -#: templates/openassessmentblock/response/oa_response_submitted.html:30 -#: templates/openassessmentblock/response/oa_response_team_already_submitted.html:25 -#: templates/openassessmentblock/self/oa_self_closed.html:30 -#: templates/openassessmentblock/student_training/student_training_closed.html:27 +#: templates/legacy/grade/oa_grade_complete.html:50 +#: templates/legacy/grade/oa_grade_complete.html:132 +#: templates/legacy/grade/oa_grade_incomplete.html:28 +#: templates/legacy/grade/oa_grade_waiting.html:28 +#: templates/legacy/message/oa_message_cancelled.html:4 +#: templates/legacy/message/oa_message_closed.html:4 +#: templates/legacy/message/oa_message_complete.html:4 +#: templates/legacy/message/oa_message_incomplete.html:4 +#: templates/legacy/peer/oa_peer_closed.html:33 +#: templates/legacy/peer/oa_peer_complete.html:30 +#: templates/legacy/peer/oa_peer_turbo_mode.html:40 +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html:34 +#: templates/legacy/peer/oa_peer_waiting.html:34 +#: templates/legacy/response/oa_response_cancelled.html:31 +#: templates/legacy/response/oa_response_closed.html:29 +#: templates/legacy/response/oa_response_submitted.html:30 +#: templates/legacy/response/oa_response_team_already_submitted.html:25 +#: templates/legacy/self/oa_self_closed.html:30 +#: templates/legacy/student_training/student_training_closed.html:27 msgid "Status" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:65 +#: templates/legacy/grade/oa_grade_complete.html:65 msgid "Overall Grade" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:70 -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html:28 +#: templates/legacy/grade/oa_grade_complete.html:70 +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html:28 msgid "Points" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:96 +#: templates/legacy/grade/oa_grade_complete.html:96 msgid "Additional comments on your response" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:117 +#: templates/legacy/grade/oa_grade_complete.html:117 msgid "Provide feedback on peer assessments" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:126 +#: templates/legacy/grade/oa_grade_complete.html:126 msgid "Submitting Feedback" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:134 +#: templates/legacy/grade/oa_grade_complete.html:134 msgid "" "Your feedback has been submitted. Course staff will be able to see this " "feedback when they review course records." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:140 +#: templates/legacy/grade/oa_grade_complete.html:140 msgid "" "Course staff will be able to see any feedback that you provide here when " "they review course records." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:146 +#: templates/legacy/grade/oa_grade_complete.html:146 msgid "" "Select the statements below that best reflect your experience with peer " "assessments." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:155 +#: templates/legacy/grade/oa_grade_complete.html:155 msgid "These assessments were useful." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:164 +#: templates/legacy/grade/oa_grade_complete.html:164 msgid "These assessments were not useful." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:173 +#: templates/legacy/grade/oa_grade_complete.html:173 msgid "I disagree with one or more of the peer assessments of my response." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:182 +#: templates/legacy/grade/oa_grade_complete.html:182 msgid "Some comments I received were inappropriate." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:187 +#: templates/legacy/grade/oa_grade_complete.html:187 msgid "" "Provide feedback on the grade or comments that you received from your peers." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:190 +#: templates/legacy/grade/oa_grade_complete.html:190 msgid "I feel the feedback I received was..." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:200 +#: templates/legacy/grade/oa_grade_complete.html:200 msgid "We could not submit your feedback" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_complete.html:206 +#: templates/legacy/grade/oa_grade_complete.html:206 msgid "Submit feedback on peer assessments" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_incomplete.html:16 +#: templates/legacy/grade/oa_grade_incomplete.html:16 msgid "Not Completed" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_incomplete.html:33 +#: templates/legacy/grade/oa_grade_incomplete.html:33 msgid "You have not completed all the steps of this problem." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_not_started.html:16 +#: templates/legacy/grade/oa_grade_not_started.html:16 msgid "Not Started" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_not_started.html:27 +#: templates/legacy/grade/oa_grade_not_started.html:27 msgid "You have not started this problem yet." msgstr "" -#: templates/openassessmentblock/grade/oa_grade_waiting.html:16 +#: templates/legacy/grade/oa_grade_waiting.html:16 msgid "Waiting for Assessments" msgstr "" -#: templates/openassessmentblock/grade/oa_grade_waiting.html:33 +#: templates/legacy/grade/oa_grade_waiting.html:33 msgid "" "You have completed your steps in the assignment, but some assessments still " "need to be done on your response. When the assessments of your response are " @@ -907,107 +905,107 @@ msgid "" "and you will receive your final grade." msgstr "" -#: templates/openassessmentblock/instructor_dashboard/oa_grade_available_responses.html:15 -#: templates/openassessmentblock/staff_area/oa_staff_area.html:16 -#: templates/openassessmentblock/staff_area/oa_staff_area.html:18 -#: templates/openassessmentblock/staff_area/oa_staff_area.html:153 +#: templates/legacy/instructor_dashboard/oa_grade_available_responses.html:15 +#: templates/legacy/staff_area/oa_staff_area.html:16 +#: templates/legacy/staff_area/oa_staff_area.html:18 +#: templates/legacy/staff_area/oa_staff_area.html:153 msgid "Grade Available Responses" msgstr "" -#: templates/openassessmentblock/instructor_dashboard/oa_grade_available_responses.html:26 +#: templates/legacy/instructor_dashboard/oa_grade_available_responses.html:26 msgid "" "Grade Available Responses is unavailable. This item is not configured for " "Staff Assessment." msgstr "" -#: templates/openassessmentblock/instructor_dashboard/oa_listing.html:6 +#: templates/legacy/instructor_dashboard/oa_listing.html:6 msgid "Please wait" msgstr "" -#: templates/openassessmentblock/instructor_dashboard/oa_waiting_step_details.html:15 +#: templates/legacy/instructor_dashboard/oa_waiting_step_details.html:15 msgid "Waiting Step Details" msgstr "" -#: templates/openassessmentblock/instructor_dashboard/oa_waiting_step_details.html:24 +#: templates/legacy/instructor_dashboard/oa_waiting_step_details.html:24 msgid "" "Waiting Step details view is unavailable. This item is not configured for " "peer assessments." msgstr "" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html:20 +#: templates/legacy/leaderboard/oa_leaderboard_show.html:20 #, python-format msgid "%(num_points)s points" msgstr "" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html:24 -#: templates/openassessmentblock/peer/oa_peer_assessment.html:74 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:53 +#: templates/legacy/leaderboard/oa_leaderboard_show.html:24 +#: templates/legacy/peer/oa_peer_assessment.html:74 +#: templates/legacy/peer/oa_peer_turbo_mode.html:53 msgid "Your peer's response to the prompt above" msgstr "" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html:19 +#: templates/legacy/leaderboard/oa_leaderboard_waiting.html:19 msgid "" "After you complete all the steps of this assignment, you can see the top-" "scoring responses from your peers." msgstr "" -#: templates/openassessmentblock/message/oa_message_cancelled.html:8 +#: templates/legacy/message/oa_message_cancelled.html:8 msgid "" "Your team’s submission has been cancelled. Your team will receive a grade of " "zero unless course staff resets your assessment to allow the team to " "resubmit a response." msgstr "" -#: templates/openassessmentblock/message/oa_message_cancelled.html:10 +#: templates/legacy/message/oa_message_cancelled.html:10 msgid "" "Your submission has been cancelled. You will receive a grade of zero unless " "course staff resets your assessment to allow you to resubmit a response." msgstr "" -#: templates/openassessmentblock/message/oa_message_closed.html:8 +#: templates/legacy/message/oa_message_closed.html:8 msgid "" "This task is not yet available. Check back to complete the assignment once " "this section has opened." msgstr "" -#: templates/openassessmentblock/message/oa_message_closed.html:10 +#: templates/legacy/message/oa_message_closed.html:10 msgid "" "This assignment has closed. One or more deadlines for this assignment have " "passed. You will receive an incomplete grade for this assignment." msgstr "" -#: templates/openassessmentblock/message/oa_message_complete.html:8 +#: templates/legacy/message/oa_message_complete.html:8 msgid "" "You have completed this assignment. Your final grade will be available when " "the assessments of your response are complete." msgstr "" -#: templates/openassessmentblock/message/oa_message_complete.html:10 +#: templates/legacy/message/oa_message_complete.html:10 msgid "" "You have completed this assignment. Review your grade and your assessment " "details." msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:9 +#: templates/legacy/message/oa_message_incomplete.html:9 msgid "" "This assignment is in progress. Learner training will close soon. Complete " "the learner training step to move on." msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:11 +#: templates/legacy/message/oa_message_incomplete.html:11 msgid "" "This assignment is in progress. Complete the learner training step to move " "on." msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:15 -#: templates/openassessmentblock/message/oa_message_incomplete.html:33 +#: templates/legacy/message/oa_message_incomplete.html:15 +#: templates/legacy/message/oa_message_incomplete.html:33 msgid "" "This assignment is in progress. Check back later when the assessment period " "has started." msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:20 +#: templates/legacy/message/oa_message_incomplete.html:20 #, python-format msgid "" "\n" @@ -1017,7 +1015,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:24 +#: templates/legacy/message/oa_message_incomplete.html:24 #, python-format msgid "" "\n" @@ -1026,7 +1024,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:38 +#: templates/legacy/message/oa_message_incomplete.html:38 #, python-format msgid "" "\n" @@ -1038,7 +1036,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:42 +#: templates/legacy/message/oa_message_incomplete.html:42 #, python-format msgid "" "\n" @@ -1049,7 +1047,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:46 +#: templates/legacy/message/oa_message_incomplete.html:46 #, python-format msgid "" "\n" @@ -1059,7 +1057,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_incomplete.html:50 +#: templates/legacy/message/oa_message_incomplete.html:50 #, python-format msgid "" "\n" @@ -1068,11 +1066,11 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_no_team.html:4 +#: templates/legacy/message/oa_message_no_team.html:4 msgid "Team membership is required to view this assignment" msgstr "" -#: templates/openassessmentblock/message/oa_message_no_team.html:7 +#: templates/legacy/message/oa_message_no_team.html:7 #, python-format msgid "" "\n" @@ -1084,7 +1082,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_open.html:7 +#: templates/legacy/message/oa_message_open.html:7 #, python-format msgid "" "\n" @@ -1094,7 +1092,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_open.html:11 +#: templates/legacy/message/oa_message_open.html:11 #, python-format msgid "" "\n" @@ -1104,74 +1102,74 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/message/oa_message_unavailable.html:4 +#: templates/legacy/message/oa_message_unavailable.html:4 msgid "Instructions Unavailable" msgstr "" -#: templates/openassessmentblock/message/oa_message_unavailable.html:6 +#: templates/legacy/message/oa_message_unavailable.html:6 msgid "The instructions for this step could not be loaded." msgstr "" -#: templates/openassessmentblock/oa_base.html:15 +#: templates/legacy/oa_base.html:15 msgid "" "This assignment has several steps. In the first step, you'll provide a " "response to the prompt. The other steps appear below the Your Response field." msgstr "" -#: templates/openassessmentblock/oa_base.html:36 +#: templates/legacy/oa_base.html:36 msgid "Loading" msgstr "" -#: templates/openassessmentblock/oa_latex_preview.html:6 +#: templates/legacy/oa_latex_preview.html:6 msgid "Preview in LaTeX" msgstr "" -#: templates/openassessmentblock/oa_latex_preview.html:9 +#: templates/legacy/oa_latex_preview.html:9 msgid "Click to preview your submission in LaTeX." msgstr "" -#: templates/openassessmentblock/oa_latex_preview.html:14 +#: templates/legacy/oa_latex_preview.html:14 msgid "Preview Response" msgstr "" -#: templates/openassessmentblock/oa_rubric.html:53 +#: templates/legacy/oa_rubric.html:53 msgid "Comments" msgstr "" -#: templates/openassessmentblock/oa_submission_answer.html:8 +#: templates/legacy/oa_submission_answer.html:8 msgid "The question for this section" msgstr "" -#: templates/openassessmentblock/oa_team_uploaded_files.html:9 +#: templates/legacy/oa_team_uploaded_files.html:9 msgid "Files that were uploaded by your teammates:" msgstr "" -#: templates/openassessmentblock/oa_team_uploaded_files.html:28 -#: templates/openassessmentblock/oa_uploaded_file.html:34 +#: templates/legacy/oa_team_uploaded_files.html:28 +#: templates/legacy/oa_uploaded_file.html:34 msgid "View the files associated with this submission:" msgstr "" -#: templates/openassessmentblock/oa_team_uploaded_files.html:32 +#: templates/legacy/oa_team_uploaded_files.html:32 msgid "Uploaded by" msgstr "" -#: templates/openassessmentblock/oa_uploaded_file.html:16 +#: templates/legacy/oa_uploaded_file.html:16 msgid "Files that were uploaded by you:" msgstr "" -#: templates/openassessmentblock/oa_uploaded_file.html:48 +#: templates/legacy/oa_uploaded_file.html:48 msgid "" "Caution: These files were uploaded by another course learner and have not " "been verified, screened, approved, reviewed, or endorsed by the site " "administrator. If you access the files, you do so at your own risk.)" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:26 +#: templates/legacy/peer/oa_peer_assessment.html:26 msgid "Assess Peers" msgstr "" #. Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 00:00 UTC (in 5 days and 45 minutes)" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:34 +#: templates/legacy/peer/oa_peer_assessment.html:34 #, python-format, python-brace-format msgid "" "\n" @@ -1183,7 +1181,7 @@ msgid "" msgstr "" #. Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 00:00 UTC (in 5 days and 45 minutes)" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:41 +#: templates/legacy/peer/oa_peer_assessment.html:41 #, python-format, python-brace-format msgid "" "\n" @@ -1194,7 +1192,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:51 +#: templates/legacy/peer/oa_peer_assessment.html:51 #, python-format msgid "" "\n" @@ -1202,36 +1200,36 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:65 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:45 +#: templates/legacy/peer/oa_peer_assessment.html:65 +#: templates/legacy/peer/oa_peer_turbo_mode.html:45 msgid "Read and assess the following response from one of your peers." msgstr "" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:77 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:56 -#: templates/openassessmentblock/self/oa_self_assessment.html:60 -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html:45 -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html:38 -#: templates/openassessmentblock/staff_area/oa_student_info.html:63 +#: templates/legacy/peer/oa_peer_assessment.html:77 +#: templates/legacy/peer/oa_peer_turbo_mode.html:56 +#: templates/legacy/self/oa_self_assessment.html:60 +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html:45 +#: templates/legacy/staff_area/oa_staff_override_assessment.html:38 +#: templates/legacy/staff_area/oa_student_info.html:63 msgid "Associated Files" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_assessment.html:91 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:70 -#: templates/openassessmentblock/self/oa_self_assessment.html:71 -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html:57 -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html:50 +#: templates/legacy/peer/oa_peer_assessment.html:91 +#: templates/legacy/peer/oa_peer_turbo_mode.html:70 +#: templates/legacy/self/oa_self_assessment.html:71 +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html:57 +#: templates/legacy/staff_area/oa_staff_override_assessment.html:50 msgid "We could not submit your assessment" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_cancelled.html:19 -#: templates/openassessmentblock/response/oa_response_cancelled.html:21 -#: templates/openassessmentblock/self/oa_self_cancelled.html:21 -#: templates/openassessmentblock/student_training/student_training_cancelled.html:18 +#: templates/legacy/peer/oa_peer_cancelled.html:19 +#: templates/legacy/response/oa_response_cancelled.html:21 +#: templates/legacy/self/oa_self_cancelled.html:21 +#: templates/legacy/student_training/student_training_cancelled.html:18 msgid "Cancelled" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_closed.html:20 +#: templates/legacy/peer/oa_peer_closed.html:20 #, python-format msgid "" "\n" @@ -1239,36 +1237,36 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/peer/oa_peer_closed.html:35 +#: templates/legacy/peer/oa_peer_closed.html:35 msgid "" "The due date for this step has passed. This step is now closed. You can no " "longer complete peer assessments or continue with this assignment, and you " "will receive a grade of Incomplete." msgstr "" -#: templates/openassessmentblock/peer/oa_peer_complete.html:13 +#: templates/legacy/peer/oa_peer_complete.html:13 msgid "Completed" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_complete.html:31 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:41 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html:36 +#: templates/legacy/peer/oa_peer_complete.html:31 +#: templates/legacy/peer/oa_peer_turbo_mode.html:41 +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html:36 msgid "" "You have successfully completed all of the required peer assessments for " "this assignment. You may assess additional peer responses if you want to. " "Completing additional assessments will not affect your final grade." msgstr "" -#: templates/openassessmentblock/peer/oa_peer_complete.html:36 +#: templates/legacy/peer/oa_peer_complete.html:36 msgid "We could not retrieve additional submissions for assessment" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_complete.html:43 +#: templates/legacy/peer/oa_peer_complete.html:43 msgid "Continue Assessing Peers" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html:26 -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html:20 +#: templates/legacy/peer/oa_peer_turbo_mode.html:26 +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html:20 #, python-format msgid "" "\n" @@ -1276,20 +1274,20 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html:38 +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html:38 msgid "" "All submitted peer responses have been assessed. Check back later to see if " "more learners have submitted responses." msgstr "" -#: templates/openassessmentblock/peer/oa_peer_unavailable.html:16 -#: templates/openassessmentblock/response/oa_response_unavailable.html:17 -#: templates/openassessmentblock/self/oa_self_unavailable.html:17 -#: templates/openassessmentblock/student_training/student_training_unavailable.html:16 +#: templates/legacy/peer/oa_peer_unavailable.html:16 +#: templates/legacy/response/oa_response_unavailable.html:17 +#: templates/legacy/self/oa_self_unavailable.html:17 +#: templates/legacy/student_training/student_training_unavailable.html:16 msgid "Not Available" msgstr "" -#: templates/openassessmentblock/peer/oa_peer_waiting.html:20 +#: templates/legacy/peer/oa_peer_waiting.html:20 #, python-format msgid "" "\n" @@ -1297,7 +1295,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/peer/oa_peer_waiting.html:37 +#: templates/legacy/peer/oa_peer_waiting.html:37 msgid "" "All available peer responses have been assessed. Check back later to see if " "more learners have submitted responses. You will receive your grade after " @@ -1305,12 +1303,12 @@ msgid "" "your response." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:27 +#: templates/legacy/response/oa_response.html:27 msgid "Your Team's Response" msgstr "" #. Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 (in 5 days and 45 minutes)" -#: templates/openassessmentblock/response/oa_response.html:39 +#: templates/legacy/response/oa_response.html:39 #, python-format, python-brace-format msgid "" "\n" @@ -1322,7 +1320,7 @@ msgid "" msgstr "" #. Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 (in 5 days and 45 minutes)" -#: templates/openassessmentblock/response/oa_response.html:46 +#: templates/legacy/response/oa_response.html:46 #, python-format, python-brace-format msgid "" "\n" @@ -1333,16 +1331,16 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:54 -#: templates/openassessmentblock/self/oa_self_assessment.html:46 +#: templates/legacy/response/oa_response.html:54 +#: templates/legacy/self/oa_self_assessment.html:46 msgid "In Progress" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:66 +#: templates/legacy/response/oa_response.html:66 msgid "Enter your team's response to the prompt." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:68 +#: templates/legacy/response/oa_response.html:68 msgid "" "\n" " Your work will save automatically and you can return " @@ -1350,7 +1348,7 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:81 +#: templates/legacy/response/oa_response.html:81 msgid "" "\n" " Your work will save automatically and you can return " @@ -1358,60 +1356,60 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:86 +#: templates/legacy/response/oa_response.html:86 msgid "" "After you submit a response on behalf of your team, it cannot be edited." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:89 +#: templates/legacy/response/oa_response.html:89 msgid "Enter your response to the prompt." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:92 +#: templates/legacy/response/oa_response.html:92 msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the subsection due date " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:94 +#: templates/legacy/response/oa_response.html:94 msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the course ends " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:96 +#: templates/legacy/response/oa_response.html:96 msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the due date " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:108 +#: templates/legacy/response/oa_response.html:108 msgid "" "Your work will save automatically and you can return to complete your " "response at any time." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:110 +#: templates/legacy/response/oa_response.html:110 msgid "After you submit your response, you cannot edit it" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:120 +#: templates/legacy/response/oa_response.html:120 msgid "What will this assignment be graded on?" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:134 +#: templates/legacy/response/oa_response.html:134 msgid "The prompt for this section" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:148 +#: templates/legacy/response/oa_response.html:148 msgid "You are on team " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:150 +#: templates/legacy/response/oa_response.html:150 msgid "Team Members: " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:155 +#: templates/legacy/response/oa_response.html:155 #, python-format msgid "" "\n" @@ -1423,25 +1421,25 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:171 +#: templates/legacy/response/oa_response.html:171 msgid "Team Response " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:173 +#: templates/legacy/response/oa_response.html:173 msgid "Your Response " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:177 -#: templates/openassessmentblock/response/oa_response.html:247 +#: templates/legacy/response/oa_response.html:177 +#: templates/legacy/response/oa_response.html:247 msgid "(Required)" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:179 -#: templates/openassessmentblock/response/oa_response.html:249 +#: templates/legacy/response/oa_response.html:179 +#: templates/legacy/response/oa_response.html:249 msgid "(Optional)" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:183 +#: templates/legacy/response/oa_response.html:183 msgid "" "\n" " Teams should designate one " @@ -1456,11 +1454,11 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:197 +#: templates/legacy/response/oa_response.html:197 msgid "Enter your response to the prompt above." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:211 +#: templates/legacy/response/oa_response.html:211 #, python-format msgid "" "\n" @@ -1476,19 +1474,19 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:224 +#: templates/legacy/response/oa_response.html:224 msgid "We could not save your progress" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:232 +#: templates/legacy/response/oa_response.html:232 msgid "Status of Your Response" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:245 +#: templates/legacy/response/oa_response.html:245 msgid "File Uploads " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:253 +#: templates/legacy/response/oa_response.html:253 msgid "" "\n" " Upload files and review files uploaded by " @@ -1498,60 +1496,60 @@ msgid "" " " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:261 +#: templates/legacy/response/oa_response.html:261 msgid "We could not upload files" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:267 +#: templates/legacy/response/oa_response.html:267 msgid "We could not delete files" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:274 +#: templates/legacy/response/oa_response.html:274 msgid "Select one or more files to upload for this submission." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:276 +#: templates/legacy/response/oa_response.html:276 msgid "Select a file to upload for this submission." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:280 +#: templates/legacy/response/oa_response.html:280 msgid "Supported file types: " msgstr "" -#: templates/openassessmentblock/response/oa_response.html:285 +#: templates/legacy/response/oa_response.html:285 msgid "Upload files" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:287 +#: templates/legacy/response/oa_response.html:287 msgid "Upload file" msgstr "" -#: templates/openassessmentblock/response/oa_response.html:304 +#: templates/legacy/response/oa_response.html:304 msgid "This is a team submission." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:306 +#: templates/legacy/response/oa_response.html:306 msgid "" "One team member should submit a response with the team’s shared files and a " "text response on behalf of the entire team." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:308 +#: templates/legacy/response/oa_response.html:308 msgid "" "One team member should submit a response with the team’s shared files on " "behalf of the entire team." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:310 +#: templates/legacy/response/oa_response.html:310 msgid "" "One team member should submit a text response on behalf of the entire team." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:312 +#: templates/legacy/response/oa_response.html:312 msgid "One team member should submit on behalf of the entire team." msgstr "" -#: templates/openassessmentblock/response/oa_response.html:314 +#: templates/legacy/response/oa_response.html:314 msgid "" "\n" " Learn more about team assignments here: (\n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/django.po b/openassessment/conf/locale/eo/LC_MESSAGES/django.po index e6ff8356dd..15226eb7fd 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/django.po @@ -119,8 +119,7 @@ msgstr "Àsséssmént Týpé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" msgid "Anonymous Scorer Id" msgstr "Ànönýmöüs Sçörér Ìd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: data.py -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: data.py templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Overall Feedback" msgstr "Övéräll Féédßäçk Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" @@ -160,15 +159,15 @@ msgstr "Réspönsé Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" msgid "No description provided." msgstr "Nö désçrïptïön prövïdéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/edit/oa_edit.html +#: templates/legacy/edit/oa_edit.html msgid "Save" msgstr "Sävé Ⱡ'σяєм ι#" -#: templates/openassessmentblock/edit/oa_edit.html +#: templates/legacy/edit/oa_edit.html msgid "Cancel" msgstr "Çänçél Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/edit/oa_edit_assessment_steps.html +#: templates/legacy/edit/oa_edit_assessment_steps.html msgid "" "Open Response Assessments allow you to configure single or multiple steps in" " a rubric based open response assessment sequence. The steps available below" @@ -184,21 +183,21 @@ msgstr "" "¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт" " єѕѕє ¢ιłłυм ∂σłσяє#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Display Name " msgstr "Dïspläý Nämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "The display name for this component." msgstr "" "Thé dïspläý nämé för thïs çömpönént. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Text Response" msgstr "Téxt Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify whether learners must include a text based response to this " "problem's prompt." @@ -206,11 +205,11 @@ msgstr "" "Spéçïfý whéthér léärnérs müst ïnçlüdé ä téxt ßäséd réspönsé tö thïs " "prößlém's prömpt. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Response Editor" msgstr "Réspönsé Édïtör Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Select which editor learners will use to include a text based response to " "this problem's prompt." @@ -218,11 +217,11 @@ msgstr "" "Séléçt whïçh édïtör léärnérs wïll üsé tö ïnçlüdé ä téxt ßäséd réspönsé tö " "thïs prößlém's prömpt. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "File Uploads Response" msgstr "Fïlé Ûplöäds Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify whether learners are able to upload files as a part of their " "response." @@ -230,27 +229,27 @@ msgstr "" "Spéçïfý whéthér léärnérs äré äßlé tö üplöäd fïlés äs ä pärt öf théïr " "réspönsé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Allow Multiple Files" msgstr "Àllöw Mültïplé Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "False" msgstr "Fälsé Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "True" msgstr "Trüé Ⱡ'σяєм ι#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify whether learners can upload more than one file. This has no effect " "if File Uploads Response is set to None. This is automatically set to True " @@ -265,34 +264,34 @@ msgstr "" "νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт " "σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "File Upload Types" msgstr "Fïlé Ûplöäd Týpés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "PDF or Image Files" msgstr "PDF ör Ìmägé Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Image Files" msgstr "Ìmägé Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Custom File Types" msgstr "Çüstöm Fïlé Týpés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify whether learners can submit files along with their text responses." msgstr "" "Spéçïfý whéthér léärnérs çän süßmït fïlés älöng wïth théïr téxt réspönsés. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "File Types" msgstr "Fïlé Týpés Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Enter the file extensions, separated by commas, that you want learners to be" " able to upload. For example: pdf,doc,docx." @@ -300,7 +299,7 @@ msgstr "" "Éntér thé fïlé éxténsïöns, sépärätéd ßý çömmäs, thät ýöü wänt léärnérs tö ßé" " äßlé tö üplöäd. För éxämplé: pdf,döç,döçx. Ⱡ'σяєм ιρѕυм#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "To add more file extensions, select Custom File Types and enter the full " "list of acceptable file extensions to be included." @@ -308,27 +307,27 @@ msgstr "" "Tö ädd möré fïlé éxténsïöns, séléçt Çüstöm Fïlé Týpés änd éntér thé füll " "lïst öf äççéptäßlé fïlé éxténsïöns tö ßé ïnçlüdéd. Ⱡ'σяєм ιρ#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Allow LaTeX Responses" msgstr "Àllöw LäTéX Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Specify whether learners can write LaTeX formatted strings" msgstr "" "Spéçïfý whéthér léärnérs çän wrïté LäTéX förmättéd strïngs Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html -#: templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html +#: templates/legacy/leaderboard/oa_leaderboard_show.html +#: templates/legacy/leaderboard/oa_leaderboard_waiting.html msgid "Top Responses" msgstr "Töp Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid " (Disabled)" msgstr " (Dïsäßléd) Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify the number of top scoring responses to display after the learner has" " submitted a response. Valid numbers are 0 to 99. If the number is 0, the " @@ -343,31 +342,31 @@ msgstr "" "αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ " "ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "When Teams Enabled is set to true, Top Responses will be disabled." msgstr "" "Whén Téäms Énäßléd ïs sét tö trüé, Töp Réspönsés wïll ßé dïsäßléd. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Teams Enabled" msgstr "Téäms Énäßléd Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Specify whether team submissions are allowed for this response." msgstr "" "Spéçïfý whéthér téäm süßmïssïöns äré ällöwéd för thïs réspönsé. Ⱡ'σяєм ιρѕυм" " ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Select Team-Set" msgstr "Séléçt Téäm-Sét Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "Show Rubric During Response" msgstr "Shöw Rüßrïç Dürïng Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/edit/oa_edit_basic_settings_list.html +#: templates/legacy/edit/oa_edit_basic_settings_list.html msgid "" "Specify whether learners can see the rubric while they are working on their " "response." @@ -375,59 +374,57 @@ msgstr "" "Spéçïfý whéthér léärnérs çän séé thé rüßrïç whïlé théý äré wörkïng ön théïr " "réspönsé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html -#: templates/openassessmentblock/staff_area/oa_student_info.html -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/edit/oa_edit_criterion.html +#: templates/legacy/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Criterion" msgstr "Çrïtérïön Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "You cannot delete a criterion after the assignment has been released." msgstr "" "Ýöü çännöt délété ä çrïtérïön äftér thé ässïgnmént häs ßéén réléäséd. Ⱡ'σяєм" " ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_criterion.html -#: templates/openassessmentblock/edit/oa_edit_option.html -#: templates/openassessmentblock/edit/oa_edit_prompt.html -#: templates/openassessmentblock/edit/oa_training_example.html +#: templates/legacy/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_option.html +#: templates/legacy/edit/oa_edit_prompt.html +#: templates/legacy/edit/oa_training_example.html msgid "Remove" msgstr "Rémövé Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "Criterion Name" msgstr "Çrïtérïön Nämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "Criterion Prompt" msgstr "Çrïtérïön Prömpt Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "Add Option" msgstr "Àdd Öptïön Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "Feedback for This Criterion" msgstr "Féédßäçk för Thïs Çrïtérïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html -#: xblock/studio_mixin.py +#: templates/legacy/edit/oa_edit_criterion.html xblock/studio_mixin.py msgid "None" msgstr "Nöné Ⱡ'σяєм ι#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html -#: xblock/studio_mixin.py +#: templates/legacy/edit/oa_edit_criterion.html xblock/studio_mixin.py msgid "Optional" msgstr "Öptïönäl Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html -#: templates/openassessmentblock/oa_rubric.html -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/edit/oa_edit_criterion.html +#: templates/legacy/oa_rubric.html +#: templates/legacy/student_training/student_training.html #: xblock/studio_mixin.py msgid "Required" msgstr "Réqüïréd Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_criterion.html +#: templates/legacy/edit/oa_edit_criterion.html msgid "" "Select one of the options above. This describes whether or not the reviewer " "will have to provide criterion feedback." @@ -435,52 +432,52 @@ msgstr "" "Séléçt öné öf thé öptïöns äßövé. Thïs désçrïßés whéthér ör nöt thé révïéwér " "wïll hävé tö prövïdé çrïtérïön féédßäçk. Ⱡ'σяєм ιρѕυм ∂σ#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_header_and_validation.html msgid "Open Response Assessment" msgstr "Öpén Réspönsé Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html -#: templates/openassessmentblock/edit/oa_edit_prompt.html +#: templates/legacy/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_prompt.html msgid "Prompt" msgstr "Prömpt Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_header_and_validation.html msgid "Rubric" msgstr "Rüßrïç Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_header_and_validation.html msgid "Schedule" msgstr "Sçhédülé Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_header_and_validation.html msgid "Assessment steps" msgstr "Àsséssmént stéps Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/edit/oa_edit_header_and_validation.html +#: templates/legacy/edit/oa_edit_header_and_validation.html msgid "Settings" msgstr "Séttïngs Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_option.html +#: templates/legacy/edit/oa_edit_option.html msgid "Option" msgstr "Öptïön Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/edit/oa_edit_option.html +#: templates/legacy/edit/oa_edit_option.html msgid "Option Name" msgstr "Öptïön Nämé Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/edit/oa_edit_option.html +#: templates/legacy/edit/oa_edit_option.html msgid "Option Points" msgstr "Öptïön Pöïnts Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_option.html +#: templates/legacy/edit/oa_edit_option.html msgid "Option Explanation" msgstr "Öptïön Éxplänätïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "Step: Peer Assessment" msgstr "Stép: Péér Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "" "Peer Assessment allows students to provide feedback to other students and " "also receive feedback from others in their final grade. Often, though not " @@ -495,7 +492,7 @@ msgstr "" "¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє " "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "" "Configuration: For this step to be configured you must specify the number of" " peer reviews a student will be assessed with, and the number of peer a " @@ -510,15 +507,15 @@ msgstr "" "αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ " "ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "View Options & Configuration" msgstr "Vïéw Öptïöns & Çönfïgürätïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "Must Grade" msgstr "Müst Grädé Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "" "Specify the number of peer assessments that each learner must complete. " "Valid numbers are 1 to 99." @@ -526,11 +523,11 @@ msgstr "" "Spéçïfý thé nümßér öf péér ässéssménts thät éäçh léärnér müst çömplété. " "Välïd nümßérs äré 1 tö 99. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "Graded By" msgstr "Grädéd Bý Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "" "Specify the number of learners that each response must be assessed by. Valid" " numbers are 1 to 99." @@ -538,13 +535,13 @@ msgstr "" "Spéçïfý thé nümßér öf léärnérs thät éäçh réspönsé müst ßé ässésséd ßý. Välïd" " nümßérs äré 1 tö 99. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "Enable Flexible Peer Grade Averaging" msgstr "" "Énäßlé Fléxïßlé Péér Grädé Àvérägïng Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html #, python-format msgid "" "When enabled, learners who have received at least 30%% of the required \\" @@ -552,7 +549,7 @@ msgstr "" "Whén énäßléd, léärnérs whö hävé réçéïvéd ät léäst 30%% öf thé réqüïréd \\ " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment.html +#: templates/legacy/edit/oa_edit_peer_assessment.html msgid "" "This feature is being enabled by the course-level setting. It can be found " "under the Open Response Assessment Settings card on the Pages & Resources " @@ -567,50 +564,50 @@ msgstr "" "νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт " "¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕє#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html msgid "Peer Assessment Deadlines" msgstr "Péér Àsséssmént Déädlïnés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "Start Date" msgstr "Stärt Däté Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "Start Time" msgstr "Stärt Tïmé Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html msgid "The date and time when learners can begin assessing peer responses." msgstr "" "Thé däté änd tïmé whén léärnérs çän ßégïn ässéssïng péér réspönsés. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Due Date" msgstr "Düé Däté Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "Due Time" msgstr "Düé Tïmé Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_edit_peer_assessment_schedule.html +#: templates/legacy/edit/oa_edit_peer_assessment_schedule.html msgid "The date and time when all peer assessments must be complete." msgstr "" "Thé däté änd tïmé whén äll péér ässéssménts müst ßé çömplété. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_prompt.html +#: templates/legacy/edit/oa_edit_prompt.html msgid "You cannot delete a prompt after the assignment has been released." msgstr "" "Ýöü çännöt délété ä prömpt äftér thé ässïgnmént häs ßéén réléäséd. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_prompts.html +#: templates/legacy/edit/oa_edit_prompts.html msgid "" "Prompts. Replace the sample text with your own text. For more information, " "see the ORA documentation." @@ -618,11 +615,11 @@ msgstr "" "Prömpts. Répläçé thé sämplé téxt wïth ýöür öwn téxt. För möré ïnförmätïön, " "séé thé ÖRÀ döçüméntätïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/edit/oa_edit_prompts.html +#: templates/legacy/edit/oa_edit_prompts.html msgid "Add Prompt" msgstr "Àdd Prömpt Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "" "Rubrics are made up of criteria, which usually contain one or more options. " "Each option has a point value. This template contains two sample criteria " @@ -638,19 +635,19 @@ msgstr "" "υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє " "∂σł#" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "Add Criterion" msgstr "Àdd Çrïtérïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "Feedback for This Response" msgstr "Féédßäçk för Thïs Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "Feedback Instructions" msgstr "Féédßäçk Ìnstrüçtïöns Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "" "Encourage learners to provide feedback on the response they have graded. You" " can replace the sample text with your own." @@ -658,11 +655,11 @@ msgstr "" "Énçöürägé léärnérs tö prövïdé féédßäçk ön thé réspönsé théý hävé grädéd. Ýöü" " çän répläçé thé sämplé téxt wïth ýöür öwn. Ⱡ'σяєм ιρѕυм#" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "Default Feedback Text" msgstr "Défäült Féédßäçk Téxt Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_rubric.html +#: templates/legacy/edit/oa_edit_rubric.html msgid "" "Enter feedback text that learners will see before they enter their own " "feedback. Use this text to show learners a good example peer assessment." @@ -676,75 +673,75 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕ#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Deadlines Configuration" msgstr "Déädlïnés Çönfïgürätïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Select a deadline configuration option" msgstr "" "Séléçt ä déädlïné çönfïgürätïön öptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid " NEW" msgstr " NÉW Ⱡ'σяєм ι#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Configure deadlines manually" msgstr "Çönfïgüré déädlïnés mänüällý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Match deadlines to the subsection due date" msgstr "" "Mätçh déädlïnés tö thé süßséçtïön düé däté Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Match deadlines to the course end date" msgstr "" "Mätçh déädlïnés tö thé çöürsé énd däté Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Learn more about open response date settings" msgstr "" "Léärn möré äßöüt öpén réspönsé däté séttïngs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Response Start Date" msgstr "Réspönsé Stärt Däté Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Response Start Time" msgstr "Réspönsé Stärt Tïmé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "The date and time when learners can begin submitting responses." msgstr "" "Thé däté änd tïmé whén léärnérs çän ßégïn süßmïttïng réspönsés. Ⱡ'σяєм ιρѕυм" " ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Response Due Date" msgstr "Réspönsé Düé Däté Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "Response Due Time" msgstr "Réspönsé Düé Tïmé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/edit/oa_edit_schedule.html +#: templates/legacy/edit/oa_edit_schedule.html msgid "The date and time when learners can no longer submit responses." msgstr "" "Thé däté änd tïmé whén léärnérs çän nö löngér süßmït réspönsés. Ⱡ'σяєм ιρѕυм" " ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_self_assessment.html +#: templates/legacy/edit/oa_edit_self_assessment.html msgid "Step: Self Assessment" msgstr "Stép: Sélf Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/edit/oa_edit_self_assessment.html +#: templates/legacy/edit/oa_edit_self_assessment.html msgid "" "Self Assessment asks learners to grade their own submissions against the " "rubric." @@ -752,27 +749,27 @@ msgstr "" "Sélf Àsséssmént äsks léärnérs tö grädé théïr öwn süßmïssïöns ägäïnst thé " "rüßrïç. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "Self Assessment Deadlines" msgstr "Sélf Àsséssmént Déädlïnés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "The date and time when learners can begin assessing their responses." msgstr "" "Thé däté änd tïmé whén léärnérs çän ßégïn ässéssïng théïr réspönsés. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_edit_self_assessment_schedule.html +#: templates/legacy/edit/oa_edit_self_assessment_schedule.html msgid "The date and time when all self assessments must be complete." msgstr "" "Thé däté änd tïmé whén äll sélf ässéssménts müst ßé çömplété. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_edit_staff_assessment.html +#: templates/legacy/edit/oa_edit_staff_assessment.html msgid "Step: Staff Assessment" msgstr "Stép: Stäff Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/edit/oa_edit_staff_assessment.html +#: templates/legacy/edit/oa_edit_staff_assessment.html msgid "" "Staff Assessment gates sets the final grade for students if enabled with " "other steps, though it can also be used as a standalone step." @@ -786,11 +783,11 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт łαвσяυм#" -#: templates/openassessmentblock/edit/oa_edit_student_training.html +#: templates/legacy/edit/oa_edit_student_training.html msgid "Step: Learner Training" msgstr "Stép: Léärnér Träïnïng Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/edit/oa_edit_student_training.html +#: templates/legacy/edit/oa_edit_student_training.html msgid "" "Learner Training is used to help students practice grading a simulated peer " "submission in order to train them on the rubric and ensure learner's " @@ -805,7 +802,7 @@ msgstr "" "¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє " "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕ#" -#: templates/openassessmentblock/edit/oa_edit_student_training.html +#: templates/legacy/edit/oa_edit_student_training.html msgid "" "Configuration: For this step to be fully configured you must provide one or " "more graded sample responses. Learners must then match this instructor score" @@ -821,19 +818,19 @@ msgstr "" "єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє" " νєłιт#" -#: templates/openassessmentblock/edit/oa_edit_student_training.html +#: templates/legacy/edit/oa_edit_student_training.html msgid "View / Add Sample Responses" msgstr "Vïéw / Àdd Sämplé Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/edit/oa_edit_student_training.html +#: templates/legacy/edit/oa_edit_student_training.html msgid "Add Sample Response" msgstr "Àdd Sämplé Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "Clone Rubric" msgstr "Çlöné Rüßrïç Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "" "To clone a rubric from an existing published or unpublished draft, you can " "search by the Block ID. Note that cloning is one-way, meaning changes made " @@ -849,53 +846,53 @@ msgstr "" "υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє " "∂σłσя ιη #" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "Block ID For this ORA:" msgstr "Blöçk ÌD För thïs ÖRÀ: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "Block ID" msgstr "Blöçk ÌD Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "No other Open Response Assessments found in course" msgstr "" "Nö öthér Öpén Réspönsé Àsséssménts föünd ïn çöürsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "Clone" msgstr "Çlöné Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/edit/oa_rubric_reuse.html +#: templates/legacy/edit/oa_rubric_reuse.html msgid "Rubric Successfully Cloned from Block ID: " msgstr "" "Rüßrïç Süççéssfüllý Çlönéd fröm Blöçk ÌD: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/edit/oa_training_example.html +#: templates/legacy/edit/oa_training_example.html msgid "Scored Response" msgstr "Sçöréd Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/edit/oa_training_example.html +#: templates/legacy/edit/oa_training_example.html msgid "Response Score" msgstr "Réspönsé Sçöré Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/edit/oa_training_example.html +#: templates/legacy/edit/oa_training_example.html msgid "Response" msgstr "Réspönsé Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/edit/oa_training_example_criterion.html +#: templates/legacy/edit/oa_training_example_criterion.html msgid "Not Selected" msgstr "Nöt Séléçtéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/edit/oa_training_example_criterion.html -#: templates/openassessmentblock/oa_rubric.html -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/edit/oa_training_example_criterion.html +#: templates/legacy/oa_rubric.html +#: templates/legacy/student_training/student_training.html msgid "points" msgstr "pöïnts Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/grade/oa_assessment_feedback.html +#: templates/legacy/grade/oa_assessment_feedback.html #, python-format msgid "" "\n" @@ -906,7 +903,7 @@ msgstr "" " %(start_tag)s%(title)s%(end_tag)s%(start_grade_tag)s - %(grade)s%(end_tag)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/grade/oa_assessment_title.html +#: templates/legacy/grade/oa_assessment_title.html #, python-format msgid "" "\n" @@ -925,21 +922,21 @@ msgstr[1] "" " %(assessment_title)s - %(points)s pöïnts\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/grade/oa_assessment_title.html +#: templates/legacy/grade/oa_assessment_title.html #, python-format msgid "More information about %(name)s" msgstr "Möré ïnförmätïön äßöüt %(name)s Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/grade/oa_grade_incomplete.html -#: templates/openassessmentblock/grade/oa_grade_not_started.html -#: templates/openassessmentblock/grade/oa_grade_waiting.html +#: templates/legacy/grade/oa_grade_cancelled.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_incomplete.html +#: templates/legacy/grade/oa_grade_not_started.html +#: templates/legacy/grade/oa_grade_waiting.html msgid "Your Grade" msgstr "Ýöür Grädé Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html +#: templates/legacy/grade/oa_grade_cancelled.html #, python-format msgid "" "\n" @@ -950,12 +947,12 @@ msgstr "" " %(points_earned)s öüt öf %(points_possible)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/grade/oa_grade_cancelled.html +#: templates/legacy/grade/oa_grade_cancelled.html msgid "Your submission has been cancelled." msgstr "" "Ýöür süßmïssïön häs ßéén çänçélléd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html #, python-format msgid "" "\n" @@ -966,67 +963,67 @@ msgstr "" " %(points_earned)s öüt öf %(points_possible)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/response/oa_response.html msgid "Your Response" msgstr "Ýöür Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Your Upload" msgstr "Ýöür Ûplöäd Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Assessments of Your Response" msgstr "Àsséssménts öf Ýöür Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/grade/oa_grade_incomplete.html -#: templates/openassessmentblock/grade/oa_grade_waiting.html -#: templates/openassessmentblock/message/oa_message_cancelled.html -#: templates/openassessmentblock/message/oa_message_closed.html -#: templates/openassessmentblock/message/oa_message_complete.html -#: templates/openassessmentblock/message/oa_message_incomplete.html -#: templates/openassessmentblock/peer/oa_peer_closed.html -#: templates/openassessmentblock/peer/oa_peer_complete.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html -#: templates/openassessmentblock/peer/oa_peer_waiting.html -#: templates/openassessmentblock/response/oa_response_cancelled.html -#: templates/openassessmentblock/response/oa_response_closed.html -#: templates/openassessmentblock/response/oa_response_submitted.html -#: templates/openassessmentblock/response/oa_response_team_already_submitted.html -#: templates/openassessmentblock/self/oa_self_closed.html -#: templates/openassessmentblock/student_training/student_training_closed.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_incomplete.html +#: templates/legacy/grade/oa_grade_waiting.html +#: templates/legacy/message/oa_message_cancelled.html +#: templates/legacy/message/oa_message_closed.html +#: templates/legacy/message/oa_message_complete.html +#: templates/legacy/message/oa_message_incomplete.html +#: templates/legacy/peer/oa_peer_closed.html +#: templates/legacy/peer/oa_peer_complete.html +#: templates/legacy/peer/oa_peer_turbo_mode.html +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html +#: templates/legacy/peer/oa_peer_waiting.html +#: templates/legacy/response/oa_response_cancelled.html +#: templates/legacy/response/oa_response_closed.html +#: templates/legacy/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_team_already_submitted.html +#: templates/legacy/self/oa_self_closed.html +#: templates/legacy/student_training/student_training_closed.html msgid "Status" msgstr "Stätüs Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Overall Grade" msgstr "Övéräll Grädé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/grade/oa_grade_complete.html -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/grade/oa_grade_complete.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Points" msgstr "Pöïnts Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Additional comments on your response" msgstr "" "Àddïtïönäl çömménts ön ýöür réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Provide feedback on peer assessments" msgstr "" "Prövïdé féédßäçk ön péér ässéssménts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Submitting Feedback" msgstr "Süßmïttïng Féédßäçk Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "" "Your feedback has been submitted. Course staff will be able to see this " "feedback when they review course records." @@ -1034,7 +1031,7 @@ msgstr "" "Ýöür féédßäçk häs ßéén süßmïttéd. Çöürsé stäff wïll ßé äßlé tö séé thïs " "féédßäçk whén théý révïéw çöürsé réçörds. Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "" "Course staff will be able to see any feedback that you provide here when " "they review course records." @@ -1042,7 +1039,7 @@ msgstr "" "Çöürsé stäff wïll ßé äßlé tö séé äný féédßäçk thät ýöü prövïdé héré whén " "théý révïéw çöürsé réçörds. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "" "Select the statements below that best reflect your experience with peer " "assessments." @@ -1050,75 +1047,75 @@ msgstr "" "Séléçt thé stätéménts ßélöw thät ßést réfléçt ýöür éxpérïénçé wïth péér " "ässéssménts. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "These assessments were useful." msgstr "Thésé ässéssménts wéré üséfül. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "These assessments were not useful." msgstr "" "Thésé ässéssménts wéré nöt üséfül. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "I disagree with one or more of the peer assessments of my response." msgstr "" "Ì dïsägréé wïth öné ör möré öf thé péér ässéssménts öf mý réspönsé. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Some comments I received were inappropriate." msgstr "" "Sömé çömménts Ì réçéïvéd wéré ïnäppröprïäté. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "" "Provide feedback on the grade or comments that you received from your peers." msgstr "" "Prövïdé féédßäçk ön thé grädé ör çömménts thät ýöü réçéïvéd fröm ýöür péérs." " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "I feel the feedback I received was..." msgstr "" "Ì féél thé féédßäçk Ì réçéïvéd wäs... Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "We could not submit your feedback" msgstr "" "Wé çöüld nöt süßmït ýöür féédßäçk Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/grade/oa_grade_complete.html +#: templates/legacy/grade/oa_grade_complete.html msgid "Submit feedback on peer assessments" msgstr "" "Süßmït féédßäçk ön péér ässéssménts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/grade/oa_grade_incomplete.html +#: templates/legacy/grade/oa_grade_incomplete.html msgid "Not Completed" msgstr "Nöt Çömplétéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/grade/oa_grade_incomplete.html +#: templates/legacy/grade/oa_grade_incomplete.html msgid "You have not completed all the steps of this problem." msgstr "" "Ýöü hävé nöt çömplétéd äll thé stéps öf thïs prößlém. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт" " αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/grade/oa_grade_not_started.html +#: templates/legacy/grade/oa_grade_not_started.html msgid "Not Started" msgstr "Nöt Stärtéd Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/grade/oa_grade_not_started.html +#: templates/legacy/grade/oa_grade_not_started.html msgid "You have not started this problem yet." msgstr "" "Ýöü hävé nöt stärtéd thïs prößlém ýét. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/grade/oa_grade_waiting.html +#: templates/legacy/grade/oa_grade_waiting.html msgid "Waiting for Assessments" msgstr "Wäïtïng för Àsséssménts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: templates/openassessmentblock/grade/oa_grade_waiting.html +#: templates/legacy/grade/oa_grade_waiting.html msgid "" "You have completed your steps in the assignment, but some assessments still " "need to be done on your response. When the assessments of your response are " @@ -1133,14 +1130,14 @@ msgstr "" "∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση " "υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυ#" -#: templates/openassessmentblock/instructor_dashboard/oa_grade_available_responses.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/instructor_dashboard/oa_grade_available_responses.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Grade Available Responses" msgstr "Grädé Àväïläßlé Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/instructor_dashboard/oa_grade_available_responses.html +#: templates/legacy/instructor_dashboard/oa_grade_available_responses.html msgid "" "Grade Available Responses is unavailable. This item is not configured for " "Staff Assessment." @@ -1148,15 +1145,15 @@ msgstr "" "Grädé Àväïläßlé Réspönsés ïs ünäväïläßlé. Thïs ïtém ïs nöt çönfïgüréd för " "Stäff Àsséssmént. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/instructor_dashboard/oa_listing.html +#: templates/legacy/instructor_dashboard/oa_listing.html msgid "Please wait" msgstr "Pléäsé wäït Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/instructor_dashboard/oa_waiting_step_details.html +#: templates/legacy/instructor_dashboard/oa_waiting_step_details.html msgid "Waiting Step Details" msgstr "Wäïtïng Stép Détäïls Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/instructor_dashboard/oa_waiting_step_details.html +#: templates/legacy/instructor_dashboard/oa_waiting_step_details.html msgid "" "Waiting Step details view is unavailable. This item is not configured for " "peer assessments." @@ -1164,20 +1161,20 @@ msgstr "" "Wäïtïng Stép détäïls vïéw ïs ünäväïläßlé. Thïs ïtém ïs nöt çönfïgüréd för " "péér ässéssménts. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html +#: templates/legacy/leaderboard/oa_leaderboard_show.html #, python-format msgid "%(num_points)s points" msgstr "%(num_points)s pöïnts Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_show.html -#: templates/openassessmentblock/peer/oa_peer_assessment.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html +#: templates/legacy/leaderboard/oa_leaderboard_show.html +#: templates/legacy/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_turbo_mode.html msgid "Your peer's response to the prompt above" msgstr "" "Ýöür péér's réspönsé tö thé prömpt äßövé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/leaderboard/oa_leaderboard_waiting.html +#: templates/legacy/leaderboard/oa_leaderboard_waiting.html msgid "" "After you complete all the steps of this assignment, you can see the top-" "scoring responses from your peers." @@ -1185,7 +1182,7 @@ msgstr "" "Àftér ýöü çömplété äll thé stéps öf thïs ässïgnmént, ýöü çän séé thé töp-" "sçörïng réspönsés fröm ýöür péérs. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/message/oa_message_cancelled.html +#: templates/legacy/message/oa_message_cancelled.html msgid "" "Your team’s submission has been cancelled. Your team will receive a grade of" " zero unless course staff resets your assessment to allow the team to " @@ -1200,7 +1197,7 @@ msgstr "" "νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт " "σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ι#" -#: templates/openassessmentblock/message/oa_message_cancelled.html +#: templates/legacy/message/oa_message_cancelled.html msgid "" "Your submission has been cancelled. You will receive a grade of zero unless " "course staff resets your assessment to allow you to resubmit a response." @@ -1214,7 +1211,7 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм#" -#: templates/openassessmentblock/message/oa_message_closed.html +#: templates/legacy/message/oa_message_closed.html msgid "" "This task is not yet available. Check back to complete the assignment once " "this section has opened." @@ -1222,7 +1219,7 @@ msgstr "" "Thïs täsk ïs nöt ýét äväïläßlé. Çhéçk ßäçk tö çömplété thé ässïgnmént önçé " "thïs séçtïön häs öpénéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/message/oa_message_closed.html +#: templates/legacy/message/oa_message_closed.html msgid "" "This assignment has closed. One or more deadlines for this assignment have " "passed. You will receive an incomplete grade for this assignment." @@ -1236,7 +1233,7 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт ł#" -#: templates/openassessmentblock/message/oa_message_complete.html +#: templates/legacy/message/oa_message_complete.html msgid "" "You have completed this assignment. Your final grade will be available when " "the assessments of your response are complete." @@ -1244,7 +1241,7 @@ msgstr "" "Ýöü hävé çömplétéd thïs ässïgnmént. Ýöür fïnäl grädé wïll ßé äväïläßlé whén " "thé ässéssménts öf ýöür réspönsé äré çömplété. Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/message/oa_message_complete.html +#: templates/legacy/message/oa_message_complete.html msgid "" "You have completed this assignment. Review your grade and your assessment " "details." @@ -1252,7 +1249,7 @@ msgstr "" "Ýöü hävé çömplétéd thïs ässïgnmént. Révïéw ýöür grädé änd ýöür ässéssmént " "détäïls. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html msgid "" "This assignment is in progress. Learner training will close soon. Complete " "the learner training step to move on." @@ -1260,7 +1257,7 @@ msgstr "" "Thïs ässïgnmént ïs ïn prögréss. Léärnér träïnïng wïll çlösé söön. Çömplété " "thé léärnér träïnïng stép tö mövé ön. Ⱡ'σяєм ιρѕυм ∂σłσя#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html msgid "" "This assignment is in progress. Complete the learner training step to move " "on." @@ -1268,8 +1265,8 @@ msgstr "" "Thïs ässïgnmént ïs ïn prögréss. Çömplété thé léärnér träïnïng stép tö mövé " "ön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/message/oa_message_incomplete.html -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html msgid "" "This assignment is in progress. Check back later when the assessment period " "has started." @@ -1277,7 +1274,7 @@ msgstr "" "Thïs ässïgnmént ïs ïn prögréss. Çhéçk ßäçk lätér whén thé ässéssmént pérïöd " "häs stärtéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1288,7 +1285,7 @@ msgstr "" " %(start_strong)sThïs ässïgnmént ïs ïn prögréss. Thé sélf ässéssmént stép wïll çlösé söön.%(end_strong)s Ýöü stïll nééd tö çömplété thé %(start_link)ssélf ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕ#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1299,7 +1296,7 @@ msgstr "" " Thïs ässïgnmént ïs ïn prögréss. Ýöü stïll nééd tö çömplété thé %(start_link)ssélf ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυ#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1310,7 +1307,7 @@ msgstr "" " Thïs ässïgnmént ïs ïn prögréss.%(start_strong)sThé péér ässéssmént stép wïll çlösé söön.%(end_strong)s Àll süßmïttéd péér réspönsés hävé ßéén ässésséd. Çhéçk ßäçk lätér tö séé ïf möré léärnérs hävé süßmïttéd réspönsés. Ýöü stïll nééd tö çömplété thé %(start_link)spéér ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιq#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1321,7 +1318,7 @@ msgstr "" " Thïs ässïgnmént ïs ïn prögréss. Àll süßmïttéd péér réspönsés hävé ßéén ässésséd. Çhéçk ßäçk lätér tö séé ïf möré léärnérs hävé süßmïttéd réspönsés. Ýöü stïll nééd tö çömplété thé %(start_link)spéér ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ #" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1332,7 +1329,7 @@ msgstr "" " Thïs ässïgnmént ïs ïn prögréss. %(start_strong)sThé péér ässéssmént stép wïll çlösé söön.%(end_strong)s Ýöü stïll nééd tö çömplété thé %(start_link)spéér ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕ#" -#: templates/openassessmentblock/message/oa_message_incomplete.html +#: templates/legacy/message/oa_message_incomplete.html #, python-format msgid "" "\n" @@ -1343,13 +1340,13 @@ msgstr "" " Thïs ässïgnmént ïs ïn prögréss. Ýöü stïll nééd tö çömplété thé %(start_link)spéér ässéssmént%(end_link)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυ#" -#: templates/openassessmentblock/message/oa_message_no_team.html +#: templates/legacy/message/oa_message_no_team.html msgid "Team membership is required to view this assignment" msgstr "" "Téäm mémßérshïp ïs réqüïréd tö vïéw thïs ässïgnmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/message/oa_message_no_team.html +#: templates/legacy/message/oa_message_no_team.html #, python-format msgid "" "\n" @@ -1364,7 +1361,7 @@ msgstr "" " Ýöü müst ßé ön ä téäm ïn téäm-sét \"%(teamset_name)s\" tö äççéss thïs téäm ässïgnmént.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяι#" -#: templates/openassessmentblock/message/oa_message_open.html +#: templates/legacy/message/oa_message_open.html #, python-format msgid "" "\n" @@ -1375,7 +1372,7 @@ msgstr "" " Àssïgnmént süßmïssïöns wïll çlösé söön. Tö réçéïvé ä grädé, fïrst prövïdé ä réspönsé tö thé prömpt, thén çömplété thé stéps ßélöw thé %(start_tag)sÝöür Réspönsé%(end_tag)s fïéld.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υ#" -#: templates/openassessmentblock/message/oa_message_open.html +#: templates/legacy/message/oa_message_open.html #, python-format msgid "" "\n" @@ -1386,17 +1383,17 @@ msgstr "" " Thïs ässïgnmént häs sévéräl stéps. Ìn thé fïrst stép, ýöü'll prövïdé ä réspönsé tö thé prömpt. Thé öthér stéps äppéär ßélöw thé %(start_tag)sÝöür Réspönsé%(end_tag)s fïéld.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ησ#" -#: templates/openassessmentblock/message/oa_message_unavailable.html +#: templates/legacy/message/oa_message_unavailable.html msgid "Instructions Unavailable" msgstr "Ìnstrüçtïöns Ûnäväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/message/oa_message_unavailable.html +#: templates/legacy/message/oa_message_unavailable.html msgid "The instructions for this step could not be loaded." msgstr "" "Thé ïnstrüçtïöns för thïs stép çöüld nöt ßé löädéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/oa_base.html +#: templates/legacy/oa_base.html msgid "" "This assignment has several steps. In the first step, you'll provide a " "response to the prompt. The other steps appear below the Your Response " @@ -1411,55 +1408,55 @@ msgstr "" " єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт " "¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм#" -#: templates/openassessmentblock/oa_base.html +#: templates/legacy/oa_base.html msgid "Loading" msgstr "Löädïng Ⱡ'σяєм ιρѕυм #" -#: templates/openassessmentblock/oa_latex_preview.html +#: templates/legacy/oa_latex_preview.html msgid "Preview in LaTeX" msgstr "Prévïéw ïn LäTéX Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/oa_latex_preview.html +#: templates/legacy/oa_latex_preview.html msgid "Click to preview your submission in LaTeX." msgstr "" "Çlïçk tö prévïéw ýöür süßmïssïön ïn LäTéX. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/oa_latex_preview.html +#: templates/legacy/oa_latex_preview.html msgid "Preview Response" msgstr "Prévïéw Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/oa_rubric.html +#: templates/legacy/oa_rubric.html msgid "Comments" msgstr "Çömménts Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/oa_submission_answer.html +#: templates/legacy/oa_submission_answer.html msgid "The question for this section" msgstr "Thé qüéstïön för thïs séçtïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/oa_team_uploaded_files.html +#: templates/legacy/oa_team_uploaded_files.html msgid "Files that were uploaded by your teammates:" msgstr "" "Fïlés thät wéré üplöädéd ßý ýöür téämmätés: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/oa_team_uploaded_files.html -#: templates/openassessmentblock/oa_uploaded_file.html +#: templates/legacy/oa_team_uploaded_files.html +#: templates/legacy/oa_uploaded_file.html msgid "View the files associated with this submission:" msgstr "" "Vïéw thé fïlés ässöçïätéd wïth thïs süßmïssïön: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт," " ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/oa_team_uploaded_files.html +#: templates/legacy/oa_team_uploaded_files.html msgid "Uploaded by" msgstr "Ûplöädéd ßý Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/oa_uploaded_file.html +#: templates/legacy/oa_uploaded_file.html msgid "Files that were uploaded by you:" msgstr "" "Fïlés thät wéré üplöädéd ßý ýöü: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/oa_uploaded_file.html +#: templates/legacy/oa_uploaded_file.html msgid "" "Caution: These files were uploaded by another course learner and have not " "been verified, screened, approved, reviewed, or endorsed by the site " @@ -1474,14 +1471,14 @@ msgstr "" "¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє " "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρт#" -#: templates/openassessmentblock/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_assessment.html msgid "Assess Peers" msgstr "Àsséss Péérs Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "available August 13th, 2014 00:00 UTC (in #. 5 days and 45 minutes)" -#: templates/openassessmentblock/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_assessment.html #, python-format, python-brace-format msgid "" "\n" @@ -1495,7 +1492,7 @@ msgstr "" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "due August 13th, 2014 00:00 UTC (in 5 days #. and 45 minutes)" -#: templates/openassessmentblock/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_assessment.html #, python-format, python-brace-format msgid "" "\n" @@ -1506,7 +1503,7 @@ msgstr "" " \n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_assessment.html #, python-format msgid "" "\n" @@ -1517,27 +1514,27 @@ msgstr "" " Ìn Prögréss (%(review_number)s öf %(num_must_grade)s)\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/peer/oa_peer_assessment.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html +#: templates/legacy/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_turbo_mode.html msgid "Read and assess the following response from one of your peers." msgstr "" "Réäd änd ässéss thé föllöwïng réspönsé fröm öné öf ýöür péérs. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/peer/oa_peer_assessment.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html -#: templates/openassessmentblock/self/oa_self_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_turbo_mode.html +#: templates/legacy/self/oa_self_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Associated Files" msgstr "Àssöçïätéd Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/peer/oa_peer_assessment.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html -#: templates/openassessmentblock/self/oa_self_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/peer/oa_peer_assessment.html +#: templates/legacy/peer/oa_peer_turbo_mode.html +#: templates/legacy/self/oa_self_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "We could not submit your assessment" msgstr "" "Wé çöüld nöt süßmït ýöür ässéssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" @@ -1549,7 +1546,7 @@ msgstr "" msgid "Cancelled" msgstr "Çänçélléd Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/peer/oa_peer_closed.html +#: templates/legacy/peer/oa_peer_closed.html #, python-format msgid "" "\n" @@ -1560,7 +1557,7 @@ msgstr "" " Ìnçömplété (%(num_graded)s öf %(num_must_grade)s)\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/peer/oa_peer_closed.html +#: templates/legacy/peer/oa_peer_closed.html msgid "" "The due date for this step has passed. This step is now closed. You can no " "longer complete peer assessments or continue with this assignment, and you " @@ -1575,13 +1572,13 @@ msgstr "" "яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα " "ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт#" -#: templates/openassessmentblock/peer/oa_peer_complete.html +#: templates/legacy/peer/oa_peer_complete.html msgid "Completed" msgstr "Çömplétéd Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/peer/oa_peer_complete.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html +#: templates/legacy/peer/oa_peer_complete.html +#: templates/legacy/peer/oa_peer_turbo_mode.html +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html msgid "" "You have successfully completed all of the required peer assessments for " "this assignment. You may assess additional peer responses if you want to. " @@ -1596,18 +1593,18 @@ msgstr "" "¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє " "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. є#" -#: templates/openassessmentblock/peer/oa_peer_complete.html +#: templates/legacy/peer/oa_peer_complete.html msgid "We could not retrieve additional submissions for assessment" msgstr "" "Wé çöüld nöt rétrïévé äddïtïönäl süßmïssïöns för ässéssmént Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/peer/oa_peer_complete.html +#: templates/legacy/peer/oa_peer_complete.html msgid "Continue Assessing Peers" msgstr "Çöntïnüé Àsséssïng Péérs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/peer/oa_peer_turbo_mode.html -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html +#: templates/legacy/peer/oa_peer_turbo_mode.html +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html #, python-format msgid "" "\n" @@ -1618,7 +1615,7 @@ msgstr "" " Çömplété (%(num_graded)s)\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/peer/oa_peer_turbo_mode_waiting.html +#: templates/legacy/peer/oa_peer_turbo_mode_waiting.html msgid "" "All submitted peer responses have been assessed. Check back later to see if " "more learners have submitted responses." @@ -1633,7 +1630,7 @@ msgstr "" msgid "Not Available" msgstr "Nöt Àväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/peer/oa_peer_waiting.html +#: templates/legacy/peer/oa_peer_waiting.html #, python-format msgid "" "\n" @@ -1644,7 +1641,7 @@ msgstr "" " Ìn Prögréss (%(review_number)s öf %(num_must_grade)s)\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/peer/oa_peer_waiting.html +#: templates/legacy/peer/oa_peer_waiting.html msgid "" "All available peer responses have been assessed. Check back later to see if " "more learners have submitted responses. You will receive your grade after " @@ -1660,14 +1657,14 @@ msgstr "" "єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє" " νєłιт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Your Team's Response" msgstr "Ýöür Téäm's Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "available August 13th, 2014 (in 5 days and #. 45 minutes)" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html #, python-format, python-brace-format msgid "" "\n" @@ -1681,7 +1678,7 @@ msgstr "" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "due August 13th, 2014 (in 5 days and 45 #. minutes)" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html #, python-format, python-brace-format msgid "" "\n" @@ -1692,18 +1689,18 @@ msgstr "" " \n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/response/oa_response.html -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/response/oa_response.html +#: templates/legacy/self/oa_self_assessment.html msgid "In Progress" msgstr "Ìn Prögréss Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Enter your team's response to the prompt." msgstr "" "Éntér ýöür téäm's réspönsé tö thé prömpt. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "\n" " Your work will save automatically and you can return to complete your team's response at any time before the due date\n" @@ -1713,7 +1710,7 @@ msgstr "" " Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür téäm's réspönsé ät äný tïmé ßéföré thé düé däté\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "\n" " Your work will save automatically and you can return to complete your team's response at any time.\n" @@ -1723,19 +1720,19 @@ msgstr "" " Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür téäm's réspönsé ät äný tïmé.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "After you submit a response on behalf of your team, it cannot be edited." msgstr "" "Àftér ýöü süßmït ä réspönsé ön ßéhälf öf ýöür téäm, ït çännöt ßé édïtéd. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Enter your response to the prompt." msgstr "" "Éntér ýöür réspönsé tö thé prömpt. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the subsection due date " @@ -1743,7 +1740,7 @@ msgstr "" "Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür " "réspönsé ät äný tïmé ßéföré thé süßséçtïön düé däté Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the course ends " @@ -1751,7 +1748,7 @@ msgstr "" "Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür " "réspönsé ät äný tïmé ßéföré thé çöürsé énds Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "Your work will save automatically and you can return to complete your " "response at any time before the due date " @@ -1759,7 +1756,7 @@ msgstr "" "Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür " "réspönsé ät äný tïmé ßéföré thé düé däté Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "Your work will save automatically and you can return to complete your " "response at any time." @@ -1767,31 +1764,31 @@ msgstr "" "Ýöür wörk wïll sävé äütömätïçällý änd ýöü çän rétürn tö çömplété ýöür " "réspönsé ät äný tïmé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "After you submit your response, you cannot edit it" msgstr "" "Àftér ýöü süßmït ýöür réspönsé, ýöü çännöt édït ït Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "What will this assignment be graded on?" msgstr "" "Whät wïll thïs ässïgnmént ßé grädéd ön? Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "The prompt for this section" msgstr "Thé prömpt för thïs séçtïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "You are on team " msgstr "Ýöü äré ön téäm Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Team Members: " msgstr "Téäm Mémßérs: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html #, python-format msgid "" "\n" @@ -1806,25 +1803,25 @@ msgstr "" " änd wïll nöt ßé ä pärt öf ýöür téäm's süßmïssïön ör ässïgnmént grädé.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє є#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Team Response " msgstr "Téäm Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Your Response " msgstr "Ýöür Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/response/oa_response.html -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "(Required)" msgstr "(Réqüïréd) Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/response/oa_response.html -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "(Optional)" msgstr "(Öptïönäl) Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "\n" " Teams should designate one team member to submit a response on behalf of the\n" @@ -1842,13 +1839,13 @@ msgstr "" " mémßér shöüld süßmït.\n" " #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Enter your response to the prompt above." msgstr "" "Éntér ýöür réspönsé tö thé prömpt äßövé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html #, python-format msgid "" "\n" @@ -1867,19 +1864,19 @@ msgstr "" " réçéïvé ä grädé för théïr süßmïssïön.\n" " #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "We could not save your progress" msgstr "Wé çöüld nöt sävé ýöür prögréss Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Status of Your Response" msgstr "Stätüs öf Ýöür Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "File Uploads " msgstr "Fïlé Ûplöäds Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "\n" " Upload files and review files uploaded by you and your teammates below. Be sure to add\n" @@ -1891,43 +1888,43 @@ msgstr "" " désçrïptïöns tö ýöür fïlés tö hélp ýöür téämmätés ïdéntïfý thém.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "We could not upload files" msgstr "Wé çöüld nöt üplöäd fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "We could not delete files" msgstr "Wé çöüld nöt délété fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Select one or more files to upload for this submission." msgstr "" "Séléçt öné ör möré fïlés tö üplöäd för thïs süßmïssïön. Ⱡ'σяєм ιρѕυм ∂σłσя " "ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Select a file to upload for this submission." msgstr "" "Séléçt ä fïlé tö üplöäd för thïs süßmïssïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Supported file types: " msgstr "Süppörtéd fïlé týpés: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Upload files" msgstr "Ûplöäd fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Upload file" msgstr "Ûplöäd fïlé Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "This is a team submission." msgstr "Thïs ïs ä téäm süßmïssïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "One team member should submit a response with the team’s shared files and a " "text response on behalf of the entire team." @@ -1935,7 +1932,7 @@ msgstr "" "Öné téäm mémßér shöüld süßmït ä réspönsé wïth thé téäm’s shäréd fïlés änd ä " "téxt réspönsé ön ßéhälf öf thé éntïré téäm. Ⱡ'σяєм ιρѕυм#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "One team member should submit a response with the team’s shared files on " "behalf of the entire team." @@ -1943,20 +1940,20 @@ msgstr "" "Öné téäm mémßér shöüld süßmït ä réspönsé wïth thé téäm’s shäréd fïlés ön " "ßéhälf öf thé éntïré téäm. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "One team member should submit a text response on behalf of the entire team." msgstr "" "Öné téäm mémßér shöüld süßmït ä téxt réspönsé ön ßéhälf öf thé éntïré téäm. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "One team member should submit on behalf of the entire team." msgstr "" "Öné téäm mémßér shöüld süßmït ön ßéhälf öf thé éntïré téäm. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "" "\n" " Learn more about team assignments here: (link)\n" @@ -1966,22 +1963,22 @@ msgstr "" " Léärn möré äßöüt téäm ässïgnménts héré: (lïnk)\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "We could not submit your response" msgstr "" "Wé çöüld nöt süßmït ýöür réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/response/oa_response.html +#: templates/legacy/response/oa_response.html msgid "Submit your response and move to the next step" msgstr "" "Süßmït ýöür réspönsé änd mövé tö thé néxt stép Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/response/oa_response_cancelled.html +#: templates/legacy/response/oa_response_cancelled.html msgid "Your submission was cancelled. " msgstr "Ýöür süßmïssïön wäs çänçélléd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/response/oa_response_cancelled.html +#: templates/legacy/response/oa_response_cancelled.html #, python-format msgid "" "\n" @@ -1992,7 +1989,7 @@ msgstr "" " Ýöür süßmïssïön häs ßéén çänçélléd ßý %(removed_by_username)s ön %(removed_datetime)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/response/oa_response_cancelled.html +#: templates/legacy/response/oa_response_cancelled.html #, python-format msgid "" "\n" @@ -2003,7 +2000,7 @@ msgstr "" " Ýöür süßmïssïön wäs çänçélléd ön %(removed_datetime)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/response/oa_response_cancelled.html +#: templates/legacy/response/oa_response_cancelled.html #, python-format msgid "" "\n" @@ -2014,13 +2011,13 @@ msgstr "" " Çömménts: %(comments)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/response/oa_response_closed.html -#: templates/openassessmentblock/self/oa_self_closed.html -#: templates/openassessmentblock/student_training/student_training_closed.html +#: templates/legacy/response/oa_response_closed.html +#: templates/legacy/self/oa_self_closed.html +#: templates/legacy/student_training/student_training_closed.html msgid "Incomplete" msgstr "Ìnçömplété Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: templates/openassessmentblock/response/oa_response_closed.html +#: templates/legacy/response/oa_response_closed.html msgid "" "The due date for this step has passed. This step is now closed. You can no " "longer submit a response or continue with this problem, and you will receive" @@ -2042,18 +2039,18 @@ msgstr "" msgid "Complete" msgstr "Çömplété Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/response/oa_response_graded.html -#: templates/openassessmentblock/response/oa_response_submitted.html -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/response/oa_response_graded.html +#: templates/legacy/response/oa_response_submitted.html +#: templates/legacy/self/oa_self_assessment.html msgid "Your response" msgstr "Ýöür réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/response/oa_response_graded.html -#: templates/openassessmentblock/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_graded.html +#: templates/legacy/response/oa_response_submitted.html msgid "Your Uploaded Files" msgstr "Ýöür Ûplöädéd Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_submitted.html msgid "" "Your response has been submitted. You will receive your grade after all " "steps are complete and your response is fully assessed." @@ -2061,7 +2058,7 @@ msgstr "" "Ýöür réspönsé häs ßéén süßmïttéd. Ýöü wïll réçéïvé ýöür grädé äftér äll " "stéps äré çömplété änd ýöür réspönsé ïs füllý ässésséd. Ⱡ'σяє#" -#: templates/openassessmentblock/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_submitted.html #, python-format msgid "" "\n" @@ -2072,7 +2069,7 @@ msgstr "" " Ýöü stïll nééd tö çömplété thé %(peer_start_tag)spéér ässéssmént%(end_tag)s änd %(self_start_tag)ssélf ässéssmént%(end_tag)s stéps.\n" " Ⱡ#" -#: templates/openassessmentblock/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_submitted.html #, python-format msgid "" "\n" @@ -2083,7 +2080,7 @@ msgstr "" " Ýöü stïll nééd tö çömplété thé %(start_tag)spéér ässéssmént%(end_tag)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/response/oa_response_submitted.html +#: templates/legacy/response/oa_response_submitted.html #, python-format msgid "" "\n" @@ -2094,11 +2091,11 @@ msgstr "" " Ýöü stïll nééd tö çömplété thé %(start_tag)ssélf ässéssmént%(end_tag)s stép.\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/response/oa_response_team_already_submitted.html +#: templates/legacy/response/oa_response_team_already_submitted.html msgid "Error" msgstr "Érrör Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/response/oa_response_team_already_submitted.html +#: templates/legacy/response/oa_response_team_already_submitted.html #, python-format msgid "" "\n" @@ -2115,14 +2112,14 @@ msgstr "" " öptïöns för thïs ässïgnmént.\n" " #" -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/self/oa_self_assessment.html msgid "Assess Your Response" msgstr "Àsséss Ýöür Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "available August 13th, 2014 (in 5 days and #. 45 minutes)" -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/self/oa_self_assessment.html #, python-format, python-brace-format msgid "" "\n" @@ -2136,7 +2133,7 @@ msgstr "" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "due August 13th, 2014 (in 5 days and 45 #. minutes)" -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/self/oa_self_assessment.html #, python-format, python-brace-format msgid "" "\n" @@ -2147,11 +2144,11 @@ msgstr "" " \n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/self/oa_self_assessment.html +#: templates/legacy/self/oa_self_assessment.html msgid "Submit your assessment" msgstr "Süßmït ýöür ässéssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/self/oa_self_closed.html +#: templates/legacy/self/oa_self_closed.html msgid "" "The due date for this step has passed. This step is now closed. You can no " "longer complete a self assessment or continue with this assignment, and you " @@ -2166,110 +2163,109 @@ msgstr "" "яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα " "ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂є#" -#: templates/openassessmentblock/staff/oa_staff_grade.html -#: xblock/grade_mixin.py +#: templates/legacy/staff/oa_staff_grade.html xblock/grade_mixin.py msgid "Staff Grade" msgstr "Stäff Grädé Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Manage Individual Learners" msgstr "Mänägé Ìndïvïdüäl Léärnérs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Manage Team Responses" msgstr "Mänägé Téäm Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "View Assignment Statistics" msgstr "Vïéw Àssïgnmént Stätïstïçs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Demo the new Grading Experience" msgstr "Démö thé néw Grädïng Éxpérïénçé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "View ORA in Studio" msgstr "Vïéw ÖRÀ ïn Stüdïö Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Close" msgstr "Çlösé Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Manage Teams" msgstr "Mänägé Téäms Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Enter an individual learner's username or email" msgstr "" "Éntér än ïndïvïdüäl léärnér's üsérnämé ör émäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт," " ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Enter a team member's username or edX email" msgstr "" "Éntér ä téäm mémßér's üsérnämé ör édX émäïl Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Submit" msgstr "Süßmït Ⱡ'σяєм ιρѕυ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Response total" msgstr "Réspönsé tötäl Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Location" msgstr "Löçätïön Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Learner Progress" msgstr "Léärnér Prögréss Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Problem Step" msgstr "Prößlém Stép Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Active Learners in Step" msgstr "Àçtïvé Léärnérs ïn Stép Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Dates" msgstr "Dätés Ⱡ'σяєм ιρѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "Release Date" msgstr "Réléäsé Däté Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: templates/openassessmentblock/staff_area/oa_staff_area.html -#: templates/openassessmentblock/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html +#: templates/legacy/staff_area/oa_staff_area.html msgid "N/A" msgstr "N/À Ⱡ'σяєм#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners.html +#: templates/legacy/staff_area/oa_staff_grade_learners.html msgid "Staff Assessment" msgstr "Stäff Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html msgid "Give this team a grade using the problem's rubric." msgstr "" "Gïvé thïs téäm ä grädé üsïng thé prößlém's rüßrïç. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html msgid "Give this learner a grade using the problem's rubric." msgstr "" "Gïvé thïs léärnér ä grädé üsïng thé prößlém's rüßrïç. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт" " αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html #, python-format msgid "" "\n" @@ -2280,8 +2276,8 @@ msgstr "" " Réspönsé för: %(team_name)s wïth %(team_usernames)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html #, python-format msgid "" "\n" @@ -2292,37 +2288,37 @@ msgstr "" " Réspönsé för: %(student_username)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "Learner Response" msgstr "Léärnér Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html msgid "The teams's response to the prompt above" msgstr "" "Thé téäms's réspönsé tö thé prömpt äßövé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_student_info.html msgid "The learner's response to the prompt above" msgstr "" "Thé léärnér's réspönsé tö thé prömpt äßövé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "Submit assessment" msgstr "Süßmït ässéssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_assessment.html +#: templates/legacy/staff_area/oa_staff_grade_learners_assessment.html msgid "Submit assessment and continue grading" msgstr "" "Süßmït ässéssmént änd çöntïnüé grädïng Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/staff_area/oa_staff_grade_learners_count.html +#: templates/legacy/staff_area/oa_staff_grade_learners_count.html #, python-format msgid "" "\n" @@ -2333,30 +2329,30 @@ msgstr "" " %(ungraded)s Àväïläßlé änd %(in_progress)s Çhéçkéd Öüt\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "Override this learner's current grade using the problem's rubric." msgstr "" "Övérrïdé thïs léärnér's çürrént grädé üsïng thé prößlém's rüßrïç. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "Override this team's current grade using the problem's rubric." msgstr "" "Övérrïdé thïs téäm's çürrént grädé üsïng thé prößlém's rüßrïç. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html msgid "Team Response" msgstr "Téäm Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: templates/openassessmentblock/staff_area/oa_staff_override_assessment.html -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_staff_override_assessment.html +#: templates/legacy/staff_area/oa_student_info.html msgid "The team's response to the prompt above" msgstr "" "Thé téäm's réspönsé tö thé prömpt äßövé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2367,7 +2363,7 @@ msgstr "" " Vïéwïng léärnér: %(learner)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2378,15 +2374,15 @@ msgstr "" " Vïéwïng téäm: %(team)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Learner's Response" msgstr "Léärnér's Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Team's Response" msgstr "Téäm's Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2397,7 +2393,7 @@ msgstr "" " Léärnér süßmïssïön rémövéd ßý %(removed_by_username)s ön %(removed_datetime)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2408,7 +2404,7 @@ msgstr "" " Léärnér süßmïssïön rémövéd ön %(removed_datetime)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2419,39 +2415,39 @@ msgstr "" " Çömménts: %(comments)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Peer Assessments for This Learner" msgstr "" "Péér Àsséssménts för Thïs Léärnér Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Peer Assessments Completed by This Learner" msgstr "" "Péér Àsséssménts Çömplétéd ßý Thïs Léärnér Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Learner's Self Assessment" msgstr "Léärnér's Sélf Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Staff Assessment for This Learner" msgstr "" "Stäff Àsséssmént för Thïs Léärnér Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Staff Assessment for this Team" msgstr "Stäff Àsséssmént för thïs Téäm Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Learner's Final Grade" msgstr "Léärnér's Fïnäl Grädé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Team's Final Grade" msgstr "Téäm's Fïnäl Grädé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2462,11 +2458,11 @@ msgstr "" " Fïnäl grädé: %(points_earned)s öüt öf %(points_possible)s\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Final Grade Details" msgstr "Fïnäl Grädé Détäïls Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html #, python-format msgid "" "\n" @@ -2485,17 +2481,17 @@ msgstr[1] "" " %(assessment_label)s - %(points)s pöïnts\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Feedback Recorded" msgstr "Féédßäçk Réçördéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "The submission is waiting for assessments." msgstr "" "Thé süßmïssïön ïs wäïtïng för ässéssménts. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "The learner's submission has been removed from peer assessment. The learner " "receives a grade of zero unless you delete the learner's state for the " @@ -2510,7 +2506,7 @@ msgstr "" "∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα" " ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ησ#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "The team’s submission has been removed from grading. The team receives a " "grade of zero unless you delete the a team member’s state for the problem to" @@ -2525,31 +2521,31 @@ msgstr "" "∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα" " ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσ#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "The problem has not been started." msgstr "" "Thé prößlém häs nöt ßéén stärtéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "The problem has not been completed." msgstr "" "Thé prößlém häs nöt ßéén çömplétéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Submit Assessment Grade Override" msgstr "" "Süßmït Àsséssmént Grädé Övérrïdé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Submit Team Grade Override" msgstr "Süßmït Téäm Grädé Övérrïdé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Unable to perform grade override" msgstr "" "Ûnäßlé tö pérförm grädé övérrïdé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "Grades are frozen. Grades are automatically frozen 30 days after the course " "end date." @@ -2557,7 +2553,7 @@ msgstr "" "Grädés äré frözén. Grädés äré äütömätïçällý frözén 30 däýs äftér thé çöürsé " "énd däté. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "This submission has been cancelled and cannot recieve a grade. Refer to " "documentation for how to delete the learner’s state for this problem to " @@ -2572,23 +2568,23 @@ msgstr "" "νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт " "σ¢¢αє¢αт ¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Remove Submission From Peer Grading" msgstr "" "Rémövé Süßmïssïön Fröm Péér Grädïng Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Remove Team Submission from Grading" msgstr "" "Rémövé Téäm Süßmïssïön fröm Grädïng Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Caution: This Action Cannot Be Undone" msgstr "" "Çäütïön: Thïs Àçtïön Çännöt Bé Ûndöné Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "Removing a learner's submission cannot be undone and should be done with " "caution." @@ -2596,7 +2592,7 @@ msgstr "" "Rémövïng ä léärnér's süßmïssïön çännöt ßé ündöné änd shöüld ßé döné wïth " "çäütïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "" "Removing a team's submission cannot be undone and should be done with " "caution." @@ -2604,21 +2600,21 @@ msgstr "" "Rémövïng ä téäm's süßmïssïön çännöt ßé ündöné änd shöüld ßé döné wïth " "çäütïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Comments:" msgstr "Çömménts: Ⱡ'σяєм ιρѕυм ∂σł#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "Remove submission" msgstr "Rémövé süßmïssïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: templates/openassessmentblock/staff_area/oa_student_info.html +#: templates/legacy/staff_area/oa_student_info.html msgid "A response was not found for this learner." msgstr "" "À réspönsé wäs nöt föünd för thïs léärnér. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html #, python-format msgid "" "\n" @@ -2629,27 +2625,27 @@ msgstr "" " Àsséssmént %(assessment_num)s:\n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Assessment Details" msgstr "Àsséssmént Détäïls Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Selected Option" msgstr "Séléçtéd Öptïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Feedback" msgstr "Féédßäçk Ⱡ'σяєм ιρѕυм ∂#" -#: templates/openassessmentblock/staff_area/oa_student_info_assessment_detail.html +#: templates/legacy/staff_area/oa_student_info_assessment_detail.html msgid "Points Possible" msgstr "Pöïnts Pössïßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "Learn to Assess Responses" msgstr "Léärn tö Àsséss Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html #, python-format msgid "" "\n" @@ -2663,7 +2659,7 @@ msgstr "" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "available August 13th, 2014 (in 5 days and #. 45 minutes)" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html #, python-format, python-brace-format msgid "" "\n" @@ -2677,7 +2673,7 @@ msgstr "" #. Translators: This string displays a date to the user, then tells them the #. time until that date. Example: "due August 13th, 2014 (in 5 days and 45 #. minutes)" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html #, python-format, python-brace-format msgid "" "\n" @@ -2688,12 +2684,12 @@ msgstr "" " \n" " Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/student_training/student_training.html -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "Learning to Assess Responses" msgstr "Léärnïng tö Àsséss Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "" "Before you begin to assess your peers' responses, you'll learn how to " "complete peer assessments by reviewing responses that instructors have " @@ -2708,7 +2704,7 @@ msgstr "" "sämé öptïöns, ýöü'll révïéw thé réspönsé änd trý ägäïn. Ⱡ'σяєм ιρѕυм ∂σłσя " "ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єι#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "" "Your assessment differs from the instructor's assessment of this response. " "Review the response and consider why the instructor may have assessed it " @@ -2723,44 +2719,44 @@ msgstr "" "∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα" " ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт ησ#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "The response to the prompt above:" msgstr "" "Thé réspönsé tö thé prömpt äßövé: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "Selected Options Agree" msgstr "Séléçtéd Öptïöns Àgréé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "The option you selected is the option that the instructor selected." msgstr "" "Thé öptïön ýöü séléçtéd ïs thé öptïön thät thé ïnstrüçtör séléçtéd. Ⱡ'σяєм " "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "Selected Options Differ" msgstr "Séléçtéd Öptïöns Dïffér Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "" "The option you selected is not the option that the instructor selected." msgstr "" "Thé öptïön ýöü séléçtéd ïs nöt thé öptïön thät thé ïnstrüçtör séléçtéd. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "We could not check your assessment" msgstr "" "Wé çöüld nöt çhéçk ýöür ässéssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: templates/openassessmentblock/student_training/student_training.html +#: templates/legacy/student_training/student_training.html msgid "Compare your selections with the instructor's selections" msgstr "" "Çömpäré ýöür séléçtïöns wïth thé ïnstrüçtör's séléçtïöns Ⱡ'σяєм ιρѕυм ∂σłσя " "ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: templates/openassessmentblock/student_training/student_training_closed.html +#: templates/legacy/student_training/student_training_closed.html msgid "" "The due date for this step has passed. This step is now closed. You can no " "longer continue with this assignment, and you will receive a grade of " @@ -2775,13 +2771,13 @@ msgstr "" "νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт " "¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσ#" -#: templates/openassessmentblock/student_training/student_training_error.html +#: templates/legacy/student_training/student_training_error.html msgid "Error Loading Learner Training Examples" msgstr "" "Érrör Löädïng Léärnér Träïnïng Éxämplés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: templates/openassessmentblock/student_training/student_training_error.html +#: templates/legacy/student_training/student_training_error.html msgid "The Learner Training Step of this assignment could not be loaded." msgstr "" "Thé Léärnér Träïnïng Stép öf thïs ässïgnmént çöüld nöt ßé löädéd. Ⱡ'σяєм " diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po index 146df4cd78..ad5ccc3b7d 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-06 21:24+0000\n" +"POT-Creation-Date: 2023-09-25 15:05+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/xblock/apis/assessments/peer_assessment_api.py b/openassessment/xblock/apis/assessments/peer_assessment_api.py index e628f47933..6ba36d979d 100644 --- a/openassessment/xblock/apis/assessments/peer_assessment_api.py +++ b/openassessment/xblock/apis/assessments/peer_assessment_api.py @@ -16,6 +16,10 @@ def __init__(self, block, continue_grading=False): super().__init__(block, "peer-assessment") self._continue_grading = continue_grading + @property + def submission_uuid(self): + return self.workflow_data.submission_uuid + @property def assessment(self): return self.config_data.get_assessment_module("peer-assessment") @@ -28,10 +32,34 @@ def continue_grading(self): def file_upload_type(self): return self.config_data.file_upload_type + @property + def num_completed(self): + _, count = self.has_finished + return count + + @property + def num_received(self): + """ + Return number of peer assessments this submission has received + or None if submission not found. + """ + return peer_api.get_graded_by_count(self.submission_uuid) + + @property + def waiting_for_submissions_to_assess(self): + """ + Determine if the student is blocked, waiting on submissions to assess. + """ + peer_submission = peer_api.get_submission_to_assess( + self.submission_uuid, self.assessment["must_be_graded_by"], + peek=True + ) + return not bool(peer_submission) + @property def has_finished(self): finished, count = peer_api.has_finished_required_evaluating( - self._block.submission_uuid, self.assessment["must_grade"] + self.submission_uuid, self.assessment["must_grade"] ) return finished, count @@ -77,7 +105,7 @@ def get_peer_submission(self): peer_submission = False try: peer_submission = peer_api.get_submission_to_assess( - self.workflow_data.submission_uuid, self.assessment["must_be_graded_by"] + self.submission_uuid, self.assessment["must_be_graded_by"] ) self.config_data.publish_event( "openassessmentblock.get_peer_submission", diff --git a/openassessment/xblock/apis/grades_api.py b/openassessment/xblock/apis/grades_api.py new file mode 100644 index 0000000000..243efe47fa --- /dev/null +++ b/openassessment/xblock/apis/grades_api.py @@ -0,0 +1,83 @@ +""" +APIs for getting grade info +""" + +from openassessment.assessment.api import peer as peer_api +from openassessment.assessment.api import self as self_api +from openassessment.assessment.api import staff as staff_api + + +class GradesAPI: + def __init__(self, block): + self._block = block + + def _get_submission_uuid(self): + return self._block.submission_uuid + + @property + def self_score(self): + """ + Get self score. + + Returns: + { + "points_earned": (Int) awarded points + "points_possible": (Int) max possible points + } + """ + submission_uuid = self._get_submission_uuid() + assessment = self_api.get_assessment(submission_uuid) + + if assessment is not None: + return { + "points_earned": assessment["points_earned"], + "points_possible": assessment["points_possible"], + } + return None + + @property + def peer_score(self): + """ + Refresh workflows and get peer score. + + Returns: + { + "points_earned": (Int) calculated peer score + "points_possible": (Int) max possible points + } + """ + submission_uuid = self._get_submission_uuid() + peer_requirements = self._block.workflow_requirements()["peer"] + course_settings = self._block.get_course_workflow_settings() + + peer_score = peer_api.get_score( + submission_uuid, peer_requirements, course_settings + ) + + if peer_score is not None: + return { + "points_earned": peer_score["points_earned"], + "points_possible": peer_score["points_possible"], + } + return None + + @property + def staff_score(self): + """ + Get staff score. + + Returns: + { + "points_earned": (Int) awarded points + "points_possible": (Int) max possible points + } + """ + submission_uuid = self._get_submission_uuid() + assessment = staff_api.get_latest_staff_assessment(submission_uuid) + + if assessment is not None: + return { + "points_earned": assessment["points_earned"], + "points_possible": assessment["points_possible"], + } + return None diff --git a/openassessment/xblock/apis/workflow_api.py b/openassessment/xblock/apis/workflow_api.py index eeb5998d96..281e3a291f 100644 --- a/openassessment/xblock/apis/workflow_api.py +++ b/openassessment/xblock/apis/workflow_api.py @@ -6,6 +6,7 @@ class WorkflowAPI: def __init__(self, block): self._block = block + self.grades = self._block.grades_data def get_workflow_info(self, submission_uuid=None): return self._block.get_workflow_info(submission_uuid) @@ -18,6 +19,10 @@ def workflow(self): def has_workflow(self): return bool(self.workflow) + @property + def assessment_steps(self): + return self._block.assessment_steps + @property def has_status(self): return bool(self.status) diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index 13ec335178..9902f36034 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -22,6 +22,7 @@ from openassessment.staffgrader.staff_grader_mixin import StaffGraderMixin from openassessment.workflow.errors import AssessmentWorkflowError +from openassessment.xblock.apis.grades_api import GradesAPI from openassessment.xblock.apis.submissions.submissions_api import SubmissionAPI from openassessment.xblock.course_items_listing_mixin import CourseItemsListingMixin from openassessment.xblock.utils.data_conversion import ( @@ -315,6 +316,10 @@ def staff_data(self): def student_training_data(self): return StudentTrainingAPI(self) + @property + def grades_data(self): + return GradesAPI(self) + @property def api_data(self): return ORADataAccessor(self) diff --git a/openassessment/xblock/test/test_student_training.py b/openassessment/xblock/test/test_student_training.py index 9d5743170b..db1c23de55 100644 --- a/openassessment/xblock/test/test_student_training.py +++ b/openassessment/xblock/test/test_student_training.py @@ -321,7 +321,7 @@ def test_studio_preview(self, xblock): @scenario('data/student_training_due.xml', user_id="Plato") def test_past_due(self, xblock): - xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION) + self.create_test_submission(xblock) expected_template = "legacy/student_training/student_training_closed.html" expected_context = { 'training_due': "2000-01-01T00:00:00+00:00", @@ -360,7 +360,7 @@ def test_internal_error(self, xblock, mock_workflow): @scenario('data/student_training_future.xml', user_id="Plato") def test_before_start(self, xblock): - xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION) + self.create_test_submission(xblock) expected_template = "legacy/student_training/student_training_unavailable.html" expected_context = { 'training_start': datetime.datetime(3000, 1, 1).replace(tzinfo=pytz.utc), diff --git a/openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py index 7de671c517..4c3b8f0a9f 100644 --- a/openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py +++ b/openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py @@ -8,14 +8,14 @@ template_paths = { - "unavailable": "openassessmentblock/peer/oa_peer_unavailable.html", - "cancelled": "openassessmentblock/peer/oa_peer_cancelled.html", - "complete": "openassessmentblock/peer/oa_peer_complete.html", - "turbo_mode": "openassessmentblock/peer/oa_peer_turbo_mode.html", - "turbo_mode_waiting": "openassessmentblock/peer/oa_peer_turbo_mode_waiting.html", - "closed": "openassessmentblock/peer/oa_peer_closed.html", - "assessment": "openassessmentblock/peer/oa_peer_assessment.html", - "waiting": "openassessmentblock/peer/oa_peer_waiting.html", + "unavailable": "legacy/peer/oa_peer_unavailable.html", + "cancelled": "legacy/peer/oa_peer_cancelled.html", + "complete": "legacy/peer/oa_peer_complete.html", + "turbo_mode": "legacy/peer/oa_peer_turbo_mode.html", + "turbo_mode_waiting": "legacy/peer/oa_peer_turbo_mode_waiting.html", + "closed": "legacy/peer/oa_peer_closed.html", + "assessment": "legacy/peer/oa_peer_assessment.html", + "waiting": "legacy/peer/oa_peer_waiting.html", } diff --git a/openassessment/xblock/ui_mixins/legacy/self_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/self_assessments/views.py index a94c8b9374..c495df5b7d 100644 --- a/openassessment/xblock/ui_mixins/legacy/self_assessments/views.py +++ b/openassessment/xblock/ui_mixins/legacy/self_assessments/views.py @@ -9,11 +9,11 @@ logger = logging.getLogger(__name__) # pylint: disable=invalid-name template_paths = { - "unavailable": "openassessmentblock/self/oa_self_unavailable.html", - "cancelled": "openassessmentblock/self/oa_self_cancelled.html", - "complete": "openassessmentblock/self/oa_self_complete.html", - "closed": "openassessmentblock/self/oa_self_closed.html", - "assessment": "openassessmentblock/self/oa_self_assessment.html", + "unavailable": "legacy/self/oa_self_unavailable.html", + "cancelled": "legacy/self/oa_self_cancelled.html", + "complete": "legacy/self/oa_self_complete.html", + "closed": "legacy/self/oa_self_closed.html", + "assessment": "legacy/self/oa_self_assessment.html", } diff --git a/openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py index 46b90403e0..8a66cd45f5 100644 --- a/openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py +++ b/openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py @@ -22,7 +22,7 @@ def staff_path_and_context(api_data): """ Retrieve the correct template path and template context for the handler to render. """ - return "openassessmentblock/staff/oa_staff_grade.html", staff_context(api_data) + return "legacy/staff/oa_staff_grade.html", staff_context(api_data) def render_staff_assessment(api_data): diff --git a/openassessment/xblock/ui_mixins/legacy/student_training/views.py b/openassessment/xblock/ui_mixins/legacy/student_training/views.py index f16852a938..10102bb6a7 100644 --- a/openassessment/xblock/ui_mixins/legacy/student_training/views.py +++ b/openassessment/xblock/ui_mixins/legacy/student_training/views.py @@ -9,12 +9,12 @@ logger = logging.getLogger(__name__) # pylint: disable=invalid-name template_paths = { - "unavailable": "openassessmentblock/student_training/student_training_unavailable.html", - "cancelled": "openassessmentblock/student_training/student_training_cancelled.html", - "complete": "openassessmentblock/student_training/student_training_complete.html", - "closed": "openassessmentblock/student_training/student_training_closed.html", - "training": "openassessmentblock/student_training/student_training.html", - "error": "openassessmentblock/student_training/student_training_error.html", + "unavailable": "legacy/student_training/student_training_unavailable.html", + "cancelled": "legacy/student_training/student_training_cancelled.html", + "complete": "legacy/student_training/student_training_complete.html", + "closed": "legacy/student_training/student_training_closed.html", + "training": "legacy/student_training/student_training.html", + "error": "legacy/student_training/student_training_error.html", } diff --git a/openassessment/xblock/ui_mixins/legacy/submissions/views.py b/openassessment/xblock/ui_mixins/legacy/submissions/views.py index e33567279e..8119502f64 100644 --- a/openassessment/xblock/ui_mixins/legacy/submissions/views.py +++ b/openassessment/xblock/ui_mixins/legacy/submissions/views.py @@ -49,7 +49,7 @@ def get_submission_path(submission_info): """ # Template Paths - template_dir = "openassessmentblock/response" + template_dir = "legacy/response" submission_template_paths = { "default": "oa_response", "closed": "oa_response_closed", diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py new file mode 100644 index 0000000000..20650f8374 --- /dev/null +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -0,0 +1,15 @@ +""" +Serializer for assessments +""" +# pylint: disable=abstract-method + +from rest_framework.serializers import Serializer + + +class AssessmentResponseSerializer(Serializer): + """ + Given we want to load an assessment response, + gather the appropriate response and serialize. + + Data same shape as Submission, but coming from different sources. + """ diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index 374d627d74..978cf19701 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -4,8 +4,13 @@ XBlock handlers which surface info about an ORA, instead of being tied to views. """ from xblock.core import XBlock +from openassessment.xblock.ui_mixins.mfe.page_context_serializer import ( + PageDataSerializer, +) -from openassessment.xblock.ui_mixins.mfe.serializers import OraBlockInfoSerializer +from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import ( + OraBlockInfoSerializer, +) class MfeMixin: @@ -13,3 +18,15 @@ class MfeMixin: def get_block_info(self, data, suffix=""): # pylint: disable=unused-argument block_info = OraBlockInfoSerializer(self) return block_info.data + + @XBlock.json_handler + def get_block_learner_submission_data(self, data, suffix=""): # pylint: disable=unused-argument + serializer_context = {"view": "submission"} + page_context = PageDataSerializer(self, context=serializer_context) + return page_context.data + + @XBlock.json_handler + def get_block_learner_assessment_data(self, data, suffix=""): # pylint: disable=unused-argument + serializer_context = {"view": "assessment"} + page_context = PageDataSerializer(self, context=serializer_context) + return page_context.data diff --git a/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py b/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py new file mode 100644 index 0000000000..6ce4a6341e --- /dev/null +++ b/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py @@ -0,0 +1,223 @@ +""" +Serializers for ORA's BFF. + +These are the response shapes that power the MFE implementation of the ORA UI. +""" +# pylint: disable=abstract-method + +from rest_framework.serializers import ( + BooleanField, + DateTimeField, + IntegerField, + Serializer, + CharField, + ListField, + SerializerMethodField, +) + + +class CharListField(ListField): + child = CharField() + + +class IsRequiredField(BooleanField): + """ + Utility for checking if a field is "required" to reduce repeated code. + """ + + def to_representation(self, value): + return value == "required" + + +class TextResponseConfigSerializer(Serializer): + enabled = SerializerMethodField() + required = IsRequiredField(source="text_response") + editorType = CharField(source="text_response_editor") + allowLatexPreview = BooleanField(source="allow_latex") + + def get_enabled(self, block): + return block.text_response is not None + + +class FileResponseConfigSerializer(Serializer): + enabled = SerializerMethodField() + required = IsRequiredField(source="file_upload_response") + fileUploadLimit = SerializerMethodField() + allowedExtensions = CharListField(source="get_allowed_file_types_or_preset") + blockedExtensions = CharListField(source="FILE_EXT_BLACK_LIST") + fileTypeDescription = CharField(source="file_upload_type") + + def get_enabled(self, block): + return block.file_upload_response is not None + + def get_fileUploadLimit(self, block): + if not block.allow_multiple_files: + return 1 + return block.MAX_FILES_COUNT + + +class TeamsConfigSerializer(Serializer): + enabled = BooleanField(source="is_team_assignment") + teamsetName = SerializerMethodField() + + def get_teamsetName(self, block): + if block.teamset_config is not None: + return block.teamset_config.name + return None + + +class SubmissionConfigSerializer(Serializer): + startDatetime = DateTimeField(source="submission_start") + endDatetime = DateTimeField(source="submission_due") + + textResponseConfig = TextResponseConfigSerializer(source="*") + fileResponseConfig = FileResponseConfigSerializer(source="*") + + teamsConfig = TeamsConfigSerializer(source="*") + + +class RubricFeedbackConfigSerializer(Serializer): + description = CharField(source="rubric_feedback_prompt") # is this this field? + defaultText = CharField(source="rubric_feedback_default_text") + + +class RubricCriterionOptionSerializer(Serializer): + name = CharField() + label = CharField() + points = IntegerField() + description = CharField(source="explanation") + + +class RubricCriterionSerializer(Serializer): + name = CharField(source="label") + description = CharField(source="prompt") + feedbackEnabled = SerializerMethodField() + feedbackRequired = IsRequiredField(source="feedback") + options = RubricCriterionOptionSerializer(many=True) + + @staticmethod + def _feedback(criterion): + # Feedback is disabled as a default + return criterion.get("feedback", "disabled") + + def get_feedbackEnabled(self, criterion): + # Feedback can be specified as optional or required + return self._feedback(criterion) != "disabled" + + +class RubricConfigSerializer(Serializer): + showDuringResponse = BooleanField(source="show_rubric_during_response") + feedbackConfig = RubricFeedbackConfigSerializer(source="*") + criteria = RubricCriterionSerializer( + many=True, source="rubric_criteria_with_labels" + ) + + +class SelfSettingsSerializer(Serializer): + required = BooleanField(default=True) + + startTime = DateTimeField(source="start") + endTime = DateTimeField(source="due") + + +class PeerSettingsSerializer(Serializer): + required = BooleanField(default=True) + + startTime = DateTimeField(source="start") + endTime = DateTimeField(source="due") + + minNumberToGrade = IntegerField(source="must_grade") + minNumberToBeGradedBy = IntegerField(source="must_be_graded_by") + + enableFlexibleGrading = BooleanField( + source="enable_flexible_grading", required=False + ) + + +class AssessmentStepSettingsSerializer(Serializer): + """ + Generic Assessments step, where we just need to know if the step is + required given the ora.rubric_assessments source. + """ + + required = BooleanField(default=True) + + def _get_step(self, rubric_assessments, step_name): + """Get the assessment step config for a given step_name""" + for step in rubric_assessments: + if step["name"] == step_name: + return step + return None + + def __init__(self, *args, **kwargs): + self.step_name = kwargs.pop("step_name") + super().__init__(*args, **kwargs) + + def to_representation(self, instance): + assessment_step = self._get_step(instance, self.step_name) + + # Special handling for the peer step which includes extra fields + if assessment_step and self.step_name == "peer-assessment": + return PeerSettingsSerializer(assessment_step).data + elif assessment_step and self.step_name == "self-assessment": + return SelfSettingsSerializer(assessment_step).data + + # If we didn't find a step, it is not required + if assessment_step is None: + assessment_step = {"required": False} + + return super().to_representation(assessment_step) + + +class AssessmentStepsSettingsSerializer(Serializer): + training = AssessmentStepSettingsSerializer( + step_name="student-training", source="rubric_assessments" + ) + peer = AssessmentStepSettingsSerializer( + step_name="peer-assessment", source="rubric_assessments" + ) + # Workaround to allow reserved keyword in serializer key + vars()["self"] = AssessmentStepSettingsSerializer( + step_name="self-assessment", source="rubric_assessments" + ) + staff = AssessmentStepSettingsSerializer( + step_name="staff-assessment", source="rubric_assessments" + ) + + +class AssessmentStepsSerializer(Serializer): + order = SerializerMethodField() + settings = AssessmentStepsSettingsSerializer(source="*") + + def get_order(self, block): + return [step["name"] for step in block.rubric_assessments] + + +class LeaderboardConfigSerializer(Serializer): + enabled = SerializerMethodField() + numberOfEntries = IntegerField(source="leaderboard_show") + + def get_enabled(self, block): + return block.leaderboard_show > 0 + + +class OraBlockInfoSerializer(Serializer): + """ + Main serializer for statically-defined ORA Block information + """ + + title = CharField() + prompts = SerializerMethodField(source="*") + baseAssetUrl = SerializerMethodField(source="*") + + submissionConfig = SubmissionConfigSerializer(source="*") + assessmentSteps = AssessmentStepsSerializer(source="*") + rubricConfig = RubricConfigSerializer(source="*") + leaderboardConfig = LeaderboardConfigSerializer(source="*") + + def get_baseAssetUrl(self, block): + # pylint: disable=protected-access + return block.get_base_url_path_for_course_assets(block.course.id) + + def get_prompts(self, block): + return [prompt["description"] for prompt in block.prompts] diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py new file mode 100644 index 0000000000..370eb90acd --- /dev/null +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -0,0 +1,219 @@ +""" +Serializers for ORA's BFF. + +These are the response shapes that power the MFE implementation of the ORA UI. +""" +# pylint: disable=abstract-method + +from rest_framework.serializers import ( + BooleanField, + IntegerField, + Serializer, + SerializerMethodField, +) + +from openassessment.xblock.ui_mixins.mfe.assessment_serializers import ( + AssessmentResponseSerializer, +) +from openassessment.xblock.ui_mixins.mfe.submission_serializers import SubmissionSerializer + +from .ora_config_serializer import RubricConfigSerializer + + +class AssessmentScoreSerializer(Serializer): + """ + Returns: + { + earned: (Int) How many points were you awarded by peers? + possible: (Int) What was the max possible grade? + } + """ + + earned = IntegerField(source="points_earned", required=False) + possible = IntegerField(source="points_possible", required=False) + + +class ReceivedGradesSerializer(Serializer): + """ + Received grades for each of the applicable graded steps + Returns: + { + self: (Assessment score object) + peer: (Assessment score object) + staff: (Assessment score object) + } + """ + + self = AssessmentScoreSerializer(source="grades.self_score") + peer = AssessmentScoreSerializer(source="grades.peer_score") + staff = AssessmentScoreSerializer(source="grades.staff_score") + + def to_representation(self, instance): + """ + Hook output to remove steps that are not part of the assignment. + + Grades are not released for steps until all steps are completed. + """ + step_names = ["self", "peer", "staff"] + + # NOTE - cache this so we don't update the workflow + configured_steps = instance.status_details.keys() + is_done = instance.is_done + + for step in step_names: + if step not in configured_steps: + self.fields.pop(step) + + if not is_done: + return {field: {} for field in self.fields} + + return super().to_representation(instance) + + +class TrainingStepInfoSerializer(Serializer): + """ + Returns: + { + numberOfAssessmentsCompleted: (Int), progress through required assessments + expectedRubricSelections: (List of rubric names and selections) + } + """ + + numberOfAssessmentsCompleted = IntegerField(source="num_completed") + expectedRubricSelections = SerializerMethodField() + + def get_expectedRubricSelections(self, instance): + """ + Get expected rubric selections for Student Training step + + WARN: It is critical we do not hit this if we are not on the student + training step, as loading an example will create a workflow. + + Returns: List of criterion names and matched selections + [ + { + name: (String) Criterion name, + selection: (String) Option name that should be selected, + } + ] + """ + example = instance.example + + options_selected = [] + for criterion in example["options_selected"]: + criterion_selection = { + "name": criterion, + "selection": example["options_selected"][criterion], + } + options_selected.append(criterion_selection) + + return options_selected + + +class PeerStepInfoSerializer(Serializer): + """ + Returns: + { + numberOfAssessmentsCompleted: (Int) Progress through required assessments + isWaitingForSubmissions: (Bool) We've run out of peers to grade, waiting for more submissions + numberOfReceivedAssessments: (Int) How many assessments has this response received + } + """ + + numberOfAssessmentsCompleted = IntegerField(source="num_completed") + isWaitingForSubmissions = BooleanField(source="waiting_for_submissions_to_assess") + numberOfReceivedAssessments = IntegerField(source="num_received") + + +class ActiveStepInfoSerializer(Serializer): + """ + Required context: + * step - The active workflow step + + Returns: + * Peer or learner training-specific data if on those steps + * Empty dict for remaining steps + """ + + require_context = True + + def to_representation(self, instance): + """ + Hook output to remove fields that are not part of the active step. + """ + active_step = self.context["step"] + + if active_step == "training": + return TrainingStepInfoSerializer(instance.student_training_data).data + elif active_step == "peer": + return PeerStepInfoSerializer(instance.peer_assessment_data()).data + elif active_step in ("submission", "done"): + return {} + else: + raise Exception(f"Bad step name: {active_step}") # pylint: disable=broad-exception-raised + + +class ProgressSerializer(Serializer): + """ + Data about the progress of a user through their ORA workflow. + + Args: WorkflowAPI + + Returns: + { + // What step are we on? An index to the configuration from ORA config call. + activeStepName: (String) one of ["training", "peer", "self", "staff"] + + hasReceivedFinalGrade: (Bool) // In effect, is the ORA complete? + receivedGrades: (Object) Staff grade data, when there is a completed staff grade. + activeStepInfo: (Object) Specific info for the active step + } + """ + + activeStepName = SerializerMethodField() + hasReceivedFinalGrade = BooleanField(source="workflow_data.is_done") + receivedGrades = ReceivedGradesSerializer(source="workflow_data") + activeStepInfo = ActiveStepInfoSerializer(source="*") + + def get_activeStepName(self, instance): + """Return the active step name: one of 'submission""" + if not instance.workflow_data.has_workflow: + return "submission" + else: + return instance.workflow_data.status + + +class PageDataSerializer(Serializer): + """ + Data for rendering a page in the ORA MFE + + Requires context to differentiate between Assessment and Submission views + """ + + require_context = True + + progress = ProgressSerializer(source="*") + submission = SerializerMethodField() + rubric = RubricConfigSerializer(source="*") + + def to_representation(self, instance): + # Loading workflow status causes a workflow refresh + # ... limit this to one refresh per page call + active_step = instance.workflow_data.status or "submission" + + self.context.update({"step": active_step}) + return super().to_representation(instance) + + def get_submission(self, instance): + """ + Has the following different use-cases: + 1) In the "submission" view, we get the user's draft / complete submission. + 2) In the "assessment" view, we get an assessment for the current assessment step. + """ + + if self.context.get("view") == "submission": + return SubmissionSerializer(instance.submission_data).data + elif self.context.get("view") == "assessment": + return AssessmentResponseSerializer(instance.api_data, context=self.context).data + else: + raise Exception("Missing view context for page") # pylint: disable=broad-exception-raised diff --git a/openassessment/xblock/ui_mixins/mfe/serializers.py b/openassessment/xblock/ui_mixins/mfe/serializers.py index ddd3d243b2..6ce4a6341e 100644 --- a/openassessment/xblock/ui_mixins/mfe/serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/serializers.py @@ -217,9 +217,7 @@ class OraBlockInfoSerializer(Serializer): def get_baseAssetUrl(self, block): # pylint: disable=protected-access - return block.get_base_url_path_for_course_assets( - block.course.id - ) + return block.get_base_url_path_for_course_assets(block.course.id) def get_prompts(self, block): return [prompt["description"] for prompt in block.prompts] diff --git a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py new file mode 100644 index 0000000000..46ef67b650 --- /dev/null +++ b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py @@ -0,0 +1,29 @@ +""" +Submission-related serializers for ORA's BFF. + +These are the response shapes that power the MFE implementation of the ORA UI. +""" +# pylint: disable=abstract-method + +from rest_framework.serializers import ( + Serializer, +) + + +class SubmissionSerializer(Serializer): + """ + submission: (Object, can be empty) + { + // Status info + hasSubmitted: (Bool) + hasCancelled: (Bool) + hasReceivedGrade: (Bool) + + // Team info needed for team responses + // Empty object for individual submissions + teamInfo: (Object) + + // The actual response to view + response: (Object) + } + """ diff --git a/openassessment/xblock/ui_mixins/mfe/test_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_serializers.py index 52baca6441..559c209c00 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_serializers.py @@ -7,7 +7,7 @@ import ddt -from openassessment.xblock.ui_mixins.mfe.serializers import ( +from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import ( AssessmentStepsSerializer, LeaderboardConfigSerializer, RubricConfigSerializer, From c1c8c1bf80c28644d788b4af916dda60d69b3d40 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Tue, 26 Sep 2023 10:38:39 -0400 Subject: [PATCH 03/27] feat: Add logic to display the new ORA UI templates (#2054) * feat: xblock iframe * feat: conditional render of new views based on mobile or waffle * fix: merge conflicts * fix: leaderboard test * chore: formatting * fix: re-enable leaderboard * fix: lock leaderboard * fix: js lint and build * fix: pr-comments --- .../conf/locale/en/LC_MESSAGES/django.po | 75 ++-- .../conf/locale/en/LC_MESSAGES/djangojs.po | 192 +++++---- .../conf/locale/eo/LC_MESSAGES/django.po | 40 +- .../conf/locale/eo/LC_MESSAGES/djangojs.po | 192 +++++---- openassessment/templates/base.html | 104 ++++- openassessment/xblock/config_mixin.py | 9 + openassessment/xblock/openassessmentblock.py | 57 ++- .../xblock/static/dist/manifest.json | 8 +- .../dist/openassessment-editor-textarea.js | 2 +- .../dist/openassessment-editor-tinymce.js | 2 +- ...penassessment-lms.692d92a6c84a3a501206.css | 3 + ...penassessment-lms.692d92a6c84a3a501206.js} | 4 +- ...penassessment-lms.983dceadf8449ca82c4f.css | 3 + ...openassessment-lms.983dceadf8449ca82c4f.js | 376 ++++++++++++++++++ ...penassessment-lms.d876ac9af6fabe98df40.css | 3 - .../xblock/static/dist/openassessment-lms.js | 4 +- .../xblock/static/dist/openassessment-ltr.js | 2 +- .../xblock/static/dist/openassessment-rtl.js | 2 +- .../static/dist/openassessment-studio.js | 2 +- .../xblock/static/js/src/lms/oa_base.js | 31 +- .../xblock/test/test_leaderboard.py | 5 + .../xblock/test/test_openassessment.py | 10 + openassessment/xblock/test/test_staff_area.py | 1 + package-lock.json | 2 +- 24 files changed, 872 insertions(+), 257 deletions(-) create mode 100644 openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.css rename openassessment/xblock/static/dist/{openassessment-lms.d876ac9af6fabe98df40.js => openassessment-lms.692d92a6c84a3a501206.js} (99%) create mode 100644 openassessment/xblock/static/dist/openassessment-lms.983dceadf8449ca82c4f.css create mode 100644 openassessment/xblock/static/dist/openassessment-lms.983dceadf8449ca82c4f.js delete mode 100644 openassessment/xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.css diff --git a/openassessment/conf/locale/en/LC_MESSAGES/django.po b/openassessment/conf/locale/en/LC_MESSAGES/django.po index 6f3cced104..a42d04c55d 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-25 15:05+0000\n" +"POT-Creation-Date: 2023-09-25 18:28+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -142,6 +142,16 @@ msgstr "" msgid "No description provided." msgstr "" +#: templates/base.html:16 templates/legacy/oa_base.html:15 +msgid "" +"This assignment has several steps. In the first step, you'll provide a " +"response to the prompt. The other steps appear below the Your Response field." +msgstr "" + +#: templates/base.html:37 templates/legacy/oa_base.html:36 +msgid "Loading" +msgstr "" + #: templates/legacy/edit/oa_edit.html:28 msgid "Save" msgstr "" @@ -1075,8 +1085,8 @@ msgstr "" msgid "" "\n" " This is a team assignment for team-set \"%(teamset_name)s\".\n" -" You are currently not on a team in team-set \"%(teamset_name)s" -"\".\n" +" You are currently not on a team in team-set " +"\"%(teamset_name)s\".\n" " You must be on a team in team-set \"%(teamset_name)s\" to access " "this team assignment.\n" " " @@ -1110,16 +1120,6 @@ msgstr "" msgid "The instructions for this step could not be loaded." msgstr "" -#: templates/legacy/oa_base.html:15 -msgid "" -"This assignment has several steps. In the first step, you'll provide a " -"response to the prompt. The other steps appear below the Your Response field." -msgstr "" - -#: templates/legacy/oa_base.html:36 -msgid "Loading" -msgstr "" - #: templates/legacy/oa_latex_preview.html:6 msgid "Preview in LaTeX" msgstr "" @@ -1175,8 +1175,8 @@ msgid "" "\n" " \n" +"%(time_until)s)\" data-timezone=\"%(user_timezone)s\" data-" +"language=\"%(user_language)s\">\n" " " msgstr "" @@ -1187,8 +1187,8 @@ msgid "" "\n" " \n" +"%(time_until)s)\" data-timezone=\"%(user_timezone)s\" data-" +"language=\"%(user_language)s\">\n" " " msgstr "" @@ -1312,10 +1312,10 @@ msgstr "" #, python-format, python-brace-format msgid "" "\n" -" \n" +" \n" " " msgstr "" @@ -1324,10 +1324,10 @@ msgstr "" #, python-format, python-brace-format msgid "" "\n" -" \n" +" \n" " " msgstr "" @@ -1552,8 +1552,9 @@ msgstr "" #: templates/legacy/response/oa_response.html:314 msgid "" "\n" -" Learn more about team assignments here: (link)\n" " " msgstr "" @@ -1689,10 +1690,10 @@ msgstr "" #, python-format, python-brace-format msgid "" "\n" -" \n" +" \n" " " msgstr "" @@ -1701,10 +1702,10 @@ msgstr "" #, python-format, python-brace-format msgid "" "\n" -" \n" +" \n" " " msgstr "" @@ -2121,8 +2122,8 @@ msgid "" "\n" " \n" +"%(time_until)s)\" data-timezone=\"%(user_timezone)s\" data-" +"language=\"%(user_language)s\">\n" " " msgstr "" diff --git a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po index dd9c6181a3..57c203773a 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-25 15:05+0000\n" +"POT-Creation-Date: 2023-09-25 18:28+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -18,430 +18,456 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:77 xblock/static/js/src/oa_server.js:113 #: xblock/static/js/src/oa_server.js:137 msgid "This section could not be loaded." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:158 msgid "The staff assessment form could not be loaded." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:180 msgid "The display of ungraded and checked out responses could not be loaded." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:214 msgid "This response could not be submitted." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:237 msgid "Please check your internet connection." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:262 msgid "This feedback could not be submitted." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:287 xblock/static/js/src/oa_server.js:378 #: xblock/static/js/src/oa_server.js:401 msgid "This assessment could not be submitted." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:424 msgid "One or more rescheduling tasks failed." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:484 msgid "This problem could not be saved." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:505 msgid "The server could not be contacted." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:531 msgid "Could not retrieve upload url." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:550 xblock/static/js/src/oa_server.js:569 msgid "Server error." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:589 msgid "Could not retrieve download url." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:615 msgid "The submission could not be removed from the grading pool." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:671 msgid "Multiple teams returned for course" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:678 msgid "Could not load teams information." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:700 msgid "User lookup failed" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:705 msgid "Error when looking up username" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:8 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:8 #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js:1 #: xblock/static/js/src/oa_server.js:729 msgid "Failed to clone rubric" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 #: xblock/static/js/src/lms/oa_course_items_listing.js:61 msgid "View and grade responses" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 #: xblock/static/js/src/lms/oa_course_items_listing.js:61 msgid "Demo the new Grading Experience" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:97 msgid "Unit Name" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:98 msgid "Units" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:105 msgid "Assessment" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:106 msgid "Assessments" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:113 +#: xblock/static/js/src/lms/oa_course_items_listing.js:114 msgid "Total Responses" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:121 +#: xblock/static/js/src/lms/oa_course_items_listing.js:122 msgid "Training" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:129 +#: xblock/static/js/src/lms/oa_course_items_listing.js:130 msgid "Peer" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:137 +#: xblock/static/js/src/lms/oa_course_items_listing.js:138 msgid "Self" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:145 +#: xblock/static/js/src/lms/oa_course_items_listing.js:146 msgid "Waiting" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:153 +#: xblock/static/js/src/lms/oa_course_items_listing.js:154 msgid "Staff" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:161 +#: xblock/static/js/src/lms/oa_course_items_listing.js:162 msgid "Final Grade Received" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:169 msgid "Staff Grader" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:200 msgid "List of Open Assessments is unavailable" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:302 +#: xblock/static/js/src/lms/oa_course_items_listing.js:353 msgid "Please wait" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:326 msgid "Block view is unavailable" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:314 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:314 +#: xblock/static/js/src/lms/oa_course_items_listing.js:338 msgid "Back to Full List" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_confirmation_alert.js:5 msgid "Confirm" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_confirmation_alert.js:7 msgid "Cancel" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:253 msgid "" "There is still file upload in progress. Please wait until it is finished." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:243 msgid "Cannot submit empty response even everything is optional." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:235 msgid "Please upload a file." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:228 msgid "Please provide a response." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:328 msgid "No files selected for upload." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:335 msgid "Please provide a description for each file you are uploading." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:344 msgid "Your file has been deleted or path has been changed: " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:439 msgid "Saving draft" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:446 msgid "" "If you leave this page without saving or submitting your response, you will " "lose any work you have done on the response." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:461 msgid "Saving draft..." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:477 msgid "Draft saved!" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:490 msgid "Error" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:511 msgid "Confirm Submit Response" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:514 msgid "" "You're about to submit your response for this assignment. After you submit " "this response, you can't change it or submit a new response." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:589 msgid "Individual file size must be {max_files_mb}MB or less." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:603 msgid "" "File upload failed: unsupported file type. Only the supported file types can " "be uploaded. If you have questions, please reach out to the course team." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:614 msgid "The maximum number files that can be saved is " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:682 #: xblock/static/js/src/lms/oa_response.js:688 msgid "Describe " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:682 msgid "(required):" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:702 msgid "Thumbnail view of " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:779 msgid "Confirm Delete Uploaded File" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_response.js:804 msgid "" "Are you sure you want to delete the following file? It cannot be restored.\n" "File: " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_self.js:138 msgid "" "If you leave this page without submitting your self assessment, you will " "lose any work you have done." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_staff_area.js:143 #: xblock/static/js/src/lms/oa_staff_area.js:253 msgid "Unexpected server error." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_staff_area.js:147 msgid "You must provide a learner name." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_staff_area.js:214 msgid "" "This grade will be applied to all members of the team. Do you want to " "continue?" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_staff_area.js:218 msgid "Confirm Grade Team Submission" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_staff_area.js:304 msgid "Error getting the number of ungraded responses" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 +#: xblock/static/js/src/lms/oa_staff_area.js:538 msgid "" "If you leave this page without submitting your staff assessment, you will " "lose any work you have done." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_training.js:130 msgid "Feedback available for selection." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:369 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:369 #: xblock/static/js/src/lms/oa_peer.js:217 msgid "" "If you leave this page without submitting your peer assessment, you will " "lose any work you have done." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Refresh" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Username" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Peers Assessed" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Peer Responses Received" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Time Spent On Current Step" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Staff assessment" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Grade Status" msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "" "The \"{name}\" problem is configured to require a minimum of {min_grades} " "peer grades, and asks to review {min_graded} peers." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "" "There are currently {stuck_learners} learners in the waiting state, meaning " "they have not yet met all requirements for Peer Assessment. " msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "" "However, {overwritten_count} of these students have received a grade through " "the staff grade override tool already." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 msgid "Error while fetching student data." msgstr "" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js:375 +#: xblock/static/js/src/lms/oa_base.js:348 msgid "Unable to load" msgstr "" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/django.po b/openassessment/conf/locale/eo/LC_MESSAGES/django.po index 15226eb7fd..a5bd8f1946 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-06 21:24+0000\n" +"POT-Creation-Date: 2023-09-25 18:28+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -159,6 +159,25 @@ msgstr "Réspönsé Fïlés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" msgid "No description provided." msgstr "Nö désçrïptïön prövïdéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" +#: templates/base.html templates/legacy/oa_base.html +msgid "" +"This assignment has several steps. In the first step, you'll provide a " +"response to the prompt. The other steps appear below the Your Response " +"field." +msgstr "" +"Thïs ässïgnmént häs sévéräl stéps. Ìn thé fïrst stép, ýöü'll prövïdé ä " +"réspönsé tö thé prömpt. Thé öthér stéps äppéär ßélöw thé Ýöür Réspönsé " +"fïéld. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ " +"єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм" +" νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα " +"¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт" +" єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт " +"¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм#" + +#: templates/base.html templates/legacy/oa_base.html +msgid "Loading" +msgstr "Löädïng Ⱡ'σяєм ιρѕυм #" + #: templates/legacy/edit/oa_edit.html msgid "Save" msgstr "Sävé Ⱡ'σяєм ι#" @@ -1393,25 +1412,6 @@ msgstr "" "Thé ïnstrüçtïöns för thïs stép çöüld nöt ßé löädéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αмєт, ¢σηѕє¢тєтυя α#" -#: templates/legacy/oa_base.html -msgid "" -"This assignment has several steps. In the first step, you'll provide a " -"response to the prompt. The other steps appear below the Your Response " -"field." -msgstr "" -"Thïs ässïgnmént häs sévéräl stéps. Ìn thé fïrst stép, ýöü'll prövïdé ä " -"réspönsé tö thé prömpt. Thé öthér stéps äppéär ßélöw thé Ýöür Réspönsé " -"fïéld. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ " -"єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм" -" νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα " -"¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт" -" єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт " -"¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм#" - -#: templates/legacy/oa_base.html -msgid "Loading" -msgstr "Löädïng Ⱡ'σяєм ιρѕυм #" - #: templates/legacy/oa_latex_preview.html msgid "Preview in LaTeX" msgstr "Prévïéw ïn LäTéX Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po index ad5ccc3b7d..e3b7e409d0 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-25 15:05+0000\n" +"POT-Creation-Date: 2023-09-25 18:28+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js xblock/static/js/src/oa_server.js #: xblock/static/js/src/oa_server.js @@ -26,7 +26,7 @@ msgid "This section could not be loaded." msgstr "" "Thïs séçtïön çöüld nöt ßé löädéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "The staff assessment form could not be loaded." @@ -34,7 +34,7 @@ msgstr "" "Thé stäff ässéssmént förm çöüld nöt ßé löädéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "The display of ungraded and checked out responses could not be loaded." @@ -42,7 +42,7 @@ msgstr "" "Thé dïspläý öf üngrädéd änd çhéçkéd öüt réspönsés çöüld nöt ßé löädéd. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "This response could not be submitted." @@ -50,7 +50,7 @@ msgstr "" "Thïs réspönsé çöüld nöt ßé süßmïttéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Please check your internet connection." @@ -58,7 +58,7 @@ msgstr "" "Pléäsé çhéçk ýöür ïntérnét çönnéçtïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "This feedback could not be submitted." @@ -66,7 +66,7 @@ msgstr "" "Thïs féédßäçk çöüld nöt ßé süßmïttéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js xblock/static/js/src/oa_server.js #: xblock/static/js/src/oa_server.js @@ -75,7 +75,7 @@ msgstr "" "Thïs ässéssmént çöüld nöt ßé süßmïttéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "One or more rescheduling tasks failed." @@ -83,40 +83,40 @@ msgstr "" "Öné ör möré résçhédülïng täsks fäïléd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "This problem could not be saved." msgstr "" "Thïs prößlém çöüld nöt ßé sävéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "The server could not be contacted." msgstr "" "Thé sérvér çöüld nöt ßé çöntäçtéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Could not retrieve upload url." msgstr "Çöüld nöt rétrïévé üplöäd ürl. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js xblock/static/js/src/oa_server.js msgid "Server error." msgstr "Sérvér érrör. Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Could not retrieve download url." msgstr "" "Çöüld nöt rétrïévé döwnlöäd ürl. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "The submission could not be removed from the grading pool." @@ -124,125 +124,149 @@ msgstr "" "Thé süßmïssïön çöüld nöt ßé rémövéd fröm thé grädïng pööl. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Multiple teams returned for course" msgstr "" "Mültïplé téäms rétürnéd för çöürsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Could not load teams information." msgstr "" "Çöüld nöt löäd téäms ïnförmätïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "User lookup failed" msgstr "Ûsér lööküp fäïléd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Error when looking up username" msgstr "Érrör whén löökïng üp üsérnämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/dist/openassessment-studio.979e8b88dd0d9cee68f7.js #: xblock/static/js/src/oa_server.js msgid "Failed to clone rubric" msgstr "Fäïléd tö çlöné rüßrïç Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_course_items_listing.js msgid "View and grade responses" msgstr "Vïéw änd grädé réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Demo the new Grading Experience" msgstr "Démö thé néw Grädïng Éxpérïénçé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Unit Name" msgstr "Ûnït Nämé Ⱡ'σяєм ιρѕυм ∂σł#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Units" msgstr "Ûnïts Ⱡ'σяєм ιρѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Assessment" msgstr "Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Assessments" msgstr "Àsséssménts Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Total Responses" msgstr "Tötäl Réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Training" msgstr "Träïnïng Ⱡ'σяєм ιρѕυм ∂#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Peer" msgstr "Péér Ⱡ'σяєм ι#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Self" msgstr "Sélf Ⱡ'σяєм ι#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Waiting" msgstr "Wäïtïng Ⱡ'σяєм ιρѕυм #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Staff" msgstr "Stäff Ⱡ'σяєм ιρѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Final Grade Received" msgstr "Fïnäl Grädé Réçéïvéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Staff Grader" msgstr "Stäff Grädér Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "List of Open Assessments is unavailable" msgstr "" "Lïst öf Öpén Àsséssménts ïs ünäväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Please wait" msgstr "Pléäsé wäït Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Block view is unavailable" msgstr "Blöçk vïéw ïs ünäväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_course_items_listing.js msgid "Back to Full List" msgstr "Bäçk tö Füll Lïst Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_confirmation_alert.js msgid "Confirm" msgstr "Çönfïrm Ⱡ'σяєм ιρѕυм #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_confirmation_alert.js msgid "Cancel" msgstr "Çänçél Ⱡ'σяєм ιρѕυ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "" "There is still file upload in progress. Please wait until it is finished." @@ -250,48 +274,48 @@ msgstr "" "Théré ïs stïll fïlé üplöäd ïn prögréss. Pléäsé wäït üntïl ït ïs fïnïshéd. " "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Cannot submit empty response even everything is optional." msgstr "" "Çännöt süßmït émptý réspönsé évén évérýthïng ïs öptïönäl. Ⱡ'σяєм ιρѕυм ∂σłσя" " ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Please upload a file." msgstr "Pléäsé üplöäd ä fïlé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Please provide a response." msgstr "Pléäsé prövïdé ä réspönsé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "No files selected for upload." msgstr "Nö fïlés séléçtéd för üplöäd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Please provide a description for each file you are uploading." msgstr "" "Pléäsé prövïdé ä désçrïptïön för éäçh fïlé ýöü äré üplöädïng. Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Your file has been deleted or path has been changed: " msgstr "" "Ýöür fïlé häs ßéén délétéd ör päth häs ßéén çhängéd: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт" " αмєт, ¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Saving draft" msgstr "Sävïng dräft Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "" "If you leave this page without saving or submitting your response, you will " @@ -300,27 +324,27 @@ msgstr "" "Ìf ýöü léävé thïs pägé wïthöüt sävïng ör süßmïttïng ýöür réspönsé, ýöü wïll " "lösé äný wörk ýöü hävé döné ön thé réspönsé. Ⱡ'σяєм ιρѕυ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Saving draft..." msgstr "Sävïng dräft... Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Draft saved!" msgstr "Dräft sävéd! Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Error" msgstr "Érrör Ⱡ'σяєм ιρѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Confirm Submit Response" msgstr "Çönfïrm Süßmït Réspönsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "" "You're about to submit your response for this assignment. After you submit " @@ -335,14 +359,14 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт łαвσяυ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Individual file size must be {max_files_mb}MB or less." msgstr "" "Ìndïvïdüäl fïlé sïzé müst ßé {max_files_mb}MB ör léss. Ⱡ'σяєм ιρѕυм ∂σłσя " "ѕιт αмєт, ¢σηѕє¢тєтυя #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "" "File upload failed: unsupported file type. Only the supported file types can" @@ -357,35 +381,35 @@ msgstr "" "¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт " "ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηι#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "The maximum number files that can be saved is " msgstr "" "Thé mäxïmüm nümßér fïlés thät çän ßé sävéd ïs Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js #: xblock/static/js/src/lms/oa_response.js msgid "Describe " msgstr "Désçrïßé Ⱡ'σяєм ιρѕυм ∂σł#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "(required):" msgstr "(réqüïréd): Ⱡ'σяєм ιρѕυм ∂σłσя #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Thumbnail view of " msgstr "Thümßnäïl vïéw öf Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "Confirm Delete Uploaded File" msgstr "Çönfïrm Délété Ûplöädéd Fïlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_response.js msgid "" "Are you sure you want to delete the following file? It cannot be restored.\n" @@ -394,7 +418,7 @@ msgstr "" "Àré ýöü süré ýöü wänt tö délété thé föllöwïng fïlé? Ìt çännöt ßé réstöréd.\n" "Fïlé: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_self.js msgid "" "If you leave this page without submitting your self assessment, you will " @@ -403,19 +427,19 @@ msgstr "" "Ìf ýöü léävé thïs pägé wïthöüt süßmïttïng ýöür sélf ässéssmént, ýöü wïll " "lösé äný wörk ýöü hävé döné. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_staff_area.js #: xblock/static/js/src/lms/oa_staff_area.js msgid "Unexpected server error." msgstr "Ûnéxpéçtéd sérvér érrör. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_staff_area.js msgid "You must provide a learner name." msgstr "" "Ýöü müst prövïdé ä léärnér nämé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_staff_area.js msgid "" "This grade will be applied to all members of the team. Do you want to " @@ -424,19 +448,20 @@ msgstr "" "Thïs grädé wïll ßé äpplïéd tö äll mémßérs öf thé téäm. Dö ýöü wänt tö " "çöntïnüé? Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_staff_area.js msgid "Confirm Grade Team Submission" msgstr "Çönfïrm Grädé Téäm Süßmïssïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_staff_area.js msgid "Error getting the number of ungraded responses" msgstr "" "Érrör géttïng thé nümßér öf üngrädéd réspönsés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя α#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_staff_area.js msgid "" "If you leave this page without submitting your staff assessment, you will " "lose any work you have done." @@ -444,13 +469,13 @@ msgstr "" "Ìf ýöü léävé thïs pägé wïthöüt süßmïttïng ýöür stäff ässéssmént, ýöü wïll " "lösé äný wörk ýöü hävé döné. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_training.js msgid "Feedback available for selection." msgstr "" "Féédßäçk äväïläßlé för séléçtïön. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js #: xblock/static/js/src/lms/oa_peer.js msgid "" "If you leave this page without submitting your peer assessment, you will " @@ -459,35 +484,35 @@ msgstr "" "Ìf ýöü léävé thïs pägé wïthöüt süßmïttïng ýöür péér ässéssmént, ýöü wïll " "lösé äný wörk ýöü hävé döné. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Refresh" msgstr "Réfrésh Ⱡ'σяєм ιρѕυм #" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Username" msgstr "Ûsérnämé Ⱡ'σяєм ιρѕυм ∂#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Peers Assessed" msgstr "Péérs Àssésséd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Peer Responses Received" msgstr "Péér Réspönsés Réçéïvéd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Time Spent On Current Step" msgstr "Tïmé Spént Ön Çürrént Stép Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Staff assessment" msgstr "Stäff ässéssmént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Grade Status" msgstr "Grädé Stätüs Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "" "The \"{name}\" problem is configured to require a minimum of {min_grades} " "peer grades, and asks to review {min_graded} peers." @@ -496,7 +521,7 @@ msgstr "" "péér grädés, änd äsks tö révïéw {min_graded} péérs. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт " "αм#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "" "There are currently {stuck_learners} learners in the waiting state, meaning " "they have not yet met all requirements for Peer Assessment. " @@ -504,7 +529,7 @@ msgstr "" "Théré äré çürréntlý {stuck_learners} léärnérs ïn thé wäïtïng stäté, méänïng " "théý hävé nöt ýét mét äll réqüïréménts för Péér Àsséssmént. Ⱡ'σяєм ιρ#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "" "However, {overwritten_count} of these students have received a grade through" " the staff grade override tool already." @@ -512,12 +537,13 @@ msgstr "" "Höwévér, {overwritten_count} öf thésé stüdénts hävé réçéïvéd ä grädé thröügh" " thé stäff grädé övérrïdé tööl älréädý. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js msgid "Error while fetching student data." msgstr "" "Érrör whïlé fétçhïng stüdént dätä. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" -#: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +#: xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js +#: xblock/static/js/src/lms/oa_base.js msgid "Unable to load" msgstr "Ûnäßlé tö löäd Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#" diff --git a/openassessment/templates/base.html b/openassessment/templates/base.html index 355760ecf3..30ba3a2ab6 100644 --- a/openassessment/templates/base.html +++ b/openassessment/templates/base.html @@ -1,3 +1,101 @@ -
    -

    Hello world

    -
    \ No newline at end of file +{% load i18n %} +{% spaceless %} + +
    + +
    +
    + {% if title %} +

    {% trans title %}

    + {% endif %} + +
    + + {% block message %} +
    +
    +

    {% trans "This assignment has several steps. In the first step, you'll provide a response to the prompt. The other steps appear below the Your Response field." %}

    +
    +
    + {% endblock %} +
    + +
      + {% for assessment in rubric_assessments %} +
    1. +
      +

      + +

      + + + + {% trans "Loading" %} + + +
      +
    2. + {% endfor %} +
    + + {% if show_staff_area %} +
    + {% endif %} +
    +
    + + +
    + + {% if leaderboard_ui_model %} +
      +
    1. +
      +

      + +

      + + + + {% trans "Loading" %} + + +
      +
    2. +
    + {% endif %} +
    + {% if show_staff_area %} +
    + {% endif %} +
    +
    +
    +
    + +{% endspaceless %} diff --git a/openassessment/xblock/config_mixin.py b/openassessment/xblock/config_mixin.py index 1d0c820237..1d74a4a7ea 100644 --- a/openassessment/xblock/config_mixin.py +++ b/openassessment/xblock/config_mixin.py @@ -14,9 +14,11 @@ USER_STATE_UPLOAD_DATA = 'user_state_upload_data' RUBRIC_REUSE = 'rubric_reuse' ENHANCED_STAFF_GRADER = 'enhanced_staff_grader' +MFE_VIEWS = 'mfe_views' FEATURE_TOGGLES_BY_FLAG_NAME = { ALL_FILES_URLS: 'ENABLE_ORA_ALL_FILE_URLS', + MFE_VIEWS: 'ENABLE_ORA_MFE_VIEWS', TEAM_SUBMISSIONS: 'ENABLE_ORA_TEAM_SUBMISSIONS', USER_STATE_UPLOAD_DATA: 'ENABLE_ORA_USER_STATE_UPLOAD_DATA', RUBRIC_REUSE: 'ENABLE_ORA_RUBRIC_REUSE', @@ -89,6 +91,13 @@ def is_feature_enabled(self, flag): return False + @cached_property + def mfe_views_enabled(self): + """ + Returns a boolean specifying if mfe views are enabled. + """ + return self.is_feature_enabled(MFE_VIEWS) + @cached_property def team_submissions_enabled(self): """ diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index 9902f36034..c80f8ee0c8 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -524,6 +524,50 @@ def get_student_item_dict(self, anonymous_user_id=None): } return student_item_dict + @togglable_mobile_support + def author_view(self, context=None): # pylint: disable=unused-argument + """The main view of OpenAssessmentBlock, displayed when viewing courses. + + View which displays the legacy UI for authoring in Studio. + + Args: + context: Not used for this view. + + Returns: + (Fragment): The HTML Fragment for this XBlock, which determines the + general frame of the Open Ended Assessment Question. + """ + # On page load, update the workflow status. + # We need to do this here because peers may have graded us, in which + # case we may have a score available. + + try: + self.update_workflow_status() + except AssessmentWorkflowError: + # Log the exception, but continue loading the page + logger.exception('An error occurred while updating the workflow on page load.') + + ui_models = self._create_ui_models() + + leaderboard_model = None + for model in ui_models: + if model["name"] == "leaderboard": + leaderboard_model = model + + # All data we intend to pass to the front end. + context_dict = { + "mfe_views": False, + "leaderboard_modal": leaderboard_model, + "prompts": self.prompts, + "prompts_type": self.prompts_type, + "rubric_assessments": ui_models, + "show_staff_area": self.is_course_staff and not self.in_studio_preview, + "title": self.title, + "xblock_id": self.get_xblock_id(), + } + template = get_template("base.html") + return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') + @togglable_mobile_support def student_view(self, context=None): # pylint: disable=unused-argument """The main view of OpenAssessmentBlock, displayed when viewing courses. @@ -550,15 +594,24 @@ def student_view(self, context=None): # pylint: disable=unused-argument logger.exception('An error occurred while updating the workflow on page load.') ui_models = self._create_ui_models() + + leaderboard_model = None + for model in ui_models: + if model["name"] == "leaderboard": + leaderboard_model = model + # All data we intend to pass to the front end. context_dict = { - "title": self.title, + "leaderboard_modal": leaderboard_model, + "mfe_views": self.mfe_views_enabled, "prompts": self.prompts, "prompts_type": self.prompts_type, "rubric_assessments": ui_models, "show_staff_area": self.is_course_staff and not self.in_studio_preview, + "title": self.title, + "xblock_id": self.get_xblock_id(), } - template = get_template("legacy/oa_base.html") + template = get_template("base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') def ora_blocks_listing_view(self, context=None): diff --git a/openassessment/xblock/static/dist/manifest.json b/openassessment/xblock/static/dist/manifest.json index 63152e4411..402986fe65 100644 --- a/openassessment/xblock/static/dist/manifest.json +++ b/openassessment/xblock/static/dist/manifest.json @@ -4,10 +4,10 @@ "openassessment-editor-textarea.js.map": "/openassessment-editor-textarea.b8f866ba96a1d2ad92a4.js.map", "openassessment-editor-tinymce.js": "/openassessment-editor-tinymce.2cc0cab55c3be729265e.js", "openassessment-editor-tinymce.js.map": "/openassessment-editor-tinymce.2cc0cab55c3be729265e.js.map", - "openassessment-lms.css": "/openassessment-lms.d876ac9af6fabe98df40.css", - "openassessment-lms.js": "/openassessment-lms.d876ac9af6fabe98df40.js", - "openassessment-lms.css.map": "/openassessment-lms.d876ac9af6fabe98df40.css.map", - "openassessment-lms.js.map": "/openassessment-lms.d876ac9af6fabe98df40.js.map", + "openassessment-lms.css": "/openassessment-lms.983dceadf8449ca82c4f.css", + "openassessment-lms.js": "/openassessment-lms.983dceadf8449ca82c4f.js", + "openassessment-lms.css.map": "/openassessment-lms.983dceadf8449ca82c4f.css.map", + "openassessment-lms.js.map": "/openassessment-lms.983dceadf8449ca82c4f.js.map", "openassessment-ltr.css": "/openassessment-ltr.fd8409d820154aa22da8.css", "openassessment-ltr.js": "/openassessment-ltr.fd8409d820154aa22da8.js", "openassessment-ltr.css.map": "/openassessment-ltr.fd8409d820154aa22da8.css.map", diff --git a/openassessment/xblock/static/dist/openassessment-editor-textarea.js b/openassessment/xblock/static/dist/openassessment-editor-textarea.js index 4b9ab34a34..8730b06be0 100644 --- a/openassessment/xblock/static/dist/openassessment-editor-textarea.js +++ b/openassessment/xblock/static/dist/openassessment-editor-textarea.js @@ -63,7 +63,7 @@ /******/ /******/ var hotApplyOnUpdate = true; /******/ // eslint-disable-next-line no-unused-vars -/******/ var hotCurrentHash = "9f178f80778ef11c1723"; +/******/ var hotCurrentHash = "6b7b5c2e4e1e02ddf84d"; /******/ var hotRequestTimeout = 10000; /******/ var hotCurrentModuleData = {}; /******/ var hotCurrentChildModule; diff --git a/openassessment/xblock/static/dist/openassessment-editor-tinymce.js b/openassessment/xblock/static/dist/openassessment-editor-tinymce.js index 0dae526ebc..454a610a8f 100644 --- a/openassessment/xblock/static/dist/openassessment-editor-tinymce.js +++ b/openassessment/xblock/static/dist/openassessment-editor-tinymce.js @@ -63,7 +63,7 @@ /******/ /******/ var hotApplyOnUpdate = true; /******/ // eslint-disable-next-line no-unused-vars -/******/ var hotCurrentHash = "9f178f80778ef11c1723"; +/******/ var hotCurrentHash = "6b7b5c2e4e1e02ddf84d"; /******/ var hotRequestTimeout = 10000; /******/ var hotCurrentModuleData = {}; /******/ var hotCurrentChildModule; diff --git a/openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.css b/openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.css new file mode 100644 index 0000000000..27db8c50bf --- /dev/null +++ b/openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.css @@ -0,0 +1,3 @@ + + +/*# sourceMappingURL=openassessment-lms.692d92a6c84a3a501206.css.map*/ \ No newline at end of file diff --git a/openassessment/xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js b/openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js similarity index 99% rename from openassessment/xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js rename to openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js index 3920357c0d..2de52f7bc6 100644 --- a/openassessment/xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js +++ b/openassessment/xblock/static/dist/openassessment-lms.692d92a6c84a3a501206.js @@ -372,5 +372,5 @@ object-assign * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * Copyright 2022 Fonticons, Inc. */ -function Qu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Zu(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;)t+="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[62*Math.random()|0];return t}function Xd(e){for(var t=[],n=(e||[]).length>>>0;n--;)t[n]=e[n];return t}function Fd(e){return e.classList?Xd(e.classList):(e.getAttribute("class")||"").split(" ").filter((function(e){return e}))}function Ud(e){return"".concat(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function Vd(e){return Object.keys(e||{}).reduce((function(t,n){return t+"".concat(n,": ").concat(e[n].trim(),";")}),"")}function Gd(e){return e.size!==Hd.size||e.x!==Hd.x||e.y!==Hd.y||e.rotate!==Hd.rotate||e.flipX||e.flipY}function $d(){var e="svg-inline--fa",t=Wd.familyPrefix,n=Wd.replacementClass,r=':root, :host {\n --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Solid";\n --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Regular";\n --fa-font-light: normal 300 1em/1 "Font Awesome 6 Light";\n --fa-font-thin: normal 100 1em/1 "Font Awesome 6 Thin";\n --fa-font-duotone: normal 900 1em/1 "Font Awesome 6 Duotone";\n --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands";\n}\n\nsvg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {\n overflow: visible;\n box-sizing: content-box;\n}\n\n.svg-inline--fa {\n display: var(--fa-display, inline-block);\n height: 1em;\n overflow: visible;\n vertical-align: -0.125em;\n}\n.svg-inline--fa.fa-2xs {\n vertical-align: 0.1em;\n}\n.svg-inline--fa.fa-xs {\n vertical-align: 0em;\n}\n.svg-inline--fa.fa-sm {\n vertical-align: -0.0714285705em;\n}\n.svg-inline--fa.fa-lg {\n vertical-align: -0.2em;\n}\n.svg-inline--fa.fa-xl {\n vertical-align: -0.25em;\n}\n.svg-inline--fa.fa-2xl {\n vertical-align: -0.3125em;\n}\n.svg-inline--fa.fa-pull-left {\n margin-right: var(--fa-pull-margin, 0.3em);\n width: auto;\n}\n.svg-inline--fa.fa-pull-right {\n margin-left: var(--fa-pull-margin, 0.3em);\n width: auto;\n}\n.svg-inline--fa.fa-li {\n width: var(--fa-li-width, 2em);\n top: 0.25em;\n}\n.svg-inline--fa.fa-fw {\n width: var(--fa-fw-width, 1.25em);\n}\n\n.fa-layers svg.svg-inline--fa {\n bottom: 0;\n left: 0;\n margin: auto;\n position: absolute;\n right: 0;\n top: 0;\n}\n\n.fa-layers-counter, .fa-layers-text {\n display: inline-block;\n position: absolute;\n text-align: center;\n}\n\n.fa-layers {\n display: inline-block;\n height: 1em;\n position: relative;\n text-align: center;\n vertical-align: -0.125em;\n width: 1em;\n}\n.fa-layers svg.svg-inline--fa {\n -webkit-transform-origin: center center;\n transform-origin: center center;\n}\n\n.fa-layers-text {\n left: 50%;\n top: 50%;\n -webkit-transform: translate(-50%, -50%);\n transform: translate(-50%, -50%);\n -webkit-transform-origin: center center;\n transform-origin: center center;\n}\n\n.fa-layers-counter {\n background-color: var(--fa-counter-background-color, #ff253a);\n border-radius: var(--fa-counter-border-radius, 1em);\n box-sizing: border-box;\n color: var(--fa-inverse, #fff);\n line-height: var(--fa-counter-line-height, 1);\n max-width: var(--fa-counter-max-width, 5em);\n min-width: var(--fa-counter-min-width, 1.5em);\n overflow: hidden;\n padding: var(--fa-counter-padding, 0.25em 0.5em);\n right: var(--fa-right, 0);\n text-overflow: ellipsis;\n top: var(--fa-top, 0);\n -webkit-transform: scale(var(--fa-counter-scale, 0.25));\n transform: scale(var(--fa-counter-scale, 0.25));\n -webkit-transform-origin: top right;\n transform-origin: top right;\n}\n\n.fa-layers-bottom-right {\n bottom: var(--fa-bottom, 0);\n right: var(--fa-right, 0);\n top: auto;\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: bottom right;\n transform-origin: bottom right;\n}\n\n.fa-layers-bottom-left {\n bottom: var(--fa-bottom, 0);\n left: var(--fa-left, 0);\n right: auto;\n top: auto;\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: bottom left;\n transform-origin: bottom left;\n}\n\n.fa-layers-top-right {\n top: var(--fa-top, 0);\n right: var(--fa-right, 0);\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: top right;\n transform-origin: top right;\n}\n\n.fa-layers-top-left {\n left: var(--fa-left, 0);\n right: auto;\n top: var(--fa-top, 0);\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: top left;\n transform-origin: top left;\n}\n\n.fa-1x {\n font-size: 1em;\n}\n\n.fa-2x {\n font-size: 2em;\n}\n\n.fa-3x {\n font-size: 3em;\n}\n\n.fa-4x {\n font-size: 4em;\n}\n\n.fa-5x {\n font-size: 5em;\n}\n\n.fa-6x {\n font-size: 6em;\n}\n\n.fa-7x {\n font-size: 7em;\n}\n\n.fa-8x {\n font-size: 8em;\n}\n\n.fa-9x {\n font-size: 9em;\n}\n\n.fa-10x {\n font-size: 10em;\n}\n\n.fa-2xs {\n font-size: 0.625em;\n line-height: 0.1em;\n vertical-align: 0.225em;\n}\n\n.fa-xs {\n font-size: 0.75em;\n line-height: 0.0833333337em;\n vertical-align: 0.125em;\n}\n\n.fa-sm {\n font-size: 0.875em;\n line-height: 0.0714285718em;\n vertical-align: 0.0535714295em;\n}\n\n.fa-lg {\n font-size: 1.25em;\n line-height: 0.05em;\n vertical-align: -0.075em;\n}\n\n.fa-xl {\n font-size: 1.5em;\n line-height: 0.0416666682em;\n vertical-align: -0.125em;\n}\n\n.fa-2xl {\n font-size: 2em;\n line-height: 0.03125em;\n vertical-align: -0.1875em;\n}\n\n.fa-fw {\n text-align: center;\n width: 1.25em;\n}\n\n.fa-ul {\n list-style-type: none;\n margin-left: var(--fa-li-margin, 2.5em);\n padding-left: 0;\n}\n.fa-ul > li {\n position: relative;\n}\n\n.fa-li {\n left: calc(var(--fa-li-width, 2em) * -1);\n position: absolute;\n text-align: center;\n width: var(--fa-li-width, 2em);\n line-height: inherit;\n}\n\n.fa-border {\n border-color: var(--fa-border-color, #eee);\n border-radius: var(--fa-border-radius, 0.1em);\n border-style: var(--fa-border-style, solid);\n border-width: var(--fa-border-width, 0.08em);\n padding: var(--fa-border-padding, 0.2em 0.25em 0.15em);\n}\n\n.fa-pull-left {\n float: left;\n margin-right: var(--fa-pull-margin, 0.3em);\n}\n\n.fa-pull-right {\n float: right;\n margin-left: var(--fa-pull-margin, 0.3em);\n}\n\n.fa-beat {\n -webkit-animation-name: fa-beat;\n animation-name: fa-beat;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);\n animation-timing-function: var(--fa-animation-timing, ease-in-out);\n}\n\n.fa-bounce {\n -webkit-animation-name: fa-bounce;\n animation-name: fa-bounce;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));\n}\n\n.fa-fade {\n -webkit-animation-name: fa-fade;\n animation-name: fa-fade;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n}\n\n.fa-beat-fade {\n -webkit-animation-name: fa-beat-fade;\n animation-name: fa-beat-fade;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n}\n\n.fa-flip {\n -webkit-animation-name: fa-flip;\n animation-name: fa-flip;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);\n animation-timing-function: var(--fa-animation-timing, ease-in-out);\n}\n\n.fa-shake {\n -webkit-animation-name: fa-shake;\n animation-name: fa-shake;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, linear);\n animation-timing-function: var(--fa-animation-timing, linear);\n}\n\n.fa-spin {\n -webkit-animation-name: fa-spin;\n animation-name: fa-spin;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 2s);\n animation-duration: var(--fa-animation-duration, 2s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, linear);\n animation-timing-function: var(--fa-animation-timing, linear);\n}\n\n.fa-spin-reverse {\n --fa-animation-direction: reverse;\n}\n\n.fa-pulse,\n.fa-spin-pulse {\n -webkit-animation-name: fa-spin;\n animation-name: fa-spin;\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, steps(8));\n animation-timing-function: var(--fa-animation-timing, steps(8));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fa-beat,\n.fa-bounce,\n.fa-fade,\n.fa-beat-fade,\n.fa-flip,\n.fa-pulse,\n.fa-shake,\n.fa-spin,\n.fa-spin-pulse {\n -webkit-animation-delay: -1ms;\n animation-delay: -1ms;\n -webkit-animation-duration: 1ms;\n animation-duration: 1ms;\n -webkit-animation-iteration-count: 1;\n animation-iteration-count: 1;\n transition-delay: 0s;\n transition-duration: 0s;\n }\n}\n@-webkit-keyframes fa-beat {\n 0%, 90% {\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 45% {\n -webkit-transform: scale(var(--fa-beat-scale, 1.25));\n transform: scale(var(--fa-beat-scale, 1.25));\n }\n}\n@keyframes fa-beat {\n 0%, 90% {\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 45% {\n -webkit-transform: scale(var(--fa-beat-scale, 1.25));\n transform: scale(var(--fa-beat-scale, 1.25));\n }\n}\n@-webkit-keyframes fa-bounce {\n 0% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 10% {\n -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n }\n 30% {\n -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n }\n 50% {\n -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n }\n 57% {\n -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n }\n 64% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 100% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n}\n@keyframes fa-bounce {\n 0% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 10% {\n -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n }\n 30% {\n -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n }\n 50% {\n -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n }\n 57% {\n -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n }\n 64% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 100% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n}\n@-webkit-keyframes fa-fade {\n 50% {\n opacity: var(--fa-fade-opacity, 0.4);\n }\n}\n@keyframes fa-fade {\n 50% {\n opacity: var(--fa-fade-opacity, 0.4);\n }\n}\n@-webkit-keyframes fa-beat-fade {\n 0%, 100% {\n opacity: var(--fa-beat-fade-opacity, 0.4);\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));\n transform: scale(var(--fa-beat-fade-scale, 1.125));\n }\n}\n@keyframes fa-beat-fade {\n 0%, 100% {\n opacity: var(--fa-beat-fade-opacity, 0.4);\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));\n transform: scale(var(--fa-beat-fade-scale, 1.125));\n }\n}\n@-webkit-keyframes fa-flip {\n 50% {\n -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n }\n}\n@keyframes fa-flip {\n 50% {\n -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n }\n}\n@-webkit-keyframes fa-shake {\n 0% {\n -webkit-transform: rotate(-15deg);\n transform: rotate(-15deg);\n }\n 4% {\n -webkit-transform: rotate(15deg);\n transform: rotate(15deg);\n }\n 8%, 24% {\n -webkit-transform: rotate(-18deg);\n transform: rotate(-18deg);\n }\n 12%, 28% {\n -webkit-transform: rotate(18deg);\n transform: rotate(18deg);\n }\n 16% {\n -webkit-transform: rotate(-22deg);\n transform: rotate(-22deg);\n }\n 20% {\n -webkit-transform: rotate(22deg);\n transform: rotate(22deg);\n }\n 32% {\n -webkit-transform: rotate(-12deg);\n transform: rotate(-12deg);\n }\n 36% {\n -webkit-transform: rotate(12deg);\n transform: rotate(12deg);\n }\n 40%, 100% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n}\n@keyframes fa-shake {\n 0% {\n -webkit-transform: rotate(-15deg);\n transform: rotate(-15deg);\n }\n 4% {\n -webkit-transform: rotate(15deg);\n transform: rotate(15deg);\n }\n 8%, 24% {\n -webkit-transform: rotate(-18deg);\n transform: rotate(-18deg);\n }\n 12%, 28% {\n -webkit-transform: rotate(18deg);\n transform: rotate(18deg);\n }\n 16% {\n -webkit-transform: rotate(-22deg);\n transform: rotate(-22deg);\n }\n 20% {\n -webkit-transform: rotate(22deg);\n transform: rotate(22deg);\n }\n 32% {\n -webkit-transform: rotate(-12deg);\n transform: rotate(-12deg);\n }\n 36% {\n -webkit-transform: rotate(12deg);\n transform: rotate(12deg);\n }\n 40%, 100% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n}\n@-webkit-keyframes fa-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@keyframes fa-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.fa-rotate-90 {\n -webkit-transform: rotate(90deg);\n transform: rotate(90deg);\n}\n\n.fa-rotate-180 {\n -webkit-transform: rotate(180deg);\n transform: rotate(180deg);\n}\n\n.fa-rotate-270 {\n -webkit-transform: rotate(270deg);\n transform: rotate(270deg);\n}\n\n.fa-flip-horizontal {\n -webkit-transform: scale(-1, 1);\n transform: scale(-1, 1);\n}\n\n.fa-flip-vertical {\n -webkit-transform: scale(1, -1);\n transform: scale(1, -1);\n}\n\n.fa-flip-both,\n.fa-flip-horizontal.fa-flip-vertical {\n -webkit-transform: scale(-1, -1);\n transform: scale(-1, -1);\n}\n\n.fa-rotate-by {\n -webkit-transform: rotate(var(--fa-rotate-angle, none));\n transform: rotate(var(--fa-rotate-angle, none));\n}\n\n.fa-stack {\n display: inline-block;\n vertical-align: middle;\n height: 2em;\n position: relative;\n width: 2.5em;\n}\n\n.fa-stack-1x,\n.fa-stack-2x {\n bottom: 0;\n left: 0;\n margin: auto;\n position: absolute;\n right: 0;\n top: 0;\n z-index: var(--fa-stack-z-index, auto);\n}\n\n.svg-inline--fa.fa-stack-1x {\n height: 1em;\n width: 1.25em;\n}\n.svg-inline--fa.fa-stack-2x {\n height: 2em;\n width: 2.5em;\n}\n\n.fa-inverse {\n color: var(--fa-inverse, #fff);\n}\n\n.sr-only,\n.fa-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n.sr-only-focusable:not(:focus),\n.fa-sr-only-focusable:not(:focus) {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n.svg-inline--fa .fa-primary {\n fill: var(--fa-primary-color, currentColor);\n opacity: var(--fa-primary-opacity, 1);\n}\n\n.svg-inline--fa .fa-secondary {\n fill: var(--fa-secondary-color, currentColor);\n opacity: var(--fa-secondary-opacity, 0.4);\n}\n\n.svg-inline--fa.fa-swap-opacity .fa-primary {\n opacity: var(--fa-secondary-opacity, 0.4);\n}\n\n.svg-inline--fa.fa-swap-opacity .fa-secondary {\n opacity: var(--fa-primary-opacity, 1);\n}\n\n.svg-inline--fa mask .fa-primary,\n.svg-inline--fa mask .fa-secondary {\n fill: black;\n}\n\n.fad.fa-inverse,\n.fa-duotone.fa-inverse {\n color: var(--fa-inverse, #fff);\n}';if("fa"!==t||n!==e){var a=new RegExp("\\.".concat("fa","\\-"),"g"),i=new RegExp("\\--".concat("fa","\\-"),"g"),o=new RegExp("\\.".concat(e),"g");r=r.replace(a,".".concat(t,"-")).replace(i,"--".concat(t,"-")).replace(o,".".concat(n))}return r}var Jd=!1;function Kd(){Wd.autoAddCss&&!Jd&&(!function(e){if(e&&_d){var t=hd.createElement("style");t.setAttribute("type","text/css"),t.innerHTML=e;for(var n=hd.head.childNodes,r=null,a=n.length-1;a>-1;a--){var i=n[a],o=(i.tagName||"").toUpperCase();["STYLE","LINK"].indexOf(o)>-1&&(r=i)}hd.head.insertBefore(t,r)}}($d()),Jd=!0)}var Qd={mixout:function(){return{dom:{css:$d,insertCss:Kd}}},hooks:function(){return{beforeDOMElementCreation:function(){Kd()},beforeI2svg:function(){Kd()}}}},Zd=md||{};Zd.___FONT_AWESOME___||(Zd.___FONT_AWESOME___={}),Zd.___FONT_AWESOME___.styles||(Zd.___FONT_AWESOME___.styles={}),Zd.___FONT_AWESOME___.hooks||(Zd.___FONT_AWESOME___.hooks={}),Zd.___FONT_AWESOME___.shims||(Zd.___FONT_AWESOME___.shims=[]);var ef=Zd.___FONT_AWESOME___,tf=[],nf=!1;function rf(e){_d&&(nf?setTimeout(e,0):tf.push(e))}function af(e){var t=e.tag,n=e.attributes,r=void 0===n?{}:n,a=e.children,i=void 0===a?[]:a;return"string"==typeof e?Ud(e):"<".concat(t," ").concat(function(e){return Object.keys(e||{}).reduce((function(t,n){return t+"".concat(n,'="').concat(Ud(e[n]),'" ')}),"").trim()}(r),">").concat(i.map(af).join(""),"")}function of(e,t,n){if(e&&e[t]&&e[t][n])return{prefix:t,iconName:n,icon:e[t][n]}}_d&&((nf=(hd.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(hd.readyState))||hd.addEventListener("DOMContentLoaded",(function e(){hd.removeEventListener("DOMContentLoaded",e),nf=1,tf.map((function(e){return e()}))})));var sf=function(e,t,n,r){var a,i,o,s=Object.keys(e),c=s.length,l=void 0!==r?function(e,t){return function(n,r,a,i){return e.call(t,n,r,a,i)}}(t,r):t;for(void 0===n?(a=1,o=e[s[0]]):(a=0,o=n);a=55296&&a<=56319&&n2&&void 0!==arguments[2]?arguments[2]:{},r=n.skipHooks,a=void 0!==r&&r,i=lf(t);"function"!=typeof ef.hooks.addPack||a?ef.styles[e]=Zu(Zu({},ef.styles[e]||{}),i):ef.hooks.addPack(e,lf(t)),"fas"===e&&uf("fa",t)}var df=ef.styles,ff=ef.shims,pf=Object.values(Ad),mf=null,hf={},bf={},Mf={},_f={},gf={},yf=Object.keys(Ld);function vf(e,t){var n,r=t.split("-"),a=r[0],i=r.slice(1).join("-");return a!==e||""===i||(n=i,~Pd.indexOf(n))?null:i}var Lf,wf=function(){var e=function(e){return sf(df,(function(t,n,r){return t[r]=sf(n,e,{}),t}),{})};hf=e((function(e,t,n){(t[3]&&(e[t[3]]=n),t[2])&&t[2].filter((function(e){return"number"==typeof e})).forEach((function(t){e[t.toString(16)]=n}));return e})),bf=e((function(e,t,n){(e[n]=n,t[2])&&t[2].filter((function(e){return"string"==typeof e})).forEach((function(t){e[t]=n}));return e})),gf=e((function(e,t,n){var r=t[2];return e[n]=n,r.forEach((function(t){e[t]=n})),e}));var t="far"in df||Wd.autoFetchSvg,n=sf(ff,(function(e,n){var r=n[0],a=n[1],i=n[2];return"far"!==a||t||(a="fas"),"string"==typeof r&&(e.names[r]={prefix:a,iconName:i}),"number"==typeof r&&(e.unicodes[r.toString(16)]={prefix:a,iconName:i}),e}),{names:{},unicodes:{}});Mf=n.names,_f=n.unicodes,mf=Sf(Wd.styleDefault)};function Af(e,t){return(hf[e]||{})[t]}function Tf(e,t){return(gf[e]||{})[t]}function Of(e){return Mf[e]||{prefix:null,iconName:null}}function kf(){return mf}Lf=function(e){mf=Sf(e.styleDefault)},qd.push(Lf),wf();function Sf(e){var t=wd[e]||wd[Ld[e]],n=e in ef.styles?e:null;return t||n||null}function zf(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.skipLookups,r=void 0!==n&&n,a=null,i=e.reduce((function(e,t){var n=vf(Wd.familyPrefix,t);if(df[t]?(t=pf.includes(t)?Td[t]:t,a=t,e.prefix=t):yf.indexOf(t)>-1?(a=t,e.prefix=Sf(t)):n?e.iconName=n:t!==Wd.replacementClass&&e.rest.push(t),!r&&e.prefix&&e.iconName){var i="fa"===a?Of(e.iconName):{},o=Tf(e.prefix,e.iconName);i.prefix&&(a=null),e.iconName=i.iconName||o||e.iconName,e.prefix=i.prefix||e.prefix,"far"!==e.prefix||df.far||!df.fas||Wd.autoFetchSvg||(e.prefix="fas")}return e}),{prefix:null,iconName:null,rest:[]});return"fa"!==i.prefix&&"fa"!==a||(i.prefix=kf()||"fas"),i}var Ef=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.definitions={}}var t,n,r;return t=e,(n=[{key:"add",value:function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r0&&s.forEach((function(t){"string"==typeof t&&(e[a][t]=o)})),e[a][i]=o})),e}}])&&td(t.prototype,n),r&&td(t,r),Object.defineProperty(t,"prototype",{writable:!1}),e}(),Nf=[],xf={},Df={},Cf=Object.keys(Df);function Yf(e,t){for(var n=arguments.length,r=new Array(n>2?n-2:0),a=2;a1?t-1:0),r=1;r0&&void 0!==arguments[0]?arguments[0]:{};return _d?(Pf("beforeI2svg",e),jf("pseudoElements2svg",e),jf("i2svg",e)):Promise.reject("Operation requires a DOM of some kind.")},watch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.autoReplaceSvgRoot;!1===Wd.autoReplaceSvg&&(Wd.autoReplaceSvg=!0),Wd.observeMutations=!0,rf((function(){Hf({autoReplaceSvgRoot:t}),Pf("watch",e)}))}},Bf={noAuto:function(){Wd.autoReplaceSvg=!1,Wd.observeMutations=!1,Pf("noAuto")},config:Wd,dom:qf,parse:{icon:function(e){if(null===e)return null;if("object"===ed(e)&&e.prefix&&e.iconName)return{prefix:e.prefix,iconName:Tf(e.prefix,e.iconName)||e.iconName};if(Array.isArray(e)&&2===e.length){var t=0===e[1].indexOf("fa-")?e[1].slice(3):e[1],n=Sf(e[0]);return{prefix:n,iconName:Tf(n,t)||t}}if("string"==typeof e&&(e.indexOf("".concat(Wd.familyPrefix,"-"))>-1||e.match(Od))){var r=zf(e.split(" "),{skipLookups:!0});return{prefix:r.prefix||kf(),iconName:Tf(r.prefix,r.iconName)||r.iconName}}if("string"==typeof e){var a=kf();return{prefix:a,iconName:Tf(a,e)||e}}}},library:Wf,findIconDefinition:Rf,toHtml:af},Hf=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.autoReplaceSvgRoot,n=void 0===t?hd:t;(Object.keys(ef.styles).length>0||Wd.autoFetchSvg)&&_d&&Wd.autoReplaceSvg&&Bf.dom.i2svg({node:n})};function If(e,t){return Object.defineProperty(e,"abstract",{get:t}),Object.defineProperty(e,"html",{get:function(){return e.abstract.map((function(e){return af(e)}))}}),Object.defineProperty(e,"node",{get:function(){if(_d){var t=hd.createElement("div");return t.innerHTML=e.html,t.children}}}),e}function Xf(e){var t=e.icons,n=t.main,r=t.mask,a=e.prefix,i=e.iconName,o=e.transform,s=e.symbol,c=e.title,l=e.maskId,u=e.titleId,d=e.extra,f=e.watchable,p=void 0!==f&&f,m=r.found?r:n,h=m.width,b=m.height,M="fak"===a,_=[Wd.replacementClass,i?"".concat(Wd.familyPrefix,"-").concat(i):""].filter((function(e){return-1===d.classes.indexOf(e)})).filter((function(e){return""!==e||!!e})).concat(d.classes).join(" "),g={children:[],attributes:Zu(Zu({},d.attributes),{},{"data-prefix":a,"data-icon":i,class:_,role:d.attributes.role||"img",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 ".concat(h," ").concat(b)})},y=M&&!~d.classes.indexOf("fa-fw")?{width:"".concat(h/b*16*.0625,"em")}:{};p&&(g.attributes["data-fa-i2svg"]=""),c&&(g.children.push({tag:"title",attributes:{id:g.attributes["aria-labelledby"]||"title-".concat(u||Id())},children:[c]}),delete g.attributes.title);var v=Zu(Zu({},g),{},{prefix:a,iconName:i,main:n,mask:r,maskId:l,transform:o,symbol:s,styles:Zu(Zu({},y),d.styles)}),L=r.found&&n.found?jf("generateAbstractMask",v)||{children:[],attributes:{}}:jf("generateAbstractIcon",v)||{children:[],attributes:{}},w=L.children,A=L.attributes;return v.children=w,v.attributes=A,s?function(e){var t=e.prefix,n=e.iconName,r=e.children,a=e.attributes,i=e.symbol,o=!0===i?"".concat(t,"-").concat(Wd.familyPrefix,"-").concat(n):i;return[{tag:"svg",attributes:{style:"display: none;"},children:[{tag:"symbol",attributes:Zu(Zu({},a),{},{id:o}),children:r}]}]}(v):function(e){var t=e.children,n=e.main,r=e.mask,a=e.attributes,i=e.styles,o=e.transform;if(Gd(o)&&n.found&&!r.found){var s={x:n.width/n.height/2,y:.5};a.style=Vd(Zu(Zu({},i),{},{"transform-origin":"".concat(s.x+o.x/16,"em ").concat(s.y+o.y/16,"em")}))}return[{tag:"svg",attributes:a,children:t}]}(v)}function Ff(e){var t=e.content,n=e.width,r=e.height,a=e.transform,i=e.title,o=e.extra,s=e.watchable,c=void 0!==s&&s,l=Zu(Zu(Zu({},o.attributes),i?{title:i}:{}),{},{class:o.classes.join(" ")});c&&(l["data-fa-i2svg"]="");var u=Zu({},o.styles);Gd(a)&&(u.transform=function(e){var t=e.transform,n=e.width,r=void 0===n?16:n,a=e.height,i=void 0===a?16:a,o=e.startCentered,s=void 0!==o&&o,c="";return c+=s&&gd?"translate(".concat(t.x/Bd-r/2,"em, ").concat(t.y/Bd-i/2,"em) "):s?"translate(calc(-50% + ".concat(t.x/Bd,"em), calc(-50% + ").concat(t.y/Bd,"em)) "):"translate(".concat(t.x/Bd,"em, ").concat(t.y/Bd,"em) "),c+="scale(".concat(t.size/Bd*(t.flipX?-1:1),", ").concat(t.size/Bd*(t.flipY?-1:1),") "),c+="rotate(".concat(t.rotate,"deg) ")}({transform:a,startCentered:!0,width:n,height:r}),u["-webkit-transform"]=u.transform);var d=Vd(u);d.length>0&&(l.style=d);var f=[];return f.push({tag:"span",attributes:l,children:[t]}),i&&f.push({tag:"span",attributes:{class:"sr-only"},children:[i]}),f}function Uf(e){var t=e.content,n=e.title,r=e.extra,a=Zu(Zu(Zu({},r.attributes),n?{title:n}:{}),{},{class:r.classes.join(" ")}),i=Vd(r.styles);i.length>0&&(a.style=i);var o=[];return o.push({tag:"span",attributes:a,children:[t]}),n&&o.push({tag:"span",attributes:{class:"sr-only"},children:[n]}),o}var Vf=ef.styles;function Gf(e){var t=e[0],n=e[1],r=rd(e.slice(4),1)[0];return{found:!0,width:t,height:n,icon:Array.isArray(r)?{tag:"g",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(xd)},children:[{tag:"path",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(Yd),fill:"currentColor",d:r[0]}},{tag:"path",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(Cd),fill:"currentColor",d:r[1]}}]}:{tag:"path",attributes:{fill:"currentColor",d:r}}}}var $f={found:!1,width:512,height:512};function Jf(e,t){var n=t;return"fa"===t&&null!==Wd.styleDefault&&(t=kf()),new Promise((function(r,a){jf("missingIconAbstract");if("fa"===n){var i=Of(e)||{};e=i.iconName||e,t=i.prefix||t}if(e&&t&&Vf[t]&&Vf[t][e])return r(Gf(Vf[t][e]));!function(e,t){vd||Wd.showMissingIcons||!e||console.error('Icon with name "'.concat(e,'" and prefix "').concat(t,'" is missing.'))}(e,t),r(Zu(Zu({},$f),{},{icon:Wd.showMissingIcons&&e&&jf("missingIconAbstract")||{}}))}))}var Kf=function(){},Qf=Wd.measurePerformance&&Md&&Md.mark&&Md.measure?Md:{mark:Kf,measure:Kf},Zf=function(e){Qf.mark("".concat('FA "6.1.2"'," ").concat(e," ends")),Qf.measure("".concat('FA "6.1.2"'," ").concat(e),"".concat('FA "6.1.2"'," ").concat(e," begins"),"".concat('FA "6.1.2"'," ").concat(e," ends"))},ep=function(e){return Qf.mark("".concat('FA "6.1.2"'," ").concat(e," begins")),function(){return Zf(e)}},tp=function(){};function np(e){return"string"==typeof(e.getAttribute?e.getAttribute("data-fa-i2svg"):null)}function rp(e){return hd.createElementNS("http://www.w3.org/2000/svg",e)}function ap(e){return hd.createElement(e)}var ip={replace:function(e){var t=e[0];if(t.parentNode)if(e[1].forEach((function(e){t.parentNode.insertBefore(function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.ceFn,a=void 0===r?"svg"===t.tag?rp:ap:r;if("string"==typeof t)return hd.createTextNode(t);var i=a(t.tag);Object.keys(t.attributes||[]).forEach((function(e){i.setAttribute(e,t.attributes[e])}));var o=t.children||[];return o.forEach((function(t){i.appendChild(e(t,{ceFn:a}))})),i}(e),t)})),null===t.getAttribute("data-fa-i2svg")&&Wd.keepOriginalSource){var n=hd.createComment(function(e){var t=" ".concat(e.outerHTML," ");return t="".concat(t,"Font Awesome fontawesome.com ")}(t));t.parentNode.replaceChild(n,t)}else t.remove()},nest:function(e){var t=e[0],n=e[1];if(~Fd(t).indexOf(Wd.replacementClass))return ip.replace(e);var r=new RegExp("".concat(Wd.familyPrefix,"-.*"));if(delete n[0].attributes.id,n[0].attributes.class){var a=n[0].attributes.class.split(" ").reduce((function(e,t){return t===Wd.replacementClass||t.match(r)?e.toSvg.push(t):e.toNode.push(t),e}),{toNode:[],toSvg:[]});n[0].attributes.class=a.toSvg.join(" "),0===a.toNode.length?t.removeAttribute("class"):t.setAttribute("class",a.toNode.join(" "))}var i=n.map((function(e){return af(e)})).join("\n");t.setAttribute("data-fa-i2svg",""),t.innerHTML=i}};function op(e){e()}function sp(e,t){var n="function"==typeof t?t:tp;if(0===e.length)n();else{var r=op;"async"===Wd.mutateApproach&&(r=md.requestAnimationFrame||op),r((function(){var t=!0===Wd.autoReplaceSvg?ip.replace:ip[Wd.autoReplaceSvg]||ip.replace,r=ep("mutate");e.map(t),r(),n()}))}}var cp=!1;function lp(){cp=!0}function up(){cp=!1}var dp=null;function fp(e){if(bd&&Wd.observeMutations){var t=e.treeCallback,n=void 0===t?tp:t,r=e.nodeCallback,a=void 0===r?tp:r,i=e.pseudoElementsCallback,o=void 0===i?tp:i,s=e.observeMutationsRoot,c=void 0===s?hd:s;dp=new bd((function(e){if(!cp){var t=kf();Xd(e).forEach((function(e){if("childList"===e.type&&e.addedNodes.length>0&&!np(e.addedNodes[0])&&(Wd.searchPseudoElements&&o(e.target),n(e.target)),"attributes"===e.type&&e.target.parentNode&&Wd.searchPseudoElements&&o(e.target.parentNode),"attributes"===e.type&&np(e.target)&&~Nd.indexOf(e.attributeName))if("class"===e.attributeName&&function(e){var t=e.getAttribute?e.getAttribute("data-prefix"):null,n=e.getAttribute?e.getAttribute("data-icon"):null;return t&&n}(e.target)){var r=zf(Fd(e.target)),i=r.prefix,s=r.iconName;e.target.setAttribute("data-prefix",i||t),s&&e.target.setAttribute("data-icon",s)}else(c=e.target)&&c.classList&&c.classList.contains&&c.classList.contains(Wd.replacementClass)&&a(e.target);var c}))}})),_d&&dp.observe(c,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}}function pp(e){var t=e.getAttribute("style"),n=[];return t&&(n=t.split(";").reduce((function(e,t){var n=t.split(":"),r=n[0],a=n.slice(1);return r&&a.length>0&&(e[r]=a.join(":").trim()),e}),{})),n}function mp(e){var t,n,r=e.getAttribute("data-prefix"),a=e.getAttribute("data-icon"),i=void 0!==e.innerText?e.innerText.trim():"",o=zf(Fd(e));return o.prefix||(o.prefix=kf()),r&&a&&(o.prefix=r,o.iconName=a),o.iconName&&o.prefix||(o.prefix&&i.length>0&&(o.iconName=(t=o.prefix,n=e.innerText,(bf[t]||{})[n]||Af(o.prefix,cf(e.innerText)))),!o.iconName&&Wd.autoFetchSvg&&e.firstChild&&e.firstChild.nodeType===Node.TEXT_NODE&&(o.iconName=e.firstChild.data)),o}function hp(e){var t=Xd(e.attributes).reduce((function(e,t){return"class"!==e.name&&"style"!==e.name&&(e[t.name]=t.value),e}),{}),n=e.getAttribute("title"),r=e.getAttribute("data-fa-title-id");return Wd.autoA11y&&(n?t["aria-labelledby"]="".concat(Wd.replacementClass,"-title-").concat(r||Id()):(t["aria-hidden"]="true",t.focusable="false")),t}function bp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{styleParser:!0},n=mp(e),r=n.iconName,a=n.prefix,i=n.rest,o=hp(e),s=Yf("parseNodeAttributes",{},e),c=t.styleParser?pp(e):[];return Zu({iconName:r,title:e.getAttribute("title"),titleId:e.getAttribute("data-fa-title-id"),prefix:a,transform:Hd,mask:{iconName:null,prefix:null,rest:[]},maskId:null,symbol:!1,extra:{classes:i,styles:c,attributes:o}},s)}var Mp=ef.styles;function _p(e){var t="nest"===Wd.autoReplaceSvg?bp(e,{styleParser:!1}):bp(e);return~t.extra.classes.indexOf("fa-layers-text")?jf("generateLayersText",e,t):jf("generateSvgReplacementMutation",e,t)}function gp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!_d)return Promise.resolve();var n=hd.documentElement.classList,r=function(e){return n.add("".concat("fontawesome-i2svg","-").concat(e))},a=function(e){return n.remove("".concat("fontawesome-i2svg","-").concat(e))},i=Wd.autoFetchSvg?Object.keys(Ld):Object.keys(Mp);i.includes("fa")||i.push("fa");var o=[".".concat("fa-layers-text",":not([").concat("data-fa-i2svg","])")].concat(i.map((function(e){return".".concat(e,":not([").concat("data-fa-i2svg","])")}))).join(", ");if(0===o.length)return Promise.resolve();var s=[];try{s=Xd(e.querySelectorAll(o))}catch(e){}if(!(s.length>0))return Promise.resolve();r("pending"),a("complete");var c=ep("onTree"),l=s.reduce((function(e,t){try{var n=_p(t);n&&e.push(n)}catch(e){vd||"MissingIcon"===e.name&&console.error(e)}return e}),[]);return new Promise((function(e,n){Promise.all(l).then((function(n){sp(n,(function(){r("active"),r("complete"),a("pending"),"function"==typeof t&&t(),c(),e()}))})).catch((function(e){c(),n(e)}))}))}function yp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;_p(e).then((function(e){e&&sp([e],t)}))}var vp=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.transform,r=void 0===n?Hd:n,a=t.symbol,i=void 0!==a&&a,o=t.mask,s=void 0===o?null:o,c=t.maskId,l=void 0===c?null:c,u=t.title,d=void 0===u?null:u,f=t.titleId,p=void 0===f?null:f,m=t.classes,h=void 0===m?[]:m,b=t.attributes,M=void 0===b?{}:b,_=t.styles,g=void 0===_?{}:_;if(e){var y=e.prefix,v=e.iconName,L=e.icon;return If(Zu({type:"icon"},e),(function(){return Pf("beforeDOMElementCreation",{iconDefinition:e,params:t}),Wd.autoA11y&&(d?M["aria-labelledby"]="".concat(Wd.replacementClass,"-title-").concat(p||Id()):(M["aria-hidden"]="true",M.focusable="false")),Xf({icons:{main:Gf(L),mask:s?Gf(s.icon):{found:!1,width:null,height:null,icon:{}}},prefix:y,iconName:v,transform:Zu(Zu({},Hd),r),symbol:i,title:d,maskId:l,titleId:p,extra:{attributes:M,styles:g,classes:h}})}))}},Lp={mixout:function(){return{icon:(e=vp,function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(t||{}).icon?t:Rf(t||{}),a=n.mask;return a&&(a=(a||{}).icon?a:Rf(a||{})),e(r,Zu(Zu({},n),{},{mask:a}))})};var e},hooks:function(){return{mutationObserverCallbacks:function(e){return e.treeCallback=gp,e.nodeCallback=yp,e}}},provides:function(e){e.i2svg=function(e){var t=e.node,n=void 0===t?hd:t,r=e.callback;return gp(n,void 0===r?function(){}:r)},e.generateSvgReplacementMutation=function(e,t){var n=t.iconName,r=t.title,a=t.titleId,i=t.prefix,o=t.transform,s=t.symbol,c=t.mask,l=t.maskId,u=t.extra;return new Promise((function(t,d){Promise.all([Jf(n,i),c.iconName?Jf(c.iconName,c.prefix):Promise.resolve({found:!1,width:512,height:512,icon:{}})]).then((function(c){var d=rd(c,2),f=d[0],p=d[1];t([e,Xf({icons:{main:f,mask:p},prefix:i,iconName:n,transform:o,symbol:s,maskId:l,title:r,titleId:a,extra:u,watchable:!0})])})).catch(d)}))},e.generateAbstractIcon=function(e){var t,n=e.children,r=e.attributes,a=e.main,i=e.transform,o=Vd(e.styles);return o.length>0&&(r.style=o),Gd(i)&&(t=jf("generateAbstractTransformGrouping",{main:a,transform:i,containerWidth:a.width,iconWidth:a.width})),n.push(t||a.icon),{children:n,attributes:r}}}},wp={mixout:function(){return{layer:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.classes,r=void 0===n?[]:n;return If({type:"layer"},(function(){Pf("beforeDOMElementCreation",{assembler:e,params:t});var n=[];return e((function(e){Array.isArray(e)?e.map((function(e){n=n.concat(e.abstract)})):n=n.concat(e.abstract)})),[{tag:"span",attributes:{class:["".concat(Wd.familyPrefix,"-layers")].concat(ad(r)).join(" ")},children:n}]}))}}}},Ap={mixout:function(){return{counter:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.title,r=void 0===n?null:n,a=t.classes,i=void 0===a?[]:a,o=t.attributes,s=void 0===o?{}:o,c=t.styles,l=void 0===c?{}:c;return If({type:"counter",content:e},(function(){return Pf("beforeDOMElementCreation",{content:e,params:t}),Uf({content:e.toString(),title:r,extra:{attributes:s,styles:l,classes:["".concat(Wd.familyPrefix,"-layers-counter")].concat(ad(i))}})}))}}}},Tp={mixout:function(){return{text:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.transform,r=void 0===n?Hd:n,a=t.title,i=void 0===a?null:a,o=t.classes,s=void 0===o?[]:o,c=t.attributes,l=void 0===c?{}:c,u=t.styles,d=void 0===u?{}:u;return If({type:"text",content:e},(function(){return Pf("beforeDOMElementCreation",{content:e,params:t}),Ff({content:e,transform:Zu(Zu({},Hd),r),title:i,extra:{attributes:l,styles:d,classes:["".concat(Wd.familyPrefix,"-layers-text")].concat(ad(s))}})}))}}},provides:function(e){e.generateLayersText=function(e,t){var n=t.title,r=t.transform,a=t.extra,i=null,o=null;if(gd){var s=parseInt(getComputedStyle(e).fontSize,10),c=e.getBoundingClientRect();i=c.width/s,o=c.height/s}return Wd.autoA11y&&!n&&(a.attributes["aria-hidden"]="true"),Promise.resolve([e,Ff({content:e.innerHTML,width:i,height:o,transform:r,title:n,extra:a,watchable:!0})])}}},Op=new RegExp('"',"ug"),kp=[1105920,1112319];function Sp(e,t){var n="".concat("data-fa-pseudo-element-pending").concat(t.replace(":","-"));return new Promise((function(r,a){if(null!==e.getAttribute(n))return r();var i,o,s,c=Xd(e.children).filter((function(e){return e.getAttribute("data-fa-pseudo-element")===t}))[0],l=md.getComputedStyle(e,t),u=l.getPropertyValue("font-family").match(kd),d=l.getPropertyValue("font-weight"),f=l.getPropertyValue("content");if(c&&!u)return e.removeChild(c),r();if(u&&"none"!==f&&""!==f){var p=l.getPropertyValue("content"),m=~["Solid","Regular","Light","Thin","Duotone","Brands","Kit"].indexOf(u[2])?wd[u[2].toLowerCase()]:Sd[d],h=function(e){var t,n,r,a,i,o=e.replace(Op,""),s=(n=0,a=(t=o).length,(i=t.charCodeAt(n))>=55296&&i<=56319&&a>n+1&&(r=t.charCodeAt(n+1))>=56320&&r<=57343?1024*(i-55296)+r-56320+65536:i),c=s>=kp[0]&&s<=kp[1],l=2===o.length&&o[0]===o[1];return{value:cf(l?o[0]:o),isSecondary:c||l}}(p),b=h.value,M=h.isSecondary,_=u[0].startsWith("FontAwesome"),g=Af(m,b),y=g;if(_){var v=(o=_f[i=b],s=Af("fas",i),o||(s?{prefix:"fas",iconName:s}:null)||{prefix:null,iconName:null});v.iconName&&v.prefix&&(g=v.iconName,m=v.prefix)}if(!g||M||c&&c.getAttribute("data-prefix")===m&&c.getAttribute("data-icon")===y)r();else{e.setAttribute(n,y),c&&e.removeChild(c);var L={iconName:null,title:null,titleId:null,prefix:null,transform:Hd,symbol:!1,mask:{iconName:null,prefix:null,rest:[]},maskId:null,extra:{classes:[],styles:{},attributes:{}}},w=L.extra;w.attributes["data-fa-pseudo-element"]=t,Jf(g,m).then((function(a){var i=Xf(Zu(Zu({},L),{},{icons:{main:a,mask:{prefix:null,iconName:null,rest:[]}},prefix:m,iconName:y,extra:w,watchable:!0})),o=hd.createElement("svg");"::before"===t?e.insertBefore(o,e.firstChild):e.appendChild(o),o.outerHTML=i.map((function(e){return af(e)})).join("\n"),e.removeAttribute(n),r()})).catch(a)}}else r()}))}function zp(e){return Promise.all([Sp(e,"::before"),Sp(e,"::after")])}function Ep(e){return!(e.parentNode===document.head||~yd.indexOf(e.tagName.toUpperCase())||e.getAttribute("data-fa-pseudo-element")||e.parentNode&&"svg"===e.parentNode.tagName)}function Np(e){if(_d)return new Promise((function(t,n){var r=Xd(e.querySelectorAll("*")).filter(Ep).map(zp),a=ep("searchPseudoElements");lp(),Promise.all(r).then((function(){a(),up(),t()})).catch((function(){a(),up(),n()}))}))}var xp=!1,Dp=function(e){return e.toLowerCase().split(" ").reduce((function(e,t){var n=t.toLowerCase().split("-"),r=n[0],a=n.slice(1).join("-");if(r&&"h"===a)return e.flipX=!0,e;if(r&&"v"===a)return e.flipY=!0,e;if(a=parseFloat(a),isNaN(a))return e;switch(r){case"grow":e.size=e.size+a;break;case"shrink":e.size=e.size-a;break;case"left":e.x=e.x-a;break;case"right":e.x=e.x+a;break;case"up":e.y=e.y-a;break;case"down":e.y=e.y+a;break;case"rotate":e.rotate=e.rotate+a}return e}),{size:16,x:0,y:0,flipX:!1,flipY:!1,rotate:0})},Cp={mixout:function(){return{parse:{transform:function(e){return Dp(e)}}}},hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-transform");return n&&(e.transform=Dp(n)),e}}},provides:function(e){e.generateAbstractTransformGrouping=function(e){var t=e.main,n=e.transform,r=e.containerWidth,a=e.iconWidth,i={transform:"translate(".concat(r/2," 256)")},o="translate(".concat(32*n.x,", ").concat(32*n.y,") "),s="scale(".concat(n.size/16*(n.flipX?-1:1),", ").concat(n.size/16*(n.flipY?-1:1),") "),c="rotate(".concat(n.rotate," 0 0)"),l={outer:i,inner:{transform:"".concat(o," ").concat(s," ").concat(c)},path:{transform:"translate(".concat(a/2*-1," -256)")}};return{tag:"g",attributes:Zu({},l.outer),children:[{tag:"g",attributes:Zu({},l.inner),children:[{tag:t.icon.tag,children:t.icon.children,attributes:Zu(Zu({},t.icon.attributes),l.path)}]}]}}}},Yp={x:0,y:0,width:"100%",height:"100%"};function Pp(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e.attributes&&(e.attributes.fill||t)&&(e.attributes.fill="black"),e}var jp,Rp={hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-mask"),r=n?zf(n.split(" ").map((function(e){return e.trim()}))):{prefix:null,iconName:null,rest:[]};return r.prefix||(r.prefix=kf()),e.mask=r,e.maskId=t.getAttribute("data-fa-mask-id"),e}}},provides:function(e){e.generateAbstractMask=function(e){var t,n=e.children,r=e.attributes,a=e.main,i=e.mask,o=e.maskId,s=e.transform,c=a.width,l=a.icon,u=i.width,d=i.icon,f=function(e){var t=e.transform,n=e.containerWidth,r=e.iconWidth,a={transform:"translate(".concat(n/2," 256)")},i="translate(".concat(32*t.x,", ").concat(32*t.y,") "),o="scale(".concat(t.size/16*(t.flipX?-1:1),", ").concat(t.size/16*(t.flipY?-1:1),") "),s="rotate(".concat(t.rotate," 0 0)");return{outer:a,inner:{transform:"".concat(i," ").concat(o," ").concat(s)},path:{transform:"translate(".concat(r/2*-1," -256)")}}}({transform:s,containerWidth:u,iconWidth:c}),p={tag:"rect",attributes:Zu(Zu({},Yp),{},{fill:"white"})},m=l.children?{children:l.children.map(Pp)}:{},h={tag:"g",attributes:Zu({},f.inner),children:[Pp(Zu({tag:l.tag,attributes:Zu(Zu({},l.attributes),f.path)},m))]},b={tag:"g",attributes:Zu({},f.outer),children:[h]},M="mask-".concat(o||Id()),_="clip-".concat(o||Id()),g={tag:"mask",attributes:Zu(Zu({},Yp),{},{id:M,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"}),children:[p,b]},y={tag:"defs",children:[{tag:"clipPath",attributes:{id:_},children:(t=d,"g"===t.tag?t.children:[t])},g]};return n.push(y,{tag:"rect",attributes:Zu({fill:"currentColor","clip-path":"url(#".concat(_,")"),mask:"url(#".concat(M,")")},Yp)}),{children:n,attributes:r}}}};jp={mixoutsTo:Bf}.mixoutsTo,Nf=[Qd,Lp,wp,Ap,Tp,{hooks:function(){return{mutationObserverCallbacks:function(e){return e.pseudoElementsCallback=Np,e}}},provides:function(e){e.pseudoElements2svg=function(e){var t=e.node,n=void 0===t?hd:t;Wd.searchPseudoElements&&Np(n)}}},{mixout:function(){return{dom:{unwatch:function(){lp(),xp=!0}}}},hooks:function(){return{bootstrap:function(){fp(Yf("mutationObserverCallbacks",{}))},noAuto:function(){dp&&dp.disconnect()},watch:function(e){var t=e.observeMutationsRoot;xp?up():fp(Yf("mutationObserverCallbacks",{observeMutationsRoot:t}))}}}},Cp,Rp,{provides:function(e){var t=!1;md.matchMedia&&(t=md.matchMedia("(prefers-reduced-motion: reduce)").matches),e.missingIconAbstract=function(){var e=[],n={fill:"currentColor"},r={attributeType:"XML",repeatCount:"indefinite",dur:"2s"};e.push({tag:"path",attributes:Zu(Zu({},n),{},{d:"M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66.8,13.6V471.4z M462,190.8c5,15.7,8.2,32.2,9.4,49.2h32.1 c-1.4-21.2-5.4-41.7-11.7-61.1L462,190.8z M92.4,397c-12-13.9-22.3-29.4-30.4-46.1l-29.8,11.9c9.9,20.7,22.6,39.8,37.6,56.9 L92.4,397z M272,40.6c18.8,1.4,36.9,5.2,54.1,11.1l12.6-29.5C317.7,14.7,295.3,10,272,8.5V40.6z M190.8,50 c15.7-5,32.2-8.2,49.2-9.4V8.5c-21.2,1.4-41.7,5.4-61.1,11.7L190.8,50z M442.3,92.3L419.6,115c12,13.9,22.3,29.4,30.5,46.1 l29.8-11.9C470,128.5,457.3,109.4,442.3,92.3z M397,92.4l22.7-22.7c-15.6-13.7-32.8-25.5-51.5-34.9l-12.6,29.5 C370.4,72.1,384.4,81.5,397,92.4z"})});var a=Zu(Zu({},r),{},{attributeName:"opacity"}),i={tag:"circle",attributes:Zu(Zu({},n),{},{cx:"256",cy:"364",r:"28"}),children:[]};return t||i.children.push({tag:"animate",attributes:Zu(Zu({},r),{},{attributeName:"r",values:"28;14;28;28;14;28;"})},{tag:"animate",attributes:Zu(Zu({},a),{},{values:"1;0;1;1;0;1;"})}),e.push(i),e.push({tag:"path",attributes:Zu(Zu({},n),{},{opacity:"1",d:"M263.7,312h-16c-6.6,0-12-5.4-12-12c0-71,77.4-63.9,77.4-107.8c0-20-17.8-40.2-57.4-40.2c-29.1,0-44.3,9.6-59.2,28.7 c-3.9,5-11.1,6-16.2,2.4l-13.1-9.2c-5.6-3.9-6.9-11.8-2.6-17.2c21.2-27.2,46.4-44.7,91.2-44.7c52.3,0,97.4,29.8,97.4,80.2 c0,67.6-77.4,63.5-77.4,107.8C275.7,306.6,270.3,312,263.7,312z"}),children:t?[]:[{tag:"animate",attributes:Zu(Zu({},a),{},{values:"1;0;0;0;0;1;"})}]}),t||e.push({tag:"path",attributes:Zu(Zu({},n),{},{opacity:"0",d:"M232.5,134.5l7,168c0.3,6.4,5.6,11.5,12,11.5h9c6.4,0,11.7-5.1,12-11.5l7-168c0.3-6.8-5.2-12.5-12-12.5h-23 C237.7,122,232.2,127.7,232.5,134.5z"}),children:[{tag:"animate",attributes:Zu(Zu({},a),{},{values:"0;0;1;1;0;0;"})}]}),{tag:"g",attributes:{class:"missing"},children:e}}}},{hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-symbol"),r=null!==n&&(""===n||n);return e.symbol=r,e}}}}],xf={},Object.keys(Df).forEach((function(e){-1===Cf.indexOf(e)&&delete Df[e]})),Nf.forEach((function(e){var t=e.mixout?e.mixout():{};if(Object.keys(t).forEach((function(e){"function"==typeof t[e]&&(jp[e]=t[e]),"object"===ed(t[e])&&Object.keys(t[e]).forEach((function(n){jp[e]||(jp[e]={}),jp[e][n]=t[e][n]}))})),e.hooks){var n=e.hooks();Object.keys(n).forEach((function(e){xf[e]||(xf[e]=[]),xf[e].push(n[e])}))}e.provides&&e.provides(Df)}));var Wp=Bf.parse,qp=Bf.icon;function Bp(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Hp(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function Up(e){return function(e){if(Array.isArray(e))return Vp(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Vp(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Vp(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vp(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0||!Array.isArray(t)&&t?Xp({},e,t):{}}var em=["forwardedRef"];function tm(e){var t=e.forwardedRef,n=Fp(e,em),r=n.icon,a=n.mask,i=n.symbol,o=n.className,s=n.title,c=n.titleId,l=n.maskId,u=Qp(r),d=Zp("classes",[].concat(Up(function(e){var t,n=e.beat,r=e.fade,a=e.beatFade,i=e.bounce,o=e.shake,s=e.flash,c=e.spin,l=e.spinPulse,u=e.spinReverse,d=e.pulse,f=e.fixedWidth,p=e.inverse,m=e.border,h=e.listItem,b=e.flip,M=e.size,_=e.rotation,g=e.pull,y=(Xp(t={"fa-beat":n,"fa-fade":r,"fa-beat-fade":a,"fa-bounce":i,"fa-shake":o,"fa-flash":s,"fa-spin":c,"fa-spin-reverse":u,"fa-spin-pulse":l,"fa-pulse":d,"fa-fw":f,"fa-inverse":p,"fa-border":m,"fa-li":h,"fa-flip":!0===b,"fa-flip-horizontal":"horizontal"===b||"both"===b,"fa-flip-vertical":"vertical"===b||"both"===b},"fa-".concat(M),null!=M),Xp(t,"fa-rotate-".concat(_),null!=_&&0!==_),Xp(t,"fa-pull-".concat(g),null!=g),Xp(t,"fa-swap-opacity",e.swapOpacity),t);return Object.keys(y).map((function(e){return y[e]?e:null})).filter((function(e){return e}))}(n)),Up(o.split(" ")))),f=Zp("transform","string"==typeof n.transform?Wp.transform(n.transform):n.transform),p=Zp("mask",Qp(a)),m=qp(u,Hp(Hp(Hp(Hp({},d),f),p),{},{symbol:i,title:s,titleId:c,maskId:l}));if(!m)return function(){var e;!Kp&&console&&"function"==typeof console.error&&(e=console).error.apply(e,arguments)}("Could not find icon",u),null;var h=m.abstract,b={ref:t};return Object.keys(n).forEach((function(e){tm.defaultProps.hasOwnProperty(e)||(b[e]=n[e])})),nm(h[0],b)}tm.displayName="FontAwesomeIcon",tm.propTypes={beat:En.a.bool,border:En.a.bool,beatFade:En.a.bool,bounce:En.a.bool,className:En.a.string,fade:En.a.bool,flash:En.a.bool,mask:En.a.oneOfType([En.a.object,En.a.array,En.a.string]),maskId:En.a.string,fixedWidth:En.a.bool,inverse:En.a.bool,flip:En.a.oneOf([!0,!1,"horizontal","vertical","both"]),icon:En.a.oneOfType([En.a.object,En.a.array,En.a.string]),listItem:En.a.bool,pull:En.a.oneOf(["right","left"]),pulse:En.a.bool,rotation:En.a.oneOf([0,90,180,270]),shake:En.a.bool,size:En.a.oneOf(["2xs","xs","sm","lg","xl","2xl","1x","2x","3x","4x","5x","6x","7x","8x","9x","10x"]),spin:En.a.bool,spinPulse:En.a.bool,spinReverse:En.a.bool,symbol:En.a.oneOfType([En.a.bool,En.a.string]),title:En.a.string,titleId:En.a.string,transform:En.a.oneOfType([En.a.string,En.a.object]),swapOpacity:En.a.bool},tm.defaultProps={border:!1,className:"",mask:null,maskId:null,fixedWidth:!1,inverse:!1,flip:!1,icon:null,listItem:!1,pull:null,pulse:!1,rotation:null,size:null,spin:!1,spinPulse:!1,spinReverse:!1,beat:!1,fade:!1,beatFade:!1,bounce:!1,shake:!1,symbol:!1,title:"",titleId:null,transform:null,swapOpacity:!1};var nm=function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if("string"==typeof n)return n;var a=(n.children||[]).map((function(n){return e(t,n)})),i=Object.keys(n.attributes||{}).reduce((function(e,t){var r=n.attributes[t];switch(t){case"class":e.attrs.className=r,delete n.attributes.class;break;case"style":e.attrs.style=Jp(r);break;default:0===t.indexOf("aria-")||0===t.indexOf("data-")?e.attrs[t.toLowerCase()]=r:e.attrs[Gp(t)]=r}return e}),{attrs:{}}),o=r.style,s=void 0===o?{}:o,c=Fp(r,$p);return i.attrs.style=Hp(Hp({},i.attrs.style),s),t.apply(void 0,[n.tag,Hp(Hp({},i.attrs),c)].concat(Up(a)))}.bind(null,V.a.createElement),rm=function(e){var t;return"undefined"==typeof document?null:null==e?Or().body:("function"==typeof e&&(e=e()),e&&"current"in e&&(e=e.current),null!=(t=e)&&t.nodeType&&e||null)};function am(e,t){var n=Object(U.useState)((function(){return rm(e)})),r=n[0],a=n[1];if(!r){var i=rm(e);i&&a(i)}return Object(U.useEffect)((function(){t&&r&&t(r)}),[t,r]),Object(U.useEffect)((function(){var t=rm(e);t!==r&&a(t)}),[e,r]),r}var im=V.a.forwardRef((function(e,t){var n=e.flip,r=e.offset,a=e.placement,i=e.containerPadding,o=void 0===i?5:i,s=e.popperConfig,c=void 0===s?{}:s,l=e.transition,u=Oc(),d=u[0],f=u[1],p=Oc(),m=p[0],h=p[1],b=Lu(f,t),M=am(e.container),_=am(e.target),g=Object(U.useState)(!e.show),y=g[0],v=g[1],L=Xl(_,d,Ql({placement:a,enableEvents:!!e.show,containerPadding:o||5,flip:n,offset:r,arrowElement:m,popperConfig:c})),w=L.styles,A=L.attributes,T=Cn(L,["styles","attributes"]);e.show?y&&v(!1):e.transition||y||v(!0);var O=e.show||l&&!y;if(Kl(d,e.onHide,{disabled:!e.rootClose||e.rootCloseDisabled,clickTrigger:e.rootCloseEvent}),!O)return null;var k=e.children(Dn({},T,{show:!!e.show,props:Dn({},A.popper,{style:w.popper,ref:b}),arrowProps:Dn({},A.arrow,{style:w.arrow,ref:h})}));if(l){var S=e.onExit,z=e.onExiting,E=e.onEnter,N=e.onEntering,x=e.onEntered;k=V.a.createElement(l,{in:e.show,appear:!0,onExit:S,onExiting:z,onExited:function(){v(!0),e.onExited&&e.onExited.apply(e,arguments)},onEnter:E,onEntering:N,onEntered:x},k)}return M?J.a.createPortal(k,M):null}));im.displayName="Overlay",im.propTypes={show:En.a.bool,placement:En.a.oneOf(il),target:En.a.any,container:En.a.any,flip:En.a.bool,children:En.a.func.isRequired,containerPadding:En.a.number,popperConfig:En.a.object,rootClose:En.a.bool,rootCloseEvent:En.a.oneOf(["click","mousedown"]),rootCloseDisabled:En.a.bool,onHide:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Dm=V.a.forwardRef((function(e,t){var n=e.children,r=e.variant,a=xm(e,km);return V.a.createElement(Om,Nm({},a,{className:xn()({"tooltip-light":"light"===r},a.className),ref:t}),n)}));Dm.propTypes=zm(zm({},Om.propTypes),{},{id:En.a.string.isRequired,placement:En.a.oneOf(["auto-start","auto","auto-end","top-start","top","top-end","right-start","right","right-end","bottom-end","bottom","bottom-start","left-end","left","left-start"]),arrowProps:En.a.shape({ref:En.a.oneOfType([En.a.func,En.a.shape({current:En.a.element})]),style:En.a.shape({})}),show:En.a.bool,popper:En.a.shape({}),bsPrefix:En.a.string,children:En.a.node,className:En.a.string,variant:En.a.string}),Dm.defaultProps=zm(zm({},Dm.defaultProps),{},{id:void 0,placement:"right",arrowProps:void 0,show:void 0,popper:void 0,children:void 0,className:void 0,variant:void 0,bsPrefix:"tooltip"});var Cm=Dm;function Ym(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var Pm=["className","alt","invertColors","icon","src","iconClassNames","onClick","size","variant","iconAs","isActive"],jm=["tooltipPlacement","tooltipContent","variant","invertColors"];function Rm(){return(Rm=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var qm=V.a.forwardRef((function(e,t){var n=e.className,r=e.alt,a=e.invertColors,i=e.icon,o=e.src,s=e.iconClassNames,c=e.onClick,l=e.size,u=e.variant,d=e.iconAs,f=e.isActive,p=Wm(e,Pm),m=a?"inverse-":"",h=f?"".concat(u,"-"):"",b=d||tm;return V.a.createElement("button",Rm({"aria-label":r,className:xn()("btn-icon","btn-icon-".concat(m).concat(u),"btn-icon-".concat(l),Ym({},"btn-icon-".concat(m).concat(h,"active"),f),n),onClick:c,type:"button",ref:t},p),V.a.createElement("span",{className:"btn-icon__icon-container"},V.a.createElement(b,{className:xn()("btn-icon__icon",s),icon:i,src:o})))}));qm.defaultProps={iconAs:void 0,src:null,icon:void 0,iconClassNames:void 0,className:void 0,invertColors:!1,variant:"primary",size:"md",onClick:function(){},isActive:!1},qm.propTypes={className:En.a.string,iconAs:En.a.elementType,src:En.a.oneOfType([En.a.element,En.a.func]),alt:En.a.string.isRequired,invertColors:En.a.bool,icon:En.a.shape({prefix:En.a.string,iconName:En.a.string,icon:En.a.array}),iconClassNames:En.a.string,onClick:En.a.func,variant:En.a.oneOf(["primary","secondary","success","warning","danger","light","dark","black","brand"]),size:En.a.oneOf(["sm","md","inline"]),isActive:En.a.bool};var Bm=function(e){var t=e.tooltipPlacement,n=e.tooltipContent,r=e.variant,a=e.invertColors,i=Wm(e,jm),o=a?"inverse-":"";return V.a.createElement(Lm,{placement:t,overlay:V.a.createElement(Cm,{id:"iconbutton-tooltip-".concat(t),variant:o?"light":""},n)},V.a.createElement(qm,Rm({variant:r,invertColors:a},i)))};Bm.defaultProps={tooltipPlacement:"top",variant:"primary",invertColors:!1},Bm.propTypes={tooltipPlacement:En.a.string,tooltipContent:En.a.node.isRequired,variant:En.a.oneOf(["primary","secondary","success","warning","danger","light","dark","black","brand"]),invertColors:En.a.bool},qm.IconButtonWithTooltip=Bm;var Hm=qm;var Im=function(){return(Im=Object.assign||function(e){for(var t,n=1,r=arguments.length;n=0})).sort(zh)},Nh=["button:enabled","select:enabled","textarea:enabled","input:enabled","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]","[tabindex]","[contenteditable]","[autofocus]"].join(","),xh="".concat(Nh,", [data-focus-guard]"),Dh=function(e,t){var n;return hh((null===(n=e.shadowRoot)||void 0===n?void 0:n.children)||e.children).reduce((function(e,n){return e.concat(n.matches(t?xh:Nh)?[n]:[],Dh(n))}),[])},Ch=function(e,t){return e.reduce((function(e,n){return e.concat(Dh(n,t),n.parentNode?hh(n.parentNode.querySelectorAll(Nh)).filter((function(e){return e===n})):[])}),[])},Yh=function(e,t){return hh(e).filter((function(e){return yh(t,e)})).filter((function(e){return function(e){return!((wh(e)||function(e){return"BUTTON"===e.tagName}(e))&&("hidden"===e.type||e.disabled))}(e)}))},Ph=function(e,t){return void 0===t&&(t=new Map),hh(e).filter((function(e){return vh(t,e)}))},jh=function(e,t,n){return Eh(Yh(Ch(e,n),t),!0,n)},Rh=function(e,t){return Eh(Yh(Ch(e),t),!1)},Wh=function(e,t){return Yh((n=e.querySelectorAll("[".concat("data-autofocus-inside","]")),hh(n).map((function(e){return Ch([e])})).reduce((function(e,t){return e.concat(t)}),[])),t);var n},qh=function(e,t){return(e.shadowRoot?qh(e.shadowRoot,t):Object.getPrototypeOf(e).contains.call(e,t))||hh(e.children).some((function(e){return qh(e,t)}))},Bh=function(e){return e.activeElement?e.activeElement.shadowRoot?Bh(e.activeElement.shadowRoot):e.activeElement:void 0},Hh=function(){return document.activeElement?document.activeElement.shadowRoot?Bh(document.activeElement.shadowRoot):document.activeElement:void 0},Ih=function(e){return e.parentNode?Ih(e.parentNode):e},Xh=function(e){return bh(e).filter(Boolean).reduce((function(e,t){var n=t.getAttribute("data-focus-lock");return e.push.apply(e,n?function(e){for(var t=new Set,n=e.length,r=0;r0&&t.add(a),(i&Node.DOCUMENT_POSITION_CONTAINS)>0&&t.add(r)}return e.filter((function(e,n){return!t.has(n)}))}(hh(Ih(t).querySelectorAll("[".concat("data-focus-lock",'="').concat(n,'"]:not([').concat("data-focus-lock-disabled",'="disabled"])')))):[t]),e}),[])},Fh=function(e){return Boolean(hh(e.querySelectorAll("iframe")).some((function(e){return e===document.activeElement})))},Uh=function(e){var t=document&&Hh();return!(!t||t.dataset&&t.dataset.focusGuard)&&Xh(e).some((function(e){return qh(e,t)||Fh(e)}))},Vh=function(e,t){return Ah(e)&&e.name?function(e,t){return t.filter(Ah).filter((function(t){return t.name===e.name})).filter((function(e){return e.checked}))[0]||e}(e,t):e},Gh=function(e){return e[0]&&e.length>1?Vh(e[0],e):e[0]},$h=function(e,t){return e.length>1?e.indexOf(Vh(e[t],e)):t},Jh=function(e,t,n,r){var a=e.length,i=e[0],o=e[a-1],s=Oh(n);if(!(n&&e.indexOf(n)>=0)){var c,l,u=void 0!==n?t.indexOf(n):-1,d=r?t.indexOf(r):u,f=r?e.indexOf(r):-1,p=u-d,m=t.indexOf(i),h=t.indexOf(o),b=(c=t,l=new Set,c.forEach((function(e){return l.add(Vh(e,c))})),c.filter((function(e){return l.has(e)}))),M=(void 0!==n?b.indexOf(n):-1)-(r?b.indexOf(r):u),_=$h(e,0),g=$h(e,a-1);return-1===u||-1===f?"NEW_FOCUS":!p&&f>=0?f:u<=m&&s&&Math.abs(p)>1?g:u>=h&&s&&Math.abs(p)>1?_:p&&Math.abs(M)>1?f:u<=m?g:u>h?_:p?Math.abs(p)>1?f:(a+f+p)%a:void 0}},Kh=function(e,t){return void 0===t&&(t=[]),t.push(e),e.parentNode&&Kh(e.parentNode.host||e.parentNode,t),t},Qh=function(e,t){for(var n=Kh(e),r=Kh(t),a=0;a=0)return i}return!1},Zh=function(e,t,n){var r=bh(e),a=bh(t),i=r[0],o=!1;return a.filter(Boolean).forEach((function(e){o=Qh(o||e,e)||o,n.filter(Boolean).forEach((function(e){var t=Qh(i,e);t&&(o=!o||qh(t,o)?t:Qh(t,o))}))})),o},eb=function(e,t){var n=document&&Hh(),r=Xh(e).filter(kh),a=Zh(n||e,e,r),i=new Map,o=Rh(r,i),s=jh(r,i).filter((function(e){var t=e.node;return kh(t)}));if(s[0]||(s=o)[0]){var c,l,u,d,f=Rh([a],i).map((function(e){return e.node})),p=(c=f,l=s,u=new Map,l.forEach((function(e){return u.set(e.node,e)})),c.map((function(e){return u.get(e)})).filter(Sh)),m=p.map((function(e){return e.node})),h=Jh(m,f,n,t);if("NEW_FOCUS"===h){var b=Ph(o.map((function(e){return e.node}))).filter((d=function(e,t){return e.reduce((function(e,n){return e.concat(Wh(n,t))}),[])}(r,i),function(e){var t;return e.autofocus||!!(null===(t=Lh(e))||void 0===t?void 0:t.autofocus)||d.indexOf(e)>=0}));return{node:b&&b.length?Gh(b):Gh(Ph(m))}}return void 0===h?h:p[h]}},tb=0,nb=!1,rb=function(e,t,n){void 0===n&&(n={});var r,a,i=eb(e,t);if(!nb&&i){if(tb>2)return console.error("FocusLock: focus-fighting detected. Only one focus management system could be active. See https://github.com/theKashey/focus-lock/#focus-fighting"),nb=!0,void setTimeout((function(){nb=!1}),1);tb++,r=i.node,a=n.focusOptions,"focus"in r&&r.focus(a),"contentWindow"in r&&r.contentWindow&&r.contentWindow.focus(),tb--}},ab=function(e){var t=Xh(e).filter(kh),n=Zh(e,e,t),r=new Map,a=jh([n],r,!0),i=jh(t,r).filter((function(e){var t=e.node;return kh(t)})).map((function(e){return e.node}));return a.map((function(e){var t=e.node;return{node:t,index:e.index,lockItem:i.indexOf(t)>=0,guard:Oh(t)}}))};function ib(e){var t=window.setImmediate;void 0!==t?t(e):setTimeout(e,1)}var ob=function(){return document&&document.activeElement===document.body||!!(e=document&&Hh())&&hh(document.querySelectorAll("[".concat("data-no-focus-lock","]"))).some((function(t){return qh(t,e)}));var e},sb=null,cb=null,lb=null,ub=!1,db=function(){return!0};function fb(e,t,n,r){var a=null,i=e;do{var o=r[i];if(o.guard)o.node.dataset.focusAutoGuard&&(a=o);else{if(!o.lockItem)break;if(i!==e)return;a=null}}while((i+=n)!==t);a&&(a.node.tabIndex=0)}var pb=function(e){return e&&"current"in e?e.current:e},mb=function(){var e,t=!1;if(sb){var n=sb,r=n.observed,a=n.persistentFocus,i=n.autoFocus,o=n.shards,s=n.crossFrame,c=n.focusOptions,l=r||lb&&lb.portaledElement,u=document&&document.activeElement;if(l){var d=[l].concat(o.map(pb).filter(Boolean));if(u&&!function(e){return(sb.whiteList||db)(e)}(u)||(a||(s?Boolean(ub):"meanwhile"===ub)||!ob()||!cb&&i)&&(l&&!(Uh(d)||u&&function(e,t){return t.some((function(t){return function e(t,n,r){return n&&(n.host===t&&(!n.activeElement||r.contains(n.activeElement))||n.parentNode&&e(t,n.parentNode,r))}(e,t,t)}))}(u,d)||(e=u,lb&&lb.portaledElement===e))&&(document&&!cb&&u&&!i?(u.blur&&u.blur(),document.body.focus()):(t=rb(d,cb,{focusOptions:c}),lb={})),ub=!1,cb=document&&document.activeElement),document){var f=document&&document.activeElement,p=ab(d),m=p.map((function(e){return e.node})).indexOf(f);m>-1&&(p.filter((function(e){var t=e.guard,n=e.node;return t&&n.dataset.focusAutoGuard})).forEach((function(e){return e.node.removeAttribute("tabIndex")})),fb(m,p.length,1,p),fb(m,-1,-1,p))}}}return t},hb=function(e){mb()&&e&&(e.stopPropagation(),e.preventDefault())},bb=function(){return ib(mb)},Mb=function(e){var t=e.target,n=e.currentTarget;n.contains(t)||(lb={observerNode:n,portaledElement:t})},_b=function(){ub="just",setTimeout((function(){ub="meanwhile"}),0)};rh.assignSyncMedium(Mb),ah.assignMedium(bb),ih.assignMedium((function(e){return e({moveFocusInside:rb,focusInside:Uh})}));var gb,yb=mh((function(e){return e.filter((function(e){return!e.disabled}))}),(function(e){var t=e.slice(-1)[0];t&&!sb&&(document.addEventListener("focusin",hb),document.addEventListener("focusout",bb),window.addEventListener("blur",_b));var n=sb,r=n&&t&&t.id===n.id;sb=t,n&&!r&&(n.onDeactivation(),e.filter((function(e){return e.id===n.id})).length||n.returnFocus(!t)),t?(cb=null,r&&n.observed===t.observed||t.onActivation(),mb(),ib(mb)):(document.removeEventListener("focusin",hb),document.removeEventListener("focusout",bb),window.removeEventListener("blur",_b),cb=null)}))((function(){return null}));ph(oh,yb);function vb(){if(!document)return null;var e=document.createElement("style");e.type="text/css";var t=gb||n.nc;return t&&e.setAttribute("nonce",t),e}var Lb=function(){var e=0,t=null;return{add:function(n){var r,a;0==e&&(t=vb())&&(a=n,(r=t).styleSheet?r.styleSheet.cssText=a:r.appendChild(document.createTextNode(a)),function(e){(document.head||document.getElementsByTagName("head")[0]).appendChild(e)}(t)),e++},remove:function(){!--e&&t&&(t.parentNode&&t.parentNode.removeChild(t),t=null)}}},wb=function(){var e,t=(e=Lb(),function(t,n){U.useEffect((function(){return e.add(t),function(){e.remove()}}),[t&&n])});return function(e){var n=e.styles,r=e.dynamic;return t(n,r),null}},Ab={left:0,top:0,right:0,gap:0},Tb=function(e){return parseInt(e||"",10)||0},Ob=function(e){if(void 0===e&&(e="margin"),"undefined"==typeof window)return Ab;var t=function(e){var t=window.getComputedStyle(document.body);var n=t["padding"===e?"paddingLeft":"marginLeft"],r=t["padding"===e?"paddingTop":"marginTop"],a=t["padding"===e?"paddingRight":"marginRight"];return[Tb(n),Tb(r),Tb(a)]}(e),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:t[0],top:t[1],right:t[2],gap:Math.max(0,r-n+t[2]-t[0])}},kb=wb(),Sb=function(e,t,n,r){var a=e.left,i=e.top,o=e.right,s=e.gap;return void 0===n&&(n="margin"),"\n .".concat("with-scroll-bars-hidden"," {\n overflow: hidden ").concat(r,";\n padding-right: ").concat(s,"px ").concat(r,";\n }\n body {\n overflow: hidden ").concat(r,";\n overscroll-behavior: contain;\n ").concat([t&&"position: relative ".concat(r,";"),"margin"===n&&"\n padding-left: ".concat(a,"px;\n padding-top: ").concat(i,"px;\n padding-right: ").concat(o,"px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(s,"px ").concat(r,";\n "),"padding"===n&&"padding-right: ".concat(s,"px ").concat(r,";")].filter(Boolean).join(""),"\n }\n \n .").concat("right-scroll-bar-position"," {\n right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat("width-before-scroll-bar"," {\n margin-right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat("right-scroll-bar-position"," .").concat("right-scroll-bar-position"," {\n right: 0 ").concat(r,";\n }\n \n .").concat("width-before-scroll-bar"," .").concat("width-before-scroll-bar"," {\n margin-right: 0 ").concat(r,";\n }\n \n body {\n ").concat("--removed-body-scroll-bar-size",": ").concat(s,"px;\n }\n")},zb=function(e){var t=e.noRelative,n=e.noImportant,r=e.gapMode,a=void 0===r?"margin":r,i=U.useMemo((function(){return Ob(a)}),[a]);return U.createElement(kb,{styles:Sb(i,!t,a,n?"":"!important")})},Eb=!1;if("undefined"!=typeof window)try{var Nb=Object.defineProperty({},"passive",{get:function(){return Eb=!0,!0}});window.addEventListener("test",Nb,Nb),window.removeEventListener("test",Nb,Nb)}catch(e){Eb=!1}var xb=!!Eb&&{passive:!1},Db=function(e,t){var n=window.getComputedStyle(e);return"hidden"!==n[t]&&!(n.overflowY===n.overflowX&&!function(e){return"TEXTAREA"===e.tagName}(e)&&"visible"===n[t])},Cb=function(e,t){var n=t;do{if("undefined"!=typeof ShadowRoot&&n instanceof ShadowRoot&&(n=n.host),Yb(e,n)){var r=Pb(e,n);if(r[1]>r[2])return!0}n=n.parentNode}while(n&&n!==document.body);return!1},Yb=function(e,t){return"v"===e?function(e){return Db(e,"overflowY")}(t):function(e){return Db(e,"overflowX")}(t)},Pb=function(e,t){return"v"===e?[(n=t).scrollTop,n.scrollHeight,n.clientHeight]:function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]}(t);var n},jb=function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},Rb=function(e){return[e.deltaX,e.deltaY]},Wb=function(e){return e&&"current"in e?e.current:e},qb=function(e){return"\n .block-interactivity-".concat(e," {pointer-events: none;}\n .allow-interactivity-").concat(e," {pointer-events: all;}\n")},Bb=0,Hb=[];ph(Qm,(function(e){var t=U.useRef([]),n=U.useRef([0,0]),r=U.useRef(),a=U.useState(Bb++)[0],i=U.useState((function(){return wb()}))[0],o=U.useRef(e);U.useEffect((function(){o.current=e}),[e]),U.useEffect((function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(a));var t=function(e,t,n){if(n||2===arguments.length)for(var r,a=0,i=t.length;aMath.abs(l)?"h":"v";if("touches"in e&&"h"===d&&"range"===u.type)return!1;var f=Cb(d,u);if(!f)return!0;if(f?a=d:(a="v"===d?"h":"v",f=Cb(d,u)),!f)return!1;if(!r.current&&"changedTouches"in e&&(c||l)&&(r.current=a),!a)return!0;var p=r.current||a;return function(e,t,n,r,a){var i=function(e,t){return"h"===e&&"rtl"===t?-1:1}(e,window.getComputedStyle(t).direction),o=i*r,s=n.target,c=t.contains(s),l=!1,u=o>0,d=0,f=0;do{var p=Pb(e,s),m=p[0],h=p[1]-p[2]-i*m;(m||h)&&Yb(e,s)&&(d+=h,f+=m),s=s.parentNode}while(!c&&s!==document.body||c&&(t.contains(s)||t===s));return(u&&(a&&0===d||!a&&o>d)||!u&&(a&&0===f||!a&&-o>f))&&(l=!0),l}(p,t,e,"h"===p?c:l,!0)}),[]),c=U.useCallback((function(e){var n=e;if(Hb.length&&Hb[Hb.length-1]===i){var r="deltaY"in n?Rb(n):jb(n),a=t.current.filter((function(e){return e.name===n.type&&e.target===n.target&&(t=e.delta,a=r,t[0]===a[0]&&t[1]===a[1]);var t,a}))[0];if(a&&a.should)n.cancelable&&n.preventDefault();else if(!a){var c=(o.current.shards||[]).map(Wb).filter(Boolean).filter((function(e){return e.contains(n.target)}));(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}}),[]),l=U.useCallback((function(e,n,r,a){var i={name:e,delta:n,target:r,should:a};t.current.push(i),setTimeout((function(){t.current=t.current.filter((function(e){return e!==i}))}),1)}),[]),u=U.useCallback((function(e){n.current=jb(e),r.current=void 0}),[]),d=U.useCallback((function(t){l(t.type,Rb(t),t.target,s(t,e.lockRef.current))}),[]),f=U.useCallback((function(t){l(t.type,jb(t),t.target,s(t,e.lockRef.current))}),[]);U.useEffect((function(){return Hb.push(i),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener("wheel",c,xb),document.addEventListener("touchmove",c,xb),document.addEventListener("touchstart",u,xb),function(){Hb=Hb.filter((function(e){return e!==i})),document.removeEventListener("wheel",c,xb),document.removeEventListener("touchmove",c,xb),document.removeEventListener("touchstart",u,xb)}}),[]);var p=e.removeScrollBar,m=e.inert;return U.createElement(U.Fragment,null,m?U.createElement(i,{styles:qb(a)}):null,p?U.createElement(zb,{gapMode:"margin"}):null)}));var Ib=new WeakMap,Xb=new WeakMap,Fb={},Ub=0,Vb=function(e,t,n){void 0===t&&(t=function(e){return"undefined"==typeof document?null:(Array.isArray(e)?e[0]:e).ownerDocument.body}(e)),void 0===n&&(n="data-aria-hidden");var r=Array.isArray(e)?e:[e];Fb[n]||(Fb[n]=new WeakMap);var a=Fb[n],i=[],o=new Set,s=function(e){e&&!o.has(e)&&(o.add(e),s(e.parentNode))};r.forEach(s);var c=function(e){!e||r.indexOf(e)>=0||Array.prototype.forEach.call(e.children,(function(e){if(o.has(e))c(e);else{var t=e.getAttribute("aria-hidden"),r=null!==t&&"false"!==t,s=(Ib.get(e)||0)+1,l=(a.get(e)||0)+1;Ib.set(e,s),a.set(e,l),i.push(e),1===s&&r&&Xb.set(e,!0),1===l&&e.setAttribute(n,"true"),r||e.setAttribute("aria-hidden","true")}}))};return c(t),o.clear(),Ub++,function(){i.forEach((function(e){var t=Ib.get(e)-1,r=a.get(e)-1;Ib.set(e,t),a.set(e,r),t||(Xb.has(e)||e.removeAttribute("aria-hidden"),Xb.delete(e)),r||e.removeAttribute(n)})),--Ub||(Ib=new WeakMap,Ib=new WeakMap,Xb=new WeakMap,Fb={})}},Gb=wb(),$b=function(){return U.createElement(Gb,{styles:"\n [data-focus-on-hidden] {\n pointer-events: none !important;\n }\n"})},Jb=function(e){return"current"in e?e.current:e};var Kb=ph(uh,(function(e){var t=e.setLockProps,n=e.onEscapeKey,r=e.onClickOutside,a=e.shards,i=e.onActivation,o=e.onDeactivation,s=e.noIsolation,c=Object(U.useState)(void 0),l=c[0],u=c[1],d=Object(U.useRef)(null),f=Object(U.useRef)(0);return U.useEffect((function(){var e=function(e){e.defaultPrevented||"Escape"!==e.code&&"Escape"!==e.key&&27!==e.keyCode||!n||n(e)},t=function(e){e.defaultPrevented||e.target===d.current||e instanceof MouseEvent&&0!==e.button||a&&a.map(Jb).some((function(t){return t&&t.contains(e.target)||t===e.target}))||r&&r(e)},i=function(e){t(e),f.current=e.touches.length},o=function(e){f.current=e.touches.length};if(l)return document.addEventListener("keydown",e),document.addEventListener("mousedown",t),document.addEventListener("touchstart",i),document.addEventListener("touchend",o),function(){document.removeEventListener("keydown",e),document.removeEventListener("mousedown",t),document.removeEventListener("touchstart",i),document.removeEventListener("touchend",o)}}),[l,r,n]),Object(U.useEffect)((function(){if(l)return i&&i(l),function(){o&&o()}}),[!!l]),Object(U.useEffect)((function(){var e=function(){return null},n=!1;return t({onMouseDown:function(e){d.current=e.target},onTouchStart:function(e){d.current=e.target},onActivation:function(t){s||(e=Vb(function(){for(var e=0,t=0,n=arguments.length;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var kM={right:[-2,10],left:[-2,10]},SM=function(e){var t=e.children,n=e.onClose,r=e.isOpen,a=e.positionRef,i=e.isBlocking,o=e.withPortal,s=e.placement,c=e.hasArrow,l=OM(e,AM),u=o?sM:V.a.Fragment,d=kM[s]||[0,10],f=[{name:"eventListeners",options:{scroll:!1}},{name:"offset",options:{offset:function(){return d}}}];return V.a.createElement(wM,{onClose:n,isOpen:r,isBlocking:i},V.a.createElement(u,null,V.a.createElement(vM,TM({modifiers:c?f:null,target:a,placement:s},l),V.a.createElement(Zb,{scrollLock:!1,enabled:r,onEscapeKey:n,onClickOutside:n},r&&V.a.createElement("div",{className:"pgn__modal-popup__tooltip"},t,c&&V.a.createElement("div",{id:"arrow",className:"pgn__modal-popup__arrow pgn__modal-popup__arrow-".concat(s),"data-popper-arrow":""}))))))};SM.propTypes={children:En.a.node.isRequired,onClose:En.a.func.isRequired,isOpen:En.a.bool.isRequired,isBlocking:En.a.bool,withPortal:En.a.bool,positionRef:En.a.oneOfType([En.a.func,En.a.shape({current:En.a.shape({})})]),placement:vM.propTypes.placement,hasArrow:En.a.bool},SM.defaultProps={isBlocking:!1,withPortal:!1,placement:"bottom-start",positionRef:null,hasArrow:!1};var zM=SM,EM=function(e){var t=e.direction,n=e.gap,r=e.children,a=e.className;return V.a.createElement("div",{className:xn()("horizontal"===t?"pgn__hstack":"pgn__vstack",n?"pgn__stack-gap--".concat(n):"",a)},r)};EM.propTypes={children:En.a.node.isRequired,direction:En.a.oneOf(["horizontal","vertical"]),gap:En.a.number,className:En.a.string},EM.defaultProps={direction:"vertical",gap:0,className:void 0};var NM=EM;function xM(e){return function(e){if(Array.isArray(e))return YM(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||CM(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function DM(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||CM(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function CM(e,t){if(e){if("string"==typeof e)return YM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?YM(e,t):void 0}}function YM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.handleToggleOn,r=t.handleToggleOff,a=t.handleToggle,i=Object(U.useState)(e||!1),o=Ju(i,2),s=o[0],c=o[1],l=Object(U.useCallback)((function(){c(!0),n&&n(),a&&a(!0)}),[n,a]),u=Object(U.useCallback)((function(){c(!1),r&&r(),a&&a(!1)}),[r,a]),d=Object(U.useCallback)((function(){(s?u:l)()}),[s,l,u]);return[s,l,u,d]}(!1),3),a=r[0],i=r[1],o=r[2],s=DM(Object(U.useState)(null),2),c=s[0],l=s[1],u=Object(U.useContext)(Vo),d=DM(u.controlledTableSelections,1)[0].isEntireTableSelected,f=u.selectedFlatRows,p=u.rows,m=Object(vc.a)().width,h=f||p,b=DM(Object(U.useMemo)((function(){if(m0&&V.a.createElement(V.a.Fragment,null,V.a.createElement(Hm,{variant:"secondary",iconAs:qa,src:No,alt:m>Ga.small.minWidth?"More actions":"Actions",id:"actions-dropdown",ref:l,onClick:i}),V.a.createElement(zM,{positionRef:c,onClose:o,placement:"bottom-end",isOpen:a},V.a.createElement("div",{className:"pgn__datatable__overflow-actions-menu"},V.a.createElement(NM,{gap:2},_.map(g))))),V.a.createElement("div",{className:"pgn__datatable__visible-actions"},M.map(g)))};RM.defaultProps={className:null},RM.propTypes={className:En.a.string,actions:En.a.arrayOf(En.a.shape({component:En.a.oneOfType([En.a.func,En.a.element]).isRequired,args:En.a.shape({})})).isRequired};var WM=RM;function qM(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return BM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return BM(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function BM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;return o||i&&!s?null:!a&&s?V.a.createElement(IM,null):V.a.createElement(FM,null)},VM=function(e){var t=e.activeValue,n=e.onChange,r=e.children,a=Object(U.useMemo)((function(){return V.a.Children.map(r,(function(e){var r=e.props.value===t;return V.a.cloneElement(e,{onClick:function(){n(e.props.value)},isActive:r,"aria-selected":r,"data-testid":"icon-btn-val-".concat(e.props.value)})}))}),[r,t,n]);return V.a.createElement("div",{className:"pgn__icon-button-toggle__container"},a)};VM.defaultProps={onChange:function(){},activeValue:void 0},VM.propTypes={activeValue:En.a.string,onChange:En.a.func,children:En.a.node.isRequired};var GM=VM;function $M(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return JM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return JM(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function JM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?null:V.a.createElement("div",{className:xn()("pgn__data-table-empty",n)},t)};n_.defaultProps={className:null},n_.propTypes={className:En.a.string,content:En.a.string.isRequired};var r_=n_,a_=function(e){return function(t,n,r){var a=t[n];return"number"==typeof a&&!Number.isNaN(a)&&a>e?null:new Error("".concat(n," in ").concat(r," must be a non-NaN number greater than ").concat(e,"."))}},i_=["children","className"];function o_(){return(o_=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c_=function(e){var t=e.children,n=e.className,r=s_(e,i_);return V.a.createElement(Y_,null,(function(e){var a=e.buttonRef,i=e.isOpen,o=e.toggle,s=e.triggerId;return V.a.createElement("button",o_({},r,{id:xn()(s,r.id),"aria-expanded":i,"aria-haspopup":!0,type:"button",ref:a,className:xn()("dropdown-toggle","btn",n),onClick:function(e){o(e),r.onClick&&r.onClick(e)}}),t)}))};c_.propTypes={children:En.a.node,className:En.a.string},c_.defaultProps={children:void 0,className:"btn-light"};var l_=c_,u_=["children"];function d_(){return(d_=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p_=function(e){var t=e.children,n=f_(e,u_);return V.a.createElement(Y_,null,(function(e){var r=e.handleMenuKeyDown,a=e.isOpen,i=e.menuRef,o=e.triggerId;return V.a.createElement("div",d_({},n,{"aria-labelledby":o,"aria-hidden":!a,ref:i,role:"menu",className:xn()("dropdown-menu",{show:a},n.className),onKeyDown:function(e){r(e),n.onKeyDown&&n.onKeyDown(e)}}),t)}))};p_.propTypes={children:En.a.node},p_.defaultProps={children:void 0};var m_=p_,h_=["type","children","className"];function b_(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function M_(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var y_=function(e){var t=e.type,n=e.children,r=e.className,a=g_(e,h_);return V.a.createElement(t,M_(M_({},a),{},{className:xn()("dropdown-item",r)}),n)};y_.propTypes={type:En.a.string,children:En.a.node,className:En.a.string},y_.defaultProps={type:"a",children:void 0,className:null};var v_=y_;function L_(e){return(L_="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function w_(e,t){for(var n=0;n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function x_(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var D_=V.a.createContext(),C_=D_.Provider,Y_=D_.Consumer,P_=function(e){!function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&A_(e,t)}(i,e);var t,n,r,a=T_(i);function i(e){var t;return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,i),x_(k_(t=a.call(this,e)),"handleDocumentClick",(function(e){t.containerRef.current.contains(e.target)&&t.containerRef.current!==e.target||t.state.open&&t.close()})),x_(k_(t),"handleMenuKeyDown",(function(e){switch(e.key){case"ArrowUp":e.preventDefault(),t.focusPrevious();break;case"ArrowDown":e.preventDefault(),t.focusNext();break;case"Tab":e.preventDefault(),e.shiftKey?t.focusPrevious():t.focusNext();break;case"Escape":e.stopPropagation(),t.close()}})),x_(k_(t),"toggle",(function(){t.state.open?t.close():t.open()})),t.state={open:!1},t.uniqueId=i.idCounter,i.idCounter+=1,t.triggerId="pgn__dropdown-trigger-".concat(t.uniqueId),t.containerRef=V.a.createRef(),t.menuRef=V.a.createRef(),t.buttonRef=V.a.createRef(),t}return t=i,(n=[{key:"componentDidUpdate",value:function(e,t){t.open!==this.state.open&&(this.state.open?this.focusFirst():this.buttonRef.current.focus())}},{key:"componentWillUnmount",value:function(){document.removeEventListener("click",this.handleDocumentClick,!0)}},{key:"getFocusableElements",value:function(){return Array.from(this.menuRef.current.querySelectorAll('button:not([disabled]), [href]:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'))}},{key:"close",value:function(){document.removeEventListener("click",this.handleDocumentClick,!0),this.setState({open:!1})}},{key:"open",value:function(){document.addEventListener("click",this.handleDocumentClick,!0),this.setState({open:!0})}},{key:"focusFirst",value:function(){var e=this.getFocusableElements();e.length&&e[0].focus()}},{key:"focusNext",value:function(){var e=this.getFocusableElements();if(0!==e.length){var t=e.indexOf(document.activeElement);e[(t+1)%e.length].focus()}}},{key:"focusPrevious",value:function(){var e=this.getFocusableElements();if(0!==e.length){var t=e.indexOf(document.activeElement);e[(t-1+e.length)%e.length].focus()}}},{key:"render",value:function(){var e=this.props,t=e.children,n=N_(e,z_);return V.a.createElement("div",E_({},n,{className:xn()("dropdown",{show:this.state.open},n.className),ref:this.containerRef}),V.a.createElement(C_,{value:{buttonRef:this.buttonRef,handleMenuKeyDown:this.handleMenuKeyDown,isOpen:this.state.open,menuRef:this.menuRef,toggle:this.toggle,triggerId:this.triggerId}},t))}}])&&w_(t.prototype,n),r&&w_(t,r),i}(V.a.Component);x_(P_,"idCounter",0),P_.propTypes={children:En.a.node.isRequired},P_.Item=v_,P_.Button=l_,P_.Menu=m_;var j_=Da(P_,"Dropdown",{menuItems:{deprType:Ea.MOVED_AND_FORMAT,message:"They should be components sent as children.",newName:"children",transform:function(e,t){return Array.isArray(e)?V.a.createElement(V.a.Fragment,null,V.a.createElement(l_,null,V.a.isValidElement(t.iconElement)?t.iconElement:null,t.title),V.a.createElement(m_,null,e.map((function(e,t){return V.a.isValidElement(e)?V.a.cloneElement(e,{className:"dropdown-item",key:t}):V.a.createElement(v_,{key:t,href:e.href},e.label)})))):null}},title:{deprType:Ea.REMOVED,message:"It should be specified inside the Dropdown.Button component"},buttonType:{deprType:Ea.REMOVED,message:"It should be specified as a className prop"},iconElement:{deprType:Ea.REMOVED,message:"It should be specified inside the buttonContent prop."}});j_.propTypes=P_.propTypes,j_.defaultProps=P_.defaultProps,j_.Item=P_.Item,j_.Button=P_.Button,j_.Menu=P_.Menu;var R_=j_;function W_(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return q_(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return q_(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function q_(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var V_=V.a.forwardRef((function(e,t){var n=e.show,r=e.autoClose,a=e.onToggle,i=U_(e,B_),o=W_(V.a.useState(n),2),s=o[0],c=o[1];return V.a.createElement(Hu,I_({show:s,onToggle:function(e,t,n){if(e)c(!0);else{var i=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;return V.a.createElement("div",{className:"pgn__data-table-side-filters"},V.a.createElement("h3",{className:"pgn__data-table-side-filters-title"},t||V.a.createElement(_a,{id:"pgn.DataTable.SidebarFilters.title",defaultMessage:"Filters",description:"Title for the sidebar filters component"})),V.a.createElement("hr",null),i.map((function(e){return V.a.createElement("div",{key:e.Header,className:"pgn__data-table-side-filters-item"},e.render("Filter"))})),o&&V.a.createElement(V.a.Fragment,null,V.a.createElement(fc,{className:"pgn__data-table-side-filters-status",showFilteredFields:!1,variant:"tertiary"})))};Cg.propTypes={title:En.a.oneOfType([En.a.string,En.a.element])},Cg.defaultProps={title:void 0};var Yg=Cg,Pg=function(e){var t=e.filtersTitle,n=e.className,r=e.children,a=Object(U.useContext)(Vo),i=a.setFilter,o=a.showFiltersInSidebar;return V.a.createElement("div",{className:xn()("pgn__data-table-layout-wrapper",n)},o&&i&&V.a.createElement("div",{className:"pgn__data-table-layout-sidebar"},V.a.createElement(Yg,{title:t})),V.a.createElement("div",{className:"pgn__data-table-layout-main"},r))};Pg.defaultProps={className:null,filtersTitle:void 0},Pg.propTypes={className:En.a.string,children:En.a.node.isRequired,filtersTitle:En.a.oneOfType([En.a.string,En.a.element])};var jg=Pg,Rg=function(e){var t=e.getToggleAllRowsExpandedProps,n=e.isAllRowsExpanded;return V.a.createElement("span",t(),n?V.a.createElement(Oi,{variant:"link",size:"inline"},V.a.createElement(_a,{id:"pgn.DataTable.ExpandAll.collapseAllLabel",defaultMessage:"Collapse all",description:"Label of an action button that collapses all expandable rows of DataTable."})):V.a.createElement(Oi,{variant:"link",size:"inline"},V.a.createElement(_a,{id:"pgn.DataTable.ExpandAll.expandAllLabel",defaultMessage:"Expand all",description:"Label of an action button that expands all expandable rows of DataTable."})))};Rg.propTypes={getToggleAllRowsExpandedProps:En.a.func.isRequired,isAllRowsExpanded:En.a.bool.isRequired};var Wg=Rg,qg=function(e){var t=e.row;return V.a.createElement("span",t.getToggleRowExpandedProps(),t.isExpanded?V.a.createElement(Hm,{src:wo,iconAs:qa,alt:"Collapse row",size:"inline"}):V.a.createElement(Hm,{src:To,iconAs:qa,alt:"Expand row",size:"inline"}))};qg.propTypes={row:En.a.shape({isExpanded:En.a.bool,getToggleRowExpandedProps:En.a.func.isRequired}).isRequired};var Bg=qg,Hg=n(25),Ig=n.n(Hg);function Xg(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Fg(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:$g,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case"SET SELECTED ROWS":var n=Ig()([].concat(Vg(e.selectedRows),Vg(t.rows)),(function(e){return e.id})),r=Fg(Fg({},e),{},{selectedRows:n});return n.length===t.itemCount&&(r.isEntireTableSelected=!0),r;case"SELECT ALL ROWS ALL PAGES":return Fg(Fg({},e),{},{isEntireTableSelected:!0});case"DELETE ROW":return{selectedRows:e.selectedRows.filter((function(e){return e.id!==t.rowId})),isEntireTableSelected:!1};case"ADD ROW":var a=Ig()([].concat(Vg(e.selectedRows),[t.row]),(function(e){return e.id})),i=a.length===t.itemCount;return{selectedRows:a,isEntireTableSelected:i};case"CLEAR SELECTION":return $g;case"CLEAR PAGE SELECTION":return{isEntireTableSelected:!1,selectedRows:e.selectedRows.filter((function(e){return!t.rowIds.includes(e.id)}))};default:return e}};function Kg(e){return function(e){if(Array.isArray(e))return ey(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||Zg(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Qg(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||Zg(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Zg(e,t){if(e){if("string"==typeof e)return ey(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?ey(e,t):void 0}}function ey(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function cy(e){var t=e.columns,n=e.data,r=e.defaultColumnValues,a=e.additionalColumns,i=e.isSelectable,o=e.isPaginated,s=e.manualPagination,c=e.pageCount,l=e.itemCount,u=e.isFilterable,d=e.manualFilters,f=e.fetchData,p=e.initialState,m=e.isSortable,h=e.manualSortBy,b=e.isExpandable,M=e.renderRowSubComponent,_=e.bulkActions,g=e.tableActions,y=e.numBreakoutFilters,v=e.initialTableOptions,L=e.EmptyTableComponent,w=e.manualSelectColumn,A=e.showFiltersInSidebar,T=e.dataViewToggleOptions,O=e.disableElevation,k=e.isLoading,S=e.children,z=sy(e,ry),E=Object(U.useMemo)((function(){return r}),[r]),N=Object(U.useMemo)((function(){return iy({columns:t,data:n,defaultColumn:E,manualFilters:d,manualPagination:s,manualSortBy:h,initialState:p},v)}),[t,n,E,d,s,p,v,h]),x=Qg(Object(U.useReducer)(Jg,$g),2),D=x[0],C=x[1];o&&s&&(N.pageCount=c||-1);var Y=uc({tableOptions:N,isFilterable:u,isSelectable:i,isPaginated:o,isSortable:m,isExpandable:b});Y.push((function(e){e.visibleColumns.push((function(e){return sc(i,e,a,w)}))}));var P={},j=D.selectedRows;if(j.length>0){var R={};j.forEach((function(e){R[e.id]=!0})),Y.push((function(e){e.useControlledState.push((function(e){return iy(iy({},e),{},{selectedRowIds:R})}))})),P.selectedFlatRows=j}var W=[D,C],q=Qi.useTable.apply(void 0,Kg(Y)),B=iy({},q.state);delete B.selectedRowIds,Object(U.useEffect)((function(){f&&f(B)}),[f,JSON.stringify(B)]);var H=function(e,t){var n=e.toggleAllRowsSelected,r=Qo(t,2),a=r[0],i=a.selectedRows,o=a.isEntireTableSelected,s=r[1];return{clearSelection:function(){i.length>0||o?s({type:"CLEAR SELECTION"}):n(!1)}}}(q,W),I=iy(iy(iy(iy({},q),{},{itemCount:l,numBreakoutFilters:y,bulkActions:_,tableActions:g,controlledTableSelections:W,showFiltersInSidebar:A,dataViewToggleOptions:T,renderRowSubComponent:M,disableElevation:O,isLoading:k},P),H),z);return V.a.createElement(Vo.Provider,{value:I},V.a.createElement(jg,null,V.a.createElement("div",{className:xn()("pgn__data-table-wrapper",{"hide-shadow":!!O})},S||V.a.createElement(V.a.Fragment,null,V.a.createElement(t_,null),V.a.createElement(ts,null),V.a.createElement(L,{content:"No results found"}),V.a.createElement(Mg,null)))))}cy.defaultProps={additionalColumns:[],defaultColumnValues:{},isFilterable:!1,isPaginated:!1,isSelectable:!1,isSortable:!1,manualFilters:!1,manualPagination:!1,manualSortBy:!1,fetchData:null,initialState:{},initialTableOptions:{},EmptyTableComponent:r_,children:null,bulkActions:[],tableActions:[],numBreakoutFilters:1,manualSelectColumn:void 0,SelectionStatusComponent:gc,FilterStatusComponent:fc,RowStatusComponent:mc,showFiltersInSidebar:!1,dataViewToggleOptions:{isDataViewToggleEnabled:!1,onDataViewToggle:function(){},defaultActiveStateValue:"card",togglePlacement:"left"},disableElevation:!1,renderRowSubComponent:void 0,isExpandable:!1,isLoading:!1},cy.propTypes={columns:En.a.arrayOf(En.a.shape({Header:En.a.oneOfType([En.a.func,En.a.node]).isRequired,accessor:(ty=En.a.string,ny="Cell",cc(ty,(function(e){return!e[ny]}),"not ".concat(ny))),Cell:En.a.oneOfType([En.a.func,En.a.element]),Filter:En.a.func,filter:En.a.string,filterChoices:En.a.arrayOf(En.a.shape({name:En.a.string,number:En.a.number,value:En.a.string}))})).isRequired,data:En.a.arrayOf(En.a.shape({})).isRequired,isSelectable:En.a.bool,manualSelectColumn:En.a.shape({id:En.a.string.isRequired,Header:En.a.oneOfType([En.a.func,En.a.node]).isRequired,Cell:En.a.func.isRequired,disableSortBy:En.a.bool.isRequired}),isSortable:En.a.bool,manualSortBy:En.a.bool,isPaginated:En.a.bool,manualPagination:En.a.bool,pageCount:lc(En.a.number,"manualPagination"),isFilterable:En.a.bool,manualFilters:En.a.bool,defaultColumnValues:En.a.shape({Filter:En.a.oneOfType([En.a.func,En.a.node])}),additionalColumns:En.a.arrayOf(En.a.shape({id:En.a.string.isRequired,Header:En.a.oneOfType([En.a.string,En.a.node]),Cell:En.a.oneOfType([En.a.func,En.a.node])})),fetchData:En.a.func,initialState:En.a.shape({pageSize:lc(En.a.number,"isPaginated"),pageIndex:lc(En.a.number,"isPaginated"),filters:lc(En.a.arrayOf(En.a.shape()),"manualFilters"),sortBy:lc(En.a.arrayOf(En.a.shape()),"manualSortBy")}),initialTableOptions:En.a.shape({}),itemCount:En.a.number.isRequired,bulkActions:En.a.oneOfType([En.a.arrayOf(En.a.oneOfType([En.a.shape({buttonText:En.a.string.isRequired,handleClick:En.a.func.isRequired,className:En.a.string,variant:En.a.string,disabled:En.a.bool}),En.a.func,En.a.element])),En.a.func,En.a.element]),tableActions:En.a.oneOfType([En.a.arrayOf(En.a.oneOfType([En.a.shape({buttonText:En.a.string.isRequired,handleClick:En.a.func.isRequired,className:En.a.string,variant:En.a.string,disabled:En.a.bool}),En.a.func,En.a.element])),En.a.func,En.a.element]),numBreakoutFilters:En.a.oneOf([1,2,3,4]),EmptyTableComponent:En.a.func,RowStatusComponent:En.a.func,SelectionStatusComponent:En.a.func,FilterStatusComponent:En.a.func,children:En.a.oneOfType([En.a.arrayOf(En.a.node),En.a.node]),showFiltersInSidebar:En.a.bool,dataViewToggleOptions:En.a.shape({isDataViewToggleEnabled:En.a.bool,onDataViewToggle:En.a.func,defaultActiveStateValue:En.a.string,togglePlacement:En.a.string}),disableElevation:En.a.bool,renderRowSubComponent:En.a.func,isExpandable:En.a.bool,isLoading:En.a.bool},cy.BulkActions=IM,cy.EmptyTable=r_,cy.DropdownFilters=$u,cy.FilterStatus=fc,cy.RowStatus=mc,cy.SelectionStatus=gc,cy.SmartStatus=yc,cy.Table=ts,cy.TableCell=Uo,cy.TableControlBar=t_,cy.TableFilters=wg,cy.TableFooter=Mg,cy.TableHeaderCell=Ro,cy.TableHeaderRow=Bo,cy.TablePagination=mg,cy.TablePaginationMinimal=hg,cy.TableActions=FM,cy.ControlledSelectionStatus=vg,cy.ControlledSelect=Sg,cy.ControlledSelectHeader=Dg,cy.ExpandAll=Wg,cy.ExpandRow=Bg;var ly=cy;function uy(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function dy(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n header .").concat(this.SLIDABLE_CLASS),this.element).focus())}},{key:"srClear",value:function(){$(this.READER_FEEDBACK_CLASS).html("")}},{key:"srReadTexts",value:function(e){var t=$(this.READER_FEEDBACK_CLASS),n="";this.srClear(),$.each(e,(function(e,t){n="".concat(n,"

    ").concat(t,"

    \n")})),t.html(n)}},{key:"areSRStepsLoading",value:function(){return this.responseView.isRendering||this.peerView.isRendering||this.selfView.isRendering||this.gradeView.isRendering||this.trainingView.isRendering||this.staffView.isRendering}},{key:"announceStatusChangeToSRandFocus",value:function(e,t,n,r,a){var i=this.getStatus(e,r,n);void 0!==t&&$(e,r.element).hasClass("is--showing")&&void 0!==a?($(a,r.element).focus(),this.srStatusUpdates.push(i)):r.announceStatus&&this.srStatusUpdates.push(i),!this.areSRStepsLoading()&&this.srStatusUpdates.length>0&&(this.srReadTexts(this.srStatusUpdates),this.srStatusUpdates=[]),r.announceStatus=!1}},{key:"getStatus",value:function(e,t,n){var r="".concat(e," .step__header .step__title "),a="".concat(r,".step__label"),i="".concat(r,".step__status");return n&&(i="".concat(r,".grade__value")),"".concat($(a,t.element).text().trim()," ").concat($(i,t.element).text().trim())}},{key:"setUpCollapseExpand",value:function(e){var t=this;$(".".concat(t.SLIDABLE_CONTROLS_CLASS),e).each((function(){$(this).on("click",(function(e){e.preventDefault();var n=$(e.target).closest(".".concat(t.SLIDABLE_CONTROLS_CLASS)),r=n.closest(".".concat(t.SLIDABLE_CONTAINER_CLASS)),a=n.find(".".concat(t.SLIDABLE_CLASS)),i=n.next(".".concat(t.SLIDABLE_CONTENT_CLASS));r.hasClass("is--showing")?(i.slideUp(),a.attr("aria-expanded","false"),r.removeClass("is--showing")):r.hasClass("has--error")||r.hasClass("is--empty")||r.hasClass("is--unavailable")||(i.slideDown(),a.attr("aria-expanded","true"),r.addClass("is--showing")),r.removeClass("is--initially--collapsed ")}))}))}},{key:"bindLatexPreview",value:function(e){e.find(".submission__preview__item").hide(),e.find(".submission__preview").click((function(t){t.preventDefault();var n=$(t.target).data("input"),r=e.find('textarea[data-preview="'.concat(n,'"]')).val(),a=e.find('.preview_content[data-preview="'.concat(n,'"]'));a.html(r.replace(/\r\n|\r|\n/g,"
    ")),a.parent().parent().parent().show(),MathJax.Hub.Queue(["Typeset",MathJax.Hub,a[0]])}))}},{key:"getUsageID",value:function(){return this.usageID||(this.usageID=$(this.element).data("usage-id")),this.usageID}},{key:"load",value:function(){this.responseView.load(),this.loadAssessmentModules(),this.staffAreaView.load()}},{key:"loadAssessmentModules",value:function(e){this.trainingView.load(e),this.peerView.load(e),this.staffView.load(e),this.selfView.load(e),this.gradeView.load(e),this.leaderboardView.load(e)}},{key:"loadMessageView",value:function(){this.messageView.load()}},{key:"toggleActionError",value:function(e,t){var n=this.element,r=null;if("save"===e?r=".response__submission__actions":"submit"===e||"peer"===e||"self"===e||"student-training"===e?r=".step__actions":"feedback_assess"===e?r=".submission__feedback__actions":"upload"===e?r=".upload__error":"delete"===e&&(r=".delete__error"),null===r?null!==t&&console.log(t):($("".concat(r," .message__content"),n).html("

    ".concat(t?_.escape(t):"","

    ")),$(r,n).toggleClass("has--error",null!==t),$("".concat(r," > .message"),n).focus()),null!==t){var a=$("".concat(r," .message__title")).text();this.srReadTexts([a,t])}}},{key:"showLoadError",value:function(e,t){t||(t=gettext("Unable to load"));var n=$(".step--".concat(e));n.toggleClass("has--error",!0),n.removeClass("is--showing"),n.find(".ui-slidable").attr("aria-expanded","false"),n.find(".step__status__value i").removeClass().addClass("icon fa fa-exclamation-triangle"),n.find(".step__status__value .copy").html(_.escape(t))}},{key:"unsavedWarningEnabled",value:function(e,t,n){if(void 0===e)return null!==window.onbeforeunload;var r=$(this.element).data("usage-id");e?(void 0!==this.unsavedChanges[r]&&this.unsavedChanges[r]||(this.unsavedChanges[r]={}),this.unsavedChanges[r][t]=n,window.onbeforeunload=function(){var e,n=this;return Object.keys(this.unsavedChanges).some((function(r){if(n.unsavedChanges.hasOwnProperty(r)){var a=n.unsavedChanges[r];return Object.keys(a).some((function(n){return!!a.hasOwnProperty(t)&&(e=a[t],!0)}))}return!1})),e}):void 0!==this.unsavedChanges[r]&&(delete this.unsavedChanges[r][t],$.isEmptyObject(this.unsavedChanges[r])&&delete this.unsavedChanges[r],$.isEmptyObject(this.unsavedChanges)&&(window.onbeforeunload=null))}},{key:"buttonEnabled",value:function(e,t){var n=$(e,this.element);return void 0===t?!n.prop("disabled"):(n.prop("disabled",!t),t)}}])&&wy(t.prototype,n),r&&wy(t,r),e}();window.OpenAssessmentBlock=function(e,t,n){var a=new r.a(e,t);new Ty(e,t,a,n).load()},window.CourseOpenResponsesListingBlock=function(e,t,n){new a.a(e,t,n).refreshGrids()},window.StaffAssessmentBlock=function(e,t,n){var a=new r.a(e,t);new Ty(e,t,a,n).staffAreaView.installHandlers()},window.WaitingStepDetailsBlock=function(e,t,n){var a=new r.a(e,t),i=new Ty(e,t,a,n);Ly(i,n)}},,,,,,,,,,,function(e,t,n){"use strict";(function(e){var r=n(0);function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;)t+="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[62*Math.random()|0];return t}function Xd(e){for(var t=[],n=(e||[]).length>>>0;n--;)t[n]=e[n];return t}function Fd(e){return e.classList?Xd(e.classList):(e.getAttribute("class")||"").split(" ").filter((function(e){return e}))}function Ud(e){return"".concat(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function Vd(e){return Object.keys(e||{}).reduce((function(t,n){return t+"".concat(n,": ").concat(e[n].trim(),";")}),"")}function Gd(e){return e.size!==Hd.size||e.x!==Hd.x||e.y!==Hd.y||e.rotate!==Hd.rotate||e.flipX||e.flipY}function $d(){var e="svg-inline--fa",t=Wd.familyPrefix,n=Wd.replacementClass,r=':root, :host {\n --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Solid";\n --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Regular";\n --fa-font-light: normal 300 1em/1 "Font Awesome 6 Light";\n --fa-font-thin: normal 100 1em/1 "Font Awesome 6 Thin";\n --fa-font-duotone: normal 900 1em/1 "Font Awesome 6 Duotone";\n --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands";\n}\n\nsvg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {\n overflow: visible;\n box-sizing: content-box;\n}\n\n.svg-inline--fa {\n display: var(--fa-display, inline-block);\n height: 1em;\n overflow: visible;\n vertical-align: -0.125em;\n}\n.svg-inline--fa.fa-2xs {\n vertical-align: 0.1em;\n}\n.svg-inline--fa.fa-xs {\n vertical-align: 0em;\n}\n.svg-inline--fa.fa-sm {\n vertical-align: -0.0714285705em;\n}\n.svg-inline--fa.fa-lg {\n vertical-align: -0.2em;\n}\n.svg-inline--fa.fa-xl {\n vertical-align: -0.25em;\n}\n.svg-inline--fa.fa-2xl {\n vertical-align: -0.3125em;\n}\n.svg-inline--fa.fa-pull-left {\n margin-right: var(--fa-pull-margin, 0.3em);\n width: auto;\n}\n.svg-inline--fa.fa-pull-right {\n margin-left: var(--fa-pull-margin, 0.3em);\n width: auto;\n}\n.svg-inline--fa.fa-li {\n width: var(--fa-li-width, 2em);\n top: 0.25em;\n}\n.svg-inline--fa.fa-fw {\n width: var(--fa-fw-width, 1.25em);\n}\n\n.fa-layers svg.svg-inline--fa {\n bottom: 0;\n left: 0;\n margin: auto;\n position: absolute;\n right: 0;\n top: 0;\n}\n\n.fa-layers-counter, .fa-layers-text {\n display: inline-block;\n position: absolute;\n text-align: center;\n}\n\n.fa-layers {\n display: inline-block;\n height: 1em;\n position: relative;\n text-align: center;\n vertical-align: -0.125em;\n width: 1em;\n}\n.fa-layers svg.svg-inline--fa {\n -webkit-transform-origin: center center;\n transform-origin: center center;\n}\n\n.fa-layers-text {\n left: 50%;\n top: 50%;\n -webkit-transform: translate(-50%, -50%);\n transform: translate(-50%, -50%);\n -webkit-transform-origin: center center;\n transform-origin: center center;\n}\n\n.fa-layers-counter {\n background-color: var(--fa-counter-background-color, #ff253a);\n border-radius: var(--fa-counter-border-radius, 1em);\n box-sizing: border-box;\n color: var(--fa-inverse, #fff);\n line-height: var(--fa-counter-line-height, 1);\n max-width: var(--fa-counter-max-width, 5em);\n min-width: var(--fa-counter-min-width, 1.5em);\n overflow: hidden;\n padding: var(--fa-counter-padding, 0.25em 0.5em);\n right: var(--fa-right, 0);\n text-overflow: ellipsis;\n top: var(--fa-top, 0);\n -webkit-transform: scale(var(--fa-counter-scale, 0.25));\n transform: scale(var(--fa-counter-scale, 0.25));\n -webkit-transform-origin: top right;\n transform-origin: top right;\n}\n\n.fa-layers-bottom-right {\n bottom: var(--fa-bottom, 0);\n right: var(--fa-right, 0);\n top: auto;\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: bottom right;\n transform-origin: bottom right;\n}\n\n.fa-layers-bottom-left {\n bottom: var(--fa-bottom, 0);\n left: var(--fa-left, 0);\n right: auto;\n top: auto;\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: bottom left;\n transform-origin: bottom left;\n}\n\n.fa-layers-top-right {\n top: var(--fa-top, 0);\n right: var(--fa-right, 0);\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: top right;\n transform-origin: top right;\n}\n\n.fa-layers-top-left {\n left: var(--fa-left, 0);\n right: auto;\n top: var(--fa-top, 0);\n -webkit-transform: scale(var(--fa-layers-scale, 0.25));\n transform: scale(var(--fa-layers-scale, 0.25));\n -webkit-transform-origin: top left;\n transform-origin: top left;\n}\n\n.fa-1x {\n font-size: 1em;\n}\n\n.fa-2x {\n font-size: 2em;\n}\n\n.fa-3x {\n font-size: 3em;\n}\n\n.fa-4x {\n font-size: 4em;\n}\n\n.fa-5x {\n font-size: 5em;\n}\n\n.fa-6x {\n font-size: 6em;\n}\n\n.fa-7x {\n font-size: 7em;\n}\n\n.fa-8x {\n font-size: 8em;\n}\n\n.fa-9x {\n font-size: 9em;\n}\n\n.fa-10x {\n font-size: 10em;\n}\n\n.fa-2xs {\n font-size: 0.625em;\n line-height: 0.1em;\n vertical-align: 0.225em;\n}\n\n.fa-xs {\n font-size: 0.75em;\n line-height: 0.0833333337em;\n vertical-align: 0.125em;\n}\n\n.fa-sm {\n font-size: 0.875em;\n line-height: 0.0714285718em;\n vertical-align: 0.0535714295em;\n}\n\n.fa-lg {\n font-size: 1.25em;\n line-height: 0.05em;\n vertical-align: -0.075em;\n}\n\n.fa-xl {\n font-size: 1.5em;\n line-height: 0.0416666682em;\n vertical-align: -0.125em;\n}\n\n.fa-2xl {\n font-size: 2em;\n line-height: 0.03125em;\n vertical-align: -0.1875em;\n}\n\n.fa-fw {\n text-align: center;\n width: 1.25em;\n}\n\n.fa-ul {\n list-style-type: none;\n margin-left: var(--fa-li-margin, 2.5em);\n padding-left: 0;\n}\n.fa-ul > li {\n position: relative;\n}\n\n.fa-li {\n left: calc(var(--fa-li-width, 2em) * -1);\n position: absolute;\n text-align: center;\n width: var(--fa-li-width, 2em);\n line-height: inherit;\n}\n\n.fa-border {\n border-color: var(--fa-border-color, #eee);\n border-radius: var(--fa-border-radius, 0.1em);\n border-style: var(--fa-border-style, solid);\n border-width: var(--fa-border-width, 0.08em);\n padding: var(--fa-border-padding, 0.2em 0.25em 0.15em);\n}\n\n.fa-pull-left {\n float: left;\n margin-right: var(--fa-pull-margin, 0.3em);\n}\n\n.fa-pull-right {\n float: right;\n margin-left: var(--fa-pull-margin, 0.3em);\n}\n\n.fa-beat {\n -webkit-animation-name: fa-beat;\n animation-name: fa-beat;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);\n animation-timing-function: var(--fa-animation-timing, ease-in-out);\n}\n\n.fa-bounce {\n -webkit-animation-name: fa-bounce;\n animation-name: fa-bounce;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));\n}\n\n.fa-fade {\n -webkit-animation-name: fa-fade;\n animation-name: fa-fade;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n}\n\n.fa-beat-fade {\n -webkit-animation-name: fa-beat-fade;\n animation-name: fa-beat-fade;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));\n}\n\n.fa-flip {\n -webkit-animation-name: fa-flip;\n animation-name: fa-flip;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);\n animation-timing-function: var(--fa-animation-timing, ease-in-out);\n}\n\n.fa-shake {\n -webkit-animation-name: fa-shake;\n animation-name: fa-shake;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, linear);\n animation-timing-function: var(--fa-animation-timing, linear);\n}\n\n.fa-spin {\n -webkit-animation-name: fa-spin;\n animation-name: fa-spin;\n -webkit-animation-delay: var(--fa-animation-delay, 0);\n animation-delay: var(--fa-animation-delay, 0);\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 2s);\n animation-duration: var(--fa-animation-duration, 2s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, linear);\n animation-timing-function: var(--fa-animation-timing, linear);\n}\n\n.fa-spin-reverse {\n --fa-animation-direction: reverse;\n}\n\n.fa-pulse,\n.fa-spin-pulse {\n -webkit-animation-name: fa-spin;\n animation-name: fa-spin;\n -webkit-animation-direction: var(--fa-animation-direction, normal);\n animation-direction: var(--fa-animation-direction, normal);\n -webkit-animation-duration: var(--fa-animation-duration, 1s);\n animation-duration: var(--fa-animation-duration, 1s);\n -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n animation-iteration-count: var(--fa-animation-iteration-count, infinite);\n -webkit-animation-timing-function: var(--fa-animation-timing, steps(8));\n animation-timing-function: var(--fa-animation-timing, steps(8));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fa-beat,\n.fa-bounce,\n.fa-fade,\n.fa-beat-fade,\n.fa-flip,\n.fa-pulse,\n.fa-shake,\n.fa-spin,\n.fa-spin-pulse {\n -webkit-animation-delay: -1ms;\n animation-delay: -1ms;\n -webkit-animation-duration: 1ms;\n animation-duration: 1ms;\n -webkit-animation-iteration-count: 1;\n animation-iteration-count: 1;\n transition-delay: 0s;\n transition-duration: 0s;\n }\n}\n@-webkit-keyframes fa-beat {\n 0%, 90% {\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 45% {\n -webkit-transform: scale(var(--fa-beat-scale, 1.25));\n transform: scale(var(--fa-beat-scale, 1.25));\n }\n}\n@keyframes fa-beat {\n 0%, 90% {\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 45% {\n -webkit-transform: scale(var(--fa-beat-scale, 1.25));\n transform: scale(var(--fa-beat-scale, 1.25));\n }\n}\n@-webkit-keyframes fa-bounce {\n 0% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 10% {\n -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n }\n 30% {\n -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n }\n 50% {\n -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n }\n 57% {\n -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n }\n 64% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 100% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n}\n@keyframes fa-bounce {\n 0% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 10% {\n -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);\n }\n 30% {\n -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));\n }\n 50% {\n -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);\n }\n 57% {\n -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));\n }\n 64% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n 100% {\n -webkit-transform: scale(1, 1) translateY(0);\n transform: scale(1, 1) translateY(0);\n }\n}\n@-webkit-keyframes fa-fade {\n 50% {\n opacity: var(--fa-fade-opacity, 0.4);\n }\n}\n@keyframes fa-fade {\n 50% {\n opacity: var(--fa-fade-opacity, 0.4);\n }\n}\n@-webkit-keyframes fa-beat-fade {\n 0%, 100% {\n opacity: var(--fa-beat-fade-opacity, 0.4);\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));\n transform: scale(var(--fa-beat-fade-scale, 1.125));\n }\n}\n@keyframes fa-beat-fade {\n 0%, 100% {\n opacity: var(--fa-beat-fade-opacity, 0.4);\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));\n transform: scale(var(--fa-beat-fade-scale, 1.125));\n }\n}\n@-webkit-keyframes fa-flip {\n 50% {\n -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n }\n}\n@keyframes fa-flip {\n 50% {\n -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));\n }\n}\n@-webkit-keyframes fa-shake {\n 0% {\n -webkit-transform: rotate(-15deg);\n transform: rotate(-15deg);\n }\n 4% {\n -webkit-transform: rotate(15deg);\n transform: rotate(15deg);\n }\n 8%, 24% {\n -webkit-transform: rotate(-18deg);\n transform: rotate(-18deg);\n }\n 12%, 28% {\n -webkit-transform: rotate(18deg);\n transform: rotate(18deg);\n }\n 16% {\n -webkit-transform: rotate(-22deg);\n transform: rotate(-22deg);\n }\n 20% {\n -webkit-transform: rotate(22deg);\n transform: rotate(22deg);\n }\n 32% {\n -webkit-transform: rotate(-12deg);\n transform: rotate(-12deg);\n }\n 36% {\n -webkit-transform: rotate(12deg);\n transform: rotate(12deg);\n }\n 40%, 100% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n}\n@keyframes fa-shake {\n 0% {\n -webkit-transform: rotate(-15deg);\n transform: rotate(-15deg);\n }\n 4% {\n -webkit-transform: rotate(15deg);\n transform: rotate(15deg);\n }\n 8%, 24% {\n -webkit-transform: rotate(-18deg);\n transform: rotate(-18deg);\n }\n 12%, 28% {\n -webkit-transform: rotate(18deg);\n transform: rotate(18deg);\n }\n 16% {\n -webkit-transform: rotate(-22deg);\n transform: rotate(-22deg);\n }\n 20% {\n -webkit-transform: rotate(22deg);\n transform: rotate(22deg);\n }\n 32% {\n -webkit-transform: rotate(-12deg);\n transform: rotate(-12deg);\n }\n 36% {\n -webkit-transform: rotate(12deg);\n transform: rotate(12deg);\n }\n 40%, 100% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n}\n@-webkit-keyframes fa-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@keyframes fa-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.fa-rotate-90 {\n -webkit-transform: rotate(90deg);\n transform: rotate(90deg);\n}\n\n.fa-rotate-180 {\n -webkit-transform: rotate(180deg);\n transform: rotate(180deg);\n}\n\n.fa-rotate-270 {\n -webkit-transform: rotate(270deg);\n transform: rotate(270deg);\n}\n\n.fa-flip-horizontal {\n -webkit-transform: scale(-1, 1);\n transform: scale(-1, 1);\n}\n\n.fa-flip-vertical {\n -webkit-transform: scale(1, -1);\n transform: scale(1, -1);\n}\n\n.fa-flip-both,\n.fa-flip-horizontal.fa-flip-vertical {\n -webkit-transform: scale(-1, -1);\n transform: scale(-1, -1);\n}\n\n.fa-rotate-by {\n -webkit-transform: rotate(var(--fa-rotate-angle, none));\n transform: rotate(var(--fa-rotate-angle, none));\n}\n\n.fa-stack {\n display: inline-block;\n vertical-align: middle;\n height: 2em;\n position: relative;\n width: 2.5em;\n}\n\n.fa-stack-1x,\n.fa-stack-2x {\n bottom: 0;\n left: 0;\n margin: auto;\n position: absolute;\n right: 0;\n top: 0;\n z-index: var(--fa-stack-z-index, auto);\n}\n\n.svg-inline--fa.fa-stack-1x {\n height: 1em;\n width: 1.25em;\n}\n.svg-inline--fa.fa-stack-2x {\n height: 2em;\n width: 2.5em;\n}\n\n.fa-inverse {\n color: var(--fa-inverse, #fff);\n}\n\n.sr-only,\n.fa-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n.sr-only-focusable:not(:focus),\n.fa-sr-only-focusable:not(:focus) {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n.svg-inline--fa .fa-primary {\n fill: var(--fa-primary-color, currentColor);\n opacity: var(--fa-primary-opacity, 1);\n}\n\n.svg-inline--fa .fa-secondary {\n fill: var(--fa-secondary-color, currentColor);\n opacity: var(--fa-secondary-opacity, 0.4);\n}\n\n.svg-inline--fa.fa-swap-opacity .fa-primary {\n opacity: var(--fa-secondary-opacity, 0.4);\n}\n\n.svg-inline--fa.fa-swap-opacity .fa-secondary {\n opacity: var(--fa-primary-opacity, 1);\n}\n\n.svg-inline--fa mask .fa-primary,\n.svg-inline--fa mask .fa-secondary {\n fill: black;\n}\n\n.fad.fa-inverse,\n.fa-duotone.fa-inverse {\n color: var(--fa-inverse, #fff);\n}';if("fa"!==t||n!==e){var a=new RegExp("\\.".concat("fa","\\-"),"g"),i=new RegExp("\\--".concat("fa","\\-"),"g"),o=new RegExp("\\.".concat(e),"g");r=r.replace(a,".".concat(t,"-")).replace(i,"--".concat(t,"-")).replace(o,".".concat(n))}return r}var Jd=!1;function Kd(){Wd.autoAddCss&&!Jd&&(!function(e){if(e&&_d){var t=hd.createElement("style");t.setAttribute("type","text/css"),t.innerHTML=e;for(var n=hd.head.childNodes,r=null,a=n.length-1;a>-1;a--){var i=n[a],o=(i.tagName||"").toUpperCase();["STYLE","LINK"].indexOf(o)>-1&&(r=i)}hd.head.insertBefore(t,r)}}($d()),Jd=!0)}var Qd={mixout:function(){return{dom:{css:$d,insertCss:Kd}}},hooks:function(){return{beforeDOMElementCreation:function(){Kd()},beforeI2svg:function(){Kd()}}}},Zd=md||{};Zd.___FONT_AWESOME___||(Zd.___FONT_AWESOME___={}),Zd.___FONT_AWESOME___.styles||(Zd.___FONT_AWESOME___.styles={}),Zd.___FONT_AWESOME___.hooks||(Zd.___FONT_AWESOME___.hooks={}),Zd.___FONT_AWESOME___.shims||(Zd.___FONT_AWESOME___.shims=[]);var ef=Zd.___FONT_AWESOME___,tf=[],nf=!1;function rf(e){_d&&(nf?setTimeout(e,0):tf.push(e))}function af(e){var t=e.tag,n=e.attributes,r=void 0===n?{}:n,a=e.children,i=void 0===a?[]:a;return"string"==typeof e?Ud(e):"<".concat(t," ").concat(function(e){return Object.keys(e||{}).reduce((function(t,n){return t+"".concat(n,'="').concat(Ud(e[n]),'" ')}),"").trim()}(r),">").concat(i.map(af).join(""),"")}function of(e,t,n){if(e&&e[t]&&e[t][n])return{prefix:t,iconName:n,icon:e[t][n]}}_d&&((nf=(hd.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(hd.readyState))||hd.addEventListener("DOMContentLoaded",(function e(){hd.removeEventListener("DOMContentLoaded",e),nf=1,tf.map((function(e){return e()}))})));var sf=function(e,t,n,r){var a,i,o,s=Object.keys(e),c=s.length,l=void 0!==r?function(e,t){return function(n,r,a,i){return e.call(t,n,r,a,i)}}(t,r):t;for(void 0===n?(a=1,o=e[s[0]]):(a=0,o=n);a=55296&&a<=56319&&n2&&void 0!==arguments[2]?arguments[2]:{},r=n.skipHooks,a=void 0!==r&&r,i=lf(t);"function"!=typeof ef.hooks.addPack||a?ef.styles[e]=Zu(Zu({},ef.styles[e]||{}),i):ef.hooks.addPack(e,lf(t)),"fas"===e&&uf("fa",t)}var df=ef.styles,ff=ef.shims,pf=Object.values(Ad),mf=null,hf={},bf={},Mf={},_f={},gf={},yf=Object.keys(Ld);function vf(e,t){var n,r=t.split("-"),a=r[0],i=r.slice(1).join("-");return a!==e||""===i||(n=i,~Pd.indexOf(n))?null:i}var Lf,wf=function(){var e=function(e){return sf(df,(function(t,n,r){return t[r]=sf(n,e,{}),t}),{})};hf=e((function(e,t,n){(t[3]&&(e[t[3]]=n),t[2])&&t[2].filter((function(e){return"number"==typeof e})).forEach((function(t){e[t.toString(16)]=n}));return e})),bf=e((function(e,t,n){(e[n]=n,t[2])&&t[2].filter((function(e){return"string"==typeof e})).forEach((function(t){e[t]=n}));return e})),gf=e((function(e,t,n){var r=t[2];return e[n]=n,r.forEach((function(t){e[t]=n})),e}));var t="far"in df||Wd.autoFetchSvg,n=sf(ff,(function(e,n){var r=n[0],a=n[1],i=n[2];return"far"!==a||t||(a="fas"),"string"==typeof r&&(e.names[r]={prefix:a,iconName:i}),"number"==typeof r&&(e.unicodes[r.toString(16)]={prefix:a,iconName:i}),e}),{names:{},unicodes:{}});Mf=n.names,_f=n.unicodes,mf=Sf(Wd.styleDefault)};function Af(e,t){return(hf[e]||{})[t]}function Tf(e,t){return(gf[e]||{})[t]}function Of(e){return Mf[e]||{prefix:null,iconName:null}}function kf(){return mf}Lf=function(e){mf=Sf(e.styleDefault)},qd.push(Lf),wf();function Sf(e){var t=wd[e]||wd[Ld[e]],n=e in ef.styles?e:null;return t||n||null}function zf(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.skipLookups,r=void 0!==n&&n,a=null,i=e.reduce((function(e,t){var n=vf(Wd.familyPrefix,t);if(df[t]?(t=pf.includes(t)?Td[t]:t,a=t,e.prefix=t):yf.indexOf(t)>-1?(a=t,e.prefix=Sf(t)):n?e.iconName=n:t!==Wd.replacementClass&&e.rest.push(t),!r&&e.prefix&&e.iconName){var i="fa"===a?Of(e.iconName):{},o=Tf(e.prefix,e.iconName);i.prefix&&(a=null),e.iconName=i.iconName||o||e.iconName,e.prefix=i.prefix||e.prefix,"far"!==e.prefix||df.far||!df.fas||Wd.autoFetchSvg||(e.prefix="fas")}return e}),{prefix:null,iconName:null,rest:[]});return"fa"!==i.prefix&&"fa"!==a||(i.prefix=kf()||"fas"),i}var Ef=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.definitions={}}var t,n,r;return t=e,(n=[{key:"add",value:function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r0&&s.forEach((function(t){"string"==typeof t&&(e[a][t]=o)})),e[a][i]=o})),e}}])&&td(t.prototype,n),r&&td(t,r),Object.defineProperty(t,"prototype",{writable:!1}),e}(),Nf=[],xf={},Df={},Cf=Object.keys(Df);function Yf(e,t){for(var n=arguments.length,r=new Array(n>2?n-2:0),a=2;a1?t-1:0),r=1;r0&&void 0!==arguments[0]?arguments[0]:{};return _d?(Pf("beforeI2svg",e),jf("pseudoElements2svg",e),jf("i2svg",e)):Promise.reject("Operation requires a DOM of some kind.")},watch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.autoReplaceSvgRoot;!1===Wd.autoReplaceSvg&&(Wd.autoReplaceSvg=!0),Wd.observeMutations=!0,rf((function(){Hf({autoReplaceSvgRoot:t}),Pf("watch",e)}))}},Bf={noAuto:function(){Wd.autoReplaceSvg=!1,Wd.observeMutations=!1,Pf("noAuto")},config:Wd,dom:qf,parse:{icon:function(e){if(null===e)return null;if("object"===ed(e)&&e.prefix&&e.iconName)return{prefix:e.prefix,iconName:Tf(e.prefix,e.iconName)||e.iconName};if(Array.isArray(e)&&2===e.length){var t=0===e[1].indexOf("fa-")?e[1].slice(3):e[1],n=Sf(e[0]);return{prefix:n,iconName:Tf(n,t)||t}}if("string"==typeof e&&(e.indexOf("".concat(Wd.familyPrefix,"-"))>-1||e.match(Od))){var r=zf(e.split(" "),{skipLookups:!0});return{prefix:r.prefix||kf(),iconName:Tf(r.prefix,r.iconName)||r.iconName}}if("string"==typeof e){var a=kf();return{prefix:a,iconName:Tf(a,e)||e}}}},library:Wf,findIconDefinition:Rf,toHtml:af},Hf=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.autoReplaceSvgRoot,n=void 0===t?hd:t;(Object.keys(ef.styles).length>0||Wd.autoFetchSvg)&&_d&&Wd.autoReplaceSvg&&Bf.dom.i2svg({node:n})};function If(e,t){return Object.defineProperty(e,"abstract",{get:t}),Object.defineProperty(e,"html",{get:function(){return e.abstract.map((function(e){return af(e)}))}}),Object.defineProperty(e,"node",{get:function(){if(_d){var t=hd.createElement("div");return t.innerHTML=e.html,t.children}}}),e}function Xf(e){var t=e.icons,n=t.main,r=t.mask,a=e.prefix,i=e.iconName,o=e.transform,s=e.symbol,c=e.title,l=e.maskId,u=e.titleId,d=e.extra,f=e.watchable,p=void 0!==f&&f,m=r.found?r:n,h=m.width,b=m.height,M="fak"===a,_=[Wd.replacementClass,i?"".concat(Wd.familyPrefix,"-").concat(i):""].filter((function(e){return-1===d.classes.indexOf(e)})).filter((function(e){return""!==e||!!e})).concat(d.classes).join(" "),g={children:[],attributes:Zu(Zu({},d.attributes),{},{"data-prefix":a,"data-icon":i,class:_,role:d.attributes.role||"img",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 ".concat(h," ").concat(b)})},y=M&&!~d.classes.indexOf("fa-fw")?{width:"".concat(h/b*16*.0625,"em")}:{};p&&(g.attributes["data-fa-i2svg"]=""),c&&(g.children.push({tag:"title",attributes:{id:g.attributes["aria-labelledby"]||"title-".concat(u||Id())},children:[c]}),delete g.attributes.title);var v=Zu(Zu({},g),{},{prefix:a,iconName:i,main:n,mask:r,maskId:l,transform:o,symbol:s,styles:Zu(Zu({},y),d.styles)}),L=r.found&&n.found?jf("generateAbstractMask",v)||{children:[],attributes:{}}:jf("generateAbstractIcon",v)||{children:[],attributes:{}},w=L.children,A=L.attributes;return v.children=w,v.attributes=A,s?function(e){var t=e.prefix,n=e.iconName,r=e.children,a=e.attributes,i=e.symbol,o=!0===i?"".concat(t,"-").concat(Wd.familyPrefix,"-").concat(n):i;return[{tag:"svg",attributes:{style:"display: none;"},children:[{tag:"symbol",attributes:Zu(Zu({},a),{},{id:o}),children:r}]}]}(v):function(e){var t=e.children,n=e.main,r=e.mask,a=e.attributes,i=e.styles,o=e.transform;if(Gd(o)&&n.found&&!r.found){var s={x:n.width/n.height/2,y:.5};a.style=Vd(Zu(Zu({},i),{},{"transform-origin":"".concat(s.x+o.x/16,"em ").concat(s.y+o.y/16,"em")}))}return[{tag:"svg",attributes:a,children:t}]}(v)}function Ff(e){var t=e.content,n=e.width,r=e.height,a=e.transform,i=e.title,o=e.extra,s=e.watchable,c=void 0!==s&&s,l=Zu(Zu(Zu({},o.attributes),i?{title:i}:{}),{},{class:o.classes.join(" ")});c&&(l["data-fa-i2svg"]="");var u=Zu({},o.styles);Gd(a)&&(u.transform=function(e){var t=e.transform,n=e.width,r=void 0===n?16:n,a=e.height,i=void 0===a?16:a,o=e.startCentered,s=void 0!==o&&o,c="";return c+=s&&gd?"translate(".concat(t.x/Bd-r/2,"em, ").concat(t.y/Bd-i/2,"em) "):s?"translate(calc(-50% + ".concat(t.x/Bd,"em), calc(-50% + ").concat(t.y/Bd,"em)) "):"translate(".concat(t.x/Bd,"em, ").concat(t.y/Bd,"em) "),c+="scale(".concat(t.size/Bd*(t.flipX?-1:1),", ").concat(t.size/Bd*(t.flipY?-1:1),") "),c+="rotate(".concat(t.rotate,"deg) ")}({transform:a,startCentered:!0,width:n,height:r}),u["-webkit-transform"]=u.transform);var d=Vd(u);d.length>0&&(l.style=d);var f=[];return f.push({tag:"span",attributes:l,children:[t]}),i&&f.push({tag:"span",attributes:{class:"sr-only"},children:[i]}),f}function Uf(e){var t=e.content,n=e.title,r=e.extra,a=Zu(Zu(Zu({},r.attributes),n?{title:n}:{}),{},{class:r.classes.join(" ")}),i=Vd(r.styles);i.length>0&&(a.style=i);var o=[];return o.push({tag:"span",attributes:a,children:[t]}),n&&o.push({tag:"span",attributes:{class:"sr-only"},children:[n]}),o}var Vf=ef.styles;function Gf(e){var t=e[0],n=e[1],r=rd(e.slice(4),1)[0];return{found:!0,width:t,height:n,icon:Array.isArray(r)?{tag:"g",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(xd)},children:[{tag:"path",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(Yd),fill:"currentColor",d:r[0]}},{tag:"path",attributes:{class:"".concat(Wd.familyPrefix,"-").concat(Cd),fill:"currentColor",d:r[1]}}]}:{tag:"path",attributes:{fill:"currentColor",d:r}}}}var $f={found:!1,width:512,height:512};function Jf(e,t){var n=t;return"fa"===t&&null!==Wd.styleDefault&&(t=kf()),new Promise((function(r,a){jf("missingIconAbstract");if("fa"===n){var i=Of(e)||{};e=i.iconName||e,t=i.prefix||t}if(e&&t&&Vf[t]&&Vf[t][e])return r(Gf(Vf[t][e]));!function(e,t){vd||Wd.showMissingIcons||!e||console.error('Icon with name "'.concat(e,'" and prefix "').concat(t,'" is missing.'))}(e,t),r(Zu(Zu({},$f),{},{icon:Wd.showMissingIcons&&e&&jf("missingIconAbstract")||{}}))}))}var Kf=function(){},Qf=Wd.measurePerformance&&Md&&Md.mark&&Md.measure?Md:{mark:Kf,measure:Kf},Zf=function(e){Qf.mark("".concat('FA "6.1.2"'," ").concat(e," ends")),Qf.measure("".concat('FA "6.1.2"'," ").concat(e),"".concat('FA "6.1.2"'," ").concat(e," begins"),"".concat('FA "6.1.2"'," ").concat(e," ends"))},ep=function(e){return Qf.mark("".concat('FA "6.1.2"'," ").concat(e," begins")),function(){return Zf(e)}},tp=function(){};function np(e){return"string"==typeof(e.getAttribute?e.getAttribute("data-fa-i2svg"):null)}function rp(e){return hd.createElementNS("http://www.w3.org/2000/svg",e)}function ap(e){return hd.createElement(e)}var ip={replace:function(e){var t=e[0];if(t.parentNode)if(e[1].forEach((function(e){t.parentNode.insertBefore(function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.ceFn,a=void 0===r?"svg"===t.tag?rp:ap:r;if("string"==typeof t)return hd.createTextNode(t);var i=a(t.tag);Object.keys(t.attributes||[]).forEach((function(e){i.setAttribute(e,t.attributes[e])}));var o=t.children||[];return o.forEach((function(t){i.appendChild(e(t,{ceFn:a}))})),i}(e),t)})),null===t.getAttribute("data-fa-i2svg")&&Wd.keepOriginalSource){var n=hd.createComment(function(e){var t=" ".concat(e.outerHTML," ");return t="".concat(t,"Font Awesome fontawesome.com ")}(t));t.parentNode.replaceChild(n,t)}else t.remove()},nest:function(e){var t=e[0],n=e[1];if(~Fd(t).indexOf(Wd.replacementClass))return ip.replace(e);var r=new RegExp("".concat(Wd.familyPrefix,"-.*"));if(delete n[0].attributes.id,n[0].attributes.class){var a=n[0].attributes.class.split(" ").reduce((function(e,t){return t===Wd.replacementClass||t.match(r)?e.toSvg.push(t):e.toNode.push(t),e}),{toNode:[],toSvg:[]});n[0].attributes.class=a.toSvg.join(" "),0===a.toNode.length?t.removeAttribute("class"):t.setAttribute("class",a.toNode.join(" "))}var i=n.map((function(e){return af(e)})).join("\n");t.setAttribute("data-fa-i2svg",""),t.innerHTML=i}};function op(e){e()}function sp(e,t){var n="function"==typeof t?t:tp;if(0===e.length)n();else{var r=op;"async"===Wd.mutateApproach&&(r=md.requestAnimationFrame||op),r((function(){var t=!0===Wd.autoReplaceSvg?ip.replace:ip[Wd.autoReplaceSvg]||ip.replace,r=ep("mutate");e.map(t),r(),n()}))}}var cp=!1;function lp(){cp=!0}function up(){cp=!1}var dp=null;function fp(e){if(bd&&Wd.observeMutations){var t=e.treeCallback,n=void 0===t?tp:t,r=e.nodeCallback,a=void 0===r?tp:r,i=e.pseudoElementsCallback,o=void 0===i?tp:i,s=e.observeMutationsRoot,c=void 0===s?hd:s;dp=new bd((function(e){if(!cp){var t=kf();Xd(e).forEach((function(e){if("childList"===e.type&&e.addedNodes.length>0&&!np(e.addedNodes[0])&&(Wd.searchPseudoElements&&o(e.target),n(e.target)),"attributes"===e.type&&e.target.parentNode&&Wd.searchPseudoElements&&o(e.target.parentNode),"attributes"===e.type&&np(e.target)&&~Nd.indexOf(e.attributeName))if("class"===e.attributeName&&function(e){var t=e.getAttribute?e.getAttribute("data-prefix"):null,n=e.getAttribute?e.getAttribute("data-icon"):null;return t&&n}(e.target)){var r=zf(Fd(e.target)),i=r.prefix,s=r.iconName;e.target.setAttribute("data-prefix",i||t),s&&e.target.setAttribute("data-icon",s)}else(c=e.target)&&c.classList&&c.classList.contains&&c.classList.contains(Wd.replacementClass)&&a(e.target);var c}))}})),_d&&dp.observe(c,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}}function pp(e){var t=e.getAttribute("style"),n=[];return t&&(n=t.split(";").reduce((function(e,t){var n=t.split(":"),r=n[0],a=n.slice(1);return r&&a.length>0&&(e[r]=a.join(":").trim()),e}),{})),n}function mp(e){var t,n,r=e.getAttribute("data-prefix"),a=e.getAttribute("data-icon"),i=void 0!==e.innerText?e.innerText.trim():"",o=zf(Fd(e));return o.prefix||(o.prefix=kf()),r&&a&&(o.prefix=r,o.iconName=a),o.iconName&&o.prefix||(o.prefix&&i.length>0&&(o.iconName=(t=o.prefix,n=e.innerText,(bf[t]||{})[n]||Af(o.prefix,cf(e.innerText)))),!o.iconName&&Wd.autoFetchSvg&&e.firstChild&&e.firstChild.nodeType===Node.TEXT_NODE&&(o.iconName=e.firstChild.data)),o}function hp(e){var t=Xd(e.attributes).reduce((function(e,t){return"class"!==e.name&&"style"!==e.name&&(e[t.name]=t.value),e}),{}),n=e.getAttribute("title"),r=e.getAttribute("data-fa-title-id");return Wd.autoA11y&&(n?t["aria-labelledby"]="".concat(Wd.replacementClass,"-title-").concat(r||Id()):(t["aria-hidden"]="true",t.focusable="false")),t}function bp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{styleParser:!0},n=mp(e),r=n.iconName,a=n.prefix,i=n.rest,o=hp(e),s=Yf("parseNodeAttributes",{},e),c=t.styleParser?pp(e):[];return Zu({iconName:r,title:e.getAttribute("title"),titleId:e.getAttribute("data-fa-title-id"),prefix:a,transform:Hd,mask:{iconName:null,prefix:null,rest:[]},maskId:null,symbol:!1,extra:{classes:i,styles:c,attributes:o}},s)}var Mp=ef.styles;function _p(e){var t="nest"===Wd.autoReplaceSvg?bp(e,{styleParser:!1}):bp(e);return~t.extra.classes.indexOf("fa-layers-text")?jf("generateLayersText",e,t):jf("generateSvgReplacementMutation",e,t)}function gp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!_d)return Promise.resolve();var n=hd.documentElement.classList,r=function(e){return n.add("".concat("fontawesome-i2svg","-").concat(e))},a=function(e){return n.remove("".concat("fontawesome-i2svg","-").concat(e))},i=Wd.autoFetchSvg?Object.keys(Ld):Object.keys(Mp);i.includes("fa")||i.push("fa");var o=[".".concat("fa-layers-text",":not([").concat("data-fa-i2svg","])")].concat(i.map((function(e){return".".concat(e,":not([").concat("data-fa-i2svg","])")}))).join(", ");if(0===o.length)return Promise.resolve();var s=[];try{s=Xd(e.querySelectorAll(o))}catch(e){}if(!(s.length>0))return Promise.resolve();r("pending"),a("complete");var c=ep("onTree"),l=s.reduce((function(e,t){try{var n=_p(t);n&&e.push(n)}catch(e){vd||"MissingIcon"===e.name&&console.error(e)}return e}),[]);return new Promise((function(e,n){Promise.all(l).then((function(n){sp(n,(function(){r("active"),r("complete"),a("pending"),"function"==typeof t&&t(),c(),e()}))})).catch((function(e){c(),n(e)}))}))}function yp(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;_p(e).then((function(e){e&&sp([e],t)}))}var vp=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.transform,r=void 0===n?Hd:n,a=t.symbol,i=void 0!==a&&a,o=t.mask,s=void 0===o?null:o,c=t.maskId,l=void 0===c?null:c,u=t.title,d=void 0===u?null:u,f=t.titleId,p=void 0===f?null:f,m=t.classes,h=void 0===m?[]:m,b=t.attributes,M=void 0===b?{}:b,_=t.styles,g=void 0===_?{}:_;if(e){var y=e.prefix,v=e.iconName,L=e.icon;return If(Zu({type:"icon"},e),(function(){return Pf("beforeDOMElementCreation",{iconDefinition:e,params:t}),Wd.autoA11y&&(d?M["aria-labelledby"]="".concat(Wd.replacementClass,"-title-").concat(p||Id()):(M["aria-hidden"]="true",M.focusable="false")),Xf({icons:{main:Gf(L),mask:s?Gf(s.icon):{found:!1,width:null,height:null,icon:{}}},prefix:y,iconName:v,transform:Zu(Zu({},Hd),r),symbol:i,title:d,maskId:l,titleId:p,extra:{attributes:M,styles:g,classes:h}})}))}},Lp={mixout:function(){return{icon:(e=vp,function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(t||{}).icon?t:Rf(t||{}),a=n.mask;return a&&(a=(a||{}).icon?a:Rf(a||{})),e(r,Zu(Zu({},n),{},{mask:a}))})};var e},hooks:function(){return{mutationObserverCallbacks:function(e){return e.treeCallback=gp,e.nodeCallback=yp,e}}},provides:function(e){e.i2svg=function(e){var t=e.node,n=void 0===t?hd:t,r=e.callback;return gp(n,void 0===r?function(){}:r)},e.generateSvgReplacementMutation=function(e,t){var n=t.iconName,r=t.title,a=t.titleId,i=t.prefix,o=t.transform,s=t.symbol,c=t.mask,l=t.maskId,u=t.extra;return new Promise((function(t,d){Promise.all([Jf(n,i),c.iconName?Jf(c.iconName,c.prefix):Promise.resolve({found:!1,width:512,height:512,icon:{}})]).then((function(c){var d=rd(c,2),f=d[0],p=d[1];t([e,Xf({icons:{main:f,mask:p},prefix:i,iconName:n,transform:o,symbol:s,maskId:l,title:r,titleId:a,extra:u,watchable:!0})])})).catch(d)}))},e.generateAbstractIcon=function(e){var t,n=e.children,r=e.attributes,a=e.main,i=e.transform,o=Vd(e.styles);return o.length>0&&(r.style=o),Gd(i)&&(t=jf("generateAbstractTransformGrouping",{main:a,transform:i,containerWidth:a.width,iconWidth:a.width})),n.push(t||a.icon),{children:n,attributes:r}}}},wp={mixout:function(){return{layer:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.classes,r=void 0===n?[]:n;return If({type:"layer"},(function(){Pf("beforeDOMElementCreation",{assembler:e,params:t});var n=[];return e((function(e){Array.isArray(e)?e.map((function(e){n=n.concat(e.abstract)})):n=n.concat(e.abstract)})),[{tag:"span",attributes:{class:["".concat(Wd.familyPrefix,"-layers")].concat(ad(r)).join(" ")},children:n}]}))}}}},Ap={mixout:function(){return{counter:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.title,r=void 0===n?null:n,a=t.classes,i=void 0===a?[]:a,o=t.attributes,s=void 0===o?{}:o,c=t.styles,l=void 0===c?{}:c;return If({type:"counter",content:e},(function(){return Pf("beforeDOMElementCreation",{content:e,params:t}),Uf({content:e.toString(),title:r,extra:{attributes:s,styles:l,classes:["".concat(Wd.familyPrefix,"-layers-counter")].concat(ad(i))}})}))}}}},Tp={mixout:function(){return{text:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.transform,r=void 0===n?Hd:n,a=t.title,i=void 0===a?null:a,o=t.classes,s=void 0===o?[]:o,c=t.attributes,l=void 0===c?{}:c,u=t.styles,d=void 0===u?{}:u;return If({type:"text",content:e},(function(){return Pf("beforeDOMElementCreation",{content:e,params:t}),Ff({content:e,transform:Zu(Zu({},Hd),r),title:i,extra:{attributes:l,styles:d,classes:["".concat(Wd.familyPrefix,"-layers-text")].concat(ad(s))}})}))}}},provides:function(e){e.generateLayersText=function(e,t){var n=t.title,r=t.transform,a=t.extra,i=null,o=null;if(gd){var s=parseInt(getComputedStyle(e).fontSize,10),c=e.getBoundingClientRect();i=c.width/s,o=c.height/s}return Wd.autoA11y&&!n&&(a.attributes["aria-hidden"]="true"),Promise.resolve([e,Ff({content:e.innerHTML,width:i,height:o,transform:r,title:n,extra:a,watchable:!0})])}}},Op=new RegExp('"',"ug"),kp=[1105920,1112319];function Sp(e,t){var n="".concat("data-fa-pseudo-element-pending").concat(t.replace(":","-"));return new Promise((function(r,a){if(null!==e.getAttribute(n))return r();var i,o,s,c=Xd(e.children).filter((function(e){return e.getAttribute("data-fa-pseudo-element")===t}))[0],l=md.getComputedStyle(e,t),u=l.getPropertyValue("font-family").match(kd),d=l.getPropertyValue("font-weight"),f=l.getPropertyValue("content");if(c&&!u)return e.removeChild(c),r();if(u&&"none"!==f&&""!==f){var p=l.getPropertyValue("content"),m=~["Solid","Regular","Light","Thin","Duotone","Brands","Kit"].indexOf(u[2])?wd[u[2].toLowerCase()]:Sd[d],h=function(e){var t,n,r,a,i,o=e.replace(Op,""),s=(n=0,a=(t=o).length,(i=t.charCodeAt(n))>=55296&&i<=56319&&a>n+1&&(r=t.charCodeAt(n+1))>=56320&&r<=57343?1024*(i-55296)+r-56320+65536:i),c=s>=kp[0]&&s<=kp[1],l=2===o.length&&o[0]===o[1];return{value:cf(l?o[0]:o),isSecondary:c||l}}(p),b=h.value,M=h.isSecondary,_=u[0].startsWith("FontAwesome"),g=Af(m,b),y=g;if(_){var v=(o=_f[i=b],s=Af("fas",i),o||(s?{prefix:"fas",iconName:s}:null)||{prefix:null,iconName:null});v.iconName&&v.prefix&&(g=v.iconName,m=v.prefix)}if(!g||M||c&&c.getAttribute("data-prefix")===m&&c.getAttribute("data-icon")===y)r();else{e.setAttribute(n,y),c&&e.removeChild(c);var L={iconName:null,title:null,titleId:null,prefix:null,transform:Hd,symbol:!1,mask:{iconName:null,prefix:null,rest:[]},maskId:null,extra:{classes:[],styles:{},attributes:{}}},w=L.extra;w.attributes["data-fa-pseudo-element"]=t,Jf(g,m).then((function(a){var i=Xf(Zu(Zu({},L),{},{icons:{main:a,mask:{prefix:null,iconName:null,rest:[]}},prefix:m,iconName:y,extra:w,watchable:!0})),o=hd.createElement("svg");"::before"===t?e.insertBefore(o,e.firstChild):e.appendChild(o),o.outerHTML=i.map((function(e){return af(e)})).join("\n"),e.removeAttribute(n),r()})).catch(a)}}else r()}))}function zp(e){return Promise.all([Sp(e,"::before"),Sp(e,"::after")])}function Ep(e){return!(e.parentNode===document.head||~yd.indexOf(e.tagName.toUpperCase())||e.getAttribute("data-fa-pseudo-element")||e.parentNode&&"svg"===e.parentNode.tagName)}function Np(e){if(_d)return new Promise((function(t,n){var r=Xd(e.querySelectorAll("*")).filter(Ep).map(zp),a=ep("searchPseudoElements");lp(),Promise.all(r).then((function(){a(),up(),t()})).catch((function(){a(),up(),n()}))}))}var xp=!1,Dp=function(e){return e.toLowerCase().split(" ").reduce((function(e,t){var n=t.toLowerCase().split("-"),r=n[0],a=n.slice(1).join("-");if(r&&"h"===a)return e.flipX=!0,e;if(r&&"v"===a)return e.flipY=!0,e;if(a=parseFloat(a),isNaN(a))return e;switch(r){case"grow":e.size=e.size+a;break;case"shrink":e.size=e.size-a;break;case"left":e.x=e.x-a;break;case"right":e.x=e.x+a;break;case"up":e.y=e.y-a;break;case"down":e.y=e.y+a;break;case"rotate":e.rotate=e.rotate+a}return e}),{size:16,x:0,y:0,flipX:!1,flipY:!1,rotate:0})},Cp={mixout:function(){return{parse:{transform:function(e){return Dp(e)}}}},hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-transform");return n&&(e.transform=Dp(n)),e}}},provides:function(e){e.generateAbstractTransformGrouping=function(e){var t=e.main,n=e.transform,r=e.containerWidth,a=e.iconWidth,i={transform:"translate(".concat(r/2," 256)")},o="translate(".concat(32*n.x,", ").concat(32*n.y,") "),s="scale(".concat(n.size/16*(n.flipX?-1:1),", ").concat(n.size/16*(n.flipY?-1:1),") "),c="rotate(".concat(n.rotate," 0 0)"),l={outer:i,inner:{transform:"".concat(o," ").concat(s," ").concat(c)},path:{transform:"translate(".concat(a/2*-1," -256)")}};return{tag:"g",attributes:Zu({},l.outer),children:[{tag:"g",attributes:Zu({},l.inner),children:[{tag:t.icon.tag,children:t.icon.children,attributes:Zu(Zu({},t.icon.attributes),l.path)}]}]}}}},Yp={x:0,y:0,width:"100%",height:"100%"};function Pp(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e.attributes&&(e.attributes.fill||t)&&(e.attributes.fill="black"),e}var jp,Rp={hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-mask"),r=n?zf(n.split(" ").map((function(e){return e.trim()}))):{prefix:null,iconName:null,rest:[]};return r.prefix||(r.prefix=kf()),e.mask=r,e.maskId=t.getAttribute("data-fa-mask-id"),e}}},provides:function(e){e.generateAbstractMask=function(e){var t,n=e.children,r=e.attributes,a=e.main,i=e.mask,o=e.maskId,s=e.transform,c=a.width,l=a.icon,u=i.width,d=i.icon,f=function(e){var t=e.transform,n=e.containerWidth,r=e.iconWidth,a={transform:"translate(".concat(n/2," 256)")},i="translate(".concat(32*t.x,", ").concat(32*t.y,") "),o="scale(".concat(t.size/16*(t.flipX?-1:1),", ").concat(t.size/16*(t.flipY?-1:1),") "),s="rotate(".concat(t.rotate," 0 0)");return{outer:a,inner:{transform:"".concat(i," ").concat(o," ").concat(s)},path:{transform:"translate(".concat(r/2*-1," -256)")}}}({transform:s,containerWidth:u,iconWidth:c}),p={tag:"rect",attributes:Zu(Zu({},Yp),{},{fill:"white"})},m=l.children?{children:l.children.map(Pp)}:{},h={tag:"g",attributes:Zu({},f.inner),children:[Pp(Zu({tag:l.tag,attributes:Zu(Zu({},l.attributes),f.path)},m))]},b={tag:"g",attributes:Zu({},f.outer),children:[h]},M="mask-".concat(o||Id()),_="clip-".concat(o||Id()),g={tag:"mask",attributes:Zu(Zu({},Yp),{},{id:M,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"}),children:[p,b]},y={tag:"defs",children:[{tag:"clipPath",attributes:{id:_},children:(t=d,"g"===t.tag?t.children:[t])},g]};return n.push(y,{tag:"rect",attributes:Zu({fill:"currentColor","clip-path":"url(#".concat(_,")"),mask:"url(#".concat(M,")")},Yp)}),{children:n,attributes:r}}}};jp={mixoutsTo:Bf}.mixoutsTo,Nf=[Qd,Lp,wp,Ap,Tp,{hooks:function(){return{mutationObserverCallbacks:function(e){return e.pseudoElementsCallback=Np,e}}},provides:function(e){e.pseudoElements2svg=function(e){var t=e.node,n=void 0===t?hd:t;Wd.searchPseudoElements&&Np(n)}}},{mixout:function(){return{dom:{unwatch:function(){lp(),xp=!0}}}},hooks:function(){return{bootstrap:function(){fp(Yf("mutationObserverCallbacks",{}))},noAuto:function(){dp&&dp.disconnect()},watch:function(e){var t=e.observeMutationsRoot;xp?up():fp(Yf("mutationObserverCallbacks",{observeMutationsRoot:t}))}}}},Cp,Rp,{provides:function(e){var t=!1;md.matchMedia&&(t=md.matchMedia("(prefers-reduced-motion: reduce)").matches),e.missingIconAbstract=function(){var e=[],n={fill:"currentColor"},r={attributeType:"XML",repeatCount:"indefinite",dur:"2s"};e.push({tag:"path",attributes:Zu(Zu({},n),{},{d:"M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66.8,13.6V471.4z M462,190.8c5,15.7,8.2,32.2,9.4,49.2h32.1 c-1.4-21.2-5.4-41.7-11.7-61.1L462,190.8z M92.4,397c-12-13.9-22.3-29.4-30.4-46.1l-29.8,11.9c9.9,20.7,22.6,39.8,37.6,56.9 L92.4,397z M272,40.6c18.8,1.4,36.9,5.2,54.1,11.1l12.6-29.5C317.7,14.7,295.3,10,272,8.5V40.6z M190.8,50 c15.7-5,32.2-8.2,49.2-9.4V8.5c-21.2,1.4-41.7,5.4-61.1,11.7L190.8,50z M442.3,92.3L419.6,115c12,13.9,22.3,29.4,30.5,46.1 l29.8-11.9C470,128.5,457.3,109.4,442.3,92.3z M397,92.4l22.7-22.7c-15.6-13.7-32.8-25.5-51.5-34.9l-12.6,29.5 C370.4,72.1,384.4,81.5,397,92.4z"})});var a=Zu(Zu({},r),{},{attributeName:"opacity"}),i={tag:"circle",attributes:Zu(Zu({},n),{},{cx:"256",cy:"364",r:"28"}),children:[]};return t||i.children.push({tag:"animate",attributes:Zu(Zu({},r),{},{attributeName:"r",values:"28;14;28;28;14;28;"})},{tag:"animate",attributes:Zu(Zu({},a),{},{values:"1;0;1;1;0;1;"})}),e.push(i),e.push({tag:"path",attributes:Zu(Zu({},n),{},{opacity:"1",d:"M263.7,312h-16c-6.6,0-12-5.4-12-12c0-71,77.4-63.9,77.4-107.8c0-20-17.8-40.2-57.4-40.2c-29.1,0-44.3,9.6-59.2,28.7 c-3.9,5-11.1,6-16.2,2.4l-13.1-9.2c-5.6-3.9-6.9-11.8-2.6-17.2c21.2-27.2,46.4-44.7,91.2-44.7c52.3,0,97.4,29.8,97.4,80.2 c0,67.6-77.4,63.5-77.4,107.8C275.7,306.6,270.3,312,263.7,312z"}),children:t?[]:[{tag:"animate",attributes:Zu(Zu({},a),{},{values:"1;0;0;0;0;1;"})}]}),t||e.push({tag:"path",attributes:Zu(Zu({},n),{},{opacity:"0",d:"M232.5,134.5l7,168c0.3,6.4,5.6,11.5,12,11.5h9c6.4,0,11.7-5.1,12-11.5l7-168c0.3-6.8-5.2-12.5-12-12.5h-23 C237.7,122,232.2,127.7,232.5,134.5z"}),children:[{tag:"animate",attributes:Zu(Zu({},a),{},{values:"0;0;1;1;0;0;"})}]}),{tag:"g",attributes:{class:"missing"},children:e}}}},{hooks:function(){return{parseNodeAttributes:function(e,t){var n=t.getAttribute("data-fa-symbol"),r=null!==n&&(""===n||n);return e.symbol=r,e}}}}],xf={},Object.keys(Df).forEach((function(e){-1===Cf.indexOf(e)&&delete Df[e]})),Nf.forEach((function(e){var t=e.mixout?e.mixout():{};if(Object.keys(t).forEach((function(e){"function"==typeof t[e]&&(jp[e]=t[e]),"object"===ed(t[e])&&Object.keys(t[e]).forEach((function(n){jp[e]||(jp[e]={}),jp[e][n]=t[e][n]}))})),e.hooks){var n=e.hooks();Object.keys(n).forEach((function(e){xf[e]||(xf[e]=[]),xf[e].push(n[e])}))}e.provides&&e.provides(Df)}));var Wp=Bf.parse,qp=Bf.icon;function Bp(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Hp(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function Up(e){return function(e){if(Array.isArray(e))return Vp(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Vp(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Vp(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vp(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0||!Array.isArray(t)&&t?Xp({},e,t):{}}var em=["forwardedRef"];function tm(e){var t=e.forwardedRef,n=Fp(e,em),r=n.icon,a=n.mask,i=n.symbol,o=n.className,s=n.title,c=n.titleId,l=n.maskId,u=Qp(r),d=Zp("classes",[].concat(Up(function(e){var t,n=e.beat,r=e.fade,a=e.beatFade,i=e.bounce,o=e.shake,s=e.flash,c=e.spin,l=e.spinPulse,u=e.spinReverse,d=e.pulse,f=e.fixedWidth,p=e.inverse,m=e.border,h=e.listItem,b=e.flip,M=e.size,_=e.rotation,g=e.pull,y=(Xp(t={"fa-beat":n,"fa-fade":r,"fa-beat-fade":a,"fa-bounce":i,"fa-shake":o,"fa-flash":s,"fa-spin":c,"fa-spin-reverse":u,"fa-spin-pulse":l,"fa-pulse":d,"fa-fw":f,"fa-inverse":p,"fa-border":m,"fa-li":h,"fa-flip":!0===b,"fa-flip-horizontal":"horizontal"===b||"both"===b,"fa-flip-vertical":"vertical"===b||"both"===b},"fa-".concat(M),null!=M),Xp(t,"fa-rotate-".concat(_),null!=_&&0!==_),Xp(t,"fa-pull-".concat(g),null!=g),Xp(t,"fa-swap-opacity",e.swapOpacity),t);return Object.keys(y).map((function(e){return y[e]?e:null})).filter((function(e){return e}))}(n)),Up(o.split(" ")))),f=Zp("transform","string"==typeof n.transform?Wp.transform(n.transform):n.transform),p=Zp("mask",Qp(a)),m=qp(u,Hp(Hp(Hp(Hp({},d),f),p),{},{symbol:i,title:s,titleId:c,maskId:l}));if(!m)return function(){var e;!Kp&&console&&"function"==typeof console.error&&(e=console).error.apply(e,arguments)}("Could not find icon",u),null;var h=m.abstract,b={ref:t};return Object.keys(n).forEach((function(e){tm.defaultProps.hasOwnProperty(e)||(b[e]=n[e])})),nm(h[0],b)}tm.displayName="FontAwesomeIcon",tm.propTypes={beat:En.a.bool,border:En.a.bool,beatFade:En.a.bool,bounce:En.a.bool,className:En.a.string,fade:En.a.bool,flash:En.a.bool,mask:En.a.oneOfType([En.a.object,En.a.array,En.a.string]),maskId:En.a.string,fixedWidth:En.a.bool,inverse:En.a.bool,flip:En.a.oneOf([!0,!1,"horizontal","vertical","both"]),icon:En.a.oneOfType([En.a.object,En.a.array,En.a.string]),listItem:En.a.bool,pull:En.a.oneOf(["right","left"]),pulse:En.a.bool,rotation:En.a.oneOf([0,90,180,270]),shake:En.a.bool,size:En.a.oneOf(["2xs","xs","sm","lg","xl","2xl","1x","2x","3x","4x","5x","6x","7x","8x","9x","10x"]),spin:En.a.bool,spinPulse:En.a.bool,spinReverse:En.a.bool,symbol:En.a.oneOfType([En.a.bool,En.a.string]),title:En.a.string,titleId:En.a.string,transform:En.a.oneOfType([En.a.string,En.a.object]),swapOpacity:En.a.bool},tm.defaultProps={border:!1,className:"",mask:null,maskId:null,fixedWidth:!1,inverse:!1,flip:!1,icon:null,listItem:!1,pull:null,pulse:!1,rotation:null,size:null,spin:!1,spinPulse:!1,spinReverse:!1,beat:!1,fade:!1,beatFade:!1,bounce:!1,shake:!1,symbol:!1,title:"",titleId:null,transform:null,swapOpacity:!1};var nm=function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if("string"==typeof n)return n;var a=(n.children||[]).map((function(n){return e(t,n)})),i=Object.keys(n.attributes||{}).reduce((function(e,t){var r=n.attributes[t];switch(t){case"class":e.attrs.className=r,delete n.attributes.class;break;case"style":e.attrs.style=Jp(r);break;default:0===t.indexOf("aria-")||0===t.indexOf("data-")?e.attrs[t.toLowerCase()]=r:e.attrs[Gp(t)]=r}return e}),{attrs:{}}),o=r.style,s=void 0===o?{}:o,c=Fp(r,$p);return i.attrs.style=Hp(Hp({},i.attrs.style),s),t.apply(void 0,[n.tag,Hp(Hp({},i.attrs),c)].concat(Up(a)))}.bind(null,V.a.createElement),rm=function(e){var t;return"undefined"==typeof document?null:null==e?Or().body:("function"==typeof e&&(e=e()),e&&"current"in e&&(e=e.current),null!=(t=e)&&t.nodeType&&e||null)};function am(e,t){var n=Object(U.useState)((function(){return rm(e)})),r=n[0],a=n[1];if(!r){var i=rm(e);i&&a(i)}return Object(U.useEffect)((function(){t&&r&&t(r)}),[t,r]),Object(U.useEffect)((function(){var t=rm(e);t!==r&&a(t)}),[e,r]),r}var im=V.a.forwardRef((function(e,t){var n=e.flip,r=e.offset,a=e.placement,i=e.containerPadding,o=void 0===i?5:i,s=e.popperConfig,c=void 0===s?{}:s,l=e.transition,u=Oc(),d=u[0],f=u[1],p=Oc(),m=p[0],h=p[1],b=Lu(f,t),M=am(e.container),_=am(e.target),g=Object(U.useState)(!e.show),y=g[0],v=g[1],L=Xl(_,d,Ql({placement:a,enableEvents:!!e.show,containerPadding:o||5,flip:n,offset:r,arrowElement:m,popperConfig:c})),w=L.styles,A=L.attributes,T=Cn(L,["styles","attributes"]);e.show?y&&v(!1):e.transition||y||v(!0);var O=e.show||l&&!y;if(Kl(d,e.onHide,{disabled:!e.rootClose||e.rootCloseDisabled,clickTrigger:e.rootCloseEvent}),!O)return null;var k=e.children(Dn({},T,{show:!!e.show,props:Dn({},A.popper,{style:w.popper,ref:b}),arrowProps:Dn({},A.arrow,{style:w.arrow,ref:h})}));if(l){var S=e.onExit,z=e.onExiting,E=e.onEnter,N=e.onEntering,x=e.onEntered;k=V.a.createElement(l,{in:e.show,appear:!0,onExit:S,onExiting:z,onExited:function(){v(!0),e.onExited&&e.onExited.apply(e,arguments)},onEnter:E,onEntering:N,onEntered:x},k)}return M?J.a.createPortal(k,M):null}));im.displayName="Overlay",im.propTypes={show:En.a.bool,placement:En.a.oneOf(il),target:En.a.any,container:En.a.any,flip:En.a.bool,children:En.a.func.isRequired,containerPadding:En.a.number,popperConfig:En.a.object,rootClose:En.a.bool,rootCloseEvent:En.a.oneOf(["click","mousedown"]),rootCloseDisabled:En.a.bool,onHide:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Dm=V.a.forwardRef((function(e,t){var n=e.children,r=e.variant,a=xm(e,km);return V.a.createElement(Om,Nm({},a,{className:xn()({"tooltip-light":"light"===r},a.className),ref:t}),n)}));Dm.propTypes=zm(zm({},Om.propTypes),{},{id:En.a.string.isRequired,placement:En.a.oneOf(["auto-start","auto","auto-end","top-start","top","top-end","right-start","right","right-end","bottom-end","bottom","bottom-start","left-end","left","left-start"]),arrowProps:En.a.shape({ref:En.a.oneOfType([En.a.func,En.a.shape({current:En.a.element})]),style:En.a.shape({})}),show:En.a.bool,popper:En.a.shape({}),bsPrefix:En.a.string,children:En.a.node,className:En.a.string,variant:En.a.string}),Dm.defaultProps=zm(zm({},Dm.defaultProps),{},{id:void 0,placement:"right",arrowProps:void 0,show:void 0,popper:void 0,children:void 0,className:void 0,variant:void 0,bsPrefix:"tooltip"});var Cm=Dm;function Ym(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var Pm=["className","alt","invertColors","icon","src","iconClassNames","onClick","size","variant","iconAs","isActive"],jm=["tooltipPlacement","tooltipContent","variant","invertColors"];function Rm(){return(Rm=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var qm=V.a.forwardRef((function(e,t){var n=e.className,r=e.alt,a=e.invertColors,i=e.icon,o=e.src,s=e.iconClassNames,c=e.onClick,l=e.size,u=e.variant,d=e.iconAs,f=e.isActive,p=Wm(e,Pm),m=a?"inverse-":"",h=f?"".concat(u,"-"):"",b=d||tm;return V.a.createElement("button",Rm({"aria-label":r,className:xn()("btn-icon","btn-icon-".concat(m).concat(u),"btn-icon-".concat(l),Ym({},"btn-icon-".concat(m).concat(h,"active"),f),n),onClick:c,type:"button",ref:t},p),V.a.createElement("span",{className:"btn-icon__icon-container"},V.a.createElement(b,{className:xn()("btn-icon__icon",s),icon:i,src:o})))}));qm.defaultProps={iconAs:void 0,src:null,icon:void 0,iconClassNames:void 0,className:void 0,invertColors:!1,variant:"primary",size:"md",onClick:function(){},isActive:!1},qm.propTypes={className:En.a.string,iconAs:En.a.elementType,src:En.a.oneOfType([En.a.element,En.a.func]),alt:En.a.string.isRequired,invertColors:En.a.bool,icon:En.a.shape({prefix:En.a.string,iconName:En.a.string,icon:En.a.array}),iconClassNames:En.a.string,onClick:En.a.func,variant:En.a.oneOf(["primary","secondary","success","warning","danger","light","dark","black","brand"]),size:En.a.oneOf(["sm","md","inline"]),isActive:En.a.bool};var Bm=function(e){var t=e.tooltipPlacement,n=e.tooltipContent,r=e.variant,a=e.invertColors,i=Wm(e,jm),o=a?"inverse-":"";return V.a.createElement(Lm,{placement:t,overlay:V.a.createElement(Cm,{id:"iconbutton-tooltip-".concat(t),variant:o?"light":""},n)},V.a.createElement(qm,Rm({variant:r,invertColors:a},i)))};Bm.defaultProps={tooltipPlacement:"top",variant:"primary",invertColors:!1},Bm.propTypes={tooltipPlacement:En.a.string,tooltipContent:En.a.node.isRequired,variant:En.a.oneOf(["primary","secondary","success","warning","danger","light","dark","black","brand"]),invertColors:En.a.bool},qm.IconButtonWithTooltip=Bm;var Hm=qm;var Im=function(){return(Im=Object.assign||function(e){for(var t,n=1,r=arguments.length;n=0})).sort(zh)},Nh=["button:enabled","select:enabled","textarea:enabled","input:enabled","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]","[tabindex]","[contenteditable]","[autofocus]"].join(","),xh="".concat(Nh,", [data-focus-guard]"),Dh=function(e,t){var n;return hh((null===(n=e.shadowRoot)||void 0===n?void 0:n.children)||e.children).reduce((function(e,n){return e.concat(n.matches(t?xh:Nh)?[n]:[],Dh(n))}),[])},Ch=function(e,t){return e.reduce((function(e,n){return e.concat(Dh(n,t),n.parentNode?hh(n.parentNode.querySelectorAll(Nh)).filter((function(e){return e===n})):[])}),[])},Yh=function(e,t){return hh(e).filter((function(e){return yh(t,e)})).filter((function(e){return function(e){return!((wh(e)||function(e){return"BUTTON"===e.tagName}(e))&&("hidden"===e.type||e.disabled))}(e)}))},Ph=function(e,t){return void 0===t&&(t=new Map),hh(e).filter((function(e){return vh(t,e)}))},jh=function(e,t,n){return Eh(Yh(Ch(e,n),t),!0,n)},Rh=function(e,t){return Eh(Yh(Ch(e),t),!1)},Wh=function(e,t){return Yh((n=e.querySelectorAll("[".concat("data-autofocus-inside","]")),hh(n).map((function(e){return Ch([e])})).reduce((function(e,t){return e.concat(t)}),[])),t);var n},qh=function(e,t){return(e.shadowRoot?qh(e.shadowRoot,t):Object.getPrototypeOf(e).contains.call(e,t))||hh(e.children).some((function(e){return qh(e,t)}))},Bh=function(e){return e.activeElement?e.activeElement.shadowRoot?Bh(e.activeElement.shadowRoot):e.activeElement:void 0},Hh=function(){return document.activeElement?document.activeElement.shadowRoot?Bh(document.activeElement.shadowRoot):document.activeElement:void 0},Ih=function(e){return e.parentNode?Ih(e.parentNode):e},Xh=function(e){return bh(e).filter(Boolean).reduce((function(e,t){var n=t.getAttribute("data-focus-lock");return e.push.apply(e,n?function(e){for(var t=new Set,n=e.length,r=0;r0&&t.add(a),(i&Node.DOCUMENT_POSITION_CONTAINS)>0&&t.add(r)}return e.filter((function(e,n){return!t.has(n)}))}(hh(Ih(t).querySelectorAll("[".concat("data-focus-lock",'="').concat(n,'"]:not([').concat("data-focus-lock-disabled",'="disabled"])')))):[t]),e}),[])},Fh=function(e){return Boolean(hh(e.querySelectorAll("iframe")).some((function(e){return e===document.activeElement})))},Uh=function(e){var t=document&&Hh();return!(!t||t.dataset&&t.dataset.focusGuard)&&Xh(e).some((function(e){return qh(e,t)||Fh(e)}))},Vh=function(e,t){return Ah(e)&&e.name?function(e,t){return t.filter(Ah).filter((function(t){return t.name===e.name})).filter((function(e){return e.checked}))[0]||e}(e,t):e},Gh=function(e){return e[0]&&e.length>1?Vh(e[0],e):e[0]},$h=function(e,t){return e.length>1?e.indexOf(Vh(e[t],e)):t},Jh=function(e,t,n,r){var a=e.length,i=e[0],o=e[a-1],s=Oh(n);if(!(n&&e.indexOf(n)>=0)){var c,l,u=void 0!==n?t.indexOf(n):-1,d=r?t.indexOf(r):u,f=r?e.indexOf(r):-1,p=u-d,m=t.indexOf(i),h=t.indexOf(o),b=(c=t,l=new Set,c.forEach((function(e){return l.add(Vh(e,c))})),c.filter((function(e){return l.has(e)}))),M=(void 0!==n?b.indexOf(n):-1)-(r?b.indexOf(r):u),_=$h(e,0),g=$h(e,a-1);return-1===u||-1===f?"NEW_FOCUS":!p&&f>=0?f:u<=m&&s&&Math.abs(p)>1?g:u>=h&&s&&Math.abs(p)>1?_:p&&Math.abs(M)>1?f:u<=m?g:u>h?_:p?Math.abs(p)>1?f:(a+f+p)%a:void 0}},Kh=function(e,t){return void 0===t&&(t=[]),t.push(e),e.parentNode&&Kh(e.parentNode.host||e.parentNode,t),t},Qh=function(e,t){for(var n=Kh(e),r=Kh(t),a=0;a=0)return i}return!1},Zh=function(e,t,n){var r=bh(e),a=bh(t),i=r[0],o=!1;return a.filter(Boolean).forEach((function(e){o=Qh(o||e,e)||o,n.filter(Boolean).forEach((function(e){var t=Qh(i,e);t&&(o=!o||qh(t,o)?t:Qh(t,o))}))})),o},eb=function(e,t){var n=document&&Hh(),r=Xh(e).filter(kh),a=Zh(n||e,e,r),i=new Map,o=Rh(r,i),s=jh(r,i).filter((function(e){var t=e.node;return kh(t)}));if(s[0]||(s=o)[0]){var c,l,u,d,f=Rh([a],i).map((function(e){return e.node})),p=(c=f,l=s,u=new Map,l.forEach((function(e){return u.set(e.node,e)})),c.map((function(e){return u.get(e)})).filter(Sh)),m=p.map((function(e){return e.node})),h=Jh(m,f,n,t);if("NEW_FOCUS"===h){var b=Ph(o.map((function(e){return e.node}))).filter((d=function(e,t){return e.reduce((function(e,n){return e.concat(Wh(n,t))}),[])}(r,i),function(e){var t;return e.autofocus||!!(null===(t=Lh(e))||void 0===t?void 0:t.autofocus)||d.indexOf(e)>=0}));return{node:b&&b.length?Gh(b):Gh(Ph(m))}}return void 0===h?h:p[h]}},tb=0,nb=!1,rb=function(e,t,n){void 0===n&&(n={});var r,a,i=eb(e,t);if(!nb&&i){if(tb>2)return console.error("FocusLock: focus-fighting detected. Only one focus management system could be active. See https://github.com/theKashey/focus-lock/#focus-fighting"),nb=!0,void setTimeout((function(){nb=!1}),1);tb++,r=i.node,a=n.focusOptions,"focus"in r&&r.focus(a),"contentWindow"in r&&r.contentWindow&&r.contentWindow.focus(),tb--}},ab=function(e){var t=Xh(e).filter(kh),n=Zh(e,e,t),r=new Map,a=jh([n],r,!0),i=jh(t,r).filter((function(e){var t=e.node;return kh(t)})).map((function(e){return e.node}));return a.map((function(e){var t=e.node;return{node:t,index:e.index,lockItem:i.indexOf(t)>=0,guard:Oh(t)}}))};function ib(e){var t=window.setImmediate;void 0!==t?t(e):setTimeout(e,1)}var ob=function(){return document&&document.activeElement===document.body||!!(e=document&&Hh())&&hh(document.querySelectorAll("[".concat("data-no-focus-lock","]"))).some((function(t){return qh(t,e)}));var e},sb=null,cb=null,lb=null,ub=!1,db=function(){return!0};function fb(e,t,n,r){var a=null,i=e;do{var o=r[i];if(o.guard)o.node.dataset.focusAutoGuard&&(a=o);else{if(!o.lockItem)break;if(i!==e)return;a=null}}while((i+=n)!==t);a&&(a.node.tabIndex=0)}var pb=function(e){return e&&"current"in e?e.current:e},mb=function(){var e,t=!1;if(sb){var n=sb,r=n.observed,a=n.persistentFocus,i=n.autoFocus,o=n.shards,s=n.crossFrame,c=n.focusOptions,l=r||lb&&lb.portaledElement,u=document&&document.activeElement;if(l){var d=[l].concat(o.map(pb).filter(Boolean));if(u&&!function(e){return(sb.whiteList||db)(e)}(u)||(a||(s?Boolean(ub):"meanwhile"===ub)||!ob()||!cb&&i)&&(l&&!(Uh(d)||u&&function(e,t){return t.some((function(t){return function e(t,n,r){return n&&(n.host===t&&(!n.activeElement||r.contains(n.activeElement))||n.parentNode&&e(t,n.parentNode,r))}(e,t,t)}))}(u,d)||(e=u,lb&&lb.portaledElement===e))&&(document&&!cb&&u&&!i?(u.blur&&u.blur(),document.body.focus()):(t=rb(d,cb,{focusOptions:c}),lb={})),ub=!1,cb=document&&document.activeElement),document){var f=document&&document.activeElement,p=ab(d),m=p.map((function(e){return e.node})).indexOf(f);m>-1&&(p.filter((function(e){var t=e.guard,n=e.node;return t&&n.dataset.focusAutoGuard})).forEach((function(e){return e.node.removeAttribute("tabIndex")})),fb(m,p.length,1,p),fb(m,-1,-1,p))}}}return t},hb=function(e){mb()&&e&&(e.stopPropagation(),e.preventDefault())},bb=function(){return ib(mb)},Mb=function(e){var t=e.target,n=e.currentTarget;n.contains(t)||(lb={observerNode:n,portaledElement:t})},_b=function(){ub="just",setTimeout((function(){ub="meanwhile"}),0)};rh.assignSyncMedium(Mb),ah.assignMedium(bb),ih.assignMedium((function(e){return e({moveFocusInside:rb,focusInside:Uh})}));var gb,yb=mh((function(e){return e.filter((function(e){return!e.disabled}))}),(function(e){var t=e.slice(-1)[0];t&&!sb&&(document.addEventListener("focusin",hb),document.addEventListener("focusout",bb),window.addEventListener("blur",_b));var n=sb,r=n&&t&&t.id===n.id;sb=t,n&&!r&&(n.onDeactivation(),e.filter((function(e){return e.id===n.id})).length||n.returnFocus(!t)),t?(cb=null,r&&n.observed===t.observed||t.onActivation(),mb(),ib(mb)):(document.removeEventListener("focusin",hb),document.removeEventListener("focusout",bb),window.removeEventListener("blur",_b),cb=null)}))((function(){return null}));ph(oh,yb);function vb(){if(!document)return null;var e=document.createElement("style");e.type="text/css";var t=gb||n.nc;return t&&e.setAttribute("nonce",t),e}var Lb=function(){var e=0,t=null;return{add:function(n){var r,a;0==e&&(t=vb())&&(a=n,(r=t).styleSheet?r.styleSheet.cssText=a:r.appendChild(document.createTextNode(a)),function(e){(document.head||document.getElementsByTagName("head")[0]).appendChild(e)}(t)),e++},remove:function(){!--e&&t&&(t.parentNode&&t.parentNode.removeChild(t),t=null)}}},wb=function(){var e,t=(e=Lb(),function(t,n){U.useEffect((function(){return e.add(t),function(){e.remove()}}),[t&&n])});return function(e){var n=e.styles,r=e.dynamic;return t(n,r),null}},Ab={left:0,top:0,right:0,gap:0},Tb=function(e){return parseInt(e||"",10)||0},Ob=function(e){if(void 0===e&&(e="margin"),"undefined"==typeof window)return Ab;var t=function(e){var t=window.getComputedStyle(document.body);var n=t["padding"===e?"paddingLeft":"marginLeft"],r=t["padding"===e?"paddingTop":"marginTop"],a=t["padding"===e?"paddingRight":"marginRight"];return[Tb(n),Tb(r),Tb(a)]}(e),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:t[0],top:t[1],right:t[2],gap:Math.max(0,r-n+t[2]-t[0])}},kb=wb(),Sb=function(e,t,n,r){var a=e.left,i=e.top,o=e.right,s=e.gap;return void 0===n&&(n="margin"),"\n .".concat("with-scroll-bars-hidden"," {\n overflow: hidden ").concat(r,";\n padding-right: ").concat(s,"px ").concat(r,";\n }\n body {\n overflow: hidden ").concat(r,";\n overscroll-behavior: contain;\n ").concat([t&&"position: relative ".concat(r,";"),"margin"===n&&"\n padding-left: ".concat(a,"px;\n padding-top: ").concat(i,"px;\n padding-right: ").concat(o,"px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(s,"px ").concat(r,";\n "),"padding"===n&&"padding-right: ".concat(s,"px ").concat(r,";")].filter(Boolean).join(""),"\n }\n \n .").concat("right-scroll-bar-position"," {\n right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat("width-before-scroll-bar"," {\n margin-right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat("right-scroll-bar-position"," .").concat("right-scroll-bar-position"," {\n right: 0 ").concat(r,";\n }\n \n .").concat("width-before-scroll-bar"," .").concat("width-before-scroll-bar"," {\n margin-right: 0 ").concat(r,";\n }\n \n body {\n ").concat("--removed-body-scroll-bar-size",": ").concat(s,"px;\n }\n")},zb=function(e){var t=e.noRelative,n=e.noImportant,r=e.gapMode,a=void 0===r?"margin":r,i=U.useMemo((function(){return Ob(a)}),[a]);return U.createElement(kb,{styles:Sb(i,!t,a,n?"":"!important")})},Eb=!1;if("undefined"!=typeof window)try{var Nb=Object.defineProperty({},"passive",{get:function(){return Eb=!0,!0}});window.addEventListener("test",Nb,Nb),window.removeEventListener("test",Nb,Nb)}catch(e){Eb=!1}var xb=!!Eb&&{passive:!1},Db=function(e,t){var n=window.getComputedStyle(e);return"hidden"!==n[t]&&!(n.overflowY===n.overflowX&&!function(e){return"TEXTAREA"===e.tagName}(e)&&"visible"===n[t])},Cb=function(e,t){var n=t;do{if("undefined"!=typeof ShadowRoot&&n instanceof ShadowRoot&&(n=n.host),Yb(e,n)){var r=Pb(e,n);if(r[1]>r[2])return!0}n=n.parentNode}while(n&&n!==document.body);return!1},Yb=function(e,t){return"v"===e?function(e){return Db(e,"overflowY")}(t):function(e){return Db(e,"overflowX")}(t)},Pb=function(e,t){return"v"===e?[(n=t).scrollTop,n.scrollHeight,n.clientHeight]:function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]}(t);var n},jb=function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},Rb=function(e){return[e.deltaX,e.deltaY]},Wb=function(e){return e&&"current"in e?e.current:e},qb=function(e){return"\n .block-interactivity-".concat(e," {pointer-events: none;}\n .allow-interactivity-").concat(e," {pointer-events: all;}\n")},Bb=0,Hb=[];ph(Qm,(function(e){var t=U.useRef([]),n=U.useRef([0,0]),r=U.useRef(),a=U.useState(Bb++)[0],i=U.useState((function(){return wb()}))[0],o=U.useRef(e);U.useEffect((function(){o.current=e}),[e]),U.useEffect((function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(a));var t=function(e,t,n){if(n||2===arguments.length)for(var r,a=0,i=t.length;aMath.abs(l)?"h":"v";if("touches"in e&&"h"===d&&"range"===u.type)return!1;var f=Cb(d,u);if(!f)return!0;if(f?a=d:(a="v"===d?"h":"v",f=Cb(d,u)),!f)return!1;if(!r.current&&"changedTouches"in e&&(c||l)&&(r.current=a),!a)return!0;var p=r.current||a;return function(e,t,n,r,a){var i=function(e,t){return"h"===e&&"rtl"===t?-1:1}(e,window.getComputedStyle(t).direction),o=i*r,s=n.target,c=t.contains(s),l=!1,u=o>0,d=0,f=0;do{var p=Pb(e,s),m=p[0],h=p[1]-p[2]-i*m;(m||h)&&Yb(e,s)&&(d+=h,f+=m),s=s.parentNode}while(!c&&s!==document.body||c&&(t.contains(s)||t===s));return(u&&(a&&0===d||!a&&o>d)||!u&&(a&&0===f||!a&&-o>f))&&(l=!0),l}(p,t,e,"h"===p?c:l,!0)}),[]),c=U.useCallback((function(e){var n=e;if(Hb.length&&Hb[Hb.length-1]===i){var r="deltaY"in n?Rb(n):jb(n),a=t.current.filter((function(e){return e.name===n.type&&e.target===n.target&&(t=e.delta,a=r,t[0]===a[0]&&t[1]===a[1]);var t,a}))[0];if(a&&a.should)n.cancelable&&n.preventDefault();else if(!a){var c=(o.current.shards||[]).map(Wb).filter(Boolean).filter((function(e){return e.contains(n.target)}));(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}}),[]),l=U.useCallback((function(e,n,r,a){var i={name:e,delta:n,target:r,should:a};t.current.push(i),setTimeout((function(){t.current=t.current.filter((function(e){return e!==i}))}),1)}),[]),u=U.useCallback((function(e){n.current=jb(e),r.current=void 0}),[]),d=U.useCallback((function(t){l(t.type,Rb(t),t.target,s(t,e.lockRef.current))}),[]),f=U.useCallback((function(t){l(t.type,jb(t),t.target,s(t,e.lockRef.current))}),[]);U.useEffect((function(){return Hb.push(i),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener("wheel",c,xb),document.addEventListener("touchmove",c,xb),document.addEventListener("touchstart",u,xb),function(){Hb=Hb.filter((function(e){return e!==i})),document.removeEventListener("wheel",c,xb),document.removeEventListener("touchmove",c,xb),document.removeEventListener("touchstart",u,xb)}}),[]);var p=e.removeScrollBar,m=e.inert;return U.createElement(U.Fragment,null,m?U.createElement(i,{styles:qb(a)}):null,p?U.createElement(zb,{gapMode:"margin"}):null)}));var Ib=new WeakMap,Xb=new WeakMap,Fb={},Ub=0,Vb=function(e,t,n){void 0===t&&(t=function(e){return"undefined"==typeof document?null:(Array.isArray(e)?e[0]:e).ownerDocument.body}(e)),void 0===n&&(n="data-aria-hidden");var r=Array.isArray(e)?e:[e];Fb[n]||(Fb[n]=new WeakMap);var a=Fb[n],i=[],o=new Set,s=function(e){e&&!o.has(e)&&(o.add(e),s(e.parentNode))};r.forEach(s);var c=function(e){!e||r.indexOf(e)>=0||Array.prototype.forEach.call(e.children,(function(e){if(o.has(e))c(e);else{var t=e.getAttribute("aria-hidden"),r=null!==t&&"false"!==t,s=(Ib.get(e)||0)+1,l=(a.get(e)||0)+1;Ib.set(e,s),a.set(e,l),i.push(e),1===s&&r&&Xb.set(e,!0),1===l&&e.setAttribute(n,"true"),r||e.setAttribute("aria-hidden","true")}}))};return c(t),o.clear(),Ub++,function(){i.forEach((function(e){var t=Ib.get(e)-1,r=a.get(e)-1;Ib.set(e,t),a.set(e,r),t||(Xb.has(e)||e.removeAttribute("aria-hidden"),Xb.delete(e)),r||e.removeAttribute(n)})),--Ub||(Ib=new WeakMap,Ib=new WeakMap,Xb=new WeakMap,Fb={})}},Gb=wb(),$b=function(){return U.createElement(Gb,{styles:"\n [data-focus-on-hidden] {\n pointer-events: none !important;\n }\n"})},Jb=function(e){return"current"in e?e.current:e};var Kb=ph(uh,(function(e){var t=e.setLockProps,n=e.onEscapeKey,r=e.onClickOutside,a=e.shards,i=e.onActivation,o=e.onDeactivation,s=e.noIsolation,c=Object(U.useState)(void 0),l=c[0],u=c[1],d=Object(U.useRef)(null),f=Object(U.useRef)(0);return U.useEffect((function(){var e=function(e){e.defaultPrevented||"Escape"!==e.code&&"Escape"!==e.key&&27!==e.keyCode||!n||n(e)},t=function(e){e.defaultPrevented||e.target===d.current||e instanceof MouseEvent&&0!==e.button||a&&a.map(Jb).some((function(t){return t&&t.contains(e.target)||t===e.target}))||r&&r(e)},i=function(e){t(e),f.current=e.touches.length},o=function(e){f.current=e.touches.length};if(l)return document.addEventListener("keydown",e),document.addEventListener("mousedown",t),document.addEventListener("touchstart",i),document.addEventListener("touchend",o),function(){document.removeEventListener("keydown",e),document.removeEventListener("mousedown",t),document.removeEventListener("touchstart",i),document.removeEventListener("touchend",o)}}),[l,r,n]),Object(U.useEffect)((function(){if(l)return i&&i(l),function(){o&&o()}}),[!!l]),Object(U.useEffect)((function(){var e=function(){return null},n=!1;return t({onMouseDown:function(e){d.current=e.target},onTouchStart:function(e){d.current=e.target},onActivation:function(t){s||(e=Vb(function(){for(var e=0,t=0,n=arguments.length;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var kM={right:[-2,10],left:[-2,10]},SM=function(e){var t=e.children,n=e.onClose,r=e.isOpen,a=e.positionRef,i=e.isBlocking,o=e.withPortal,s=e.placement,c=e.hasArrow,l=OM(e,AM),u=o?sM:V.a.Fragment,d=kM[s]||[0,10],f=[{name:"eventListeners",options:{scroll:!1}},{name:"offset",options:{offset:function(){return d}}}];return V.a.createElement(wM,{onClose:n,isOpen:r,isBlocking:i},V.a.createElement(u,null,V.a.createElement(vM,TM({modifiers:c?f:null,target:a,placement:s},l),V.a.createElement(Zb,{scrollLock:!1,enabled:r,onEscapeKey:n,onClickOutside:n},r&&V.a.createElement("div",{className:"pgn__modal-popup__tooltip"},t,c&&V.a.createElement("div",{id:"arrow",className:"pgn__modal-popup__arrow pgn__modal-popup__arrow-".concat(s),"data-popper-arrow":""}))))))};SM.propTypes={children:En.a.node.isRequired,onClose:En.a.func.isRequired,isOpen:En.a.bool.isRequired,isBlocking:En.a.bool,withPortal:En.a.bool,positionRef:En.a.oneOfType([En.a.func,En.a.shape({current:En.a.shape({})})]),placement:vM.propTypes.placement,hasArrow:En.a.bool},SM.defaultProps={isBlocking:!1,withPortal:!1,placement:"bottom-start",positionRef:null,hasArrow:!1};var zM=SM,EM=function(e){var t=e.direction,n=e.gap,r=e.children,a=e.className;return V.a.createElement("div",{className:xn()("horizontal"===t?"pgn__hstack":"pgn__vstack",n?"pgn__stack-gap--".concat(n):"",a)},r)};EM.propTypes={children:En.a.node.isRequired,direction:En.a.oneOf(["horizontal","vertical"]),gap:En.a.number,className:En.a.string},EM.defaultProps={direction:"vertical",gap:0,className:void 0};var NM=EM;function xM(e){return function(e){if(Array.isArray(e))return YM(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||CM(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function DM(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||CM(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function CM(e,t){if(e){if("string"==typeof e)return YM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?YM(e,t):void 0}}function YM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.handleToggleOn,r=t.handleToggleOff,a=t.handleToggle,i=Object(U.useState)(e||!1),o=Ju(i,2),s=o[0],c=o[1],l=Object(U.useCallback)((function(){c(!0),n&&n(),a&&a(!0)}),[n,a]),u=Object(U.useCallback)((function(){c(!1),r&&r(),a&&a(!1)}),[r,a]),d=Object(U.useCallback)((function(){(s?u:l)()}),[s,l,u]);return[s,l,u,d]}(!1),3),a=r[0],i=r[1],o=r[2],s=DM(Object(U.useState)(null),2),c=s[0],l=s[1],u=Object(U.useContext)(Vo),d=DM(u.controlledTableSelections,1)[0].isEntireTableSelected,f=u.selectedFlatRows,p=u.rows,m=Object(vc.a)().width,h=f||p,b=DM(Object(U.useMemo)((function(){if(m0&&V.a.createElement(V.a.Fragment,null,V.a.createElement(Hm,{variant:"secondary",iconAs:qa,src:No,alt:m>Ga.small.minWidth?"More actions":"Actions",id:"actions-dropdown",ref:l,onClick:i}),V.a.createElement(zM,{positionRef:c,onClose:o,placement:"bottom-end",isOpen:a},V.a.createElement("div",{className:"pgn__datatable__overflow-actions-menu"},V.a.createElement(NM,{gap:2},_.map(g))))),V.a.createElement("div",{className:"pgn__datatable__visible-actions"},M.map(g)))};RM.defaultProps={className:null},RM.propTypes={className:En.a.string,actions:En.a.arrayOf(En.a.shape({component:En.a.oneOfType([En.a.func,En.a.element]).isRequired,args:En.a.shape({})})).isRequired};var WM=RM;function qM(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return BM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return BM(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function BM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;return o||i&&!s?null:!a&&s?V.a.createElement(IM,null):V.a.createElement(FM,null)},VM=function(e){var t=e.activeValue,n=e.onChange,r=e.children,a=Object(U.useMemo)((function(){return V.a.Children.map(r,(function(e){var r=e.props.value===t;return V.a.cloneElement(e,{onClick:function(){n(e.props.value)},isActive:r,"aria-selected":r,"data-testid":"icon-btn-val-".concat(e.props.value)})}))}),[r,t,n]);return V.a.createElement("div",{className:"pgn__icon-button-toggle__container"},a)};VM.defaultProps={onChange:function(){},activeValue:void 0},VM.propTypes={activeValue:En.a.string,onChange:En.a.func,children:En.a.node.isRequired};var GM=VM;function $M(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return JM(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return JM(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function JM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?null:V.a.createElement("div",{className:xn()("pgn__data-table-empty",n)},t)};n_.defaultProps={className:null},n_.propTypes={className:En.a.string,content:En.a.string.isRequired};var r_=n_,a_=function(e){return function(t,n,r){var a=t[n];return"number"==typeof a&&!Number.isNaN(a)&&a>e?null:new Error("".concat(n," in ").concat(r," must be a non-NaN number greater than ").concat(e,"."))}},i_=["children","className"];function o_(){return(o_=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c_=function(e){var t=e.children,n=e.className,r=s_(e,i_);return V.a.createElement(Y_,null,(function(e){var a=e.buttonRef,i=e.isOpen,o=e.toggle,s=e.triggerId;return V.a.createElement("button",o_({},r,{id:xn()(s,r.id),"aria-expanded":i,"aria-haspopup":!0,type:"button",ref:a,className:xn()("dropdown-toggle","btn",n),onClick:function(e){o(e),r.onClick&&r.onClick(e)}}),t)}))};c_.propTypes={children:En.a.node,className:En.a.string},c_.defaultProps={children:void 0,className:"btn-light"};var l_=c_,u_=["children"];function d_(){return(d_=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p_=function(e){var t=e.children,n=f_(e,u_);return V.a.createElement(Y_,null,(function(e){var r=e.handleMenuKeyDown,a=e.isOpen,i=e.menuRef,o=e.triggerId;return V.a.createElement("div",d_({},n,{"aria-labelledby":o,"aria-hidden":!a,ref:i,role:"menu",className:xn()("dropdown-menu",{show:a},n.className),onKeyDown:function(e){r(e),n.onKeyDown&&n.onKeyDown(e)}}),t)}))};p_.propTypes={children:En.a.node},p_.defaultProps={children:void 0};var m_=p_,h_=["type","children","className"];function b_(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function M_(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var y_=function(e){var t=e.type,n=e.children,r=e.className,a=g_(e,h_);return V.a.createElement(t,M_(M_({},a),{},{className:xn()("dropdown-item",r)}),n)};y_.propTypes={type:En.a.string,children:En.a.node,className:En.a.string},y_.defaultProps={type:"a",children:void 0,className:null};var v_=y_;function L_(e){return(L_="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function w_(e,t){for(var n=0;n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function x_(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var D_=V.a.createContext(),C_=D_.Provider,Y_=D_.Consumer,P_=function(e){!function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&A_(e,t)}(i,e);var t,n,r,a=T_(i);function i(e){var t;return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,i),x_(k_(t=a.call(this,e)),"handleDocumentClick",(function(e){t.containerRef.current.contains(e.target)&&t.containerRef.current!==e.target||t.state.open&&t.close()})),x_(k_(t),"handleMenuKeyDown",(function(e){switch(e.key){case"ArrowUp":e.preventDefault(),t.focusPrevious();break;case"ArrowDown":e.preventDefault(),t.focusNext();break;case"Tab":e.preventDefault(),e.shiftKey?t.focusPrevious():t.focusNext();break;case"Escape":e.stopPropagation(),t.close()}})),x_(k_(t),"toggle",(function(){t.state.open?t.close():t.open()})),t.state={open:!1},t.uniqueId=i.idCounter,i.idCounter+=1,t.triggerId="pgn__dropdown-trigger-".concat(t.uniqueId),t.containerRef=V.a.createRef(),t.menuRef=V.a.createRef(),t.buttonRef=V.a.createRef(),t}return t=i,(n=[{key:"componentDidUpdate",value:function(e,t){t.open!==this.state.open&&(this.state.open?this.focusFirst():this.buttonRef.current.focus())}},{key:"componentWillUnmount",value:function(){document.removeEventListener("click",this.handleDocumentClick,!0)}},{key:"getFocusableElements",value:function(){return Array.from(this.menuRef.current.querySelectorAll('button:not([disabled]), [href]:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'))}},{key:"close",value:function(){document.removeEventListener("click",this.handleDocumentClick,!0),this.setState({open:!1})}},{key:"open",value:function(){document.addEventListener("click",this.handleDocumentClick,!0),this.setState({open:!0})}},{key:"focusFirst",value:function(){var e=this.getFocusableElements();e.length&&e[0].focus()}},{key:"focusNext",value:function(){var e=this.getFocusableElements();if(0!==e.length){var t=e.indexOf(document.activeElement);e[(t+1)%e.length].focus()}}},{key:"focusPrevious",value:function(){var e=this.getFocusableElements();if(0!==e.length){var t=e.indexOf(document.activeElement);e[(t-1+e.length)%e.length].focus()}}},{key:"render",value:function(){var e=this.props,t=e.children,n=N_(e,z_);return V.a.createElement("div",E_({},n,{className:xn()("dropdown",{show:this.state.open},n.className),ref:this.containerRef}),V.a.createElement(C_,{value:{buttonRef:this.buttonRef,handleMenuKeyDown:this.handleMenuKeyDown,isOpen:this.state.open,menuRef:this.menuRef,toggle:this.toggle,triggerId:this.triggerId}},t))}}])&&w_(t.prototype,n),r&&w_(t,r),i}(V.a.Component);x_(P_,"idCounter",0),P_.propTypes={children:En.a.node.isRequired},P_.Item=v_,P_.Button=l_,P_.Menu=m_;var j_=Da(P_,"Dropdown",{menuItems:{deprType:Ea.MOVED_AND_FORMAT,message:"They should be components sent as children.",newName:"children",transform:function(e,t){return Array.isArray(e)?V.a.createElement(V.a.Fragment,null,V.a.createElement(l_,null,V.a.isValidElement(t.iconElement)?t.iconElement:null,t.title),V.a.createElement(m_,null,e.map((function(e,t){return V.a.isValidElement(e)?V.a.cloneElement(e,{className:"dropdown-item",key:t}):V.a.createElement(v_,{key:t,href:e.href},e.label)})))):null}},title:{deprType:Ea.REMOVED,message:"It should be specified inside the Dropdown.Button component"},buttonType:{deprType:Ea.REMOVED,message:"It should be specified as a className prop"},iconElement:{deprType:Ea.REMOVED,message:"It should be specified inside the buttonContent prop."}});j_.propTypes=P_.propTypes,j_.defaultProps=P_.defaultProps,j_.Item=P_.Item,j_.Button=P_.Button,j_.Menu=P_.Menu;var R_=j_;function W_(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return q_(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return q_(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function q_(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var V_=V.a.forwardRef((function(e,t){var n=e.show,r=e.autoClose,a=e.onToggle,i=U_(e,B_),o=W_(V.a.useState(n),2),s=o[0],c=o[1];return V.a.createElement(Hu,I_({show:s,onToggle:function(e,t,n){if(e)c(!0);else{var i=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;return V.a.createElement("div",{className:"pgn__data-table-side-filters"},V.a.createElement("h3",{className:"pgn__data-table-side-filters-title"},t||V.a.createElement(_a,{id:"pgn.DataTable.SidebarFilters.title",defaultMessage:"Filters",description:"Title for the sidebar filters component"})),V.a.createElement("hr",null),i.map((function(e){return V.a.createElement("div",{key:e.Header,className:"pgn__data-table-side-filters-item"},e.render("Filter"))})),o&&V.a.createElement(V.a.Fragment,null,V.a.createElement(fc,{className:"pgn__data-table-side-filters-status",showFilteredFields:!1,variant:"tertiary"})))};Cg.propTypes={title:En.a.oneOfType([En.a.string,En.a.element])},Cg.defaultProps={title:void 0};var Yg=Cg,Pg=function(e){var t=e.filtersTitle,n=e.className,r=e.children,a=Object(U.useContext)(Vo),i=a.setFilter,o=a.showFiltersInSidebar;return V.a.createElement("div",{className:xn()("pgn__data-table-layout-wrapper",n)},o&&i&&V.a.createElement("div",{className:"pgn__data-table-layout-sidebar"},V.a.createElement(Yg,{title:t})),V.a.createElement("div",{className:"pgn__data-table-layout-main"},r))};Pg.defaultProps={className:null,filtersTitle:void 0},Pg.propTypes={className:En.a.string,children:En.a.node.isRequired,filtersTitle:En.a.oneOfType([En.a.string,En.a.element])};var jg=Pg,Rg=function(e){var t=e.getToggleAllRowsExpandedProps,n=e.isAllRowsExpanded;return V.a.createElement("span",t(),n?V.a.createElement(Oi,{variant:"link",size:"inline"},V.a.createElement(_a,{id:"pgn.DataTable.ExpandAll.collapseAllLabel",defaultMessage:"Collapse all",description:"Label of an action button that collapses all expandable rows of DataTable."})):V.a.createElement(Oi,{variant:"link",size:"inline"},V.a.createElement(_a,{id:"pgn.DataTable.ExpandAll.expandAllLabel",defaultMessage:"Expand all",description:"Label of an action button that expands all expandable rows of DataTable."})))};Rg.propTypes={getToggleAllRowsExpandedProps:En.a.func.isRequired,isAllRowsExpanded:En.a.bool.isRequired};var Wg=Rg,qg=function(e){var t=e.row;return V.a.createElement("span",t.getToggleRowExpandedProps(),t.isExpanded?V.a.createElement(Hm,{src:wo,iconAs:qa,alt:"Collapse row",size:"inline"}):V.a.createElement(Hm,{src:To,iconAs:qa,alt:"Expand row",size:"inline"}))};qg.propTypes={row:En.a.shape({isExpanded:En.a.bool,getToggleRowExpandedProps:En.a.func.isRequired}).isRequired};var Bg=qg,Hg=n(25),Ig=n.n(Hg);function Xg(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Fg(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:$g,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case"SET SELECTED ROWS":var n=Ig()([].concat(Vg(e.selectedRows),Vg(t.rows)),(function(e){return e.id})),r=Fg(Fg({},e),{},{selectedRows:n});return n.length===t.itemCount&&(r.isEntireTableSelected=!0),r;case"SELECT ALL ROWS ALL PAGES":return Fg(Fg({},e),{},{isEntireTableSelected:!0});case"DELETE ROW":return{selectedRows:e.selectedRows.filter((function(e){return e.id!==t.rowId})),isEntireTableSelected:!1};case"ADD ROW":var a=Ig()([].concat(Vg(e.selectedRows),[t.row]),(function(e){return e.id})),i=a.length===t.itemCount;return{selectedRows:a,isEntireTableSelected:i};case"CLEAR SELECTION":return $g;case"CLEAR PAGE SELECTION":return{isEntireTableSelected:!1,selectedRows:e.selectedRows.filter((function(e){return!t.rowIds.includes(e.id)}))};default:return e}};function Kg(e){return function(e){if(Array.isArray(e))return ey(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||Zg(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Qg(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||Zg(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Zg(e,t){if(e){if("string"==typeof e)return ey(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?ey(e,t):void 0}}function ey(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}function cy(e){var t=e.columns,n=e.data,r=e.defaultColumnValues,a=e.additionalColumns,i=e.isSelectable,o=e.isPaginated,s=e.manualPagination,c=e.pageCount,l=e.itemCount,u=e.isFilterable,d=e.manualFilters,f=e.fetchData,p=e.initialState,m=e.isSortable,h=e.manualSortBy,b=e.isExpandable,M=e.renderRowSubComponent,_=e.bulkActions,g=e.tableActions,y=e.numBreakoutFilters,v=e.initialTableOptions,L=e.EmptyTableComponent,w=e.manualSelectColumn,A=e.showFiltersInSidebar,T=e.dataViewToggleOptions,O=e.disableElevation,k=e.isLoading,S=e.children,z=sy(e,ry),E=Object(U.useMemo)((function(){return r}),[r]),N=Object(U.useMemo)((function(){return iy({columns:t,data:n,defaultColumn:E,manualFilters:d,manualPagination:s,manualSortBy:h,initialState:p},v)}),[t,n,E,d,s,p,v,h]),x=Qg(Object(U.useReducer)(Jg,$g),2),D=x[0],C=x[1];o&&s&&(N.pageCount=c||-1);var Y=uc({tableOptions:N,isFilterable:u,isSelectable:i,isPaginated:o,isSortable:m,isExpandable:b});Y.push((function(e){e.visibleColumns.push((function(e){return sc(i,e,a,w)}))}));var P={},j=D.selectedRows;if(j.length>0){var R={};j.forEach((function(e){R[e.id]=!0})),Y.push((function(e){e.useControlledState.push((function(e){return iy(iy({},e),{},{selectedRowIds:R})}))})),P.selectedFlatRows=j}var W=[D,C],q=Qi.useTable.apply(void 0,Kg(Y)),B=iy({},q.state);delete B.selectedRowIds,Object(U.useEffect)((function(){f&&f(B)}),[f,JSON.stringify(B)]);var H=function(e,t){var n=e.toggleAllRowsSelected,r=Qo(t,2),a=r[0],i=a.selectedRows,o=a.isEntireTableSelected,s=r[1];return{clearSelection:function(){i.length>0||o?s({type:"CLEAR SELECTION"}):n(!1)}}}(q,W),I=iy(iy(iy(iy({},q),{},{itemCount:l,numBreakoutFilters:y,bulkActions:_,tableActions:g,controlledTableSelections:W,showFiltersInSidebar:A,dataViewToggleOptions:T,renderRowSubComponent:M,disableElevation:O,isLoading:k},P),H),z);return V.a.createElement(Vo.Provider,{value:I},V.a.createElement(jg,null,V.a.createElement("div",{className:xn()("pgn__data-table-wrapper",{"hide-shadow":!!O})},S||V.a.createElement(V.a.Fragment,null,V.a.createElement(t_,null),V.a.createElement(ts,null),V.a.createElement(L,{content:"No results found"}),V.a.createElement(Mg,null)))))}cy.defaultProps={additionalColumns:[],defaultColumnValues:{},isFilterable:!1,isPaginated:!1,isSelectable:!1,isSortable:!1,manualFilters:!1,manualPagination:!1,manualSortBy:!1,fetchData:null,initialState:{},initialTableOptions:{},EmptyTableComponent:r_,children:null,bulkActions:[],tableActions:[],numBreakoutFilters:1,manualSelectColumn:void 0,SelectionStatusComponent:gc,FilterStatusComponent:fc,RowStatusComponent:mc,showFiltersInSidebar:!1,dataViewToggleOptions:{isDataViewToggleEnabled:!1,onDataViewToggle:function(){},defaultActiveStateValue:"card",togglePlacement:"left"},disableElevation:!1,renderRowSubComponent:void 0,isExpandable:!1,isLoading:!1},cy.propTypes={columns:En.a.arrayOf(En.a.shape({Header:En.a.oneOfType([En.a.func,En.a.node]).isRequired,accessor:(ty=En.a.string,ny="Cell",cc(ty,(function(e){return!e[ny]}),"not ".concat(ny))),Cell:En.a.oneOfType([En.a.func,En.a.element]),Filter:En.a.func,filter:En.a.string,filterChoices:En.a.arrayOf(En.a.shape({name:En.a.string,number:En.a.number,value:En.a.string}))})).isRequired,data:En.a.arrayOf(En.a.shape({})).isRequired,isSelectable:En.a.bool,manualSelectColumn:En.a.shape({id:En.a.string.isRequired,Header:En.a.oneOfType([En.a.func,En.a.node]).isRequired,Cell:En.a.func.isRequired,disableSortBy:En.a.bool.isRequired}),isSortable:En.a.bool,manualSortBy:En.a.bool,isPaginated:En.a.bool,manualPagination:En.a.bool,pageCount:lc(En.a.number,"manualPagination"),isFilterable:En.a.bool,manualFilters:En.a.bool,defaultColumnValues:En.a.shape({Filter:En.a.oneOfType([En.a.func,En.a.node])}),additionalColumns:En.a.arrayOf(En.a.shape({id:En.a.string.isRequired,Header:En.a.oneOfType([En.a.string,En.a.node]),Cell:En.a.oneOfType([En.a.func,En.a.node])})),fetchData:En.a.func,initialState:En.a.shape({pageSize:lc(En.a.number,"isPaginated"),pageIndex:lc(En.a.number,"isPaginated"),filters:lc(En.a.arrayOf(En.a.shape()),"manualFilters"),sortBy:lc(En.a.arrayOf(En.a.shape()),"manualSortBy")}),initialTableOptions:En.a.shape({}),itemCount:En.a.number.isRequired,bulkActions:En.a.oneOfType([En.a.arrayOf(En.a.oneOfType([En.a.shape({buttonText:En.a.string.isRequired,handleClick:En.a.func.isRequired,className:En.a.string,variant:En.a.string,disabled:En.a.bool}),En.a.func,En.a.element])),En.a.func,En.a.element]),tableActions:En.a.oneOfType([En.a.arrayOf(En.a.oneOfType([En.a.shape({buttonText:En.a.string.isRequired,handleClick:En.a.func.isRequired,className:En.a.string,variant:En.a.string,disabled:En.a.bool}),En.a.func,En.a.element])),En.a.func,En.a.element]),numBreakoutFilters:En.a.oneOf([1,2,3,4]),EmptyTableComponent:En.a.func,RowStatusComponent:En.a.func,SelectionStatusComponent:En.a.func,FilterStatusComponent:En.a.func,children:En.a.oneOfType([En.a.arrayOf(En.a.node),En.a.node]),showFiltersInSidebar:En.a.bool,dataViewToggleOptions:En.a.shape({isDataViewToggleEnabled:En.a.bool,onDataViewToggle:En.a.func,defaultActiveStateValue:En.a.string,togglePlacement:En.a.string}),disableElevation:En.a.bool,renderRowSubComponent:En.a.func,isExpandable:En.a.bool,isLoading:En.a.bool},cy.BulkActions=IM,cy.EmptyTable=r_,cy.DropdownFilters=$u,cy.FilterStatus=fc,cy.RowStatus=mc,cy.SelectionStatus=gc,cy.SmartStatus=yc,cy.Table=ts,cy.TableCell=Uo,cy.TableControlBar=t_,cy.TableFilters=wg,cy.TableFooter=Mg,cy.TableHeaderCell=Ro,cy.TableHeaderRow=Bo,cy.TablePagination=mg,cy.TablePaginationMinimal=hg,cy.TableActions=FM,cy.ControlledSelectionStatus=vg,cy.ControlledSelect=Sg,cy.ControlledSelectHeader=Dg,cy.ExpandAll=Wg,cy.ExpandRow=Bg;var ly=cy;function uy(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function dy(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n header .").concat(this.SLIDABLE_CLASS),this.element).focus())}},{key:"srClear",value:function(){$(this.READER_FEEDBACK_CLASS).html("")}},{key:"srReadTexts",value:function(e){var t=$(this.READER_FEEDBACK_CLASS),n="";this.srClear(),$.each(e,(function(e,t){n="".concat(n,"

    ").concat(t,"

    \n")})),t.html(n)}},{key:"areSRStepsLoading",value:function(){return this.responseView.isRendering||this.peerView.isRendering||this.selfView.isRendering||this.gradeView.isRendering||this.trainingView.isRendering||this.staffView.isRendering}},{key:"announceStatusChangeToSRandFocus",value:function(e,t,n,r,a){var i=this.getStatus(e,r,n);void 0!==t&&$(e,r.element).hasClass("is--showing")&&void 0!==a?($(a,r.element).focus(),this.srStatusUpdates.push(i)):r.announceStatus&&this.srStatusUpdates.push(i),!this.areSRStepsLoading()&&this.srStatusUpdates.length>0&&(this.srReadTexts(this.srStatusUpdates),this.srStatusUpdates=[]),r.announceStatus=!1}},{key:"getStatus",value:function(e,t,n){var r="".concat(e," .step__header .step__title "),a="".concat(r,".step__label"),i="".concat(r,".step__status");return n&&(i="".concat(r,".grade__value")),"".concat($(a,t.element).text().trim()," ").concat($(i,t.element).text().trim())}},{key:"setUpCollapseExpand",value:function(e){var t=this;$(".".concat(t.SLIDABLE_CONTROLS_CLASS),e).each((function(){$(this).on("click",(function(e){e.preventDefault();var n=$(e.target).closest(".".concat(t.SLIDABLE_CONTROLS_CLASS)),r=n.closest(".".concat(t.SLIDABLE_CONTAINER_CLASS)),a=n.find(".".concat(t.SLIDABLE_CLASS)),i=n.next(".".concat(t.SLIDABLE_CONTENT_CLASS));r.hasClass("is--showing")?(i.slideUp(),a.attr("aria-expanded","false"),r.removeClass("is--showing")):r.hasClass("has--error")||r.hasClass("is--empty")||r.hasClass("is--unavailable")||(i.slideDown(),a.attr("aria-expanded","true"),r.addClass("is--showing")),r.removeClass("is--initially--collapsed ")}))}))}},{key:"bindLatexPreview",value:function(e){e.find(".submission__preview__item").hide(),e.find(".submission__preview").click((function(t){t.preventDefault();var n=$(t.target).data("input"),r=e.find('textarea[data-preview="'.concat(n,'"]')).val(),a=e.find('.preview_content[data-preview="'.concat(n,'"]'));a.html(r.replace(/\r\n|\r|\n/g,"
    ")),a.parent().parent().parent().show(),MathJax.Hub.Queue(["Typeset",MathJax.Hub,a[0]])}))}},{key:"getUsageID",value:function(){return this.usageID||(this.usageID=$(this.element).data("usage-id")),this.usageID}},{key:"load",value:function(){this.responseView.load(),this.loadAssessmentModules(),this.staffAreaView.load()}},{key:"loadAssessmentModules",value:function(e){this.trainingView.load(e),this.peerView.load(e),this.staffView.load(e),this.selfView.load(e),this.gradeView.load(e),this.leaderboardView.load(e)}},{key:"loadMessageView",value:function(){this.messageView.load()}},{key:"toggleActionError",value:function(e,t){var n=this.element,r=null;if("save"===e?r=".response__submission__actions":"submit"===e||"peer"===e||"self"===e||"student-training"===e?r=".step__actions":"feedback_assess"===e?r=".submission__feedback__actions":"upload"===e?r=".upload__error":"delete"===e&&(r=".delete__error"),null===r?null!==t&&console.log(t):($("".concat(r," .message__content"),n).html("

    ".concat(t?_.escape(t):"","

    ")),$(r,n).toggleClass("has--error",null!==t),$("".concat(r," > .message"),n).focus()),null!==t){var a=$("".concat(r," .message__title")).text();this.srReadTexts([a,t])}}},{key:"showLoadError",value:function(e,t){t||(t=gettext("Unable to load"));var n=$(".step--".concat(e));n.toggleClass("has--error",!0),n.removeClass("is--showing"),n.find(".ui-slidable").attr("aria-expanded","false"),n.find(".step__status__value i").removeClass().addClass("icon fa fa-exclamation-triangle"),n.find(".step__status__value .copy").html(_.escape(t))}},{key:"unsavedWarningEnabled",value:function(e,t,n){if(void 0===e)return null!==window.onbeforeunload;var r=$(this.element).data("usage-id");e?(void 0!==this.unsavedChanges[r]&&this.unsavedChanges[r]||(this.unsavedChanges[r]={}),this.unsavedChanges[r][t]=n,window.onbeforeunload=function(){var e,n=this;return Object.keys(this.unsavedChanges).some((function(r){if(n.unsavedChanges.hasOwnProperty(r)){var a=n.unsavedChanges[r];return Object.keys(a).some((function(n){return!!a.hasOwnProperty(t)&&(e=a[t],!0)}))}return!1})),e}):void 0!==this.unsavedChanges[r]&&(delete this.unsavedChanges[r][t],$.isEmptyObject(this.unsavedChanges[r])&&delete this.unsavedChanges[r],$.isEmptyObject(this.unsavedChanges)&&(window.onbeforeunload=null))}},{key:"buttonEnabled",value:function(e,t){var n=$(e,this.element);return void 0===t?!n.prop("disabled"):(n.prop("disabled",!t),t)}}])&&wy(t.prototype,n),r&&wy(t,r),e}();window.OpenAssessmentBlock=function(e,t,n){var a=new r.a(e,t);new Ty(e,t,a,n).load()},window.CourseOpenResponsesListingBlock=function(e,t,n){new a.a(e,t,n).refreshGrids()},window.StaffAssessmentBlock=function(e,t,n){var a=new r.a(e,t);new Ty(e,t,a,n).staffAreaView.installHandlers()},window.WaitingStepDetailsBlock=function(e,t,n){var a=new r.a(e,t),i=new Ty(e,t,a,n);Ly(i,n)}},,,,,,,,,,,function(e,t,n){"use strict";(function(e){var r=n(0);function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(e)))return;var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n>>0;for(t=0;t0)for(n=0;n<_.length;n++)l(a=t[r=_[n]])||(e[r]=a);return e}function v(e){y(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===g&&(g=!0,a.updateOffset(this),g=!1)}function L(e){return e instanceof v||null!=e&&null!=e._isAMomentObject}function w(e){!1===a.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function A(e,t){var n=!0;return p((function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,e),n){var r,i,o,c=[];for(i=0;i=0?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+r}a.suppressDeprecationWarnings=!1,a.deprecationHandler=null,T=Object.keys?Object.keys:function(e){var t,n=[];for(t in e)s(e,t)&&n.push(t);return n};var x=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,D=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,C={},Y={};function P(e,t,n,r){var a=r;"string"==typeof r&&(a=function(){return this[r]()}),e&&(Y[e]=a),t&&(Y[t[0]]=function(){return N(a.apply(this,arguments),t[1],t[2])}),n&&(Y[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),e)})}function j(e,t){return e.isValid()?(t=R(t,e.localeData()),C[t]=C[t]||function(e){var t,n,r,a=e.match(x);for(t=0,n=a.length;t=0&&D.test(e);)e=e.replace(D,r),D.lastIndex=0,n-=1;return e}var W={};function q(e,t){var n=e.toLowerCase();W[n]=W[n+"s"]=W[t]=e}function B(e){return"string"==typeof e?W[e]||W[e.toLowerCase()]:void 0}function H(e){var t,n,r={};for(n in e)s(e,n)&&(t=B(n))&&(r[t]=e[n]);return r}var I={};function X(e,t){I[e]=t}function F(e){return e%4==0&&e%100!=0||e%400==0}function U(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function V(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=U(t)),n}function G(e,t){return function(n){return null!=n?(J(this,e,n),a.updateOffset(this,t),this):$(this,e)}}function $(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function J(e,t,n){e.isValid()&&!isNaN(n)&&("FullYear"===t&&F(e.year())&&1===e.month()&&29===e.date()?(n=V(n),e._d["set"+(e._isUTC?"UTC":"")+t](n,e.month(),Le(n,e.month()))):e._d["set"+(e._isUTC?"UTC":"")+t](n))}var K,Q=/\d/,Z=/\d\d/,ee=/\d{3}/,te=/\d{4}/,ne=/[+-]?\d{6}/,re=/\d\d?/,ae=/\d\d\d\d?/,ie=/\d\d\d\d\d\d?/,oe=/\d{1,3}/,se=/\d{1,4}/,ce=/[+-]?\d{1,6}/,le=/\d+/,ue=/[+-]?\d+/,de=/Z|[+-]\d\d:?\d\d/gi,fe=/Z|[+-]\d\d(?::?\d\d)?/gi,pe=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function me(e,t,n){K[e]=S(t)?t:function(e,r){return e&&n?n:t}}function he(e,t){return s(K,e)?K[e](t._strict,t._locale):new RegExp(be(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,(function(e,t,n,r,a){return t||n||r||a}))))}function be(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}K={};var Me,_e={};function ge(e,t){var n,r=t;for("string"==typeof e&&(e=[e]),u(t)&&(r=function(e,n){n[t]=V(e)}),n=0;n68?1900:2e3)};var De=G("FullYear",!0);function Ce(e,t,n,r,a,i,o){var s;return e<100&&e>=0?(s=new Date(e+400,t,n,r,a,i,o),isFinite(s.getFullYear())&&s.setFullYear(e)):s=new Date(e,t,n,r,a,i,o),s}function Ye(e){var t,n;return e<100&&e>=0?((n=Array.prototype.slice.call(arguments))[0]=e+400,t=new Date(Date.UTC.apply(null,n)),isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e)):t=new Date(Date.UTC.apply(null,arguments)),t}function Pe(e,t,n){var r=7+t-n;return-(7+Ye(e,0,r).getUTCDay()-t)%7+r-1}function je(e,t,n,r,a){var i,o,s=1+7*(t-1)+(7+n-r)%7+Pe(e,r,a);return s<=0?o=xe(i=e-1)+s:s>xe(e)?(i=e+1,o=s-xe(e)):(i=e,o=s),{year:i,dayOfYear:o}}function Re(e,t,n){var r,a,i=Pe(e.year(),t,n),o=Math.floor((e.dayOfYear()-i-1)/7)+1;return o<1?r=o+We(a=e.year()-1,t,n):o>We(e.year(),t,n)?(r=o-We(e.year(),t,n),a=e.year()+1):(a=e.year(),r=o),{week:r,year:a}}function We(e,t,n){var r=Pe(e,t,n),a=Pe(e+1,t,n);return(xe(e)-r+a)/7}function qe(e,t){return e.slice(t,7).concat(e.slice(0,t))}P("w",["ww",2],"wo","week"),P("W",["WW",2],"Wo","isoWeek"),q("week","w"),q("isoWeek","W"),X("week",5),X("isoWeek",5),me("w",re),me("ww",re,Z),me("W",re),me("WW",re,Z),ye(["w","ww","W","WW"],(function(e,t,n,r){t[r.substr(0,1)]=V(e)})),P("d",0,"do","day"),P("dd",0,0,(function(e){return this.localeData().weekdaysMin(this,e)})),P("ddd",0,0,(function(e){return this.localeData().weekdaysShort(this,e)})),P("dddd",0,0,(function(e){return this.localeData().weekdays(this,e)})),P("e",0,0,"weekday"),P("E",0,0,"isoWeekday"),q("day","d"),q("weekday","e"),q("isoWeekday","E"),X("day",11),X("weekday",11),X("isoWeekday",11),me("d",re),me("e",re),me("E",re),me("dd",(function(e,t){return t.weekdaysMinRegex(e)})),me("ddd",(function(e,t){return t.weekdaysShortRegex(e)})),me("dddd",(function(e,t){return t.weekdaysRegex(e)})),ye(["dd","ddd","dddd"],(function(e,t,n,r){var a=n._locale.weekdaysParse(e,r,n._strict);null!=a?t.d=a:h(n).invalidWeekday=e})),ye(["d","e","E"],(function(e,t,n,r){t[r]=V(e)}));var Be="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),He="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ie="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Xe=pe,Fe=pe,Ue=pe;function Ve(e,t,n){var r,a,i,o=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],r=0;r<7;++r)i=m([2e3,1]).day(r),this._minWeekdaysParse[r]=this.weekdaysMin(i,"").toLocaleLowerCase(),this._shortWeekdaysParse[r]=this.weekdaysShort(i,"").toLocaleLowerCase(),this._weekdaysParse[r]=this.weekdays(i,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(a=Me.call(this._weekdaysParse,o))?a:null:"ddd"===t?-1!==(a=Me.call(this._shortWeekdaysParse,o))?a:null:-1!==(a=Me.call(this._minWeekdaysParse,o))?a:null:"dddd"===t?-1!==(a=Me.call(this._weekdaysParse,o))||-1!==(a=Me.call(this._shortWeekdaysParse,o))||-1!==(a=Me.call(this._minWeekdaysParse,o))?a:null:"ddd"===t?-1!==(a=Me.call(this._shortWeekdaysParse,o))||-1!==(a=Me.call(this._weekdaysParse,o))||-1!==(a=Me.call(this._minWeekdaysParse,o))?a:null:-1!==(a=Me.call(this._minWeekdaysParse,o))||-1!==(a=Me.call(this._weekdaysParse,o))||-1!==(a=Me.call(this._shortWeekdaysParse,o))?a:null}function Ge(){function e(e,t){return t.length-e.length}var t,n,r,a,i,o=[],s=[],c=[],l=[];for(t=0;t<7;t++)n=m([2e3,1]).day(t),r=be(this.weekdaysMin(n,"")),a=be(this.weekdaysShort(n,"")),i=be(this.weekdays(n,"")),o.push(r),s.push(a),c.push(i),l.push(r),l.push(a),l.push(i);o.sort(e),s.sort(e),c.sort(e),l.sort(e),this._weekdaysRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+c.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function $e(){return this.hours()%12||12}function Je(e,t){P(e,0,0,(function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)}))}function Ke(e,t){return t._meridiemParse}P("H",["HH",2],0,"hour"),P("h",["hh",2],0,$e),P("k",["kk",2],0,(function(){return this.hours()||24})),P("hmm",0,0,(function(){return""+$e.apply(this)+N(this.minutes(),2)})),P("hmmss",0,0,(function(){return""+$e.apply(this)+N(this.minutes(),2)+N(this.seconds(),2)})),P("Hmm",0,0,(function(){return""+this.hours()+N(this.minutes(),2)})),P("Hmmss",0,0,(function(){return""+this.hours()+N(this.minutes(),2)+N(this.seconds(),2)})),Je("a",!0),Je("A",!1),q("hour","h"),X("hour",13),me("a",Ke),me("A",Ke),me("H",re),me("h",re),me("k",re),me("HH",re,Z),me("hh",re,Z),me("kk",re,Z),me("hmm",ae),me("hmmss",ie),me("Hmm",ae),me("Hmmss",ie),ge(["H","HH"],3),ge(["k","kk"],(function(e,t,n){var r=V(e);t[3]=24===r?0:r})),ge(["a","A"],(function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e})),ge(["h","hh"],(function(e,t,n){t[3]=V(e),h(n).bigHour=!0})),ge("hmm",(function(e,t,n){var r=e.length-2;t[3]=V(e.substr(0,r)),t[4]=V(e.substr(r)),h(n).bigHour=!0})),ge("hmmss",(function(e,t,n){var r=e.length-4,a=e.length-2;t[3]=V(e.substr(0,r)),t[4]=V(e.substr(r,2)),t[5]=V(e.substr(a)),h(n).bigHour=!0})),ge("Hmm",(function(e,t,n){var r=e.length-2;t[3]=V(e.substr(0,r)),t[4]=V(e.substr(r))})),ge("Hmmss",(function(e,t,n){var r=e.length-4,a=e.length-2;t[3]=V(e.substr(0,r)),t[4]=V(e.substr(r,2)),t[5]=V(e.substr(a))}));var Qe,Ze=G("Hours",!0),et={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:we,monthsShort:Ae,week:{dow:0,doy:6},weekdays:Be,weekdaysMin:Ie,weekdaysShort:He,meridiemParse:/[ap]\.?m?\.?/i},tt={},nt={};function rt(e,t){var n,r=Math.min(e.length,t.length);for(n=0;n0;){if(r=it(a.slice(0,t).join("-")))return r;if(n&&n.length>=t&&rt(a,n)>=t-1)break;t--}i++}return Qe}(e)}function lt(e){var t,n=e._a;return n&&-2===h(e).overflow&&(t=n[1]<0||n[1]>11?1:n[2]<1||n[2]>Le(n[0],n[1])?2:n[3]<0||n[3]>24||24===n[3]&&(0!==n[4]||0!==n[5]||0!==n[6])?3:n[4]<0||n[4]>59?4:n[5]<0||n[5]>59?5:n[6]<0||n[6]>999?6:-1,h(e)._overflowDayOfYear&&(t<0||t>2)&&(t=2),h(e)._overflowWeeks&&-1===t&&(t=7),h(e)._overflowWeekday&&-1===t&&(t=8),h(e).overflow=t),e}var ut=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,dt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,ft=/Z|[+-]\d\d(?::?\d\d)?/,pt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],mt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],ht=/^\/?Date\((-?\d+)/i,bt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Mt={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function _t(e){var t,n,r,a,i,o,s=e._i,c=ut.exec(s)||dt.exec(s);if(c){for(h(e).iso=!0,t=0,n=pt.length;t7)&&(c=!0)):(i=e._locale._week.dow,o=e._locale._week.doy,l=Re(Ot(),i,o),n=vt(t.gg,e._a[0],l.year),r=vt(t.w,l.week),null!=t.d?((a=t.d)<0||a>6)&&(c=!0):null!=t.e?(a=t.e+i,(t.e<0||t.e>6)&&(c=!0)):a=i),r<1||r>We(n,i,o)?h(e)._overflowWeeks=!0:null!=c?h(e)._overflowWeekday=!0:(s=je(n,r,a,i,o),e._a[0]=s.year,e._dayOfYear=s.dayOfYear)}(e),null!=e._dayOfYear&&(o=vt(e._a[0],r[0]),(e._dayOfYear>xe(o)||0===e._dayOfYear)&&(h(e)._overflowDayOfYear=!0),n=Ye(o,0,e._dayOfYear),e._a[1]=n.getUTCMonth(),e._a[2]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=s[t]=r[t];for(;t<7;t++)e._a[t]=s[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[3]&&0===e._a[4]&&0===e._a[5]&&0===e._a[6]&&(e._nextDay=!0,e._a[3]=0),e._d=(e._useUTC?Ye:Ce).apply(null,s),i=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[3]=24),e._w&&void 0!==e._w.d&&e._w.d!==i&&(h(e).weekdayMismatch=!0)}}function wt(e){if(e._f!==a.ISO_8601)if(e._f!==a.RFC_2822){e._a=[],h(e).empty=!0;var t,n,r,i,o,s,c=""+e._i,l=c.length,u=0;for(r=R(e._f,e._locale).match(x)||[],t=0;t0&&h(e).unusedInput.push(o),c=c.slice(c.indexOf(n)+n.length),u+=n.length),Y[i]?(n?h(e).empty=!1:h(e).unusedTokens.push(i),ve(i,n,e)):e._strict&&!n&&h(e).unusedTokens.push(i);h(e).charsLeftOver=l-u,c.length>0&&h(e).unusedInput.push(c),e._a[3]<=12&&!0===h(e).bigHour&&e._a[3]>0&&(h(e).bigHour=void 0),h(e).parsedDateParts=e._a.slice(0),h(e).meridiem=e._meridiem,e._a[3]=function(e,t,n){var r;return null==n?t:null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?((r=e.isPM(n))&&t<12&&(t+=12),r||12!==t||(t=0),t):t}(e._locale,e._a[3],e._meridiem),null!==(s=h(e).era)&&(e._a[0]=e._locale.erasConvertYear(s,e._a[0])),Lt(e),lt(e)}else yt(e);else _t(e)}function At(e){var t=e._i,n=e._f;return e._locale=e._locale||ct(e._l),null===t||void 0===n&&""===t?M({nullInput:!0}):("string"==typeof t&&(e._i=t=e._locale.preparse(t)),L(t)?new v(lt(t)):(d(t)?e._d=t:i(n)?function(e){var t,n,r,a,i,o,s=!1;if(0===e._f.length)return h(e).invalidFormat=!0,void(e._d=new Date(NaN));for(a=0;athis?this:e:M()}));function zt(e,t){var n,r;if(1===t.length&&i(t[0])&&(t=t[0]),!t.length)return Ot();for(n=t[0],r=1;r=0?new Date(e+400,t,n)-126227808e5:new Date(e,t,n).valueOf()}function an(e,t,n){return e<100&&e>=0?Date.UTC(e+400,t,n)-126227808e5:Date.UTC(e,t,n)}function on(e,t){return t.erasAbbrRegex(e)}function sn(){var e,t,n=[],r=[],a=[],i=[],o=this.eras();for(e=0,t=o.length;e(i=We(e,r,a))&&(t=i),un.call(this,e,t,n,r,a))}function un(e,t,n,r,a){var i=je(e,t,n,r,a),o=Ye(i.year,0,i.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}P("N",0,0,"eraAbbr"),P("NN",0,0,"eraAbbr"),P("NNN",0,0,"eraAbbr"),P("NNNN",0,0,"eraName"),P("NNNNN",0,0,"eraNarrow"),P("y",["y",1],"yo","eraYear"),P("y",["yy",2],0,"eraYear"),P("y",["yyy",3],0,"eraYear"),P("y",["yyyy",4],0,"eraYear"),me("N",on),me("NN",on),me("NNN",on),me("NNNN",(function(e,t){return t.erasNameRegex(e)})),me("NNNNN",(function(e,t){return t.erasNarrowRegex(e)})),ge(["N","NN","NNN","NNNN","NNNNN"],(function(e,t,n,r){var a=n._locale.erasParse(e,r,n._strict);a?h(n).era=a:h(n).invalidEra=e})),me("y",le),me("yy",le),me("yyy",le),me("yyyy",le),me("yo",(function(e,t){return t._eraYearOrdinalRegex||le})),ge(["y","yy","yyy","yyyy"],0),ge(["yo"],(function(e,t,n,r){var a;n._locale._eraYearOrdinalRegex&&(a=e.match(n._locale._eraYearOrdinalRegex)),n._locale.eraYearOrdinalParse?t[0]=n._locale.eraYearOrdinalParse(e,a):t[0]=parseInt(e,10)})),P(0,["gg",2],0,(function(){return this.weekYear()%100})),P(0,["GG",2],0,(function(){return this.isoWeekYear()%100})),cn("gggg","weekYear"),cn("ggggg","weekYear"),cn("GGGG","isoWeekYear"),cn("GGGGG","isoWeekYear"),q("weekYear","gg"),q("isoWeekYear","GG"),X("weekYear",1),X("isoWeekYear",1),me("G",ue),me("g",ue),me("GG",re,Z),me("gg",re,Z),me("GGGG",se,te),me("gggg",se,te),me("GGGGG",ce,ne),me("ggggg",ce,ne),ye(["gggg","ggggg","GGGG","GGGGG"],(function(e,t,n,r){t[r.substr(0,2)]=V(e)})),ye(["gg","GG"],(function(e,t,n,r){t[r]=a.parseTwoDigitYear(e)})),P("Q",0,"Qo","quarter"),q("quarter","Q"),X("quarter",7),me("Q",Q),ge("Q",(function(e,t){t[1]=3*(V(e)-1)})),P("D",["DD",2],"Do","date"),q("date","D"),X("date",9),me("D",re),me("DD",re,Z),me("Do",(function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient})),ge(["D","DD"],2),ge("Do",(function(e,t){t[2]=V(e.match(re)[0])}));var dn=G("Date",!0);P("DDD",["DDDD",3],"DDDo","dayOfYear"),q("dayOfYear","DDD"),X("dayOfYear",4),me("DDD",oe),me("DDDD",ee),ge(["DDD","DDDD"],(function(e,t,n){n._dayOfYear=V(e)})),P("m",["mm",2],0,"minute"),q("minute","m"),X("minute",14),me("m",re),me("mm",re,Z),ge(["m","mm"],4);var fn=G("Minutes",!1);P("s",["ss",2],0,"second"),q("second","s"),X("second",15),me("s",re),me("ss",re,Z),ge(["s","ss"],5);var pn,mn,hn=G("Seconds",!1);for(P("S",0,0,(function(){return~~(this.millisecond()/100)})),P(0,["SS",2],0,(function(){return~~(this.millisecond()/10)})),P(0,["SSS",3],0,"millisecond"),P(0,["SSSS",4],0,(function(){return 10*this.millisecond()})),P(0,["SSSSS",5],0,(function(){return 100*this.millisecond()})),P(0,["SSSSSS",6],0,(function(){return 1e3*this.millisecond()})),P(0,["SSSSSSS",7],0,(function(){return 1e4*this.millisecond()})),P(0,["SSSSSSSS",8],0,(function(){return 1e5*this.millisecond()})),P(0,["SSSSSSSSS",9],0,(function(){return 1e6*this.millisecond()})),q("millisecond","ms"),X("millisecond",16),me("S",oe,Q),me("SS",oe,Z),me("SSS",oe,ee),pn="SSSS";pn.length<=9;pn+="S")me(pn,le);function bn(e,t){t[6]=V(1e3*("0."+e))}for(pn="S";pn.length<=9;pn+="S")ge(pn,bn);mn=G("Milliseconds",!1),P("z",0,0,"zoneAbbr"),P("zz",0,0,"zoneName");var Mn=v.prototype;function _n(e){return e}Mn.add=Vt,Mn.calendar=function(e,t){1===arguments.length&&(arguments[0]?Jt(arguments[0])?(e=arguments[0],t=void 0):Kt(arguments[0])&&(t=arguments[0],e=void 0):(e=void 0,t=void 0));var n=e||Ot(),r=jt(n,this).startOf("day"),i=a.calendarFormat(this,r)||"sameElse",o=t&&(S(t[i])?t[i].call(this,n):t[i]);return this.format(o||this.localeData().calendar(i,this,Ot(n)))},Mn.clone=function(){return new v(this)},Mn.diff=function(e,t,n){var r,a,i;if(!this.isValid())return NaN;if(!(r=jt(e,this)).isValid())return NaN;switch(a=6e4*(r.utcOffset()-this.utcOffset()),t=B(t)){case"year":i=Qt(this,r)/12;break;case"month":i=Qt(this,r);break;case"quarter":i=Qt(this,r)/3;break;case"second":i=(this-r)/1e3;break;case"minute":i=(this-r)/6e4;break;case"hour":i=(this-r)/36e5;break;case"day":i=(this-r-a)/864e5;break;case"week":i=(this-r-a)/6048e5;break;default:i=this-r}return n?i:U(i)},Mn.endOf=function(e){var t,n;if(void 0===(e=B(e))||"millisecond"===e||!this.isValid())return this;switch(n=this._isUTC?an:rn,e){case"year":t=n(this.year()+1,0,1)-1;break;case"quarter":t=n(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":t=n(this.year(),this.month()+1,1)-1;break;case"week":t=n(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":t=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":t=n(this.year(),this.month(),this.date()+1)-1;break;case"hour":t=this._d.valueOf(),t+=36e5-nn(t+(this._isUTC?0:6e4*this.utcOffset()),36e5)-1;break;case"minute":t=this._d.valueOf(),t+=6e4-nn(t,6e4)-1;break;case"second":t=this._d.valueOf(),t+=1e3-nn(t,1e3)-1}return this._d.setTime(t),a.updateOffset(this,!0),this},Mn.format=function(e){e||(e=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var t=j(this,e);return this.localeData().postformat(t)},Mn.from=function(e,t){return this.isValid()&&(L(e)&&e.isValid()||Ot(e).isValid())?Ht({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Mn.fromNow=function(e){return this.from(Ot(),e)},Mn.to=function(e,t){return this.isValid()&&(L(e)&&e.isValid()||Ot(e).isValid())?Ht({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Mn.toNow=function(e){return this.to(Ot(),e)},Mn.get=function(e){return S(this[e=B(e)])?this[e]():this},Mn.invalidAt=function(){return h(this).overflow},Mn.isAfter=function(e,t){var n=L(e)?e:Ot(e);return!(!this.isValid()||!n.isValid())&&("millisecond"===(t=B(t)||"millisecond")?this.valueOf()>n.valueOf():n.valueOf()9999?j(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):S(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",j(n,"Z")):j(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},Mn.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,t,n,r="moment",a="";return this.isLocal()||(r=0===this.utcOffset()?"moment.utc":"moment.parseZone",a="Z"),e="["+r+'("]',t=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",n=a+'[")]',this.format(e+t+"-MM-DD[T]HH:mm:ss.SSS"+n)},"undefined"!=typeof Symbol&&null!=Symbol.for&&(Mn[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),Mn.toJSON=function(){return this.isValid()?this.toISOString():null},Mn.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},Mn.unix=function(){return Math.floor(this.valueOf()/1e3)},Mn.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},Mn.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},Mn.eraName=function(){var e,t,n,r=this.localeData().eras();for(e=0,t=r.length;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},Mn.isLocal=function(){return!!this.isValid()&&!this._isUTC},Mn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},Mn.isUtc=Wt,Mn.isUTC=Wt,Mn.zoneAbbr=function(){return this._isUTC?"UTC":""},Mn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},Mn.dates=A("dates accessor is deprecated. Use date instead.",dn),Mn.months=A("months accessor is deprecated. Use month instead",Ee),Mn.years=A("years accessor is deprecated. Use year instead",De),Mn.zone=A("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",(function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()})),Mn.isDSTShifted=A("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",(function(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e,t={};return y(t,this),(t=At(t))._a?(e=t._isUTC?m(t._a):Ot(t._a),this._isDSTShifted=this.isValid()&&function(e,t,n){var r,a=Math.min(e.length,t.length),i=Math.abs(e.length-t.length),o=0;for(r=0;r0):this._isDSTShifted=!1,this._isDSTShifted}));var gn=E.prototype;function yn(e,t,n,r){var a=ct(),i=m().set(r,t);return a[n](i,e)}function vn(e,t,n){if(u(e)&&(t=e,e=void 0),e=e||"",null!=t)return yn(e,t,n,"month");var r,a=[];for(r=0;r<12;r++)a[r]=yn(e,r,n,"month");return a}function Ln(e,t,n,r){"boolean"==typeof e?(u(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,u(t)&&(n=t,t=void 0),t=t||"");var a,i=ct(),o=e?i._week.dow:0,s=[];if(null!=n)return yn(t,(n+o)%7,r,"day");for(a=0;a<7;a++)s[a]=yn(t,(a+o)%7,r,"day");return s}gn.calendar=function(e,t,n){var r=this._calendar[e]||this._calendar.sameElse;return S(r)?r.call(t,n):r},gn.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.match(x).map((function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e})).join(""),this._longDateFormat[e])},gn.invalidDate=function(){return this._invalidDate},gn.ordinal=function(e){return this._ordinal.replace("%d",e)},gn.preparse=_n,gn.postformat=_n,gn.relativeTime=function(e,t,n,r){var a=this._relativeTime[n];return S(a)?a(e,t,n,r):a.replace(/%d/i,e)},gn.pastFuture=function(e,t){var n=this._relativeTime[e>0?"future":"past"];return S(n)?n(t):n.replace(/%s/i,t)},gn.set=function(e){var t,n;for(n in e)s(e,n)&&(S(t=e[n])?this[n]=t:this["_"+n]=t);this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},gn.eras=function(e,t){var n,r,i,o=this._eras||ct("en")._eras;for(n=0,r=o.length;n=0)return c[r]},gn.erasConvertYear=function(e,t){var n=e.since<=e.until?1:-1;return void 0===t?a(e.since).year():a(e.since).year()+(t-e.offset)*n},gn.erasAbbrRegex=function(e){return s(this,"_erasAbbrRegex")||sn.call(this),e?this._erasAbbrRegex:this._erasRegex},gn.erasNameRegex=function(e){return s(this,"_erasNameRegex")||sn.call(this),e?this._erasNameRegex:this._erasRegex},gn.erasNarrowRegex=function(e){return s(this,"_erasNarrowRegex")||sn.call(this),e?this._erasNarrowRegex:this._erasRegex},gn.months=function(e,t){return e?i(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Te).test(t)?"format":"standalone"][e.month()]:i(this._months)?this._months:this._months.standalone},gn.monthsShort=function(e,t){return e?i(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Te.test(t)?"format":"standalone"][e.month()]:i(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},gn.monthsParse=function(e,t,n){var r,a,i;if(this._monthsParseExact)return Se.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),r=0;r<12;r++){if(a=m([2e3,r]),n&&!this._longMonthsParse[r]&&(this._longMonthsParse[r]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[r]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),n||this._monthsParse[r]||(i="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[r]=new RegExp(i.replace(".",""),"i")),n&&"MMMM"===t&&this._longMonthsParse[r].test(e))return r;if(n&&"MMM"===t&&this._shortMonthsParse[r].test(e))return r;if(!n&&this._monthsParse[r].test(e))return r}},gn.monthsRegex=function(e){return this._monthsParseExact?(s(this,"_monthsRegex")||Ne.call(this),e?this._monthsStrictRegex:this._monthsRegex):(s(this,"_monthsRegex")||(this._monthsRegex=ke),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},gn.monthsShortRegex=function(e){return this._monthsParseExact?(s(this,"_monthsRegex")||Ne.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(s(this,"_monthsShortRegex")||(this._monthsShortRegex=Oe),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},gn.week=function(e){return Re(e,this._week.dow,this._week.doy).week},gn.firstDayOfYear=function(){return this._week.doy},gn.firstDayOfWeek=function(){return this._week.dow},gn.weekdays=function(e,t){var n=i(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(t)?"format":"standalone"];return!0===e?qe(n,this._week.dow):e?n[e.day()]:n},gn.weekdaysMin=function(e){return!0===e?qe(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin},gn.weekdaysShort=function(e){return!0===e?qe(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort},gn.weekdaysParse=function(e,t,n){var r,a,i;if(this._weekdaysParseExact)return Ve.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),r=0;r<7;r++){if(a=m([2e3,1]).day(r),n&&!this._fullWeekdaysParse[r]&&(this._fullWeekdaysParse[r]=new RegExp("^"+this.weekdays(a,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[r]=new RegExp("^"+this.weekdaysShort(a,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[r]=new RegExp("^"+this.weekdaysMin(a,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[r]||(i="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[r]=new RegExp(i.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[r].test(e))return r;if(n&&"ddd"===t&&this._shortWeekdaysParse[r].test(e))return r;if(n&&"dd"===t&&this._minWeekdaysParse[r].test(e))return r;if(!n&&this._weekdaysParse[r].test(e))return r}},gn.weekdaysRegex=function(e){return this._weekdaysParseExact?(s(this,"_weekdaysRegex")||Ge.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(s(this,"_weekdaysRegex")||(this._weekdaysRegex=Xe),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},gn.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(s(this,"_weekdaysRegex")||Ge.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(s(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Fe),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},gn.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(s(this,"_weekdaysRegex")||Ge.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(s(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Ue),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},gn.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},gn.meridiem=function(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"},ot("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===V(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),a.lang=A("moment.lang is deprecated. Use moment.locale instead.",ot),a.langData=A("moment.langData is deprecated. Use moment.localeData instead.",ct);var wn=Math.abs;function An(e,t,n,r){var a=Ht(t,n);return e._milliseconds+=r*a._milliseconds,e._days+=r*a._days,e._months+=r*a._months,e._bubble()}function Tn(e){return e<0?Math.floor(e):Math.ceil(e)}function On(e){return 4800*e/146097}function kn(e){return 146097*e/4800}function Sn(e){return function(){return this.as(e)}}var zn=Sn("ms"),En=Sn("s"),Nn=Sn("m"),xn=Sn("h"),Dn=Sn("d"),Cn=Sn("w"),Yn=Sn("M"),Pn=Sn("Q"),jn=Sn("y");function Rn(e){return function(){return this.isValid()?this._data[e]:NaN}}var Wn=Rn("milliseconds"),qn=Rn("seconds"),Bn=Rn("minutes"),Hn=Rn("hours"),In=Rn("days"),Xn=Rn("months"),Fn=Rn("years"),Un=Math.round,Vn={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function Gn(e,t,n,r,a){return a.relativeTime(t||1,!!n,e,r)}var $n=Math.abs;function Jn(e){return(e>0)-(e<0)||+e}function Kn(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,r,a,i,o,s,c=$n(this._milliseconds)/1e3,l=$n(this._days),u=$n(this._months),d=this.asSeconds();return d?(e=U(c/60),t=U(e/60),c%=60,e%=60,n=U(u/12),u%=12,r=c?c.toFixed(3).replace(/\.?0+$/,""):"",a=d<0?"-":"",i=Jn(this._months)!==Jn(d)?"-":"",o=Jn(this._days)!==Jn(d)?"-":"",s=Jn(this._milliseconds)!==Jn(d)?"-":"",a+"P"+(n?i+n+"Y":"")+(u?i+u+"M":"")+(l?o+l+"D":"")+(t||e||c?"T":"")+(t?s+t+"H":"")+(e?s+e+"M":"")+(c?s+r+"S":"")):"P0D"}var Qn=Nt.prototype;return Qn.isValid=function(){return this._isValid},Qn.abs=function(){var e=this._data;return this._milliseconds=wn(this._milliseconds),this._days=wn(this._days),this._months=wn(this._months),e.milliseconds=wn(e.milliseconds),e.seconds=wn(e.seconds),e.minutes=wn(e.minutes),e.hours=wn(e.hours),e.months=wn(e.months),e.years=wn(e.years),this},Qn.add=function(e,t){return An(this,e,t,1)},Qn.subtract=function(e,t){return An(this,e,t,-1)},Qn.as=function(e){if(!this.isValid())return NaN;var t,n,r=this._milliseconds;if("month"===(e=B(e))||"quarter"===e||"year"===e)switch(t=this._days+r/864e5,n=this._months+On(t),e){case"month":return n;case"quarter":return n/3;case"year":return n/12}else switch(t=this._days+Math.round(kn(this._months)),e){case"week":return t/7+r/6048e5;case"day":return t+r/864e5;case"hour":return 24*t+r/36e5;case"minute":return 1440*t+r/6e4;case"second":return 86400*t+r/1e3;case"millisecond":return Math.floor(864e5*t)+r;default:throw new Error("Unknown unit "+e)}},Qn.asMilliseconds=zn,Qn.asSeconds=En,Qn.asMinutes=Nn,Qn.asHours=xn,Qn.asDays=Dn,Qn.asWeeks=Cn,Qn.asMonths=Yn,Qn.asQuarters=Pn,Qn.asYears=jn,Qn.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*V(this._months/12):NaN},Qn._bubble=function(){var e,t,n,r,a,i=this._milliseconds,o=this._days,s=this._months,c=this._data;return i>=0&&o>=0&&s>=0||i<=0&&o<=0&&s<=0||(i+=864e5*Tn(kn(s)+o),o=0,s=0),c.milliseconds=i%1e3,e=U(i/1e3),c.seconds=e%60,t=U(e/60),c.minutes=t%60,n=U(t/60),c.hours=n%24,o+=U(n/24),a=U(On(o)),s+=a,o-=Tn(kn(a)),r=U(s/12),s%=12,c.days=o,c.months=s,c.years=r,this},Qn.clone=function(){return Ht(this)},Qn.get=function(e){return e=B(e),this.isValid()?this[e+"s"]():NaN},Qn.milliseconds=Wn,Qn.seconds=qn,Qn.minutes=Bn,Qn.hours=Hn,Qn.days=In,Qn.weeks=function(){return U(this.days()/7)},Qn.months=Xn,Qn.years=Fn,Qn.humanize=function(e,t){if(!this.isValid())return this.localeData().invalidDate();var n,r,a=!1,i=Vn;return"object"==typeof e&&(t=e,e=!1),"boolean"==typeof e&&(a=e),"object"==typeof t&&(i=Object.assign({},Vn,t),null!=t.s&&null==t.ss&&(i.ss=t.s-1)),n=this.localeData(),r=function(e,t,n,r){var a=Ht(e).abs(),i=Un(a.as("s")),o=Un(a.as("m")),s=Un(a.as("h")),c=Un(a.as("d")),l=Un(a.as("M")),u=Un(a.as("w")),d=Un(a.as("y")),f=i<=n.ss&&["s",i]||i0,f[4]=r,Gn.apply(null,f)}(this,!a,i,n),a&&(r=n.pastFuture(+this,r)),n.postformat(r)},Qn.toISOString=Kn,Qn.toString=Kn,Qn.toJSON=Kn,Qn.locale=Zt,Qn.localeData=tn,Qn.toIsoString=A("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Kn),Qn.lang=en,P("X",0,0,"unix"),P("x",0,0,"valueOf"),me("x",ue),me("X",/[+-]?\d+(\.\d{1,3})?/),ge("X",(function(e,t,n){n._d=new Date(1e3*parseFloat(e))})),ge("x",(function(e,t,n){n._d=new Date(V(e))})), +//! moment.js +a.version="2.29.1",t=Ot,a.fn=Mn,a.min=function(){var e=[].slice.call(arguments,0);return zt("isBefore",e)},a.max=function(){var e=[].slice.call(arguments,0);return zt("isAfter",e)},a.now=function(){return Date.now?Date.now():+new Date},a.utc=m,a.unix=function(e){return Ot(1e3*e)},a.months=function(e,t){return vn(e,t,"months")},a.isDate=d,a.locale=ot,a.invalid=M,a.duration=Ht,a.isMoment=L,a.weekdays=function(e,t,n){return Ln(e,t,n,"weekdays")},a.parseZone=function(){return Ot.apply(null,arguments).parseZone()},a.localeData=ct,a.isDuration=xt,a.monthsShort=function(e,t){return vn(e,t,"monthsShort")},a.weekdaysMin=function(e,t,n){return Ln(e,t,n,"weekdaysMin")},a.defineLocale=st,a.updateLocale=function(e,t){if(null!=t){var n,r,a=et;null!=tt[e]&&null!=tt[e].parentLocale?tt[e].set(z(tt[e]._config,t)):(null!=(r=it(e))&&(a=r._config),t=z(a,t),null==r&&(t.abbr=e),(n=new E(t)).parentLocale=tt[e],tt[e]=n),ot(e)}else null!=tt[e]&&(null!=tt[e].parentLocale?(tt[e]=tt[e].parentLocale,e===ot()&&ot(e)):null!=tt[e]&&delete tt[e]);return tt[e]},a.locales=function(){return T(tt)},a.weekdaysShort=function(e,t,n){return Ln(e,t,n,"weekdaysShort")},a.normalizeUnits=B,a.relativeTimeRounding=function(e){return void 0===e?Un:"function"==typeof e&&(Un=e,!0)},a.relativeTimeThreshold=function(e,t){return void 0!==Vn[e]&&(void 0===t?Vn[e]:(Vn[e]=t,"s"===e&&(Vn.ss=t-1),!0))},a.calendarFormat=function(e,t){var n=e.diff(t,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"},a.prototype=Mn,a.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},a}()}).call(this,n(30)(e))},function(e,t,n){"use strict";(function(e){n.d(t,"e",(function(){return r})),n.d(t,"p",(function(){return a})),n.d(t,"a",(function(){return i})),n.d(t,"c",(function(){return o})),n.d(t,"d",(function(){return s})),n.d(t,"o",(function(){return c})),n.d(t,"q",(function(){return l})),n.d(t,"t",(function(){return u})),n.d(t,"i",(function(){return d})),n.d(t,"r",(function(){return f})),n.d(t,"s",(function(){return p})),n.d(t,"k",(function(){return m})),n.d(t,"m",(function(){return h})),n.d(t,"j",(function(){return b})),n.d(t,"l",(function(){return M})),n.d(t,"g",(function(){return _})),n.d(t,"f",(function(){return g})),n.d(t,"h",(function(){return y})),n.d(t,"n",(function(){return v})),n.d(t,"b",(function(){return L}));var r="1.13.2",a="object"==typeof self&&self.self===self&&self||"object"==typeof e&&e.global===e&&e||Function("return this")()||{},i=Array.prototype,o=Object.prototype,s="undefined"!=typeof Symbol?Symbol.prototype:null,c=i.push,l=i.slice,u=o.toString,d=o.hasOwnProperty,f="undefined"!=typeof ArrayBuffer,p="undefined"!=typeof DataView,m=Array.isArray,h=Object.keys,b=Object.create,M=f&&ArrayBuffer.isView,_=isNaN,g=isFinite,y=!{toString:null}.propertyIsEnumerable("toString"),v=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],L=Math.pow(2,53)-1}).call(this,n(7))},function(e,t,n){var r; +/*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0&&n<=a.b}}function Y(e){return function(t){return null==t?void 0:t[e]}}var P=Y("byteLength"),j=C(P),R=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var W=a.r?function(e){return a.l?Object(a.l)(e)&&!O(e):j(e)&&R.test(a.t.call(e))}:D(!1),q=Y("length");function B(e,t){t=function(e){for(var t={},n=e.length,r=0;r":">",'"':""","'":"'","`":"`"},We=je(Re),qe=je(le(Re)),Be=F.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},He=/(.)^/,Ie={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Xe=/\\|'|\r|\n|\u2028|\u2029/g;function Fe(e){return"\\"+Ie[e]}var Ue=/^\s*(\w|\$)+\s*$/;function Ve(e,t,n){!t&&n&&(t=n),t=me({},t,F.templateSettings);var r=RegExp([(t.escape||He).source,(t.interpolate||He).source,(t.evaluate||He).source].join("|")+"|$","g"),a=0,i="__p+='";e.replace(r,(function(t,n,r,o,s){return i+=e.slice(a,s).replace(Xe,Fe),a=s+t.length,n?i+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?i+="'+\n((__t=("+r+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t})),i+="';\n";var o,s=t.variable;if(s){if(!Ue.test(s))throw new Error("variable is not a bare identifier: "+s)}else i="with(obj||{}){\n"+i+"}\n",s="obj";i="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{o=new Function(s,"_",i)}catch(e){throw e.source=i,e}var c=function(e){return o.call(this,e,F)};return c.source="function("+s+"){\n"+i+"}",c}function Ge(e,t,n){var r=(t=ye(t)).length;if(!r)return v(n)?n.call(e):n;for(var a=0;a1)rt(s,t-1,n,r),a=r.length;else for(var c=0,l=s.length;ct?(r&&(clearTimeout(r),r=null),s=l,o=e.apply(a,i),r||(a=i=null)):r||!1===n.trailing||(r=setTimeout(c,u)),o};return l.cancel=function(){clearTimeout(r),s=0,r=a=i=null},l}function lt(e,t,n){var r,a,o,s,c,l=function(){var i=Pe()-a;t>i?r=setTimeout(l,t-i):(r=null,n||(s=e.apply(c,o)),r||(o=c=null))},u=i((function(i){return c=this,o=i,a=Pe(),r||(r=setTimeout(l,t),n&&(s=e.apply(c,o))),s}));return u.cancel=function(){clearTimeout(r),r=o=c=null},u}function ut(e,t){return et(t,e)}function dt(e){return function(){return!e.apply(this,arguments)}}function ft(){var e=arguments,t=e.length-1;return function(){for(var n=t,r=e[t].apply(this,arguments);n--;)r=e[n].call(this,r);return r}}function pt(e,t){return function(){if(--e<1)return t.apply(this,arguments)}}function mt(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}}var ht=et(mt,2);function bt(e,t,n){t=Ee(t,n);for(var r,a=H(e),i=0,o=a.length;i0?0:a-1;i>=0&&i0?s=o>=0?o:Math.max(o+c,s):c=o>=0?Math.min(o+1,c):o+c+1;else if(n&&o&&c)return r[o=n(r,i)]===i?o:-1;if(i!=i)return(o=t(a.q.call(r,s,c),x))>=0?o+s:-1;for(o=e>0?s:c-1;o>=0&&o0?0:o-1;for(a||(r=t[i?i[s]:s],s+=e);s>=0&&s=3;return t(e,ke(n,a,4),r,i)}}var zt=St(1),Et=St(-1);function Nt(e,t,n){var r=[];return t=Ee(t,n),Ot(e,(function(e,n,a){t(e,n,a)&&r.push(e)})),r}function xt(e,t,n){return Nt(e,dt(Ee(t)),n)}function Dt(e,t,n){t=Ee(t,n);for(var r=!nt(e)&&H(e),a=(r||e).length,i=0;i=0}var Pt=i((function(e,t,n){var r,a;return v(t)?a=t:(t=ye(t),r=t.slice(0,-1),t=t[t.length-1]),kt(e,(function(e){var i=a;if(!i){if(r&&r.length&&(e=ve(e,r)),null==e)return;i=e[t]}return null==i?i:i.apply(e,n)}))}));function jt(e,t){return kt(e,Oe(t))}function Rt(e,t){return Nt(e,Te(t))}function Wt(e,t,n){var r,a,i=-1/0,o=-1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,c=(e=nt(e)?e:se(e)).length;si&&(i=r);else t=Ee(t,n),Ot(e,(function(e,n,r){((a=t(e,n,r))>o||a===-1/0&&i===-1/0)&&(i=e,o=a)}));return i}function qt(e,t,n){var r,a,i=1/0,o=1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,c=(e=nt(e)?e:se(e)).length;sr||void 0===n)return 1;if(n1&&(r=ke(r,t[1])),t=$(e)):(r=Qt,t=rt(t,!1,!1),e=Object(e));for(var a=0,i=t.length;a1&&(n=t[1])):(t=kt(rt(t,!1,!1),String),r=function(e,n){return!Yt(t,n)}),Zt(e,r,n)}));function tn(e,t,n){return a.q.call(e,0,Math.max(0,e.length-(null==t||n?1:t)))}function nn(e,t,n){return null==e||e.length<1?null==t||n?void 0:[]:null==t||n?e[0]:tn(e,e.length-t)}function rn(e,t,n){return a.q.call(e,null==t||n?1:t)}function an(e,t,n){return null==e||e.length<1?null==t||n?void 0:[]:null==t||n?e[e.length-1]:rn(e,Math.max(0,e.length-t))}function on(e){return Nt(e,Boolean)}function sn(e,t){return rt(e,t,!1)}var cn=i((function(e,t){return t=rt(t,!0,!0),Nt(e,(function(e){return!Yt(t,e)}))})),ln=i((function(e,t){return cn(e,t)}));function un(e,t,n,r){l(t)||(r=n,n=t,t=!1),null!=n&&(n=Ee(n,r));for(var a=[],i=[],o=0,s=q(e);o1?r.rejectWith(this,[gettext("Multiple teams returned for course")]):0===e.count?r.resolveWith(this,[null]):r.resolveWith(this,[e.results[0]])})).fail((function(){r.rejectWith(this,[gettext("Could not load teams information.")])}))})).promise()}},{key:"getUsername",value:function(){var e=this.url("get_student_username");return $.Deferred((function(t){$.ajax({type:"POST",url:e,data:JSON.stringify({}),contentType:a}).done((function(e){null===e.username?t.rejectWith(this,[gettext("User lookup failed")]):t.resolveWith(this,[e.username])})).fail((function(){t.rejectWith(this,[gettext("Error when looking up username")])}))}))}},{key:"cloneRubric",value:function(e){var t=this.url("get_rubric"),n={target_rubric_block_id:String(e)};return $.Deferred((function(e){$.ajax({type:"POST",url:t,data:JSON.stringify(n),contentType:a}).done((function(t){t.success?e.resolveWith(this,[t.rubric]):e.rejectWith(this,[t.msg])})).fail((function(){e.rejectWith(this,[gettext("Failed to clone rubric")])}))}))}}])&&r(t.prototype,n),i&&r(t,i),e}();t.a=i},,,function(e,t,n){e.exports={xs:"0",sm:"576px",md:"768px",lg:"992px",xl:"1200px",xxl:"1400px"}},,function(e,t,n){var r,a,i; +/*! + * jQuery JavaScript Library v2.2.4 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-05-20T17:23Z + */a="undefined"!=typeof window?window:this,i=function(n,a){var i=[],o=n.document,s=i.slice,c=i.concat,l=i.push,u=i.indexOf,d={},f=d.toString,p=d.hasOwnProperty,m={},h=function(e,t){return new h.fn.init(e,t)},b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,M=/^-ms-/,_=/-([\da-z])/gi,g=function(e,t){return t.toUpperCase()};function y(e){var t=!!e&&"length"in e&&e.length,n=h.type(e);return"function"!==n&&!h.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}h.fn=h.prototype={jquery:"2.2.4",constructor:h,selector:"",length:0,toArray:function(){return s.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:s.call(this)},pushStack:function(e){var t=h.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e){return h.each(this,e)},map:function(e){return this.pushStack(h.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n=0},isPlainObject:function(e){var t;if("object"!==h.type(e)||e.nodeType||h.isWindow(e))return!1;if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype||{},"isPrototypeOf"))return!1;for(t in e);return void 0===t||p.call(e,t)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?d[f.call(e)]||"object":typeof e},globalEval:function(e){var t,n=eval;(e=h.trim(e))&&(1===e.indexOf("use strict")?((t=o.createElement("script")).text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(M,"ms-").replace(_,g)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var n,r=0;if(y(e))for(n=e.length;r+~]|"+P+")"+P+"*"),X=new RegExp("="+P+"*([^\\]'\"]*?)"+P+"*\\]","g"),F=new RegExp(W),U=new RegExp("^"+j+"$"),V={ID:new RegExp("^#("+j+")"),CLASS:new RegExp("^\\.("+j+")"),TAG:new RegExp("^("+j+"|[*])"),ATTR:new RegExp("^"+R),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:new RegExp("^(?:"+Y+")$","i"),needsContext:new RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,$=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Q=/[+~]/,Z=/'|\\/g,ee=new RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),te=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},ne=function(){f()};try{x.apply(z=D.call(v.childNodes),v.childNodes),z[v.childNodes.length].nodeType}catch(e){x={apply:z.length?function(e,t){N.apply(e,D.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function re(e,t,r,a){var i,s,l,u,d,m,M,_,L=t&&t.ownerDocument,w=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==w&&9!==w&&11!==w)return r;if(!a&&((t?t.ownerDocument||t:v)!==p&&f(t),t=t||p,h)){if(11!==w&&(m=K.exec(e)))if(i=m[1]){if(9===w){if(!(l=t.getElementById(i)))return r;if(l.id===i)return r.push(l),r}else if(L&&(l=L.getElementById(i))&&g(t,l)&&l.id===i)return r.push(l),r}else{if(m[2])return x.apply(r,t.getElementsByTagName(e)),r;if((i=m[3])&&n.getElementsByClassName&&t.getElementsByClassName)return x.apply(r,t.getElementsByClassName(i)),r}if(n.qsa&&!O[e+" "]&&(!b||!b.test(e))){if(1!==w)L=t,_=e;else if("object"!==t.nodeName.toLowerCase()){for((u=t.getAttribute("id"))?u=u.replace(Z,"\\$&"):t.setAttribute("id",u=y),s=(M=o(e)).length,d=U.test(u)?"#"+u:"[id='"+u+"']";s--;)M[s]=d+" "+me(M[s]);_=M.join(","),L=Q.test(e)&&fe(t.parentNode)||t}if(_)try{return x.apply(r,L.querySelectorAll(_)),r}catch(e){}finally{u===y&&t.removeAttribute("id")}}}return c(e.replace(B,"$1"),t,r,a)}function ae(){var e=[];return function t(n,a){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=a}}function ie(e){return e[y]=!0,e}function oe(e){var t=p.createElement("div");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function se(e,t){for(var n=e.split("|"),a=n.length;a--;)r.attrHandle[n[a]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||1<<31)-(~e.sourceIndex||1<<31);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function le(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function ue(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return ie((function(t){return t=+t,ie((function(n,r){for(var a,i=e([],n.length,t),o=i.length;o--;)n[a=i[o]]&&(n[a]=!(r[a]=n[a]))}))}))}function fe(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=re.support={},i=re.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},f=re.setDocument=function(e){var t,a,o=e?e.ownerDocument||e:v;return o!==p&&9===o.nodeType&&o.documentElement?(m=(p=o).documentElement,h=!i(p),(a=p.defaultView)&&a.top!==a&&(a.addEventListener?a.addEventListener("unload",ne,!1):a.attachEvent&&a.attachEvent("onunload",ne)),n.attributes=oe((function(e){return e.className="i",!e.getAttribute("className")})),n.getElementsByTagName=oe((function(e){return e.appendChild(p.createComment("")),!e.getElementsByTagName("*").length})),n.getElementsByClassName=J.test(p.getElementsByClassName),n.getById=oe((function(e){return m.appendChild(e).id=y,!p.getElementsByName||!p.getElementsByName(y).length})),n.getById?(r.find.ID=function(e,t){if(void 0!==t.getElementById&&h){var n=t.getElementById(e);return n?[n]:[]}},r.filter.ID=function(e){var t=e.replace(ee,te);return function(e){return e.getAttribute("id")===t}}):(delete r.find.ID,r.filter.ID=function(e){var t=e.replace(ee,te);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],a=0,i=t.getElementsByTagName(e);if("*"===e){for(;n=i[a++];)1===n.nodeType&&r.push(n);return r}return i},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&h)return t.getElementsByClassName(e)},M=[],b=[],(n.qsa=J.test(p.querySelectorAll))&&(oe((function(e){m.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&b.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||b.push("\\["+P+"*(?:value|"+Y+")"),e.querySelectorAll("[id~="+y+"-]").length||b.push("~="),e.querySelectorAll(":checked").length||b.push(":checked"),e.querySelectorAll("a#"+y+"+*").length||b.push(".#.+[+~]")})),oe((function(e){var t=p.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&b.push("name"+P+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||b.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),b.push(",.*:")}))),(n.matchesSelector=J.test(_=m.matches||m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&oe((function(e){n.disconnectedMatch=_.call(e,"div"),_.call(e,"[s!='']:x"),M.push("!=",W)})),b=b.length&&new RegExp(b.join("|")),M=M.length&&new RegExp(M.join("|")),t=J.test(m.compareDocumentPosition),g=t||J.test(m.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},k=t?function(e,t){if(e===t)return d=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===p||e.ownerDocument===v&&g(v,e)?-1:t===p||t.ownerDocument===v&&g(v,t)?1:u?C(u,e)-C(u,t):0:4&r?-1:1)}:function(e,t){if(e===t)return d=!0,0;var n,r=0,a=e.parentNode,i=t.parentNode,o=[e],s=[t];if(!a||!i)return e===p?-1:t===p?1:a?-1:i?1:u?C(u,e)-C(u,t):0;if(a===i)return ce(e,t);for(n=e;n=n.parentNode;)o.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;o[r]===s[r];)r++;return r?ce(o[r],s[r]):o[r]===v?-1:s[r]===v?1:0},p):p},re.matches=function(e,t){return re(e,null,null,t)},re.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&f(e),t=t.replace(X,"='$1']"),n.matchesSelector&&h&&!O[t+" "]&&(!M||!M.test(t))&&(!b||!b.test(t)))try{var r=_.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return re(t,p,null,[e]).length>0},re.contains=function(e,t){return(e.ownerDocument||e)!==p&&f(e),g(e,t)},re.attr=function(e,t){(e.ownerDocument||e)!==p&&f(e);var a=r.attrHandle[t.toLowerCase()],i=a&&S.call(r.attrHandle,t.toLowerCase())?a(e,t,!h):void 0;return void 0!==i?i:n.attributes||!h?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null},re.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},re.uniqueSort=function(e){var t,r=[],a=0,i=0;if(d=!n.detectDuplicates,u=!n.sortStable&&e.slice(0),e.sort(k),d){for(;t=e[i++];)t===e[i]&&(a=r.push(i));for(;a--;)e.splice(r[a],1)}return u=null,e},a=re.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=a(t);return n},(r=re.selectors={cacheLength:50,createPseudo:ie,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(ee,te),e[3]=(e[3]||e[4]||e[5]||"").replace(ee,te),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||re.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&re.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&F.test(n)&&(t=o(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(ee,te).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=A[e+" "];return t||(t=new RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&A(e,(function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")}))},ATTR:function(e,t,n){return function(r){var a=re.attr(r,e);return null==a?"!="===t:!t||(a+="","="===t?a===n:"!="===t?a!==n:"^="===t?n&&0===a.indexOf(n):"*="===t?n&&a.indexOf(n)>-1:"$="===t?n&&a.slice(-n.length)===n:"~="===t?(" "+a.replace(q," ")+" ").indexOf(n)>-1:"|="===t&&(a===n||a.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,a){var i="nth"!==e.slice(0,3),o="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===a?function(e){return!!e.parentNode}:function(t,n,c){var l,u,d,f,p,m,h=i!==o?"nextSibling":"previousSibling",b=t.parentNode,M=s&&t.nodeName.toLowerCase(),_=!c&&!s,g=!1;if(b){if(i){for(;h;){for(f=t;f=f[h];)if(s?f.nodeName.toLowerCase()===M:1===f.nodeType)return!1;m=h="only"===e&&!m&&"nextSibling"}return!0}if(m=[o?b.firstChild:b.lastChild],o&&_){for(g=(p=(l=(u=(d=(f=b)[y]||(f[y]={}))[f.uniqueID]||(d[f.uniqueID]={}))[e]||[])[0]===L&&l[1])&&l[2],f=p&&b.childNodes[p];f=++p&&f&&f[h]||(g=p=0)||m.pop();)if(1===f.nodeType&&++g&&f===t){u[e]=[L,p,g];break}}else if(_&&(g=p=(l=(u=(d=(f=t)[y]||(f[y]={}))[f.uniqueID]||(d[f.uniqueID]={}))[e]||[])[0]===L&&l[1]),!1===g)for(;(f=++p&&f&&f[h]||(g=p=0)||m.pop())&&((s?f.nodeName.toLowerCase()!==M:1!==f.nodeType)||!++g||(_&&((u=(d=f[y]||(f[y]={}))[f.uniqueID]||(d[f.uniqueID]={}))[e]=[L,g]),f!==t)););return(g-=a)===r||g%r==0&&g/r>=0}}},PSEUDO:function(e,t){var n,a=r.pseudos[e]||r.setFilters[e.toLowerCase()]||re.error("unsupported pseudo: "+e);return a[y]?a(t):a.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?ie((function(e,n){for(var r,i=a(e,t),o=i.length;o--;)e[r=C(e,i[o])]=!(n[r]=i[o])})):function(e){return a(e,0,n)}):a}},pseudos:{not:ie((function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[y]?ie((function(e,t,n,a){for(var i,o=r(e,null,a,[]),s=e.length;s--;)(i=o[s])&&(e[s]=!(t[s]=i))})):function(e,a,i){return t[0]=e,r(t,null,i,n),t[0]=null,!n.pop()}})),has:ie((function(e){return function(t){return re(e,t).length>0}})),contains:ie((function(e){return e=e.replace(ee,te),function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}})),lang:ie((function(e){return U.test(e||"")||re.error("unsupported lang: "+e),e=e.replace(ee,te).toLowerCase(),function(t){var n;do{if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===m},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return!1===e.disabled},disabled:function(e){return!0===e.disabled},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return $.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:de((function(){return[0]})),last:de((function(e,t){return[t-1]})),eq:de((function(e,t,n){return[n<0?n+t:n]})),even:de((function(e,t){for(var n=0;n=0;)e.push(r);return e})),gt:de((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var a=e.length;a--;)if(!e[a](t,n,r))return!1;return!0}:e[0]}function Me(e,t,n,r,a){for(var i,o=[],s=0,c=e.length,l=null!=t;s-1&&(i[l]=!(o[l]=d))}}else M=Me(M===o?M.splice(m,M.length):M),a?a(null,o,M,c):x.apply(o,M)}))}function ge(e){for(var t,n,a,i=e.length,o=r.relative[e[0].type],s=o||r.relative[" "],c=o?1:0,u=he((function(e){return e===t}),s,!0),d=he((function(e){return C(t,e)>-1}),s,!0),f=[function(e,n,r){var a=!o&&(r||n!==l)||((t=n).nodeType?u(e,n,r):d(e,n,r));return t=null,a}];c1&&be(f),c>1&&me(e.slice(0,c-1).concat({value:" "===e[c-2].type?"*":""})).replace(B,"$1"),n,c0,a=e.length>0,i=function(i,o,s,c,u){var d,m,b,M=0,_="0",g=i&&[],y=[],v=l,w=i||a&&r.find.TAG("*",u),A=L+=null==v?1:Math.random()||.1,T=w.length;for(u&&(l=o===p||o||u);_!==T&&null!=(d=w[_]);_++){if(a&&d){for(m=0,o||d.ownerDocument===p||(f(d),s=!h);b=e[m++];)if(b(d,o||p,s)){c.push(d);break}u&&(L=A)}n&&((d=!b&&d)&&M--,i&&g.push(d))}if(M+=_,n&&_!==M){for(m=0;b=t[m++];)b(g,y,o,s);if(i){if(M>0)for(;_--;)g[_]||y[_]||(y[_]=E.call(c));y=Me(y)}x.apply(c,y),u&&!i&&y.length>0&&M+t.length>1&&re.uniqueSort(c)}return u&&(L=A,l=v),g};return n?ie(i):i}(i,a))).selector=e}return s},c=re.select=function(e,t,a,i){var c,l,u,d,f,p="function"==typeof e&&e,m=!i&&o(e=p.selector||e);if(a=a||[],1===m.length){if((l=m[0]=m[0].slice(0)).length>2&&"ID"===(u=l[0]).type&&n.getById&&9===t.nodeType&&h&&r.relative[l[1].type]){if(!(t=(r.find.ID(u.matches[0].replace(ee,te),t)||[])[0]))return a;p&&(t=t.parentNode),e=e.slice(l.shift().value.length)}for(c=V.needsContext.test(e)?0:l.length;c--&&(u=l[c],!r.relative[d=u.type]);)if((f=r.find[d])&&(i=f(u.matches[0].replace(ee,te),Q.test(l[0].type)&&fe(t.parentNode)||t))){if(l.splice(c,1),!(e=i.length&&me(l)))return x.apply(a,i),a;break}}return(p||s(e,m))(i,t,!h,a,!t||Q.test(e)&&fe(t.parentNode)||t),a},n.sortStable=y.split("").sort(k).join("")===y,n.detectDuplicates=!!d,f(),n.sortDetached=oe((function(e){return 1&e.compareDocumentPosition(p.createElement("div"))})),oe((function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")}))||se("type|href|height|width",(function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)})),n.attributes&&oe((function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}))||se("value",(function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue})),oe((function(e){return null==e.getAttribute("disabled")}))||se(Y,(function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null})),re}(n);h.find=v,h.expr=v.selectors,h.expr[":"]=h.expr.pseudos,h.uniqueSort=h.unique=v.uniqueSort,h.text=v.getText,h.isXMLDoc=v.isXML,h.contains=v.contains;var L=function(e,t,n){for(var r=[],a=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(a&&h(e).is(n))break;r.push(e)}return r},w=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},A=h.expr.match.needsContext,T=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,O=/^.[^:#\[\.,]*$/;function k(e,t,n){if(h.isFunction(t))return h.grep(e,(function(e,r){return!!t.call(e,r,e)!==n}));if(t.nodeType)return h.grep(e,(function(e){return e===t!==n}));if("string"==typeof t){if(O.test(t))return h.filter(t,e,n);t=h.filter(t,e)}return h.grep(e,(function(e){return u.call(t,e)>-1!==n}))}h.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?h.find.matchesSelector(r,e)?[r]:[]:h.find.matches(e,h.grep(t,(function(e){return 1===e.nodeType})))},h.fn.extend({find:function(e){var t,n=this.length,r=[],a=this;if("string"!=typeof e)return this.pushStack(h(e).filter((function(){for(t=0;t1?h.unique(r):r)).selector=this.selector?this.selector+" "+e:e,r},filter:function(e){return this.pushStack(k(this,e||[],!1))},not:function(e){return this.pushStack(k(this,e||[],!0))},is:function(e){return!!k(this,"string"==typeof e&&A.test(e)?h(e):e||[],!1).length}});var S,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;(h.fn.init=function(e,t,n){var r,a;if(!e)return this;if(n=n||S,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:z.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof h?t[0]:t,h.merge(this,h.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),T.test(r[1])&&h.isPlainObject(t))for(r in t)h.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(a=o.getElementById(r[2]))&&a.parentNode&&(this.length=1,this[0]=a),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):h.isFunction(e)?void 0!==n.ready?n.ready(e):e(h):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),h.makeArray(e,this))}).prototype=h.fn,S=h(o);var E=/^(?:parents|prev(?:Until|All))/,N={children:!0,contents:!0,next:!0,prev:!0};function x(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}h.fn.extend({has:function(e){var t=h(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1:1===n.nodeType&&h.find.matchesSelector(n,e))){i.push(n);break}return this.pushStack(i.length>1?h.uniqueSort(i):i)},index:function(e){return e?"string"==typeof e?u.call(h(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(h.uniqueSort(h.merge(this.get(),h(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),h.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return L(e,"parentNode")},parentsUntil:function(e,t,n){return L(e,"parentNode",n)},next:function(e){return x(e,"nextSibling")},prev:function(e){return x(e,"previousSibling")},nextAll:function(e){return L(e,"nextSibling")},prevAll:function(e){return L(e,"previousSibling")},nextUntil:function(e,t,n){return L(e,"nextSibling",n)},prevUntil:function(e,t,n){return L(e,"previousSibling",n)},siblings:function(e){return w((e.parentNode||{}).firstChild,e)},children:function(e){return w(e.firstChild)},contents:function(e){return e.contentDocument||h.merge([],e.childNodes)}},(function(e,t){h.fn[e]=function(n,r){var a=h.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(a=h.filter(r,a)),this.length>1&&(N[e]||h.uniqueSort(a),E.test(e)&&a.reverse()),this.pushStack(a)}}));var D,C=/\S+/g;function Y(){o.removeEventListener("DOMContentLoaded",Y),n.removeEventListener("load",Y),h.ready()}h.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return h.each(e.match(C)||[],(function(e,n){t[n]=!0})),t}(e):h.extend({},e);var t,n,r,a,i=[],o=[],s=-1,c=function(){for(a=e.once,r=t=!0;o.length;s=-1)for(n=o.shift();++s-1;)i.splice(n,1),n<=s&&s--})),this},has:function(e){return e?h.inArray(e,i)>-1:i.length>0},empty:function(){return i&&(i=[]),this},disable:function(){return a=o=[],i=n="",this},disabled:function(){return!i},lock:function(){return a=o=[],n||(i=n=""),this},locked:function(){return!!a},fireWith:function(e,n){return a||(n=[e,(n=n||[]).slice?n.slice():n],o.push(n),t||c()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l},h.extend({Deferred:function(e){var t=[["resolve","done",h.Callbacks("once memory"),"resolved"],["reject","fail",h.Callbacks("once memory"),"rejected"],["notify","progress",h.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return a.done(arguments).fail(arguments),this},then:function(){var e=arguments;return h.Deferred((function(n){h.each(t,(function(t,i){var o=h.isFunction(e[t])&&e[t];a[i[1]]((function(){var e=o&&o.apply(this,arguments);e&&h.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[i[0]+"With"](this===r?n.promise():this,o?[e]:arguments)}))})),e=null})).promise()},promise:function(e){return null!=e?h.extend(e,r):r}},a={};return r.pipe=r.then,h.each(t,(function(e,i){var o=i[2],s=i[3];r[i[1]]=o.add,s&&o.add((function(){n=s}),t[1^e][2].disable,t[2][2].lock),a[i[0]]=function(){return a[i[0]+"With"](this===a?r:this,arguments),this},a[i[0]+"With"]=o.fireWith})),r.promise(a),e&&e.call(a,a),a},when:function(e){var t,n,r,a=0,i=s.call(arguments),o=i.length,c=1!==o||e&&h.isFunction(e.promise)?o:0,l=1===c?e:h.Deferred(),u=function(e,n,r){return function(a){n[e]=this,r[e]=arguments.length>1?s.call(arguments):a,r===t?l.notifyWith(n,r):--c||l.resolveWith(n,r)}};if(o>1)for(t=new Array(o),n=new Array(o),r=new Array(o);a0||(D.resolveWith(o,[h]),h.fn.triggerHandler&&(h(o).triggerHandler("ready"),h(o).off("ready"))))}}),h.ready.promise=function(e){return D||(D=h.Deferred(),"complete"===o.readyState||"loading"!==o.readyState&&!o.documentElement.doScroll?n.setTimeout(h.ready):(o.addEventListener("DOMContentLoaded",Y),n.addEventListener("load",Y))),D.promise(e)},h.ready.promise();var P=function(e,t,n,r,a,i,o){var s=0,c=e.length,l=null==n;if("object"===h.type(n))for(s in a=!0,n)P(e,t,s,n[s],!0,i,o);else if(void 0!==r&&(a=!0,h.isFunction(r)||(o=!0),l&&(o?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(h(e),n)})),t))for(;s-1&&void 0!==n&&q.set(this,e,t)}))}),null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each((function(){q.remove(this,e)}))}}),h.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=W.get(e,t),n&&(!r||h.isArray(n)?r=W.access(e,t,h.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=h.queue(e,t),r=n.length,a=n.shift(),i=h._queueHooks(e,t);"inprogress"===a&&(a=n.shift(),r--),a&&("fx"===t&&n.unshift("inprogress"),delete i.stop,a.call(e,(function(){h.dequeue(e,t)}),i)),!r&&i&&i.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return W.get(e,n)||W.access(e,n,{empty:h.Callbacks("once memory").add((function(){W.remove(e,[t+"queue",n])}))})}}),h.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length",""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function Z(e,t){var n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[];return void 0===t||t&&h.nodeName(e,t)?h.merge([e],n):n}function ee(e,t){for(var n=0,r=e.length;n-1)a&&a.push(i);else if(l=h.contains(i.ownerDocument,i),o=Z(d.appendChild(i),"script"),l&&ee(o),n)for(u=0;i=o[u++];)K.test(i.type||"")&&n.push(i);return d}te=o.createDocumentFragment().appendChild(o.createElement("div")),(ne=o.createElement("input")).setAttribute("type","radio"),ne.setAttribute("checked","checked"),ne.setAttribute("name","t"),te.appendChild(ne),m.checkClone=te.cloneNode(!0).cloneNode(!0).lastChild.checked,te.innerHTML="",m.noCloneChecked=!!te.cloneNode(!0).lastChild.defaultValue;var ie=/^key/,oe=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,se=/^([^.]*)(?:\.(.+)|)/;function ce(){return!0}function le(){return!1}function ue(){try{return o.activeElement}catch(e){}}function de(e,t,n,r,a,i){var o,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)de(e,s,n,r,t[s],i);return e}if(null==r&&null==a?(a=n,r=n=void 0):null==a&&("string"==typeof n?(a=r,r=void 0):(a=r,r=n,n=void 0)),!1===a)a=le;else if(!a)return e;return 1===i&&(o=a,(a=function(e){return h().off(e),o.apply(this,arguments)}).guid=o.guid||(o.guid=h.guid++)),e.each((function(){h.event.add(this,t,a,r,n)}))}h.event={global:{},add:function(e,t,n,r,a){var i,o,s,c,l,u,d,f,p,m,b,M=W.get(e);if(M)for(n.handler&&(n=(i=n).handler,a=i.selector),n.guid||(n.guid=h.guid++),(c=M.events)||(c=M.events={}),(o=M.handle)||(o=M.handle=function(t){return void 0!==h&&h.event.triggered!==t.type?h.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(C)||[""]).length;l--;)p=b=(s=se.exec(t[l])||[])[1],m=(s[2]||"").split(".").sort(),p&&(d=h.event.special[p]||{},p=(a?d.delegateType:d.bindType)||p,d=h.event.special[p]||{},u=h.extend({type:p,origType:b,data:r,handler:n,guid:n.guid,selector:a,needsContext:a&&h.expr.match.needsContext.test(a),namespace:m.join(".")},i),(f=c[p])||((f=c[p]=[]).delegateCount=0,d.setup&&!1!==d.setup.call(e,r,m,o)||e.addEventListener&&e.addEventListener(p,o)),d.add&&(d.add.call(e,u),u.handler.guid||(u.handler.guid=n.guid)),a?f.splice(f.delegateCount++,0,u):f.push(u),h.event.global[p]=!0)},remove:function(e,t,n,r,a){var i,o,s,c,l,u,d,f,p,m,b,M=W.hasData(e)&&W.get(e);if(M&&(c=M.events)){for(l=(t=(t||"").match(C)||[""]).length;l--;)if(p=b=(s=se.exec(t[l])||[])[1],m=(s[2]||"").split(".").sort(),p){for(d=h.event.special[p]||{},f=c[p=(r?d.delegateType:d.bindType)||p]||[],s=s[2]&&new RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"),o=i=f.length;i--;)u=f[i],!a&&b!==u.origType||n&&n.guid!==u.guid||s&&!s.test(u.namespace)||r&&r!==u.selector&&("**"!==r||!u.selector)||(f.splice(i,1),u.selector&&f.delegateCount--,d.remove&&d.remove.call(e,u));o&&!f.length&&(d.teardown&&!1!==d.teardown.call(e,m,M.handle)||h.removeEvent(e,p,M.handle),delete c[p])}else for(p in c)h.event.remove(e,p+t[l],n,r,!0);h.isEmptyObject(c)&&W.remove(e,"handle events")}},dispatch:function(e){e=h.event.fix(e);var t,n,r,a,i,o=[],c=s.call(arguments),l=(W.get(this,"events")||{})[e.type]||[],u=h.event.special[e.type]||{};if(c[0]=e,e.delegateTarget=this,!u.preDispatch||!1!==u.preDispatch.call(this,e)){for(o=h.event.handlers.call(this,e,l),t=0;(a=o[t++])&&!e.isPropagationStopped();)for(e.currentTarget=a.elem,n=0;(i=a.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(i.namespace)||(e.handleObj=i,e.data=i.data,void 0!==(r=((h.event.special[i.origType]||{}).handle||i.handler).apply(a.elem,c))&&!1===(e.result=r)&&(e.preventDefault(),e.stopPropagation()));return u.postDispatch&&u.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,a,i,o=[],s=t.delegateCount,c=e.target;if(s&&c.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&(!0!==c.disabled||"click"!==e.type)){for(r=[],n=0;n-1:h.find(a,this,null,[c]).length),r[a]&&r.push(i);r.length&&o.push({elem:c,handlers:r})}return s]*)\/>/gi,pe=/\s*$/g;function Me(e,t){return h.nodeName(e,"table")&&h.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function _e(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ge(e){var t=he.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function ye(e,t){var n,r,a,i,o,s,c,l;if(1===t.nodeType){if(W.hasData(e)&&(i=W.access(e),o=W.set(t,i),l=i.events))for(a in delete o.handle,o.events={},l)for(n=0,r=l[a].length;n1&&"string"==typeof b&&!m.checkClone&&me.test(b))return e.each((function(a){var i=e.eq(a);M&&(t[0]=b.call(this,a,i.html())),ve(i,t,n,r)}));if(f&&(i=(a=ae(t,e[0].ownerDocument,!1,e,r)).firstChild,1===a.childNodes.length&&(a=i),i||r)){for(s=(o=h.map(Z(a,"script"),_e)).length;d")},clone:function(e,t,n){var r,a,i,o,s,c,l,u=e.cloneNode(!0),d=h.contains(e.ownerDocument,e);if(!(m.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||h.isXMLDoc(e)))for(o=Z(u),r=0,a=(i=Z(e)).length;r0&&ee(o,!d&&Z(e,"script")),u},cleanData:function(e){for(var t,n,r,a=h.event.special,i=0;void 0!==(n=e[i]);i++)if(j(n)){if(t=n[W.expando]){if(t.events)for(r in t.events)a[r]?h.event.remove(n,r):h.removeEvent(n,r,t.handle);n[W.expando]=void 0}n[q.expando]&&(n[q.expando]=void 0)}}}),h.fn.extend({domManip:ve,detach:function(e){return Le(this,e,!0)},remove:function(e){return Le(this,e)},text:function(e){return P(this,(function(e){return void 0===e?h.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return ve(this,arguments,(function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Me(this,e).appendChild(e)}))},prepend:function(){return ve(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Me(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return ve(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return ve(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(h.cleanData(Z(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return h.clone(this,e,t)}))},html:function(e){return P(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!pe.test(e)&&!Q[(J.exec(e)||["",""])[1].toLowerCase()]){e=h.htmlPrefilter(e);try{for(;n")).appendTo(t.documentElement))[0].contentDocument).write(),t.close(),n=Te(e,t),we.detach()),Ae[e]=n),n}var ke=/^margin/,Se=new RegExp("^("+X+")(?!px)[a-z%]+$","i"),ze=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=n),t.getComputedStyle(e)},Ee=function(e,t,n,r){var a,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in a=n.apply(e,r||[]),t)e.style[i]=o[i];return a},Ne=o.documentElement;function xe(e,t,n){var r,a,i,o,s=e.style;return""!==(o=(n=n||ze(e))?n.getPropertyValue(t)||n[t]:void 0)&&void 0!==o||h.contains(e.ownerDocument,e)||(o=h.style(e,t)),n&&!m.pixelMarginRight()&&Se.test(o)&&ke.test(t)&&(r=s.width,a=s.minWidth,i=s.maxWidth,s.minWidth=s.maxWidth=s.width=o,o=n.width,s.width=r,s.minWidth=a,s.maxWidth=i),void 0!==o?o+"":o}function De(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){var e,t,r,a,i=o.createElement("div"),s=o.createElement("div");function c(){s.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",s.innerHTML="",Ne.appendChild(i);var o=n.getComputedStyle(s);e="1%"!==o.top,a="2px"===o.marginLeft,t="4px"===o.width,s.style.marginRight="50%",r="4px"===o.marginRight,Ne.removeChild(i)}s.style&&(s.style.backgroundClip="content-box",s.cloneNode(!0).style.backgroundClip="",m.clearCloneStyle="content-box"===s.style.backgroundClip,i.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",i.appendChild(s),h.extend(m,{pixelPosition:function(){return c(),e},boxSizingReliable:function(){return null==t&&c(),t},pixelMarginRight:function(){return null==t&&c(),r},reliableMarginLeft:function(){return null==t&&c(),a},reliableMarginRight:function(){var e,t=s.appendChild(o.createElement("div"));return t.style.cssText=s.style.cssText="-webkit-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",t.style.marginRight=t.style.width="0",s.style.width="1px",Ne.appendChild(i),e=!parseFloat(n.getComputedStyle(t).marginRight),Ne.removeChild(i),s.removeChild(t),e}}))}();var Ce=/^(none|table(?!-c[ea]).+)/,Ye={position:"absolute",visibility:"hidden",display:"block"},Pe={letterSpacing:"0",fontWeight:"400"},je=["Webkit","O","Moz","ms"],Re=o.createElement("div").style;function We(e){if(e in Re)return e;for(var t=e[0].toUpperCase()+e.slice(1),n=je.length;n--;)if((e=je[n]+t)in Re)return e}function qe(e,t,n){var r=F.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Be(e,t,n,r,a){for(var i=n===(r?"border":"content")?4:"width"===t?1:0,o=0;i<4;i+=2)"margin"===n&&(o+=h.css(e,n+U[i],!0,a)),r?("content"===n&&(o-=h.css(e,"padding"+U[i],!0,a)),"margin"!==n&&(o-=h.css(e,"border"+U[i]+"Width",!0,a))):(o+=h.css(e,"padding"+U[i],!0,a),"padding"!==n&&(o+=h.css(e,"border"+U[i]+"Width",!0,a)));return o}function He(e,t,n){var r=!0,a="width"===t?e.offsetWidth:e.offsetHeight,i=ze(e),o="border-box"===h.css(e,"boxSizing",!1,i);if(a<=0||null==a){if(((a=xe(e,t,i))<0||null==a)&&(a=e.style[t]),Se.test(a))return a;r=o&&(m.boxSizingReliable()||a===e.style[t]),a=parseFloat(a)||0}return a+Be(e,t,n||(o?"border":"content"),r,i)+"px"}function Ie(e,t){for(var n,r,a,i=[],o=0,s=e.length;o1)},show:function(){return Ie(this,!0)},hide:function(){return Ie(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each((function(){V(this)?h(this).show():h(this).hide()}))}}),h.Tween=Xe,Xe.prototype={constructor:Xe,init:function(e,t,n,r,a,i){this.elem=e,this.prop=n,this.easing=a||h.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=i||(h.cssNumber[n]?"":"px")},cur:function(){var e=Xe.propHooks[this.prop];return e&&e.get?e.get(this):Xe.propHooks._default.get(this)},run:function(e){var t,n=Xe.propHooks[this.prop];return this.options.duration?this.pos=t=h.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Xe.propHooks._default.set(this),this}},Xe.prototype.init.prototype=Xe.prototype,Xe.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=h.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){h.fx.step[e.prop]?h.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[h.cssProps[e.prop]]&&!h.cssHooks[e.prop]?e.elem[e.prop]=e.now:h.style(e.elem,e.prop,e.now+e.unit)}}},Xe.propHooks.scrollTop=Xe.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},h.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},h.fx=Xe.prototype.init,h.fx.step={};var Fe,Ue,Ve=/^(?:toggle|show|hide)$/,Ge=/queueHooks$/;function $e(){return n.setTimeout((function(){Fe=void 0})),Fe=h.now()}function Je(e,t){var n,r=0,a={height:e};for(t=t?1:0;r<4;r+=2-t)a["margin"+(n=U[r])]=a["padding"+n]=e;return t&&(a.opacity=a.width=e),a}function Ke(e,t,n){for(var r,a=(Qe.tweeners[t]||[]).concat(Qe.tweeners["*"]),i=0,o=a.length;i1)},removeAttr:function(e){return this.each((function(){h.removeAttr(this,e)}))}}),h.extend({attr:function(e,t,n){var r,a,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return void 0===e.getAttribute?h.prop(e,t,n):(1===i&&h.isXMLDoc(e)||(t=t.toLowerCase(),a=h.attrHooks[t]||(h.expr.match.bool.test(t)?Ze:void 0)),void 0!==n?null===n?void h.removeAttr(e,t):a&&"set"in a&&void 0!==(r=a.set(e,n,t))?r:(e.setAttribute(t,n+""),n):a&&"get"in a&&null!==(r=a.get(e,t))?r:null==(r=h.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!m.radioValue&&"radio"===t&&h.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,a=0,i=t&&t.match(C);if(i&&1===e.nodeType)for(;n=i[a++];)r=h.propFix[n]||n,h.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)}}),Ze={set:function(e,t,n){return!1===t?h.removeAttr(e,n):e.setAttribute(n,n),n}},h.each(h.expr.match.bool.source.match(/\w+/g),(function(e,t){var n=et[t]||h.find.attr;et[t]=function(e,t,r){var a,i;return r||(i=et[t],et[t]=a,a=null!=n(e,t,r)?t.toLowerCase():null,et[t]=i),a}}));var tt=/^(?:input|select|textarea|button)$/i,nt=/^(?:a|area)$/i;h.fn.extend({prop:function(e,t){return P(this,h.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each((function(){delete this[h.propFix[e]||e]}))}}),h.extend({prop:function(e,t,n){var r,a,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return 1===i&&h.isXMLDoc(e)||(t=h.propFix[t]||t,a=h.propHooks[t]),void 0!==n?a&&"set"in a&&void 0!==(r=a.set(e,n,t))?r:e[t]=n:a&&"get"in a&&null!==(r=a.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=h.find.attr(e,"tabindex");return t?parseInt(t,10):tt.test(e.nodeName)||nt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),m.optSelected||(h.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),h.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],(function(){h.propFix[this.toLowerCase()]=this}));var rt=/[\t\r\n\f]/g;function at(e){return e.getAttribute&&e.getAttribute("class")||""}h.fn.extend({addClass:function(e){var t,n,r,a,i,o,s,c=0;if(h.isFunction(e))return this.each((function(t){h(this).addClass(e.call(this,t,at(this)))}));if("string"==typeof e&&e)for(t=e.match(C)||[];n=this[c++];)if(a=at(n),r=1===n.nodeType&&(" "+a+" ").replace(rt," ")){for(o=0;i=t[o++];)r.indexOf(" "+i+" ")<0&&(r+=i+" ");a!==(s=h.trim(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,a,i,o,s,c=0;if(h.isFunction(e))return this.each((function(t){h(this).removeClass(e.call(this,t,at(this)))}));if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(C)||[];n=this[c++];)if(a=at(n),r=1===n.nodeType&&(" "+a+" ").replace(rt," ")){for(o=0;i=t[o++];)for(;r.indexOf(" "+i+" ")>-1;)r=r.replace(" "+i+" "," ");a!==(s=h.trim(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):h.isFunction(e)?this.each((function(n){h(this).toggleClass(e.call(this,n,at(this),t),t)})):this.each((function(){var t,r,a,i;if("string"===n)for(r=0,a=h(this),i=e.match(C)||[];t=i[r++];)a.hasClass(t)?a.removeClass(t):a.addClass(t);else void 0!==e&&"boolean"!==n||((t=at(this))&&W.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":W.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+at(n)+" ").replace(rt," ").indexOf(t)>-1)return!0;return!1}});var it=/\r/g,ot=/[\x20\t\r\n\f]+/g;h.fn.extend({val:function(e){var t,n,r,a=this[0];return arguments.length?(r=h.isFunction(e),this.each((function(n){var a;1===this.nodeType&&(null==(a=r?e.call(this,n,h(this).val()):e)?a="":"number"==typeof a?a+="":h.isArray(a)&&(a=h.map(a,(function(e){return null==e?"":e+""}))),(t=h.valHooks[this.type]||h.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,a,"value")||(this.value=a))}))):a?(t=h.valHooks[a.type]||h.valHooks[a.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(a,"value"))?n:"string"==typeof(n=a.value)?n.replace(it,""):null==n?"":n:void 0}}),h.extend({valHooks:{option:{get:function(e){var t=h.find.attr(e,"value");return null!=t?t:h.trim(h.text(e)).replace(ot," ")}},select:{get:function(e){for(var t,n,r=e.options,a=e.selectedIndex,i="select-one"===e.type||a<0,o=i?null:[],s=i?a+1:r.length,c=a<0?s:i?a:0;c-1)&&(n=!0);return n||(e.selectedIndex=-1),i}}}}),h.each(["radio","checkbox"],(function(){h.valHooks[this]={set:function(e,t){if(h.isArray(t))return e.checked=h.inArray(h(e).val(),t)>-1}},m.checkOn||(h.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}));var st=/^(?:focusinfocus|focusoutblur)$/;h.extend(h.event,{trigger:function(e,t,r,a){var i,s,c,l,u,d,f,m=[r||o],b=p.call(e,"type")?e.type:e,M=p.call(e,"namespace")?e.namespace.split("."):[];if(s=c=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!st.test(b+h.event.triggered)&&(b.indexOf(".")>-1&&(M=b.split("."),b=M.shift(),M.sort()),u=b.indexOf(":")<0&&"on"+b,(e=e[h.expando]?e:new h.Event(b,"object"==typeof e&&e)).isTrigger=a?2:3,e.namespace=M.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+M.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=r),t=null==t?[e]:h.makeArray(t,[e]),f=h.event.special[b]||{},a||!f.trigger||!1!==f.trigger.apply(r,t))){if(!a&&!f.noBubble&&!h.isWindow(r)){for(l=f.delegateType||b,st.test(l+b)||(s=s.parentNode);s;s=s.parentNode)m.push(s),c=s;c===(r.ownerDocument||o)&&m.push(c.defaultView||c.parentWindow||n)}for(i=0;(s=m[i++])&&!e.isPropagationStopped();)e.type=i>1?l:f.bindType||b,(d=(W.get(s,"events")||{})[e.type]&&W.get(s,"handle"))&&d.apply(s,t),(d=u&&s[u])&&d.apply&&j(s)&&(e.result=d.apply(s,t),!1===e.result&&e.preventDefault());return e.type=b,a||e.isDefaultPrevented()||f._default&&!1!==f._default.apply(m.pop(),t)||!j(r)||u&&h.isFunction(r[b])&&!h.isWindow(r)&&((c=r[u])&&(r[u]=null),h.event.triggered=b,r[b](),h.event.triggered=void 0,c&&(r[u]=c)),e.result}},simulate:function(e,t,n){var r=h.extend(new h.Event,n,{type:e,isSimulated:!0});h.event.trigger(r,null,t)}}),h.fn.extend({trigger:function(e,t){return this.each((function(){h.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return h.event.trigger(e,t,n,!0)}}),h.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),(function(e,t){h.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}})),h.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),m.focusin="onfocusin"in n,m.focusin||h.each({focus:"focusin",blur:"focusout"},(function(e,t){var n=function(e){h.event.simulate(t,e.target,h.event.fix(e))};h.event.special[t]={setup:function(){var r=this.ownerDocument||this,a=W.access(r,t);a||r.addEventListener(e,n,!0),W.access(r,t,(a||0)+1)},teardown:function(){var r=this.ownerDocument||this,a=W.access(r,t)-1;a?W.access(r,t,a):(r.removeEventListener(e,n,!0),W.remove(r,t))}}}));var ct=n.location,lt=h.now(),ut=/\?/;h.parseJSON=function(e){return JSON.parse(e+"")},h.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||h.error("Invalid XML: "+e),t};var dt=/#.*$/,ft=/([?&])_=[^&]*/,pt=/^(.*?):[ \t]*([^\r\n]*)$/gm,mt=/^(?:GET|HEAD)$/,ht=/^\/\//,bt={},Mt={},_t="*/".concat("*"),gt=o.createElement("a");function yt(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,a=0,i=t.toLowerCase().match(C)||[];if(h.isFunction(n))for(;r=i[a++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function vt(e,t,n,r){var a={},i=e===Mt;function o(s){var c;return a[s]=!0,h.each(e[s]||[],(function(e,s){var l=s(t,n,r);return"string"!=typeof l||i||a[l]?i?!(c=l):void 0:(t.dataTypes.unshift(l),o(l),!1)})),c}return o(t.dataTypes[0])||!a["*"]&&o("*")}function Lt(e,t){var n,r,a=h.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((a[n]?e:r||(r={}))[n]=t[n]);return r&&h.extend(!0,e,r),e}gt.href=ct.href,h.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ct.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":_t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":h.parseJSON,"text xml":h.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Lt(Lt(e,h.ajaxSettings),t):Lt(h.ajaxSettings,e)},ajaxPrefilter:yt(bt),ajaxTransport:yt(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,a,i,s,c,l,u,d,f=h.ajaxSetup({},t),p=f.context||f,m=f.context&&(p.nodeType||p.jquery)?h(p):h.event,b=h.Deferred(),M=h.Callbacks("once memory"),_=f.statusCode||{},g={},y={},v=0,L="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!s)for(s={};t=pt.exec(i);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,g[e]=t),this},overrideMimeType:function(e){return v||(f.mimeType=e),this},statusCode:function(e){var t;if(e)if(v<2)for(t in e)_[t]=[_[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||L;return r&&r.abort(t),A(0,t),this}};if(b.promise(w).complete=M.add,w.success=w.done,w.error=w.fail,f.url=((e||f.url||ct.href)+"").replace(dt,"").replace(ht,ct.protocol+"//"),f.type=t.method||t.type||f.method||f.type,f.dataTypes=h.trim(f.dataType||"*").toLowerCase().match(C)||[""],null==f.crossDomain){l=o.createElement("a");try{l.href=f.url,l.href=l.href,f.crossDomain=gt.protocol+"//"+gt.host!=l.protocol+"//"+l.host}catch(e){f.crossDomain=!0}}if(f.data&&f.processData&&"string"!=typeof f.data&&(f.data=h.param(f.data,f.traditional)),vt(bt,f,t,w),2===v)return w;for(d in(u=h.event&&f.global)&&0==h.active++&&h.event.trigger("ajaxStart"),f.type=f.type.toUpperCase(),f.hasContent=!mt.test(f.type),a=f.url,f.hasContent||(f.data&&(a=f.url+=(ut.test(a)?"&":"?")+f.data,delete f.data),!1===f.cache&&(f.url=ft.test(a)?a.replace(ft,"$1_="+lt++):a+(ut.test(a)?"&":"?")+"_="+lt++)),f.ifModified&&(h.lastModified[a]&&w.setRequestHeader("If-Modified-Since",h.lastModified[a]),h.etag[a]&&w.setRequestHeader("If-None-Match",h.etag[a])),(f.data&&f.hasContent&&!1!==f.contentType||t.contentType)&&w.setRequestHeader("Content-Type",f.contentType),w.setRequestHeader("Accept",f.dataTypes[0]&&f.accepts[f.dataTypes[0]]?f.accepts[f.dataTypes[0]]+("*"!==f.dataTypes[0]?", "+_t+"; q=0.01":""):f.accepts["*"]),f.headers)w.setRequestHeader(d,f.headers[d]);if(f.beforeSend&&(!1===f.beforeSend.call(p,w,f)||2===v))return w.abort();for(d in L="abort",{success:1,error:1,complete:1})w[d](f[d]);if(r=vt(Mt,f,t,w)){if(w.readyState=1,u&&m.trigger("ajaxSend",[w,f]),2===v)return w;f.async&&f.timeout>0&&(c=n.setTimeout((function(){w.abort("timeout")}),f.timeout));try{v=1,r.send(g,A)}catch(e){if(!(v<2))throw e;A(-1,e)}}else A(-1,"No Transport");function A(e,t,o,s){var l,d,g,y,L,A=t;2!==v&&(v=2,c&&n.clearTimeout(c),r=void 0,i=s||"",w.readyState=e>0?4:0,l=e>=200&&e<300||304===e,o&&(y=function(e,t,n){for(var r,a,i,o,s=e.contents,c=e.dataTypes;"*"===c[0];)c.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(a in s)if(s[a]&&s[a].test(r)){c.unshift(a);break}if(c[0]in n)i=c[0];else{for(a in n){if(!c[0]||e.converters[a+" "+c[0]]){i=a;break}o||(o=a)}i=i||o}if(i)return i!==c[0]&&c.unshift(i),n[i]}(f,w,o)),y=function(e,t,n,r){var a,i,o,s,c,l={},u=e.dataTypes.slice();if(u[1])for(o in e.converters)l[o.toLowerCase()]=e.converters[o];for(i=u.shift();i;)if(e.responseFields[i]&&(n[e.responseFields[i]]=t),!c&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),c=i,i=u.shift())if("*"===i)i=c;else if("*"!==c&&c!==i){if(!(o=l[c+" "+i]||l["* "+i]))for(a in l)if((s=a.split(" "))[1]===i&&(o=l[c+" "+s[0]]||l["* "+s[0]])){!0===o?o=l[a]:!0!==l[a]&&(i=s[0],u.unshift(s[1]));break}if(!0!==o)if(o&&e.throws)t=o(t);else try{t=o(t)}catch(e){return{state:"parsererror",error:o?e:"No conversion from "+c+" to "+i}}}return{state:"success",data:t}}(f,y,w,l),l?(f.ifModified&&((L=w.getResponseHeader("Last-Modified"))&&(h.lastModified[a]=L),(L=w.getResponseHeader("etag"))&&(h.etag[a]=L)),204===e||"HEAD"===f.type?A="nocontent":304===e?A="notmodified":(A=y.state,d=y.data,l=!(g=y.error))):(g=A,!e&&A||(A="error",e<0&&(e=0))),w.status=e,w.statusText=(t||A)+"",l?b.resolveWith(p,[d,A,w]):b.rejectWith(p,[w,A,g]),w.statusCode(_),_=void 0,u&&m.trigger(l?"ajaxSuccess":"ajaxError",[w,f,l?d:g]),M.fireWith(p,[w,A]),u&&(m.trigger("ajaxComplete",[w,f]),--h.active||h.event.trigger("ajaxStop")))}return w},getJSON:function(e,t,n){return h.get(e,t,n,"json")},getScript:function(e,t){return h.get(e,void 0,t,"script")}}),h.each(["get","post"],(function(e,t){h[t]=function(e,n,r,a){return h.isFunction(n)&&(a=a||r,r=n,n=void 0),h.ajax(h.extend({url:e,type:t,dataType:a,data:n,success:r},h.isPlainObject(e)&&e))}})),h._evalUrl=function(e){return h.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,throws:!0})},h.fn.extend({wrapAll:function(e){var t;return h.isFunction(e)?this.each((function(t){h(this).wrapAll(e.call(this,t))})):(this[0]&&(t=h(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e})).append(this)),this)},wrapInner:function(e){return h.isFunction(e)?this.each((function(t){h(this).wrapInner(e.call(this,t))})):this.each((function(){var t=h(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=h.isFunction(e);return this.each((function(n){h(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(){return this.parent().each((function(){h.nodeName(this,"body")||h(this).replaceWith(this.childNodes)})).end()}}),h.expr.filters.hidden=function(e){return!h.expr.filters.visible(e)},h.expr.filters.visible=function(e){return e.offsetWidth>0||e.offsetHeight>0||e.getClientRects().length>0};var wt=/%20/g,At=/\[\]$/,Tt=/\r?\n/g,Ot=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function St(e,t,n,r){var a;if(h.isArray(t))h.each(t,(function(t,a){n||At.test(e)?r(e,a):St(e+"["+("object"==typeof a&&null!=a?t:"")+"]",a,n,r)}));else if(n||"object"!==h.type(t))r(e,t);else for(a in t)St(e+"["+a+"]",t[a],n,r)}h.param=function(e,t){var n,r=[],a=function(e,t){t=h.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=h.ajaxSettings&&h.ajaxSettings.traditional),h.isArray(e)||e.jquery&&!h.isPlainObject(e))h.each(e,(function(){a(this.name,this.value)}));else for(n in e)St(n,e[n],t,a);return r.join("&").replace(wt,"+")},h.fn.extend({serialize:function(){return h.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=h.prop(this,"elements");return e?h.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!h(this).is(":disabled")&&kt.test(this.nodeName)&&!Ot.test(e)&&(this.checked||!$.test(e))})).map((function(e,t){var n=h(this).val();return null==n?null:h.isArray(n)?h.map(n,(function(e){return{name:t.name,value:e.replace(Tt,"\r\n")}})):{name:t.name,value:n.replace(Tt,"\r\n")}})).get()}}),h.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var zt={0:200,1223:204},Et=h.ajaxSettings.xhr();m.cors=!!Et&&"withCredentials"in Et,m.ajax=Et=!!Et,h.ajaxTransport((function(e){var t,r;if(m.cors||Et&&!e.crossDomain)return{send:function(a,i){var o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(o in e.xhrFields)s[o]=e.xhrFields[o];for(o in e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||a["X-Requested-With"]||(a["X-Requested-With"]="XMLHttpRequest"),a)s.setRequestHeader(o,a[o]);t=function(e){return function(){t&&(t=r=s.onload=s.onerror=s.onabort=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?i(0,"error"):i(s.status,s.statusText):i(zt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=t(),r=s.onerror=t("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&n.setTimeout((function(){t&&r()}))},t=t("abort");try{s.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}})),h.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return h.globalEval(e),e}}}),h.ajaxPrefilter("script",(function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")})),h.ajaxTransport("script",(function(e){var t,n;if(e.crossDomain)return{send:function(r,a){t=h(" -{% endspaceless %} diff --git a/openassessment/templates/openassessmentblock/base.html b/openassessment/templates/openassessmentblock/base.html new file mode 100644 index 0000000000..d6d58fbdc3 --- /dev/null +++ b/openassessment/templates/openassessmentblock/base.html @@ -0,0 +1,51 @@ +{% load i18n %} +{% spaceless %} +
    +
    +
    + {% if title %} +

    {% trans title %}

    + {% endif %} + +
    + + {% block message %} +
    +
    +

    {% trans "This assignment has several steps. In the first step, you'll provide a response to the prompt. The other steps appear below the Your Response field." %}

    +
    +
    + {% endblock %} +
    + +
      + {% for assessment in rubric_assessments %} +
    1. +
      +

      + +

      + + + + {% trans "Loading" %} + + +
      +
    2. + {% endfor %} +
    + + {% if show_staff_area %} +
    + {% endif %} +
    +
    +
    +
    +{% endspaceless %} diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index c80f8ee0c8..a0b2a507c8 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -565,7 +565,7 @@ def author_view(self, context=None): # pylint: disable=unused-argument "title": self.title, "xblock_id": self.get_xblock_id(), } - template = get_template("base.html") + template = get_template("openassessmentblock/base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') @togglable_mobile_support @@ -611,7 +611,7 @@ def student_view(self, context=None): # pylint: disable=unused-argument "title": self.title, "xblock_id": self.get_xblock_id(), } - template = get_template("base.html") + template = get_template("openassessmentblock/base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') def ora_blocks_listing_view(self, context=None): From 066c172d2bc508983e5dc3c391cc5bcf7539bcb6 Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Thu, 19 Oct 2023 10:40:11 -0400 Subject: [PATCH 10/27] refactor: BFF contract updates (round 2) (#2079) * chore: remove rubric field from page data * refactor: remove submission hasReceivedGrade * refactor: move submitted / cancelled to step info Required a fix in how we check cancellation info when no workflow. * refactor: rename "submission" key to "response" * fix: require_context to requires_context * refactor: combine assessment/submission endpoints New get_learner_data endpoint covers both modes, while internally routing to the correct view / step / jump step * refactor: move team info to step info * fix: typo in received grade * refactor: move team file uploads to submission * refactor: move response data up a level Also included a refactor to make draft / complete submission serializer inputs similar. * docs: update some comments / docstrings * fix: add missing teams step * refactor: start/endTime to start/endDatetime --------- Co-authored-by: Leangseu Kim --- openassessment/xblock/apis/step_data_api.py | 2 + .../apis/submissions/submissions_api.py | 7 +- openassessment/xblock/apis/workflow_api.py | 2 +- openassessment/xblock/ui_mixins/mfe/mixin.py | 73 ++++- .../ui_mixins/mfe/ora_config_serializer.py | 8 +- .../ui_mixins/mfe/page_context_serializer.py | 123 +++++--- .../xblock/ui_mixins/mfe/serializer_utils.py | 3 +- .../ui_mixins/mfe/submission_serializers.py | 95 +++--- .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 263 +++++++--------- .../mfe/test_page_context_serializer.py | 208 +++++++++++-- .../xblock/ui_mixins/mfe/test_serializers.py | 4 +- .../mfe/test_submission_serializers.py | 293 ++++++++---------- 12 files changed, 619 insertions(+), 462 deletions(-) diff --git a/openassessment/xblock/apis/step_data_api.py b/openassessment/xblock/apis/step_data_api.py index b2ae77fa57..3d50280c5e 100644 --- a/openassessment/xblock/apis/step_data_api.py +++ b/openassessment/xblock/apis/step_data_api.py @@ -34,6 +34,8 @@ def workflow_data(self): @property def has_reached_step(self): """Util for determining if we have reached or surpassed this step""" + if self._step == "submission": + return True if self.workflow_data.status == self._step: return True step_info = self.workflow_data.status_details.get(str(self._step), {}) diff --git a/openassessment/xblock/apis/submissions/submissions_api.py b/openassessment/xblock/apis/submissions/submissions_api.py index c824fb7104..56d7f2aeb2 100644 --- a/openassessment/xblock/apis/submissions/submissions_api.py +++ b/openassessment/xblock/apis/submissions/submissions_api.py @@ -38,7 +38,7 @@ def has_submitted(self): @property def has_been_cancelled(self): - return self.workflow and self.workflow["status"] == "cancelled" + return bool(self.workflow) and self.workflow["status"] == "cancelled" @property def cancellation_info(self): @@ -178,6 +178,9 @@ def team_submission_uuid(self): return self.workflow.get("team_submission_uuid") def get_submission_team_info(self, workflow): + """ + Returns tuple (team info, team ID) + """ if not self.is_team_assignment: return {}, None @@ -196,7 +199,7 @@ def get_submission_team_info(self, workflow): # for shared files lookup. If the learner has submitted already for a different team # and then joined another team, we should show the submission that they are actually a part of, # rather than just their current team. If they have a submission (and therefore a workflow) then - # that takes precidence. + # that takes precedence. team_submission = get_team_submission(workflow['team_submission_uuid']) team_id = team_submission['team_id'] return team_info, team_id diff --git a/openassessment/xblock/apis/workflow_api.py b/openassessment/xblock/apis/workflow_api.py index 285a1e83c1..53932bfacc 100644 --- a/openassessment/xblock/apis/workflow_api.py +++ b/openassessment/xblock/apis/workflow_api.py @@ -83,7 +83,7 @@ def status(self): return self.workflow.get("status") @property - def has_recieved_grade(self): + def has_received_grade(self): return bool(self.workflow.get('score')) def get_workflow_status_counts(self): diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index 33b79cc652..a84a0549d0 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -48,25 +48,66 @@ def get_block_info(self, data, suffix=""): # pylint: disable=unused-argument return block_info.data @XBlock.json_handler - def get_block_learner_submission_data(self, data, suffix=""): # pylint: disable=unused-argument - serializer_context = {"view": "submission"} - page_context = PageDataSerializer(self, context=serializer_context) - return page_context.data - - @XBlock.json_handler - def get_block_learner_assessment_data(self, data, suffix=""): # pylint: disable=unused-argument - serializer_context = {"view": "assessment", "step": suffix} + def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument + """ + Get data for the user / step of the ORA + - If no step provided, go to current workflow step + - If not submitted, load draft submission + - If submitted, load fir + - If user provides jumpable step + - Check if we can get to that step + - If we can, go to that step + - Otherwise, raise an error + """ + workflow_step = self.workflow_data.status or "submission" + jump_step = suffix + serializer_context = {"step": workflow_step} # Allow jumping to a specific step, within our allowed steps - # NOTE should probably also verify this step is in our assessment steps - # though the serializer also covers for this currently - jumpable_steps = "peer" - if suffix in jumpable_steps: - serializer_context.update({"jump_to_step": suffix}) + if jump_step: + jumpable_steps = ("submission", "peer", "grades") + if jump_step not in jumpable_steps: + return JsonHandlerError(404, f"Invalid jump to step: {jump_step}") + if self._can_jump_to_step(workflow_step, jump_step): + serializer_context.update({"jump_to_step": suffix}) + else: + return JsonHandlerError(400, f"Cannot jump to step: {jump_step}") + + # Determine which mode we are viewing in, since data comes from different sources + if workflow_step or jump_step == "submission": + has_submitted = self.workflow_data.has_submitted + + # View our submitted response + if has_submitted: + serializer_context.update({"view": "submission"}) + + # View our draft response + else: + serializer_context.update({"view": "draft"}) + + # View the selected assessment step + else: + serializer_context.update({"view": "assessment"}) page_context = PageDataSerializer(self, context=serializer_context) return page_context.data + def _can_jump_to_step(self, workflow_step, jump_step): + """ A helper to determine if we can jump to a step or not """ + + if jump_step == workflow_step: + return True + + jump_step_to_workflow_step = { + "submission": "submission", + "peer": "peer", + "grades": "done" + } + jump_step_name = jump_step_to_workflow_step[jump_step] + + step_status = self.workflow_data.status_details.get(jump_step_name, {}) + return step_status.get("complete", False) + def _submission_draft_handler(self, data): try: student_submission_data = data['response']['text_responses'] @@ -201,9 +242,11 @@ def _get_in_progress_team_file_upload_data(self, team_id=None): return self.submission_data.files.file_manager.team_file_descriptors(team_id=team_id) def get_learner_submission_data(self): + # TODO - Move this out of mixin, this is only here because it accesses + # private functions in the mixin but should actually be in SubmissionAPI workflow = self.get_team_workflow_info() if self.is_team_assignment() else self.get_workflow_info() team_info, team_id = self.submission_data.get_submission_team_info(workflow) - # If there is a submission, we do not need to load file upload data seprately because files + # If there is a submission, we do not need to load file upload data separately because files # will already have been gathered into the submission. If there is no submission, we need to # load file data from learner state and the SharedUpload db model if self.submission_data.has_submitted: @@ -220,7 +263,7 @@ def get_learner_submission_data(self): 'workflow': { 'has_submitted': self.submission_data.has_submitted, 'has_cancelled': self.workflow_data.is_cancelled, - 'has_recieved_grade': self.workflow_data.has_recieved_grade, + 'has_received_grade': self.workflow_data.has_received_grade, }, 'team_info': team_info, 'response': response, diff --git a/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py b/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py index 5186d2a2d9..db26b92642 100644 --- a/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py @@ -113,15 +113,15 @@ class RubricConfigSerializer(Serializer): class SelfSettingsSerializer(Serializer): required = BooleanField(default=True) - startTime = DateTimeField(source="start") - endTime = DateTimeField(source="due") + startDatetime = DateTimeField(source="start") + endDatetime = DateTimeField(source="due") class PeerSettingsSerializer(Serializer): required = BooleanField(default=True) - startTime = DateTimeField(source="start") - endTime = DateTimeField(source="due") + startDatetime = DateTimeField(source="start") + endDatetime = DateTimeField(source="due") minNumberToGrade = IntegerField(source="must_grade") minNumberToBeGradedBy = IntegerField(source="must_be_graded_by") diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index 01ed83759d..6c0280263e 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -5,6 +5,7 @@ """ # pylint: disable=abstract-method +from rest_framework.fields import ValidationError, CharField from rest_framework.serializers import ( BooleanField, IntegerField, @@ -15,10 +16,8 @@ AssessmentGradeSerializer, AssessmentResponseSerializer, ) -from openassessment.xblock.ui_mixins.mfe.submission_serializers import PageDataSubmissionSerializer -from openassessment.xblock.ui_mixins.mfe.serializer_utils import STEP_NAME_MAPPINGS - -from .ora_config_serializer import RubricConfigSerializer +from openassessment.xblock.ui_mixins.mfe.submission_serializers import DraftResponseSerializer, SubmissionSerializer +from openassessment.xblock.ui_mixins.mfe.serializer_utils import STEP_NAME_MAPPINGS, CharListField class AssessmentScoreSerializer(Serializer): @@ -97,10 +96,69 @@ def to_representation(self, instance): return super().to_representation(instance) +class TeamInfoSerializer(Serializer): + """ + Returns: Empty object for individual assignments, or the below for team assignments + { + teamName: (String) + teamUsernames: (Array [String]) + + // Learner submitted on a previous team + previousTeamName: (String / Nullable) + + // Current team has submitted response (learner may not have) + hasSubmitted: (Bool) + } + """ + teamName = CharField(source="team_name") + teamUsernames = CharListField(source="team_usernames") + previousTeamName = CharField(source="previous_team_name", allow_null=True) + hasSubmitted = BooleanField(source="has_submitted") + + def to_representation(self, instance): + # If there's no team name, there's no team info to show + if 'team_name' not in instance: + return {} + return super().to_representation(instance) + + +class SubmissionStepInfoSerializer(ClosedInfoSerializer): + """ + Returns: + { + closed: (Bool / Null for Assessment) + closedReason: (Enum/ Null if open), one of "notAvailable", "pastDue" + + hasSubmitted: (Bool, Null for Assessment) + hasCancelled: (Bool, Null for Assessment) + + // Team info needed for team responses - Empty object for individual submissions + teamInfo: (Object, can be empty / Null for assessment) + { + See TeamInfoSerializer + } + } + """ + + hasSubmitted = BooleanField(source="has_submitted") + hasCancelled = BooleanField(source="has_been_cancelled", default=False) + + teamInfo = SerializerMethodField() + + def get_teamInfo(self, instance): + if not instance.is_team_assignment: + return {} + team_info, _ = instance.get_submission_team_info(instance.workflow) + + return TeamInfoSerializer(team_info).data + + class StudentTrainingStepInfoSerializer(StepInfoBaseSerializer): """ Returns: { + closed: (Bool) + closedReason: (Enum/ Null if open), one of "notAvailable", "pastDue" numberOfAssessmentsCompleted: (Int), progress through required assessments expectedRubricSelections: (List of rubric names and selections) } @@ -141,6 +199,8 @@ class PeerStepInfoSerializer(StepInfoBaseSerializer): """ Returns: { + closed: (Bool) + closedReason: (Enum/ Null if open), one of "notAvailable", "pastDue" numberOfAssessmentsCompleted: (Int) Progress through required assessments isWaitingForSubmissions: (Bool) We've run out of peers to grade, waiting for more submissions numberOfReceivedAssessments: (Int) How many assessments has this response received @@ -172,8 +232,9 @@ class StepInfoSerializer(Serializer): * Empty dict for remaining steps """ - require_context = True + requires_context = True + submission = SubmissionStepInfoSerializer(source="submission_data") studentTraining = StudentTrainingStepInfoSerializer(source="student_training_data") peer = PeerStepInfoSerializer(source="peer_assessment_data") _self = SelfStepInfoSerializer(source="self_data") @@ -209,7 +270,7 @@ class ProgressSerializer(Serializer): Returns: { // What step are we on? An index to the configuration from ORA config call. - activeStepName: (String) one of ["studentTraining", "peer", "self", "staff"] + activeStepName: (String) one of ["submission", "studentTraining", "peer", "self", "staff", "done] hasReceivedFinalGrade: (Bool) // In effect, is the ORA complete? receivedGrades: (Object) Staff grade data, when there is a completed staff grade. @@ -237,58 +298,46 @@ class PageDataSerializer(Serializer): Requires context to differentiate between Assessment and Submission views """ - require_context = True + requires_context = True progress = ProgressSerializer(source="*") - submission = SerializerMethodField() - rubric = RubricConfigSerializer(source="*") + response = SerializerMethodField() assessment = SerializerMethodField() def to_representation(self, instance): - # Loading workflow status causes a workflow refresh - # ... limit this to one refresh per page call - if not self.context.get("step"): - active_step = instance.workflow_data.status or "submission" - self.context.update({"step": active_step}) + if "step" not in self.context: + raise ValidationError("Missing required context: step") + if "view" not in self.context: + raise ValidationError("Missing required context: view") return super().to_representation(instance) - def _can_jump_to_step(self, workflow_step, workflow_data, step_name): - """ - Helper to determine if a student can jump to a specific step: - 1) Student is on that step. - 2) Student has completed that step. - - NOTE that this should probably happen at the handler level, but for - added safety, check here as well. - """ - if step_name == workflow_step: - return True - step_status = workflow_data.status_details.get(step_name, {}) - return step_status.get("complete", False) - - def get_submission(self, instance): + def get_response(self, instance): """ we get the user's draft / complete submission. """ # pylint: disable=broad-exception-raised + # Submission Views if self.context.get("view") == "submission": - learner_page_data_submission_data = instance.get_learner_submission_data() - return PageDataSubmissionSerializer(learner_page_data_submission_data).data + learner_submission_data = instance.get_learner_submission_data() + + # Draft response + if not instance.submission_data.has_submitted: + return DraftResponseSerializer(learner_submission_data).data + + # Submitted response + return SubmissionSerializer(learner_submission_data).data + # Assessment Views elif self.context.get("view") == "assessment": # Can't view assessments without completing submission if self.context["step"] == "submission": raise Exception("Cannot view assessments without having completed submission.") - # If the student is trying to jump to a step, verify they can - jump_to_step = self.context.get("jump_to_step") - workflow_step = self.context["step"] - if jump_to_step and not self._can_jump_to_step(workflow_step, instance.workflow_data, jump_to_step): - raise Exception(f"Can't jump to {jump_to_step} step before completion") - # Go to the current step, or jump to the selected step + jump_to_step = self.context.get("jump_to_step", None) + workflow_step = self.context["step"] active_step = jump_to_step or workflow_step if active_step == "training": diff --git a/openassessment/xblock/ui_mixins/mfe/serializer_utils.py b/openassessment/xblock/ui_mixins/mfe/serializer_utils.py index 9b588fa568..6bf57c4485 100644 --- a/openassessment/xblock/ui_mixins/mfe/serializer_utils.py +++ b/openassessment/xblock/ui_mixins/mfe/serializer_utils.py @@ -10,9 +10,10 @@ "peer": "peer", "training": "studentTraining", "self": "self", - "staff": "staff", + "teams": "teams", "ai": "ai", "waiting": "waiting", + "staff": "staff", "done": "done", } diff --git a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py index 280e6bfece..837c630cd6 100644 --- a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py @@ -2,7 +2,6 @@ # pylint: disable=abstract-method from rest_framework.serializers import ( - BooleanField, IntegerField, Serializer, CharField, @@ -10,7 +9,7 @@ SerializerMethodField, URLField, ) -from openassessment.xblock.ui_mixins.mfe.serializer_utils import CharListField +from openassessment.xblock.ui_mixins.mfe.serializer_utils import CharListField, NullField class FileIndexListField(ListField): @@ -30,15 +29,33 @@ class SubmissionFileSerializer(Serializer): class SubmissionSerializer(Serializer): + """ + Args: + * get_learner_submission_data shape + + Returns: + { + textResponses + uploadedFiles + teamUploadedFiles (Null) + } + """ textResponses = CharListField(allow_empty=True, source='get_text_responses') uploadedFiles = SerializerMethodField() + teamUploadedFiles = NullField(source="*") - def get_uploadedFiles(self, submission): + def get_uploadedFiles(self, response): result = [] - for index, uploaded_file in enumerate(submission.get_file_uploads(generate_urls=True)): + for index, uploaded_file in enumerate(response.get_file_uploads(generate_urls=True)): result.append(SubmissionFileSerializer(({'file': uploaded_file, 'file_index': index})).data) return result + def to_representation(self, instance): + # Unpack response. + # This is to keep signature similar between the draft and submitted responses. + response = instance["response"] + return super().to_representation(response) + class FileDescriptorSerializer(Serializer): fileUrl = URLField(source='file.download_url') @@ -48,23 +65,6 @@ class FileDescriptorSerializer(Serializer): fileIndex = IntegerField(source="file_index") -class InProgressResponseSerializer(Serializer): - textResponses = SerializerMethodField() - uploadedFiles = SerializerMethodField() - - def get_textResponses(self, data): - return [ - part['text'] - for part in data['response']['answer']['parts'] - ] - - def get_uploadedFiles(self, data): - result = [] - for index, uploaded_file in enumerate(data['file_data']): - result.append(FileDescriptorSerializer(({'file': uploaded_file, 'file_index': index})).data) - return result - - class TeamFileDescriptorSerializer(Serializer): fileUrl = URLField(source='download_url') fileDescription = CharField(source='description') @@ -73,40 +73,39 @@ class TeamFileDescriptorSerializer(Serializer): uploadedBy = CharField(source="uploaded_by") -class TeamInfoSerializer(Serializer): - teamName = CharField(source="team_name") - teamUsernames = CharListField(source="team_usernames") - previousTeamName = CharField(source="previous_team_name", allow_null=True) - hasSubmitted = BooleanField(source="has_submitted") +class DraftResponseSerializer(Serializer): + """ + Args: + * get_learner_submission_data shape + + Returns: + { + textResponses + uploadedFiles + teamUploadedFiles + } + """ + textResponses = SerializerMethodField() + uploadedFiles = SerializerMethodField() teamUploadedFiles = ListField( - source="team_uploaded_files", + source="team_info.team_uploaded_files", allow_empty=True, child=TeamFileDescriptorSerializer(), + default=None, required=False ) - def to_representation(self, instance): - # If there's no team name, there's no team info to show - if 'team_name' not in instance: - return {} - return super().to_representation(instance) - + def get_textResponses(self, data): + return [ + part['text'] + for part in data['response']['answer']['parts'] + ] -class PageDataSubmissionSerializer(Serializer): - """ - Main serializer for learner submission status / info - """ - hasSubmitted = BooleanField(source="workflow.has_submitted") - hasCancelled = BooleanField(source="workflow.has_cancelled", default=False) - hasRecievedGrade = BooleanField(source="workflow.has_recieved_grade", default=False) - teamInfo = TeamInfoSerializer(source="team_info") - response = SerializerMethodField(source="*") - - def get_response(self, data): - # The source data is different if we have an in-progress response vs a submitted response - if data['workflow']['has_submitted']: - return SubmissionSerializer(data['response']).data - return InProgressResponseSerializer(data).data + def get_uploadedFiles(self, data): + result = [] + for index, uploaded_file in enumerate(data['file_data']): + result.append(FileDescriptorSerializer(({'file': uploaded_file, 'file_index': index})).data) + return result class AddFileRequestSerializer(Serializer): diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index eac98ffeba..33f9e7546d 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -32,7 +32,7 @@ from openassessment.xblock.test.test_submission import COURSE_ID, setup_mock_team from openassessment.xblock.test.test_team import MOCK_TEAM_ID, MockTeamsService from openassessment.xblock.ui_mixins.mfe.constants import error_codes, handler_suffixes -from openassessment.xblock.ui_mixins.mfe.submission_serializers import PageDataSubmissionSerializer +from openassessment.xblock.ui_mixins.mfe.submission_serializers import DraftResponseSerializer, SubmissionSerializer class MFEHandlersTestBase(XBlockHandlerTestCase): @@ -146,6 +146,8 @@ def assert_called_once_with_helper(mock, expected_first_arg, expected_additional class GetLearnerSubmissionDataIndividualSubmissionTest(MFEHandlersTestBase): + maxDiff = None + def setup_xblock(self, xblock): xblock.xmodule_runtime = Mock( user_is_staff=False, @@ -158,16 +160,11 @@ def setup_xblock(self, xblock): def test_nothing(self, xblock): with self.mock_get_url(): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = DraftResponseSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': False, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': {}, - 'response': { - 'textResponses': ['', ''], - 'uploadedFiles': [] - } + 'textResponses': ['', ''], + 'uploadedFiles': [], + 'teamUploadedFiles': [], } @scenario("data/file_upload_scenario.xml", user_id='r5') @@ -185,31 +182,26 @@ def test_not_yet_submitted(self, xblock): base_key + '/1': 'www.downloadfiles.xyz/1' }): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = DraftResponseSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': False, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': {}, - 'response': { - 'textResponses': ['hello world', 'goodnight moon'], - 'uploadedFiles': [ - { - 'fileUrl': 'www.downloadfiles.xyz/0', - 'fileName': 'file1.ppt', - 'fileDescription': 'my presentation', - 'fileSize': 2, - 'fileIndex': 0, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/1', - 'fileName': 'file3.mp4', - 'fileDescription': 'video of presentation', - 'fileSize': 3, - 'fileIndex': 1, - }, - ] - } + 'textResponses': ['hello world', 'goodnight moon'], + 'uploadedFiles': [ + { + 'fileUrl': 'www.downloadfiles.xyz/0', + 'fileName': 'file1.ppt', + 'fileDescription': 'my presentation', + 'fileSize': 2, + 'fileIndex': 0, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/1', + 'fileName': 'file3.mp4', + 'fileDescription': 'video of presentation', + 'fileSize': 3, + 'fileIndex': 1, + }, + ], + 'teamUploadedFiles': [], } @scenario("data/file_upload_scenario.xml", user_id='r5') @@ -231,31 +223,26 @@ def test_submitted(self, xblock): with self.mock_get_url(): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = SubmissionSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': True, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': {}, - 'response': { - 'textResponses': ['hello world', 'goodnight world'], - 'uploadedFiles': [ - { - 'fileUrl': 'www.downloadfiles.xyz/f1', - 'fileName': 'f1.txt', - 'fileDescription': 'file1', - 'fileSize': 10, - 'fileIndex': 0, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/f2', - 'fileName': 'f2.pdf', - 'fileDescription': 'file2', - 'fileSize': 300, - 'fileIndex': 1, - }, - ] - } + 'textResponses': ['hello world', 'goodnight world'], + 'uploadedFiles': [ + { + 'fileUrl': 'www.downloadfiles.xyz/f1', + 'fileName': 'f1.txt', + 'fileDescription': 'file1', + 'fileSize': 10, + 'fileIndex': 0, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/f2', + 'fileName': 'f2.pdf', + 'fileDescription': 'file2', + 'fileSize': 300, + 'fileIndex': 1, + }, + ], + 'teamUploadedFiles': None, } @@ -275,22 +262,11 @@ def test_nothing(self, xblock): self.setup_xblock(xblock) with self.mock_get_url(): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = DraftResponseSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': False, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': { - 'teamName': 'Red Squadron', - 'teamUsernames': ['Red Leader', 'Red Two', 'Red Five'], - 'previousTeamName': None, - 'hasSubmitted': False, - 'teamUploadedFiles': [], - }, - 'response': { - 'textResponses': ['', ''], - 'uploadedFiles': [] - }, + 'textResponses': ['', ''], + 'uploadedFiles': [], + 'teamUploadedFiles': [], } @scenario("data/team_submission_file_scenario.xml", user_id='r5') @@ -329,52 +305,41 @@ def test_not_yet_submitted(self, xblock): shared_file_2_key: 'www.downloadfiles.xyz/shared2', }): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = DraftResponseSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': False, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': { - 'teamName': 'Red Squadron', - 'teamUsernames': ['Red Leader', 'Red Two', 'Red Five'], - 'previousTeamName': None, - 'hasSubmitted': False, - 'teamUploadedFiles': [ - { - 'fileUrl': 'www.downloadfiles.xyz/shared1', - 'fileName': shared_file_1.name, - 'fileDescription': shared_file_1.description, - 'fileSize': shared_file_1.size, - 'uploadedBy': r1.username, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/shared2', - 'fileName': shared_file_2.name, - 'fileDescription': shared_file_2.description, - 'fileSize': shared_file_2.size, - 'uploadedBy': r2.username, - }, - ], - }, - 'response': { - 'textResponses': ['hello world', 'goodnight moon'], - 'uploadedFiles': [ - { - 'fileUrl': 'www.downloadfiles.xyz/0', - 'fileName': 'file1.ppt', - 'fileDescription': 'my presentation', - 'fileSize': 2, - 'fileIndex': 0, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/1', - 'fileName': 'file3.mp4', - 'fileDescription': 'video of presentation', - 'fileSize': 3, - 'fileIndex': 1, - }, - ] - } + 'textResponses': ['hello world', 'goodnight moon'], + 'uploadedFiles': [ + { + 'fileUrl': 'www.downloadfiles.xyz/0', + 'fileName': 'file1.ppt', + 'fileDescription': 'my presentation', + 'fileSize': 2, + 'fileIndex': 0, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/1', + 'fileName': 'file3.mp4', + 'fileDescription': 'video of presentation', + 'fileSize': 3, + 'fileIndex': 1, + }, + ], + 'teamUploadedFiles': [ + { + 'fileUrl': 'www.downloadfiles.xyz/shared1', + 'fileName': shared_file_1.name, + 'fileDescription': shared_file_1.description, + 'fileSize': shared_file_1.size, + 'uploadedBy': r1.username, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/shared2', + 'fileName': shared_file_2.name, + 'fileDescription': shared_file_2.description, + 'fileSize': shared_file_2.size, + 'uploadedBy': r2.username, + }, + ], } @scenario("data/team_submission_file_scenario.xml", user_id='r5') @@ -397,43 +362,33 @@ def test_submitted(self, xblock): ) with self.mock_get_url(): learner_submission_data = xblock.get_learner_submission_data() - data = PageDataSubmissionSerializer(learner_submission_data).data + data = SubmissionSerializer(learner_submission_data).data assert data == { - 'hasSubmitted': True, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': { - 'teamName': 'Red Squadron', - 'teamUsernames': ['Red Leader', 'Red Two', 'Red Five'], - 'previousTeamName': None, - 'hasSubmitted': True, - }, - 'response': { - 'textResponses': ['This is the answer'], - 'uploadedFiles': [ - { - 'fileUrl': 'www.downloadfiles.xyz/k1', - 'fileName': '1.txt', - 'fileDescription': '1', - 'fileSize': 12, - 'fileIndex': 0, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/k2', - 'fileName': '2.txt', - 'fileDescription': '2', - 'fileSize': 1, - 'fileIndex': 1, - }, - { - 'fileUrl': 'www.downloadfiles.xyz/k3', - 'fileName': '3.txt', - 'fileDescription': '3', - 'fileSize': 56, - 'fileIndex': 2, - }, - ] - } + 'textResponses': ['This is the answer'], + 'uploadedFiles': [ + { + 'fileUrl': 'www.downloadfiles.xyz/k1', + 'fileName': '1.txt', + 'fileDescription': '1', + 'fileSize': 12, + 'fileIndex': 0, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/k2', + 'fileName': '2.txt', + 'fileDescription': '2', + 'fileSize': 1, + 'fileIndex': 1, + }, + { + 'fileUrl': 'www.downloadfiles.xyz/k3', + 'fileName': '3.txt', + 'fileDescription': '3', + 'fileSize': 56, + 'fileIndex': 2, + }, + ], + 'teamUploadedFiles': None, } def _create_team_submission_and_workflow( diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index ff3a1304f6..0e766eb35e 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -4,7 +4,11 @@ from copy import deepcopy from json import dumps, loads -from unittest.mock import patch +from unittest import TestCase +from unittest.case import skip +from unittest.mock import Mock, patch +from openassessment.fileupload.api import TeamFileDescriptor +from openassessment.xblock.apis.submissions.submissions_actions import create_team_submission from openassessment.xblock.test.base import ( @@ -14,16 +18,21 @@ XBlockHandlerTestCase, scenario, ) -from openassessment.xblock.ui_mixins.mfe.page_context_serializer import PageDataSerializer, ProgressSerializer +from openassessment.xblock.test.test_submission import setup_mock_team +from openassessment.xblock.ui_mixins.mfe.page_context_serializer import ( + PageDataSerializer, + ProgressSerializer, + TeamInfoSerializer, +) class TestPageContextSerializer(XBlockHandlerTestCase, SubmitAssessmentsMixin): @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.AssessmentResponseSerializer") - @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.PageDataSubmissionSerializer") + @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.DraftResponseSerializer") @scenario("data/basic_scenario.xml", user_id="Alan") def test_submission_view(self, xblock, mock_submission_serializer, mock_assessment_serializer): # Given we are asking for the submission view - context = {"view": "submission"} + context = {"view": "submission", "step": "submission"} # When I ask for my submission data _ = PageDataSerializer(xblock, context=context).data @@ -33,12 +42,12 @@ def test_submission_view(self, xblock, mock_submission_serializer, mock_assessme mock_assessment_serializer.assert_not_called() @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.AssessmentResponseSerializer") - @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.PageDataSubmissionSerializer") + @patch("openassessment.xblock.ui_mixins.mfe.page_context_serializer.SubmissionSerializer") @scenario("data/basic_scenario.xml", user_id="Alan") def test_assessment_view(self, xblock, mock_submission_serializer, mock_assessment_serializer): # Given we are asking for the assessment view self.create_test_submission(xblock) - context = {"view": "assessment"} + context = {"view": "assessment", "step": "peer"} # When I ask for assessment data _ = PageDataSerializer(xblock, context=context).data @@ -61,6 +70,8 @@ def setUp(self): @scenario("data/basic_scenario.xml", user_id="Alan") def test_submission(self, xblock): # Given we are asking for assessment data too early (still on submission step) + self.context = {"view": "assessment", "step": "submission"} + # When I load my response # Then I get an Exception with self.assertRaises(Exception): @@ -70,9 +81,10 @@ def test_submission(self, xblock): def test_student_training(self, xblock): # Given we are on the student training step self.create_test_submission(xblock) + self.context = {"view": "assessment", "step": "training"} # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # I get the appropriate response expected_response = { @@ -84,7 +96,6 @@ def test_student_training(self, xblock): # ... along with these always-none fields assessments self.assertIsNone(response_data["hasSubmitted"]) self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["hasReceivedGrade"]) self.assertIsNone(response_data["teamInfo"]) @scenario("data/peer_only_scenario.xml", user_id="Alan") @@ -107,7 +118,8 @@ def test_peer_response(self, xblock): self.create_test_submission(xblock, student_item=student_item, submission_text=text_responses) # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + self.context = {"view": "assessment", "step": "peer"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # I get the appropriate response expected_response = { @@ -119,7 +131,6 @@ def test_peer_response(self, xblock): # ... along with these always-none fields assessments self.assertIsNone(response_data["hasSubmitted"]) self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["hasReceivedGrade"]) self.assertIsNone(response_data["teamInfo"]) @scenario("data/peer_only_scenario.xml", user_id="Alan") @@ -130,7 +141,8 @@ def test_peer_response_not_available(self, xblock): # ... but with no responses to assess # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + self.context = {"view": "assessment", "step": "peer"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # I get the appropriate response expected_response = {} @@ -139,7 +151,6 @@ def test_peer_response_not_available(self, xblock): # ... along with these always-none fields assessments self.assertIsNone(response_data["hasSubmitted"]) self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["hasReceivedGrade"]) self.assertIsNone(response_data["teamInfo"]) @scenario("data/staff_grade_scenario.xml", user_id="Alan") @@ -148,7 +159,8 @@ def test_staff_response(self, xblock): self.create_test_submission(xblock) # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + self.context = {"view": "assessment", "step": "staff"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # Then I get an empty object expected_response = {} @@ -160,7 +172,8 @@ def test_waiting_response(self, xblock): self.create_test_submission(xblock) # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + self.context = {"view": "assessment", "step": "staff"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # Then I get an empty object expected_response = {} @@ -170,8 +183,10 @@ def test_waiting_response(self, xblock): def test_done_response(self, xblock): # Given I'm on the done step self.create_submission_and_assessments(xblock, self.SUBMISSION, [], [], SELF_ASSESSMENT) + # When I load my response - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + self.context = {"view": "assessment", "step": "done"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # Then I get an empty object expected_response = {} @@ -195,8 +210,9 @@ def test_jump_to_peer_response(self, xblock): self.create_submission_and_assessments(xblock, self.SUBMISSION, self.PEERS, PEER_ASSESSMENTS, None) # When I try to jump back to that step + self.context = {"view": "assessment", "step": "done"} self.context["jump_to_step"] = "peer" - response_data = PageDataSerializer(xblock, context=self.context).data["submission"] + response_data = PageDataSerializer(xblock, context=self.context).data["response"] # Then I can continue to receive peer responses to grade expected_response = { @@ -211,6 +227,7 @@ def test_jump_to_bad_step(self, xblock): self.create_test_submission(xblock) # When I try to jump to a bad step + self.context = {"view": "assessment", "step": "peer"} self.context["jump_to_step"] = "to the left" # Then I expect the serializer to raise an exception @@ -219,18 +236,6 @@ def test_jump_to_bad_step(self, xblock): with self.assertRaises(Exception): _ = PageDataSerializer(xblock, context=self.context).data - @scenario("data/student_training.xml", user_id="Bernard") - def test_jump_to_inaccessible_step(self, xblock): - # Given I'm on an early step like student training - self.create_test_submission(xblock) - - # When I try to jump ahead to a step I can't yet access - self.context["jump_to_step"] = "peer" - - # Then I expect the serializer to raise an exception - with self.assertRaises(Exception): - _ = PageDataSerializer(xblock, context=self.context).data - class TestPageContextProgress(XBlockHandlerTestCase, SubmitAssessmentsMixin): # Show full dict diffs @@ -255,7 +260,17 @@ def test_submission(self, xblock): "activeStepName": "submission", "hasReceivedFinalGrade": False, "receivedGrades": {}, - "stepInfo": {"peer": None, "self": None}, + "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": False, + "hasCancelled": False, + "teamInfo": {}, + }, + "peer": None, + "self": None + }, } self.assertNestedDictEquals(expected_data, progress_data) @@ -278,6 +293,13 @@ def test_student_training(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "studentTraining": { "closed": False, "closedReason": None, @@ -314,6 +336,13 @@ def test_student_training_due(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": True, + "closedReason": "pastDue", + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "studentTraining": { "closed": True, "closedReason": "pastDue", @@ -350,6 +379,13 @@ def test_student_training_not_yet_available(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "studentTraining": { "closed": True, "closedReason": "notAvailableYet", @@ -386,6 +422,13 @@ def test_peer_assessment(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "peer": { "closed": False, "closedReason": None, @@ -416,6 +459,13 @@ def test_self_assessment(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "self": { "closed": False, "closedReason": None, @@ -444,6 +494,13 @@ def test_self_assessment_closed(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": True, + "closedReason": "pastDue", + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "peer": None, "self": { "closed": True, @@ -473,6 +530,13 @@ def test_self_assessment_not_available(self, xblock): "staff": {}, }, "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": {}, + }, "peer": None, "self": { "closed": True, @@ -482,3 +546,89 @@ def test_self_assessment_not_available(self, xblock): } self.assertNestedDictEquals(expected_data, progress_data) + + @skip + @scenario("data/team_submission.xml", user_id="Alan") + def test_team_assignment(self, xblock): + # Given I am on a team assignment + setup_mock_team(xblock) + xblock.is_team_assignment = Mock(return_value=True) + self.create_test_submission(xblock) + + create_team_submission( + xblock.get_student_item_dict(), + {"answer": {"parts": ["a", "b"]}}, + xblock.config_data, + xblock.submission_data, + xblock.workflow_data + ) + + # When I ask for progress + context = {"step": "staff"} + progress_data = ProgressSerializer(xblock, context=context).data + + # Then I get the expected shapes + expected_data = { + "activeStepName": "staff", + "hasReceivedFinalGrade": False, + "receivedGrades": { + # NOTE - Teams actually have a different step type that should go here + }, + "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": False, + "teamInfo": { + "teamName": "Red Squadron", + "teamUsernames": ["Red Leader", "Red Two", "Red Five"], + "previousTeamName": None, + "hasSubmitted": True, + }, + }, + }, + } + + self.assertNestedDictEquals(expected_data, progress_data) + + +class TestTeamInfoSerializer(TestCase): + def test_serialize(self): + team_info = { + 'team_name': 'Team1', + 'team_usernames': ['Bob', 'Alice'], + 'previous_team_name': 'Team4', + 'has_submitted': True, + 'team_uploaded_files': [ + TeamFileDescriptor('www.example.com/files/123', 'desc-123', 'name-123', 123, 'Chrissy')._asdict(), + TeamFileDescriptor('www.example.com/files/5555', 'desc-5555', 'name-5555', 5555, 'Billy')._asdict(), + ] + } + assert TeamInfoSerializer(team_info).data == { + 'teamName': 'Team1', + 'teamUsernames': ['Bob', 'Alice'], + 'previousTeamName': 'Team4', + 'hasSubmitted': True, + } + + def test_no_team(self): + team_info = { + 'team_uploaded_files': [] + } + assert not TeamInfoSerializer(team_info).data + + def test_no_files(self): + team_info = { + 'team_name': 'Team1', + 'team_usernames': ['Bob', 'Alice'], + 'previous_team_name': None, + 'has_submitted': False, + 'team_uploaded_files': [] + } + assert TeamInfoSerializer(team_info).data == { + 'teamName': 'Team1', + 'teamUsernames': ['Bob', 'Alice'], + 'previousTeamName': None, + 'hasSubmitted': False, + } diff --git a/openassessment/xblock/ui_mixins/mfe/test_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_serializers.py index e91619c5d8..5d782589b8 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_serializers.py @@ -306,8 +306,8 @@ def test_peer_dates(self, xblock): ] # Then I get the right dates - self.assertEqual(peer_config["startTime"], expected_start) - self.assertEqual(peer_config["endTime"], expected_due) + self.assertEqual(peer_config["startDatetime"], expected_start) + self.assertEqual(peer_config["endDatetime"], expected_due) @scenario("data/peer_assessment_flex_grading_scenario.xml") def test_flex_grading(self, xblock): diff --git a/openassessment/xblock/ui_mixins/mfe/test_submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_submission_serializers.py index a3a2836f9f..82a15acb35 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_submission_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_submission_serializers.py @@ -4,10 +4,8 @@ from openassessment.fileupload.api import FileDescriptor, TeamFileDescriptor from openassessment.xblock.ui_mixins.mfe.submission_serializers import ( - InProgressResponseSerializer, - SubmissionSerializer, - TeamInfoSerializer, - PageDataSubmissionSerializer + DraftResponseSerializer, + SubmissionSerializer ) from openassessment.data import OraSubmissionAnswer, SubmissionFileUpload @@ -41,8 +39,22 @@ def test_serializer(self): mock_uploaded_files = [ _mock_uploaded_file(file_id) for file_id in [1, 22] ] - mock_submission_answer = MockOraSubmissionAnswer(mock_text_responses, mock_uploaded_files) - assert SubmissionSerializer(mock_submission_answer).data == { + data = { + 'workflow': { + 'has_submitted': True, + 'has_cancelled': False, + 'has_received_grade': True, + }, + 'team_info': { + 'team_name': 'Team1', + 'team_usernames': ['Bob', 'Alice'], + 'previous_team_name': None, + 'has_submitted': True, + }, + 'response': MockOraSubmissionAnswer(mock_text_responses, mock_uploaded_files), + 'file_data': [] + } + assert SubmissionSerializer(data).data == { 'textResponses': mock_text_responses, 'uploadedFiles': [ { @@ -59,18 +71,35 @@ def test_serializer(self): 'fileSize': 22, 'fileIndex': 1 } - ] + ], + "teamUploadedFiles": None } def test_empty(self): - mock_submission_answer = MockOraSubmissionAnswer([], []) - assert SubmissionSerializer(mock_submission_answer).data == { + data = { + 'workflow': { + 'has_submitted': True, + 'has_cancelled': False, + 'has_received_grade': True, + }, + 'team_info': { + 'team_name': 'Team1', + 'team_usernames': ['Bob', 'Alice'], + 'previous_team_name': None, + 'has_submitted': True, + }, + 'response': MockOraSubmissionAnswer([], []), + 'file_data': [] + } + assert SubmissionSerializer(data).data == { 'textResponses': [], - 'uploadedFiles': [] + 'uploadedFiles': [], + 'teamUploadedFiles': None } -class TestInProgressResponseSerializer(TestCase): +class TestDraftResponseSerializer(TestCase): + def test_serializer(self): data = { 'response': { @@ -92,7 +121,7 @@ def test_serializer(self): FileDescriptor('www.mysite.com/files/22', 'desc-22', 'name-22', 22, True)._asdict(), ] } - assert InProgressResponseSerializer(data).data == { + assert DraftResponseSerializer(data).data == { 'textResponses': [ 'Response to prompt 1', 'Response to prompt 2' @@ -112,7 +141,8 @@ def test_serializer(self): 'fileSize': 22, 'fileIndex': 1 } - ] + ], + 'teamUploadedFiles': None, } def test_empty(self): @@ -133,79 +163,25 @@ def test_empty(self): }, 'file_data': [] } - assert InProgressResponseSerializer(data).data == { + assert DraftResponseSerializer(data).data == { 'textResponses': ['', ''], 'uploadedFiles': [], - } - - -class TestTeamInfoSerializer(TestCase): - def test_serialize(self): - team_info = { - 'team_name': 'Team1', - 'team_usernames': ['Bob', 'Alice'], - 'previous_team_name': 'Team4', - 'has_submitted': True, - 'team_uploaded_files': [ - TeamFileDescriptor('www.mysite.com/files/123', 'desc-123', 'name-123', 123, 'Chrissy')._asdict(), - TeamFileDescriptor('www.mysite.com/files/5555', 'desc-5555', 'name-5555', 5555, 'Billy')._asdict(), - ] - } - assert TeamInfoSerializer(team_info).data == { - 'teamName': 'Team1', - 'teamUsernames': ['Bob', 'Alice'], - 'previousTeamName': 'Team4', - 'hasSubmitted': True, - 'teamUploadedFiles': [ - { - 'fileUrl': 'www.mysite.com/files/123', - 'fileDescription': 'desc-123', - 'fileName': 'name-123', - 'fileSize': 123, - 'uploadedBy': 'Chrissy' - }, - { - 'fileUrl': 'www.mysite.com/files/5555', - 'fileDescription': 'desc-5555', - 'fileName': 'name-5555', - 'fileSize': 5555, - 'uploadedBy': 'Billy' - } - ] - } - - def test_no_team(self): - team_info = { - 'team_uploaded_files': [] - } - assert not TeamInfoSerializer(team_info).data - - def test_no_files(self): - team_info = { - 'team_name': 'Team1', - 'team_usernames': ['Bob', 'Alice'], - 'previous_team_name': None, - 'has_submitted': False, - 'team_uploaded_files': [] - } - assert TeamInfoSerializer(team_info).data == { - 'teamName': 'Team1', - 'teamUsernames': ['Bob', 'Alice'], - 'previousTeamName': None, - 'hasSubmitted': False, - 'teamUploadedFiles': [], + 'teamUploadedFiles': None, } @ddt.ddt -class TestPageDataSubmissionSerializer(TestCase): +class TestPageDataResponseSerializer(TestCase): + + # Show full dictionary diffs + maxDiff = None def test_integration_not_submitted(self): data = { 'workflow': { 'has_submitted': False, 'has_cancelled': False, - 'has_recieved_grade': False, + 'has_received_grade': False, }, 'team_info': { 'team_name': 'Team1', @@ -236,54 +212,43 @@ def test_integration_not_submitted(self): FileDescriptor('www.mysite.com/files/22', 'desc-22', 'name-22', 22, True)._asdict(), ] } - assert PageDataSubmissionSerializer(data).data == { - 'hasSubmitted': False, - 'hasCancelled': False, - 'hasRecievedGrade': False, - 'teamInfo': { - 'teamName': 'Team1', - 'teamUsernames': ['Bob', 'Alice'], - 'previousTeamName': None, - 'hasSubmitted': False, - 'teamUploadedFiles': [ - { - 'fileUrl': 'www.mysite.com/files/123', - 'fileDescription': 'desc-123', - 'fileName': 'name-123', - 'fileSize': 123, - 'uploadedBy': 'Bob' - }, - { - 'fileUrl': 'www.mysite.com/files/5555', - 'fileDescription': 'desc-5555', - 'fileName': 'name-5555', - 'fileSize': 5555, - 'uploadedBy': 'Billy' - } - ] - }, - 'response': { - 'textResponses': [ - 'Response to prompt 1', - 'Response to prompt 2' - ], - 'uploadedFiles': [ - { - 'fileUrl': 'www.mysite.com/files/1', - 'fileDescription': 'desc-1', - 'fileName': 'name-1', - 'fileSize': 1, - 'fileIndex': 0 - }, - { - 'fileUrl': 'www.mysite.com/files/22', - 'fileDescription': 'desc-22', - 'fileName': 'name-22', - 'fileSize': 22, - 'fileIndex': 1 - } - ] - } + assert DraftResponseSerializer(data).data == { + 'textResponses': [ + 'Response to prompt 1', + 'Response to prompt 2' + ], + 'uploadedFiles': [ + { + 'fileUrl': 'www.mysite.com/files/1', + 'fileDescription': 'desc-1', + 'fileName': 'name-1', + 'fileSize': 1, + 'fileIndex': 0 + }, + { + 'fileUrl': 'www.mysite.com/files/22', + 'fileDescription': 'desc-22', + 'fileName': 'name-22', + 'fileSize': 22, + 'fileIndex': 1 + } + ], + 'teamUploadedFiles': [ + { + 'fileUrl': 'www.mysite.com/files/123', + 'fileDescription': 'desc-123', + 'fileName': 'name-123', + 'fileSize': 123, + 'uploadedBy': 'Bob' + }, + { + 'fileUrl': 'www.mysite.com/files/5555', + 'fileDescription': 'desc-5555', + 'fileName': 'name-5555', + 'fileSize': 5555, + 'uploadedBy': 'Billy' + } + ] } def test_integration_submitted(self): @@ -291,7 +256,7 @@ def test_integration_submitted(self): 'workflow': { 'has_submitted': True, 'has_cancelled': False, - 'has_recieved_grade': True, + 'has_received_grade': True, }, 'team_info': { 'team_name': 'Team1', @@ -313,50 +278,40 @@ def test_integration_submitted(self): ), 'file_data': [] } - assert PageDataSubmissionSerializer(data).data == { - 'hasSubmitted': True, - 'hasCancelled': False, - 'hasRecievedGrade': True, - 'teamInfo': { - 'teamName': 'Team1', - 'teamUsernames': ['Bob', 'Alice'], - 'previousTeamName': None, - 'hasSubmitted': True, - }, - 'response': { - 'textResponses': [ - 'Response to prompt 1', - 'Response to prompt 2' - ], - 'uploadedFiles': [ - { - 'fileUrl': 'www.mysite.com/files/1', - 'fileDescription': 'desc-1', - 'fileName': 'name-1', - 'fileSize': 1, - 'fileIndex': 0 - }, - { - 'fileUrl': 'www.mysite.com/files/22', - 'fileDescription': 'desc-22', - 'fileName': 'name-22', - 'fileSize': 22, - 'fileIndex': 1 - }, - { - 'fileUrl': 'www.mysite.com/files/123', - 'fileDescription': 'desc-123', - 'fileName': 'name-123', - 'fileSize': 123, - 'fileIndex': 2 - }, - { - 'fileUrl': 'www.mysite.com/files/5555', - 'fileDescription': 'desc-5555', - 'fileName': 'name-5555', - 'fileSize': 5555, - 'fileIndex': 3 - } - ] - } + assert SubmissionSerializer(data).data == { + 'textResponses': [ + 'Response to prompt 1', + 'Response to prompt 2' + ], + 'uploadedFiles': [ + { + 'fileUrl': 'www.mysite.com/files/1', + 'fileDescription': 'desc-1', + 'fileName': 'name-1', + 'fileSize': 1, + 'fileIndex': 0 + }, + { + 'fileUrl': 'www.mysite.com/files/22', + 'fileDescription': 'desc-22', + 'fileName': 'name-22', + 'fileSize': 22, + 'fileIndex': 1 + }, + { + 'fileUrl': 'www.mysite.com/files/123', + 'fileDescription': 'desc-123', + 'fileName': 'name-123', + 'fileSize': 123, + 'fileIndex': 2 + }, + { + 'fileUrl': 'www.mysite.com/files/5555', + 'fileDescription': 'desc-5555', + 'fileName': 'name-5555', + 'fileSize': 5555, + 'fileIndex': 3 + } + ], + "teamUploadedFiles": None, } From 4a90832035c2a5e04f53cedc2f44210ffabf614b Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 19 Oct 2023 11:27:27 -0400 Subject: [PATCH 11/27] feat: xblock view (#2080) * feat: load xblock view * fix: remove initial height, which breaks height override * fix: prop loading and postMessage forwarding * fix: merge refactors --- .../templates/openassessmentblock/base.html | 66 ++++++++++++++++++- openassessment/xblock/openassessmentblock.py | 1 + 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/openassessment/templates/openassessmentblock/base.html b/openassessment/templates/openassessmentblock/base.html index d6d58fbdc3..2bc378f73c 100644 --- a/openassessment/templates/openassessmentblock/base.html +++ b/openassessment/templates/openassessmentblock/base.html @@ -1,7 +1,13 @@ {% load i18n %} {% spaceless %} +
    -
    + +
    {% if title %}

    {% trans title %}

    @@ -46,6 +52,64 @@

    {% endif %}

    + + +
    + + {% if leaderboard_ui_model %} +
      +
    1. +
      +

      + +

      + + + + {% trans "Loading" %} + + +
      +
    2. +
    + {% endif %} +
    + {% if show_staff_area %} +
    + {% endif %} +
    +
    + {% endspaceless %} diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index a0b2a507c8..5cf0641964 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -610,6 +610,7 @@ def student_view(self, context=None): # pylint: disable=unused-argument "show_staff_area": self.is_course_staff and not self.in_studio_preview, "title": self.title, "xblock_id": self.get_xblock_id(), + "course_id": self.course_id, } template = get_template("openassessmentblock/base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') From 1e49de66bcb1bc0527b4969fc6b95458d9ab9350 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 19 Oct 2023 15:36:38 -0400 Subject: [PATCH 12/27] feat: mfe upload confirm endpoint (#2083) --- .../ui_mixins/mfe/constants/error_codes.py | 1 + .../mfe/constants/handler_suffixes.py | 1 + openassessment/xblock/ui_mixins/mfe/mixin.py | 23 ++++++- .../ui_mixins/mfe/submission_serializers.py | 8 +++ .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 65 +++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py b/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py index dc5060ebe5..66a3b91100 100644 --- a/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py +++ b/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py @@ -16,3 +16,4 @@ UNABLE_TO_GENERATE_UPLOAD_URL = "ERR_UNABLE_TO_GENERATE_UPLOAD_URL" TOO_MANY_UPLOADS = "ERR_TOO_MANY_UPLOADS" UNSUPPORTED_FILETYPE = "ERR_UNSUPPORTED_FILETYPE" +FILE_NOT_FOUND = "ERR_FILE_NOT_FOUND" diff --git a/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py b/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py index 9eb75e7968..ea0bb065fb 100644 --- a/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py +++ b/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py @@ -4,3 +4,4 @@ SUBMISSION_SUBMIT = 'submit' FILE_ADD = 'add' FILE_DELETE = 'delete' +FILE_UPLOAD_CALLBACK = 'upload_response' diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index a84a0549d0..4feaf509f8 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -23,7 +23,10 @@ from openassessment.xblock.ui_mixins.mfe.constants import error_codes, handler_suffixes from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import OraBlockInfoSerializer from openassessment.xblock.ui_mixins.mfe.page_context_serializer import PageDataSerializer -from openassessment.xblock.ui_mixins.mfe.submission_serializers import AddFileRequestSerializer +from openassessment.xblock.ui_mixins.mfe.submission_serializers import ( + AddFileRequestSerializer, + FileUploadCallbackRequestSerializer +) class OraApiException(JsonHandlerError): @@ -222,12 +225,30 @@ def _file_add_handler(self, data): 'fileIndex': newly_added_file.index, } + def _file_upload_callback_handler(self, data): + serializer = FileUploadCallbackRequestSerializer(data=data) + if not serializer.is_valid(): + raise OraApiException(400, error_codes.INCORRECT_PARAMETERS, serializer.errors) + fileIndex = serializer.validated_data['fileIndex'] + + if not serializer.validated_data['success']: + self.submission_data.files.delete_uploaded_file(fileIndex) + return None + + url = self.submission_data.files.get_download_url(fileIndex) + if url is None: + self.submission_data.files.delete_uploaded_file(fileIndex) + raise OraApiException(404, error_codes.FILE_NOT_FOUND) + return {'downloadUrl': url} + @XBlock.json_handler def file(self, data, suffix=""): if suffix == handler_suffixes.FILE_DELETE: return self._file_delete_handler(data) elif suffix == handler_suffixes.FILE_ADD: return self._file_add_handler(data) + elif suffix == handler_suffixes.FILE_UPLOAD_CALLBACK: + return self._file_upload_callback_handler(data) else: raise OraApiException(404, error_codes.UNKNOWN_SUFFIX) diff --git a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py index 837c630cd6..538fd42536 100644 --- a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py @@ -116,3 +116,11 @@ class AddFileRequestSerializer(Serializer): fileName = CharField(source='name') fileSize = IntegerField(source='size', min_value=0) contentType = CharField() + + +class FileUploadCallbackRequestSerializer(Serializer): + """ + Input request serializer for file upload callback handler + """ + fileIndex = IntegerField(min_value=0) + success = BooleanField() diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index 33f9e7546d..f1cda5c951 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -106,6 +106,15 @@ def request_delete_file(self, xblock, payload=None): response_format='response' ) + def request_file_callback(self, xblock, payload): + return super().request( + xblock, + 'file', + json.dumps(payload), + suffix=handler_suffixes.FILE_UPLOAD_CALLBACK, + response_format='response' + ) + def assert_error_response(response, status_code, error_code, context=''): assert response.status_code == status_code @@ -666,3 +675,59 @@ def test_delete_file(self, xblock): resp = self.request_delete_file(xblock) assert resp.status_code == 200 assert_called_once_with_helper(mock_remove_file, 1, 2) + + +@ddt.ddt +class FileCallbackTests(MFEHandlersTestBase): + + @contextmanager + def _mock_delete_uploaded_file(self): + with patch.object(FileAPI, 'delete_uploaded_file') as mock_delete_file: + yield mock_delete_file + + @contextmanager + def _mock_get_download_url(self, **kwargs): + with patch.object(FileAPI, 'get_download_url', **kwargs) as mock_get_url: + yield mock_get_url + + @ddt.data( + {}, + {'fileIndex': 1}, + {'success': False}, + { + 'success': True, + 'fileIndex': -30 + } + ) + @scenario("data/basic_scenario.xml") + def test_bad_params(self, xblock, payload): + resp = self.request_file_callback(xblock, payload) + assert resp.status_code == 400 + assert resp.json['error']['error_code'] == error_codes.INCORRECT_PARAMETERS + + @scenario("data/basic_scenario.xml") + def test_success(self, xblock): + test_url = 'www.xyz-123/file123423452' + with self._mock_get_download_url(return_value=test_url): + with self._mock_delete_uploaded_file() as mock_delete_file: + resp = self.request_file_callback(xblock, {'success': True, 'fileIndex': 1}) + assert resp.status_code == 200 + assert resp.json == {'downloadUrl': test_url} + mock_delete_file.assert_not_called() + + @scenario("data/basic_scenario.xml") + def test_success_file_not_found(self, xblock): + with self._mock_get_download_url(return_value=None): + with self._mock_delete_uploaded_file() as mock_delete_file: + resp = self.request_file_callback(xblock, {'success': True, 'fileIndex': 6}) + assert_error_response(resp, 404, error_codes.FILE_NOT_FOUND) + mock_delete_file.assert_called_once_with(6) + + @scenario("data/basic_scenario.xml") + def test_faliure(self, xblock): + with self._mock_get_download_url() as mock_get_download_url: + with self._mock_delete_uploaded_file() as mock_delete_file: + resp = self.request_file_callback(xblock, {'success': False, 'fileIndex': 4}) + assert resp.status_code == 200 + mock_get_download_url.assert_not_called() + mock_delete_file.assert_called_once_with(4) From a32165d7359cb892a9e6c94c4f912a06f38df6d9 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Mon, 23 Oct 2023 12:51:10 -0400 Subject: [PATCH 13/27] test: fix failing tests by mocking xmodule runtime (#2088) --- openassessment/xblock/test/base.py | 24 +++++++++++++ .../xblock/test/test_leaderboard.py | 17 ++++++++++ .../xblock/test/test_openassessment.py | 34 ++++++++++++++++++- openassessment/xblock/test/test_staff_area.py | 24 ------------- .../ui_mixins/mfe/submission_serializers.py | 1 + 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/openassessment/xblock/test/base.py b/openassessment/xblock/test/base.py index 914d700642..c3a408584e 100644 --- a/openassessment/xblock/test/base.py +++ b/openassessment/xblock/test/base.py @@ -310,6 +310,30 @@ def load_fixture_str(path): with open(os.path.join(base_dir, path)) as file_handle: return file_handle.read() + @staticmethod + def _create_mock_runtime( + item_id, + is_staff, + is_admin, + anonymous_user_id, + user_is_beta=False, + ): + """ + Internal helper to define a mock runtime. + """ + mock_runtime = mock.Mock( + course_id='test_course', + item_id=item_id, + anonymous_student_id=anonymous_user_id, + user_is_staff=is_staff, + user_is_admin=is_admin, + user_is_beta=user_is_beta, + service=lambda self, service: mock.Mock( + get_anonymous_student_id=lambda user_id, course_id: anonymous_user_id + ) + ) + return mock_runtime + class XBlockHandlerTestCase(XBlockHandlerTestCaseMixin, CacheResetTest): """ diff --git a/openassessment/xblock/test/test_leaderboard.py b/openassessment/xblock/test/test_leaderboard.py index 876360216b..4a4bd967c3 100644 --- a/openassessment/xblock/test/test_leaderboard.py +++ b/openassessment/xblock/test/test_leaderboard.py @@ -27,6 +27,10 @@ class TestLeaderboardRender(XBlockHandlerTransactionTestCase): @scenario('data/basic_scenario.xml') def test_no_leaderboard(self, xblock): xblock.mfe_views_enabled = False + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) + # Since there's no leaderboard set in the problem XML, # it should not be visible self._assert_leaderboard_visible(xblock, False) @@ -34,6 +38,9 @@ def test_no_leaderboard(self, xblock): @scenario('data/leaderboard_unavailable.xml') def test_unavailable(self, xblock): xblock.mfe_views_enabled = False + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Start date is in the future for this scenario self._assert_path_and_context( xblock, @@ -44,6 +51,9 @@ def test_unavailable(self, xblock): @scenario('data/leaderboard_show.xml') def test_show_no_submissions(self, xblock): + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = False # No submissions created yet, so the leaderboard shouldn't display any scores self._assert_scores(xblock, []) @@ -52,6 +62,10 @@ def test_show_no_submissions(self, xblock): @scenario('data/leaderboard_show.xml') def test_show_submissions(self, xblock): xblock.mfe_views_enabled = False + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) + # Create some submissions (but fewer than the max that can be shown) self._create_submissions_and_scores(xblock, [ (prepare_submission_for_serialization(('test answer 1 part 1', 'test answer 1 part 2')), 1), @@ -98,6 +112,9 @@ def test_show_submissions(self, xblock): @scenario('data/leaderboard_show.xml') def test_show_submissions_that_have_greater_than_0_score(self, xblock): xblock.mfe_views_enabled = False + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Create some submissions (but fewer than the max that can be shown) self._create_submissions_and_scores(xblock, [ (prepare_submission_for_serialization(('test answer 0 part 1', 'test answer 0 part 2')), 0), diff --git a/openassessment/xblock/test/test_openassessment.py b/openassessment/xblock/test/test_openassessment.py index 91bfd847b7..86e3ebc17f 100644 --- a/openassessment/xblock/test/test_openassessment.py +++ b/openassessment/xblock/test/test_openassessment.py @@ -79,6 +79,9 @@ def test_load_student_view(self, xblock): Open Assessment XBlock. We don't want to match too heavily against the contents. """ + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = True xblock_fragment = self.runtime.render(xblock, "student_view") self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html()) @@ -284,6 +287,9 @@ def test_ora_blocks_listing_view_include_esg_flag(self, xblock, esg_flag_input, @scenario('data/empty_prompt.xml') def test_prompt_intentionally_empty(self, xblock): xblock.mfe_views_enabled = True + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Verify that prompts intentionally left empty don't create DOM elements xblock_fragment = self.runtime.render(xblock, "student_view") body_html = xblock_fragment.body_html() @@ -294,6 +300,9 @@ def test_prompt_intentionally_empty(self, xblock): @scenario('data/basic_scenario.xml') def test_page_load_updates_workflow(self, xblock): + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = True # No submission made, so don't update the workflow @@ -315,6 +324,9 @@ def test_page_load_updates_workflow(self, xblock): @scenario('data/basic_scenario.xml') def test_student_view_workflow_error(self, xblock): xblock.mfe_views_enabled = True + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Simulate an error from updating the workflow xblock.submission_uuid = 'test_submission' @@ -339,6 +351,9 @@ def test_load_student_view_with_dates(self, time_zone, expected_date): time_zone_fn.return_value['user_timezone'] = pytz.timezone(time_zone) xblock = self.load_scenario('data/dates_scenario.xml') + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = True xblock_fragment = self.runtime.render(xblock, "student_view") self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html()) @@ -520,7 +535,9 @@ def test_formatted_end_dates_for_beta_tester_with_nonetype_days_early(self, time @scenario('data/basic_scenario.xml', user_id='Bob') def test_default_fields(self, xblock): - + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Reset all fields in the XBlock to their default values for field_name, field in xblock.fields.items(): setattr(xblock, field_name, field.default) @@ -552,6 +569,9 @@ def test_use_xmodule_runtime(self, xblock): @scenario('data/basic_scenario.xml', user_id='Bob') def test_ignore_unknown_assessment_types(self, xblock): xblock.mfe_views_enabled = True + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # If the XBlock contains an unknown assessment type # (perhaps after a roll-back), it should ignore it. xblock.rubric_assessments.append({'name': 'unknown'}) @@ -565,6 +585,9 @@ def test_ignore_unknown_assessment_types(self, xblock): @scenario('data/grade_scenario_self_staff.xml', user_id='Bob') def test_assessment_type_with_staff(self, xblock): + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = True # Check that staff-assessment is in assessment_steps self.assertIn('staff-assessment', xblock.assessment_steps) @@ -574,6 +597,9 @@ def test_assessment_type_with_staff(self, xblock): @scenario('data/grade_scenario_self_only.xml', user_id='Bob') def test_assessment_type_without_staff(self, xblock): + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) xblock.mfe_views_enabled = True # Check that staff-assessment is not in assessment_steps self.assertNotIn('staff-assessment', xblock.assessment_steps) @@ -584,6 +610,9 @@ def test_assessment_type_without_staff(self, xblock): @scenario('data/grade_scenario_self_staff_not_required.xml', user_id='Bob') def test_assessment_type_with_staff_not_required(self, xblock): xblock.mfe_views_enabled = True + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) StaffAssessmentAPI.staff_assessment_exists = lambda submission_uuid: False # Check that staff-assessment is not in assessment_steps self.assertNotIn('staff-assessment', xblock.assessment_steps) @@ -594,6 +623,9 @@ def test_assessment_type_with_staff_not_required(self, xblock): @scenario('data/grade_scenario_self_staff_not_required.xml', user_id='Bob') def test_assessment_type_with_staff_override(self, xblock): xblock.mfe_views_enabled = True + xblock.xmodule_runtime = self._create_mock_runtime( + xblock.scope_ids.usage_id, False, False, "Bob" + ) # Override the staff_assessment_exists function to always return True StaffAssessmentAPI.staff_assessment_exists = lambda submission_uuid: True diff --git a/openassessment/xblock/test/test_staff_area.py b/openassessment/xblock/test/test_staff_area.py index aed4ab4881..4526ca2b77 100644 --- a/openassessment/xblock/test/test_staff_area.py +++ b/openassessment/xblock/test/test_staff_area.py @@ -1436,30 +1436,6 @@ def _verify_staff_assessment_context(self, context, required, ungraded=None, in_ self.assertEqual(ungraded, context['staff_assessment_ungraded']) self.assertEqual(in_progress, context['staff_assessment_in_progress']) - @staticmethod - def _create_mock_runtime( - item_id, - is_staff, - is_admin, - anonymous_user_id, - user_is_beta=False, - ): - """ - Internal helper to define a mock runtime. - """ - mock_runtime = Mock( - course_id='test_course', - item_id=item_id, - anonymous_student_id=anonymous_user_id, - user_is_staff=is_staff, - user_is_admin=is_admin, - user_is_beta=user_is_beta, - service=lambda self, service: Mock( - get_anonymous_student_id=lambda user_id, course_id: anonymous_user_id - ) - ) - return mock_runtime - @staticmethod def _create_submission(item, values, types): """ Create a submission and corresponding workflow. """ diff --git a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py index 538fd42536..1c7d627967 100644 --- a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py @@ -2,6 +2,7 @@ # pylint: disable=abstract-method from rest_framework.serializers import ( + BooleanField, IntegerField, Serializer, CharField, From a56beeba2c3061aedbe6a0873b1a2b807bbaf784 Mon Sep 17 00:00:00 2001 From: Jenkins Date: Sun, 24 Sep 2023 20:57:02 +0000 Subject: [PATCH 14/27] chore(i18n): update translations --- openassessment/conf/locale/ar/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/cs/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/de_DE/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/el/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/es_419/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/es_ES/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/eu_ES/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/fa_IR/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/fr/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po | 6 +++--- openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po | 4 ++-- openassessment/conf/locale/he/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/hi/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/id/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/it_IT/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/ja_JP/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/ka/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/lt_LT/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/lv/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/mn/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/nb/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/pl/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/pt_BR/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/pt_PT/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/ro/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/ru/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/sq/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/sw_KE/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/th/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/tr_TR/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/uk/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/vi/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/zh_CN/LC_MESSAGES/django.po | 2 +- openassessment/conf/locale/zh_TW/LC_MESSAGES/django.po | 2 +- 34 files changed, 37 insertions(+), 37 deletions(-) diff --git a/openassessment/conf/locale/ar/LC_MESSAGES/django.po b/openassessment/conf/locale/ar/LC_MESSAGES/django.po index 3a4f62bce8..5aa5957cf9 100644 --- a/openassessment/conf/locale/ar/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/ar/LC_MESSAGES/django.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Omar Al-Ithawi , 2023\n" "Language-Team: Arabic (http://app.transifex.com/open-edx/edx-platform/language/ar/)\n" diff --git a/openassessment/conf/locale/cs/LC_MESSAGES/django.po b/openassessment/conf/locale/cs/LC_MESSAGES/django.po index 2195e72cb0..3566136ed4 100644 --- a/openassessment/conf/locale/cs/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/cs/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Jiří Podhorecký, 2023\n" "Language-Team: Czech (http://app.transifex.com/open-edx/edx-platform/language/cs/)\n" diff --git a/openassessment/conf/locale/de_DE/LC_MESSAGES/django.po b/openassessment/conf/locale/de_DE/LC_MESSAGES/django.po index 71cae8020e..90b625feda 100644 --- a/openassessment/conf/locale/de_DE/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/de_DE/LC_MESSAGES/django.po @@ -30,7 +30,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Stefania Trabucchi , 2018-2021\n" "Language-Team: German (Germany) (http://app.transifex.com/open-edx/edx-platform/language/de_DE/)\n" diff --git a/openassessment/conf/locale/el/LC_MESSAGES/django.po b/openassessment/conf/locale/el/LC_MESSAGES/django.po index b95b057fce..65ab3859ea 100644 --- a/openassessment/conf/locale/el/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/el/LC_MESSAGES/django.po @@ -25,7 +25,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Dimitris Voudouris , 2023\n" "Language-Team: Greek (http://app.transifex.com/open-edx/edx-platform/language/el/)\n" diff --git a/openassessment/conf/locale/es_419/LC_MESSAGES/django.po b/openassessment/conf/locale/es_419/LC_MESSAGES/django.po index 99b65fbc46..229be65d1c 100644 --- a/openassessment/conf/locale/es_419/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/es_419/LC_MESSAGES/django.po @@ -35,7 +35,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Zimeng Chen, 2023\n" "Language-Team: Spanish (Latin America) (http://app.transifex.com/open-edx/edx-platform/language/es_419/)\n" diff --git a/openassessment/conf/locale/es_ES/LC_MESSAGES/django.po b/openassessment/conf/locale/es_ES/LC_MESSAGES/django.po index bdc4eb9e75..4cc2df9b19 100644 --- a/openassessment/conf/locale/es_ES/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/es_ES/LC_MESSAGES/django.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Jesica Greco, 2022-2023\n" "Language-Team: Spanish (Spain) (http://app.transifex.com/open-edx/edx-platform/language/es_ES/)\n" diff --git a/openassessment/conf/locale/eu_ES/LC_MESSAGES/django.po b/openassessment/conf/locale/eu_ES/LC_MESSAGES/django.po index a310371a49..7b5007e84e 100644 --- a/openassessment/conf/locale/eu_ES/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/eu_ES/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Abel Camacho , 2019-2020\n" "Language-Team: Basque (Spain) (http://app.transifex.com/open-edx/edx-platform/language/eu_ES/)\n" diff --git a/openassessment/conf/locale/fa_IR/LC_MESSAGES/django.po b/openassessment/conf/locale/fa_IR/LC_MESSAGES/django.po index 6d0e657676..ccc4fe34d7 100644 --- a/openassessment/conf/locale/fa_IR/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/fa_IR/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: SeyedMahdi Saeid , 2023\n" "Language-Team: Persian (Iran) (http://app.transifex.com/open-edx/edx-platform/language/fa_IR/)\n" diff --git a/openassessment/conf/locale/fr/LC_MESSAGES/django.po b/openassessment/conf/locale/fr/LC_MESSAGES/django.po index a0d90bd120..b8375c7200 100644 --- a/openassessment/conf/locale/fr/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/fr/LC_MESSAGES/django.po @@ -44,7 +44,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: alexis swyngedauw, 2022\n" "Language-Team: French (http://app.transifex.com/open-edx/edx-platform/language/fr/)\n" diff --git a/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po b/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po index 958e07fde7..eba398ced9 100644 --- a/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po @@ -97,7 +97,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Pierre Mailhot , 2016-2023\n" "Language-Team: French (Canada) (http://app.transifex.com/open-edx/edx-platform/language/fr_CA/)\n" @@ -921,7 +921,7 @@ msgstr "Soumission de commentaires" msgid "" "Your feedback has been submitted. Course staff will be able to see this " "feedback when they review course records." -msgstr "Votre rétroaction a été soumise. Elle sera accessible à au personnel du cours lorsqu'ils examineront les dossiers du cours." +msgstr "Votre rétroaction a été soumise. Elle sera accessible à aux membres de du personnel du cours lorsqu'ils examineront les dossiers du cours." #: templates/openassessmentblock/grade/oa_grade_complete.html:140 msgid "" @@ -2410,7 +2410,7 @@ msgstr "Aucune autre réponse d'apprenant disponible pour notation en ce moment. #: xblock/staff_area_mixin.py:388 msgid "Error getting staff grade information." -msgstr "Erreur lors de la récupération des notes attribuées par le personnel et leur compte." +msgstr "Erreur lors de la récupération de la note du personnel." #: xblock/staff_area_mixin.py:409 msgid "Error getting staff grade ungraded and checked out counts." diff --git a/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po index 0cf9a17b30..76aaa8474a 100644 --- a/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po @@ -58,7 +58,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-09-24 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Pierre Mailhot , 2016,2018-2023\n" "Language-Team: French (Canada) (http://app.transifex.com/open-edx/edx-platform/language/fr_CA/)\n" @@ -485,7 +485,7 @@ msgstr "Il y a {stuck_learners} apprenants dans l'étape d'attente, c'est-à-dir msgid "" "However, {overwritten_count} of these students have received a grade through" " the staff grade override tool already." -msgstr "Toutefois, {overwritten_count} étudiants ont déjà reçu une note fournie par le personnel." +msgstr "Toutefois, {overwritten_count} étudiants ont déjà reçu une note fournie par l'outil de remplacement du personnel." #: xblock/static/dist/openassessment-lms.d876ac9af6fabe98df40.js:375 msgid "Error while fetching student data." diff --git a/openassessment/conf/locale/he/LC_MESSAGES/django.po b/openassessment/conf/locale/he/LC_MESSAGES/django.po index 6be607f83d..ba787539ae 100644 --- a/openassessment/conf/locale/he/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/he/LC_MESSAGES/django.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Hodaya Zada , 2019,2021\n" "Language-Team: Hebrew (http://app.transifex.com/open-edx/edx-platform/language/he/)\n" diff --git a/openassessment/conf/locale/hi/LC_MESSAGES/django.po b/openassessment/conf/locale/hi/LC_MESSAGES/django.po index a7ed94c1ce..4443bd064d 100644 --- a/openassessment/conf/locale/hi/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/hi/LC_MESSAGES/django.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Manish Manish , 2020\n" "Language-Team: Hindi (http://app.transifex.com/open-edx/edx-platform/language/hi/)\n" diff --git a/openassessment/conf/locale/id/LC_MESSAGES/django.po b/openassessment/conf/locale/id/LC_MESSAGES/django.po index c6e56d9144..a8fc55c645 100644 --- a/openassessment/conf/locale/id/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/id/LC_MESSAGES/django.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Faizar Septiawan , 2023\n" "Language-Team: Indonesian (http://app.transifex.com/open-edx/edx-platform/language/id/)\n" diff --git a/openassessment/conf/locale/it_IT/LC_MESSAGES/django.po b/openassessment/conf/locale/it_IT/LC_MESSAGES/django.po index 6a45e3a137..844bb5bb24 100644 --- a/openassessment/conf/locale/it_IT/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/it_IT/LC_MESSAGES/django.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Diana Huang , 2022\n" "Language-Team: Italian (Italy) (http://app.transifex.com/open-edx/edx-platform/language/it_IT/)\n" diff --git a/openassessment/conf/locale/ja_JP/LC_MESSAGES/django.po b/openassessment/conf/locale/ja_JP/LC_MESSAGES/django.po index 6a5fbfcd48..1c763d55cf 100644 --- a/openassessment/conf/locale/ja_JP/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/ja_JP/LC_MESSAGES/django.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Kyoto University , 2017,2019\n" "Language-Team: Japanese (Japan) (http://app.transifex.com/open-edx/edx-platform/language/ja_JP/)\n" diff --git a/openassessment/conf/locale/ka/LC_MESSAGES/django.po b/openassessment/conf/locale/ka/LC_MESSAGES/django.po index 2cadcc11aa..7fd54007b7 100644 --- a/openassessment/conf/locale/ka/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/ka/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Lasha Kokilashvili, 2018\n" "Language-Team: Georgian (http://app.transifex.com/open-edx/edx-platform/language/ka/)\n" diff --git a/openassessment/conf/locale/lt_LT/LC_MESSAGES/django.po b/openassessment/conf/locale/lt_LT/LC_MESSAGES/django.po index 7e8be8ccd0..bf933e8a57 100644 --- a/openassessment/conf/locale/lt_LT/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/lt_LT/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Edukometrija , 2015\n" "Language-Team: Lithuanian (Lithuania) (http://app.transifex.com/open-edx/edx-platform/language/lt_LT/)\n" diff --git a/openassessment/conf/locale/lv/LC_MESSAGES/django.po b/openassessment/conf/locale/lv/LC_MESSAGES/django.po index bc59057d49..ec4302f494 100644 --- a/openassessment/conf/locale/lv/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/lv/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: Latvian (http://app.transifex.com/open-edx/edx-platform/language/lv/)\n" diff --git a/openassessment/conf/locale/mn/LC_MESSAGES/django.po b/openassessment/conf/locale/mn/LC_MESSAGES/django.po index 6494b30f27..bff036f8b5 100644 --- a/openassessment/conf/locale/mn/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/mn/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Myagmarjav Enkhbileg , 2021\n" "Language-Team: Mongolian (http://app.transifex.com/open-edx/edx-platform/language/mn/)\n" diff --git a/openassessment/conf/locale/nb/LC_MESSAGES/django.po b/openassessment/conf/locale/nb/LC_MESSAGES/django.po index 8b5bc5619d..fe3d1447c5 100644 --- a/openassessment/conf/locale/nb/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/nb/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Frode Arntsen , 2014,2016-2017\n" "Language-Team: Norwegian Bokmål (http://app.transifex.com/open-edx/edx-platform/language/nb/)\n" diff --git a/openassessment/conf/locale/pl/LC_MESSAGES/django.po b/openassessment/conf/locale/pl/LC_MESSAGES/django.po index 0b1e261b06..871871380c 100644 --- a/openassessment/conf/locale/pl/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/pl/LC_MESSAGES/django.po @@ -24,7 +24,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Klara Sielicka-Baryłka, 2022\n" "Language-Team: Polish (http://app.transifex.com/open-edx/edx-platform/language/pl/)\n" diff --git a/openassessment/conf/locale/pt_BR/LC_MESSAGES/django.po b/openassessment/conf/locale/pt_BR/LC_MESSAGES/django.po index 20bac2e957..abf1144d6a 100644 --- a/openassessment/conf/locale/pt_BR/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/pt_BR/LC_MESSAGES/django.po @@ -32,7 +32,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Emmanuel Halbout , 2020\n" "Language-Team: Portuguese (Brazil) (http://app.transifex.com/open-edx/edx-platform/language/pt_BR/)\n" diff --git a/openassessment/conf/locale/pt_PT/LC_MESSAGES/django.po b/openassessment/conf/locale/pt_PT/LC_MESSAGES/django.po index d0310e48c2..2e9ecf9970 100644 --- a/openassessment/conf/locale/pt_PT/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/pt_PT/LC_MESSAGES/django.po @@ -23,7 +23,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Ivo Branco , 2021,2023\n" "Language-Team: Portuguese (Portugal) (http://app.transifex.com/open-edx/edx-platform/language/pt_PT/)\n" diff --git a/openassessment/conf/locale/ro/LC_MESSAGES/django.po b/openassessment/conf/locale/ro/LC_MESSAGES/django.po index fc6ac4fe70..9c50544575 100644 --- a/openassessment/conf/locale/ro/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/ro/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Bogdan Mateescu, 2018\n" "Language-Team: Romanian (http://app.transifex.com/open-edx/edx-platform/language/ro/)\n" diff --git a/openassessment/conf/locale/ru/LC_MESSAGES/django.po b/openassessment/conf/locale/ru/LC_MESSAGES/django.po index fb201cc6f5..72998e12c8 100644 --- a/openassessment/conf/locale/ru/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/ru/LC_MESSAGES/django.po @@ -28,7 +28,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Dmitry Broover, 2022\n" "Language-Team: Russian (http://app.transifex.com/open-edx/edx-platform/language/ru/)\n" diff --git a/openassessment/conf/locale/sq/LC_MESSAGES/django.po b/openassessment/conf/locale/sq/LC_MESSAGES/django.po index 91a6f13365..f824ad58e7 100644 --- a/openassessment/conf/locale/sq/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/sq/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Faton Nuha , 2014-2016\n" "Language-Team: Albanian (http://app.transifex.com/open-edx/edx-platform/language/sq/)\n" diff --git a/openassessment/conf/locale/sw_KE/LC_MESSAGES/django.po b/openassessment/conf/locale/sw_KE/LC_MESSAGES/django.po index 0732de45ec..de447d06ef 100644 --- a/openassessment/conf/locale/sw_KE/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/sw_KE/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: YAHAYA MWAVURIZI , 2017\n" "Language-Team: Swahili (Kenya) (http://app.transifex.com/open-edx/edx-platform/language/sw_KE/)\n" diff --git a/openassessment/conf/locale/th/LC_MESSAGES/django.po b/openassessment/conf/locale/th/LC_MESSAGES/django.po index 6ff6dac531..e05c787373 100644 --- a/openassessment/conf/locale/th/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/th/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Noppadol Choti , 2019\n" "Language-Team: Thai (http://app.transifex.com/open-edx/edx-platform/language/th/)\n" diff --git a/openassessment/conf/locale/tr_TR/LC_MESSAGES/django.po b/openassessment/conf/locale/tr_TR/LC_MESSAGES/django.po index 21e9a4e9e6..52f8f71e63 100644 --- a/openassessment/conf/locale/tr_TR/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/tr_TR/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Ali Işıngör , 2018-2023\n" "Language-Team: Turkish (Turkey) (http://app.transifex.com/open-edx/edx-platform/language/tr_TR/)\n" diff --git a/openassessment/conf/locale/uk/LC_MESSAGES/django.po b/openassessment/conf/locale/uk/LC_MESSAGES/django.po index 354c3d780a..1f475ddf8a 100644 --- a/openassessment/conf/locale/uk/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/uk/LC_MESSAGES/django.po @@ -22,7 +22,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Danylo Shcherbak , 2021\n" "Language-Team: Ukrainian (http://app.transifex.com/open-edx/edx-platform/language/uk/)\n" diff --git a/openassessment/conf/locale/vi/LC_MESSAGES/django.po b/openassessment/conf/locale/vi/LC_MESSAGES/django.po index 2797890f79..43142ff3bb 100644 --- a/openassessment/conf/locale/vi/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/vi/LC_MESSAGES/django.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Lam Nguyen , 2020\n" "Language-Team: Vietnamese (http://app.transifex.com/open-edx/edx-platform/language/vi/)\n" diff --git a/openassessment/conf/locale/zh_CN/LC_MESSAGES/django.po b/openassessment/conf/locale/zh_CN/LC_MESSAGES/django.po index 9650db769e..91bfddef68 100644 --- a/openassessment/conf/locale/zh_CN/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/zh_CN/LC_MESSAGES/django.po @@ -39,7 +39,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: 亚峰 乔 , 2019\n" "Language-Team: Chinese (China) (http://app.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" diff --git a/openassessment/conf/locale/zh_TW/LC_MESSAGES/django.po b/openassessment/conf/locale/zh_TW/LC_MESSAGES/django.po index 61e294f321..e424b560ca 100644 --- a/openassessment/conf/locale/zh_TW/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/zh_TW/LC_MESSAGES/django.po @@ -29,7 +29,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-08 18:36+0000\n" +"POT-Creation-Date: 2023-09-17 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: 黃蕙君 , 2020\n" "Language-Team: Chinese (Taiwan) (http://app.transifex.com/open-edx/edx-platform/language/zh_TW/)\n" From 077860b9ee3aec8aca8690a07564b774e74b28bb Mon Sep 17 00:00:00 2001 From: leangseu-edx <83240113+leangseu-edx@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:15:58 -0400 Subject: [PATCH 15/27] chore: update assessment data shape (#2089) * chore: update assessment data shape * chore: rename response criterions to assessmentCriterions * chore: update translations * chore: update test --- .../conf/locale/ar/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/ar_SA/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/cs/LC_MESSAGES/django.po | 2 +- .../conf/locale/cs/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/de_DE/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/el/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/en/LC_MESSAGES/django.po | 11 +- .../conf/locale/en/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/eo/LC_MESSAGES/django.po | 8 +- .../conf/locale/eo/LC_MESSAGES/djangojs.po | 2 +- .../locale/es_419/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/es_AR/LC_MESSAGES/django.mo | Bin 7550 -> 7549 bytes .../conf/locale/es_AR/LC_MESSAGES/django.po | 14 +-- .../conf/locale/es_AR/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/es_ES/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/eu_ES/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/fa_IR/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/fr/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/fr_CA/LC_MESSAGES/django.po | 2 +- .../conf/locale/fr_CA/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/he/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/hi/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/id/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/it_IT/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/ja_JP/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/ka/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/lt_LT/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/lv/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/nb/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/pl/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/pt_BR/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/pt_PT/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/ro/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/ru/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/sk/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/sq/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/sw_KE/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/th/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/tr_TR/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/uk/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/vi/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/zh_CN/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/zh_TW/LC_MESSAGES/djangojs.po | 2 +- .../ui_mixins/mfe/assessment_serializers.py | 36 +++--- .../mfe/test_assessment_serializers.py | 110 ++++++++++++++++++ 45 files changed, 189 insertions(+), 68 deletions(-) diff --git a/openassessment/conf/locale/ar/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ar/LC_MESSAGES/djangojs.po index 6318cc50c2..f0e1c4aa32 100644 --- a/openassessment/conf/locale/ar/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ar/LC_MESSAGES/djangojs.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Ghassan Maslamani , 2021\n" "Language-Team: Arabic (http://app.transifex.com/open-edx/edx-platform/language/ar/)\n" diff --git a/openassessment/conf/locale/ar_SA/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ar_SA/LC_MESSAGES/djangojs.po index 7716d4faf6..3994bfb350 100644 --- a/openassessment/conf/locale/ar_SA/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ar_SA/LC_MESSAGES/djangojs.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: NELC Open edX Translation , 2020\n" "Language-Team: Arabic (Saudi Arabia) (http://app.transifex.com/open-edx/edx-platform/language/ar_SA/)\n" diff --git a/openassessment/conf/locale/cs/LC_MESSAGES/django.po b/openassessment/conf/locale/cs/LC_MESSAGES/django.po index 3566136ed4..5c98d13b58 100644 --- a/openassessment/conf/locale/cs/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/cs/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-17 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Jiří Podhorecký, 2023\n" "Language-Team: Czech (http://app.transifex.com/open-edx/edx-platform/language/cs/)\n" diff --git a/openassessment/conf/locale/cs/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/cs/LC_MESSAGES/djangojs.po index f4fe5109be..5802aff445 100644 --- a/openassessment/conf/locale/cs/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/cs/LC_MESSAGES/djangojs.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Jiří Podhorecký, 2023\n" "Language-Team: Czech (http://app.transifex.com/open-edx/edx-platform/language/cs/)\n" diff --git a/openassessment/conf/locale/de_DE/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/de_DE/LC_MESSAGES/djangojs.po index e3bb2dc475..167b5f6ce3 100644 --- a/openassessment/conf/locale/de_DE/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/de_DE/LC_MESSAGES/djangojs.po @@ -23,7 +23,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Stefania Trabucchi , 2020-2021\n" "Language-Team: German (Germany) (http://app.transifex.com/open-edx/edx-platform/language/de_DE/)\n" diff --git a/openassessment/conf/locale/el/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/el/LC_MESSAGES/djangojs.po index 9bc453efe1..2cc1e38aa4 100644 --- a/openassessment/conf/locale/el/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/el/LC_MESSAGES/djangojs.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Angelos Chraniotis, 2023\n" "Language-Team: Greek (http://app.transifex.com/open-edx/edx-platform/language/el/)\n" diff --git a/openassessment/conf/locale/en/LC_MESSAGES/django.po b/openassessment/conf/locale/en/LC_MESSAGES/django.po index 2b1fabbb49..64c9e41bd0 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-17 17:46+0000\n" +"POT-Creation-Date: 2023-10-24 13:27+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -1110,13 +1110,14 @@ msgstr "" msgid "The instructions for this step could not be loaded." msgstr "" -#: templates/legacy/oa_base.html:15 templates/openassessmentblock/base.html:15 +#: templates/legacy/oa_base.html:15 templates/openassessmentblock/base.html:21 msgid "" "This assignment has several steps. In the first step, you'll provide a " "response to the prompt. The other steps appear below the Your Response field." msgstr "" -#: templates/legacy/oa_base.html:36 templates/openassessmentblock/base.html:36 +#: templates/legacy/oa_base.html:36 templates/openassessmentblock/base.html:42 +#: templates/openassessmentblock/base.html:82 msgid "Loading" msgstr "" @@ -2433,6 +2434,10 @@ msgstr "" msgid "Successfully updated OpenAssessment XBlock" msgstr "" +#: xblock/ui_mixins/legacy/submissions/file_actions.py:71 +msgid "Files metadata could not be saved." +msgstr "" + #: xblock/utils/data_conversion.py:315 msgid "You must provide options selected in the assessment." msgstr "" diff --git a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po index 619d4a37ac..9ad8259f99 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-17 17:46+0000\n" +"POT-Creation-Date: 2023-10-24 13:27+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/django.po b/openassessment/conf/locale/eo/LC_MESSAGES/django.po index 86b27da8e1..1649b6a72a 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-17 17:46+0000\n" +"POT-Creation-Date: 2023-10-24 13:27+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -1409,6 +1409,7 @@ msgstr "" "¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм#" #: templates/legacy/oa_base.html templates/openassessmentblock/base.html +#: templates/openassessmentblock/base.html msgid "Loading" msgstr "Löädïng Ⱡ'σяєм ιρѕυм #" @@ -3080,6 +3081,11 @@ msgstr "" "Süççéssfüllý üpdätéd ÖpénÀsséssmént XBlöçk Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" +#: xblock/ui_mixins/legacy/submissions/file_actions.py +msgid "Files metadata could not be saved." +msgstr "" +"Fïlés métädätä çöüld nöt ßé sävéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" + #: xblock/utils/data_conversion.py msgid "You must provide options selected in the assessment." msgstr "" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po index 36ee397e53..6486d5fa68 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-17 17:46+0000\n" +"POT-Creation-Date: 2023-10-24 13:27+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/es_419/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/es_419/LC_MESSAGES/djangojs.po index 2c5f652eaa..d00406e472 100644 --- a/openassessment/conf/locale/es_419/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/es_419/LC_MESSAGES/djangojs.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Jesica Greco, 2023\n" "Language-Team: Spanish (Latin America) (http://app.transifex.com/open-edx/edx-platform/language/es_419/)\n" diff --git a/openassessment/conf/locale/es_AR/LC_MESSAGES/django.mo b/openassessment/conf/locale/es_AR/LC_MESSAGES/django.mo index 96bfc3fb34b306db4fd828426b7663b71c8cd5ef..7aa7a1be49459ef314937c1ddc22eb566fee7220 100644 GIT binary patch delta 611 zcmXZZJxD@P6u|LQev~PxSz6kM6cHE%E>VsJ5q&J-P+MjaQ6^Z{5(q^@5Dn1~1P%>> zTlAo=fy55E(*>mKmzh^<`vAHc=BEA(xk9%M!YX4b+R>qvn4??d+SiZWbBn#xK+Z?3AgM zhp`CvSZ)vnaiZM*0wW+= delta 612 zcmXZZJxD@P6u|LQrsfCb%hF0KiGrvgatL&cs3@AMp*AsxAW<};A#f-ff@r8Eh#VTi zrobR*Xs~E?X=)J~-XcMJ82yhuc)Z{Jc=w!h&uhegm`(IYaCr>Nh(qX$2598HX%5s-oy459%MAI@PvuHztP zt@#=DF~7qLe8n!@2>u7&K{xY#?8HNC$8&4_3N`L6+OUE{_!caPv@tMQ(1Uf7LhTeXj!HT-A^D(l12@9j9gw$EQ{!3{(yS1XVmyr)XvtdeY3zo4}PO2uv4a1 z9zrLM;2ut*2DrfvEaM7Ra1DL@$1hA_5?8|_+(90(nHZaik>-hsUW_%Y4fnu*3k}rP zhEf036zWYjQ4?>WwmM%f*$+J4rBr@9nTRapQprqt+9, 2017,2019-2020\n" "Language-Team: Basque (Spain) (http://app.transifex.com/open-edx/edx-platform/language/eu_ES/)\n" diff --git a/openassessment/conf/locale/fa_IR/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/fa_IR/LC_MESSAGES/djangojs.po index adb2745027..cee985d342 100644 --- a/openassessment/conf/locale/fa_IR/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/fa_IR/LC_MESSAGES/djangojs.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: SeyedMahdi Saeid , 2023\n" "Language-Team: Persian (Iran) (http://app.transifex.com/open-edx/edx-platform/language/fa_IR/)\n" diff --git a/openassessment/conf/locale/fr/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/fr/LC_MESSAGES/djangojs.po index 0410f77a39..654283cf34 100644 --- a/openassessment/conf/locale/fr/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/fr/LC_MESSAGES/djangojs.po @@ -22,7 +22,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: iderr , 2021-2022\n" "Language-Team: French (http://app.transifex.com/open-edx/edx-platform/language/fr/)\n" diff --git a/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po b/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po index eba398ced9..409fc760f5 100644 --- a/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/fr_CA/LC_MESSAGES/django.po @@ -97,7 +97,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-17 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:03+0000\n" "Last-Translator: Pierre Mailhot , 2016-2023\n" "Language-Team: French (Canada) (http://app.transifex.com/open-edx/edx-platform/language/fr_CA/)\n" diff --git a/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po index 76aaa8474a..8d1915d748 100644 --- a/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/fr_CA/LC_MESSAGES/djangojs.po @@ -58,7 +58,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-24 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Pierre Mailhot , 2016,2018-2023\n" "Language-Team: French (Canada) (http://app.transifex.com/open-edx/edx-platform/language/fr_CA/)\n" diff --git a/openassessment/conf/locale/he/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/he/LC_MESSAGES/djangojs.po index 408c1c3fc4..5a26fef2c8 100644 --- a/openassessment/conf/locale/he/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/he/LC_MESSAGES/djangojs.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Hodaya Zada , 2019\n" "Language-Team: Hebrew (http://app.transifex.com/open-edx/edx-platform/language/he/)\n" diff --git a/openassessment/conf/locale/hi/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/hi/LC_MESSAGES/djangojs.po index b53d6d4b06..3aee883a36 100644 --- a/openassessment/conf/locale/hi/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/hi/LC_MESSAGES/djangojs.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Manish Manish , 2021\n" "Language-Team: Hindi (http://app.transifex.com/open-edx/edx-platform/language/hi/)\n" diff --git a/openassessment/conf/locale/id/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/id/LC_MESSAGES/djangojs.po index 2238092ff6..7ec3f2f1aa 100644 --- a/openassessment/conf/locale/id/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/id/LC_MESSAGES/djangojs.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Faizar Septiawan , 2022\n" "Language-Team: Indonesian (http://app.transifex.com/open-edx/edx-platform/language/id/)\n" diff --git a/openassessment/conf/locale/it_IT/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/it_IT/LC_MESSAGES/djangojs.po index 5485f289c6..e002cb078b 100644 --- a/openassessment/conf/locale/it_IT/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/it_IT/LC_MESSAGES/djangojs.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Domenico Casanica , 2021\n" "Language-Team: Italian (Italy) (http://app.transifex.com/open-edx/edx-platform/language/it_IT/)\n" diff --git a/openassessment/conf/locale/ja_JP/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ja_JP/LC_MESSAGES/djangojs.po index 1b4ab58773..d55b1c036b 100644 --- a/openassessment/conf/locale/ja_JP/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ja_JP/LC_MESSAGES/djangojs.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Toshiboumi Ohta , 2018\n" "Language-Team: Japanese (Japan) (http://app.transifex.com/open-edx/edx-platform/language/ja_JP/)\n" diff --git a/openassessment/conf/locale/ka/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ka/LC_MESSAGES/djangojs.po index 80bb94f829..6a25465d3e 100644 --- a/openassessment/conf/locale/ka/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ka/LC_MESSAGES/djangojs.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Giorgi Goderdzishvili , 2016\n" "Language-Team: Georgian (http://app.transifex.com/open-edx/edx-platform/language/ka/)\n" diff --git a/openassessment/conf/locale/lt_LT/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/lt_LT/LC_MESSAGES/djangojs.po index a021b04afd..d500fedee8 100644 --- a/openassessment/conf/locale/lt_LT/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/lt_LT/LC_MESSAGES/djangojs.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Edukometrija , 2015\n" "Language-Team: Lithuanian (Lithuania) (http://app.transifex.com/open-edx/edx-platform/language/lt_LT/)\n" diff --git a/openassessment/conf/locale/lv/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/lv/LC_MESSAGES/djangojs.po index e9df950ad8..d9eeca4387 100644 --- a/openassessment/conf/locale/lv/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/lv/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: Latvian (http://app.transifex.com/open-edx/edx-platform/language/lv/)\n" diff --git a/openassessment/conf/locale/nb/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/nb/LC_MESSAGES/djangojs.po index 476abcf5cb..f4f9dd0d3c 100644 --- a/openassessment/conf/locale/nb/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/nb/LC_MESSAGES/djangojs.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Frode Arntsen , 2018\n" "Language-Team: Norwegian Bokmål (http://app.transifex.com/open-edx/edx-platform/language/nb/)\n" diff --git a/openassessment/conf/locale/pl/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/pl/LC_MESSAGES/djangojs.po index 3b687a7c21..185d97c767 100644 --- a/openassessment/conf/locale/pl/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/pl/LC_MESSAGES/djangojs.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Magdalena Dulęba , 2022\n" "Language-Team: Polish (http://app.transifex.com/open-edx/edx-platform/language/pl/)\n" diff --git a/openassessment/conf/locale/pt_BR/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/pt_BR/LC_MESSAGES/djangojs.po index 6a8f48adcc..d387281244 100644 --- a/openassessment/conf/locale/pt_BR/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/pt_BR/LC_MESSAGES/djangojs.po @@ -24,7 +24,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Emmanuel Halbout , 2020\n" "Language-Team: Portuguese (Brazil) (http://app.transifex.com/open-edx/edx-platform/language/pt_BR/)\n" diff --git a/openassessment/conf/locale/pt_PT/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/pt_PT/LC_MESSAGES/djangojs.po index e5c168347f..ad0bc2bb05 100644 --- a/openassessment/conf/locale/pt_PT/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/pt_PT/LC_MESSAGES/djangojs.po @@ -25,7 +25,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Ivo Branco , 2023\n" "Language-Team: Portuguese (Portugal) (http://app.transifex.com/open-edx/edx-platform/language/pt_PT/)\n" diff --git a/openassessment/conf/locale/ro/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ro/LC_MESSAGES/djangojs.po index dac4518dee..16ccc9425d 100644 --- a/openassessment/conf/locale/ro/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ro/LC_MESSAGES/djangojs.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Manuel, 2021\n" "Language-Team: Romanian (http://app.transifex.com/open-edx/edx-platform/language/ro/)\n" diff --git a/openassessment/conf/locale/ru/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/ru/LC_MESSAGES/djangojs.po index 42e8923bcd..6af2a5f78f 100644 --- a/openassessment/conf/locale/ru/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/ru/LC_MESSAGES/djangojs.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: ashed , 2022-2023\n" "Language-Team: Russian (http://app.transifex.com/open-edx/edx-platform/language/ru/)\n" diff --git a/openassessment/conf/locale/sk/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/sk/LC_MESSAGES/djangojs.po index 7e8d3307d0..d90a7df4b9 100644 --- a/openassessment/conf/locale/sk/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/sk/LC_MESSAGES/djangojs.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Vladimír Záhradník , 2015\n" "Language-Team: Slovak (http://app.transifex.com/open-edx/edx-platform/language/sk/)\n" diff --git a/openassessment/conf/locale/sq/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/sq/LC_MESSAGES/djangojs.po index 1e46226637..8a40423a47 100644 --- a/openassessment/conf/locale/sq/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/sq/LC_MESSAGES/djangojs.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Faton Nuha , 2014,2016\n" "Language-Team: Albanian (http://app.transifex.com/open-edx/edx-platform/language/sq/)\n" diff --git a/openassessment/conf/locale/sw_KE/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/sw_KE/LC_MESSAGES/djangojs.po index 1c72b34941..cd03240b0d 100644 --- a/openassessment/conf/locale/sw_KE/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/sw_KE/LC_MESSAGES/djangojs.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Innocent Masue , 2017\n" "Language-Team: Swahili (Kenya) (http://app.transifex.com/open-edx/edx-platform/language/sw_KE/)\n" diff --git a/openassessment/conf/locale/th/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/th/LC_MESSAGES/djangojs.po index afcf639ec3..692150758a 100644 --- a/openassessment/conf/locale/th/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/th/LC_MESSAGES/djangojs.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Jirayu Chamamahattana , 2015\n" "Language-Team: Thai (http://app.transifex.com/open-edx/edx-platform/language/th/)\n" diff --git a/openassessment/conf/locale/tr_TR/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/tr_TR/LC_MESSAGES/djangojs.po index 353f3ec1ea..a51690418f 100644 --- a/openassessment/conf/locale/tr_TR/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/tr_TR/LC_MESSAGES/djangojs.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Leangseu Kim, 2023\n" "Language-Team: Turkish (Turkey) (http://app.transifex.com/open-edx/edx-platform/language/tr_TR/)\n" diff --git a/openassessment/conf/locale/uk/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/uk/LC_MESSAGES/djangojs.po index c1877b20e7..788abbf007 100644 --- a/openassessment/conf/locale/uk/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/uk/LC_MESSAGES/djangojs.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Danylo Shcherbak , 2021\n" "Language-Team: Ukrainian (http://app.transifex.com/open-edx/edx-platform/language/uk/)\n" diff --git a/openassessment/conf/locale/vi/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/vi/LC_MESSAGES/djangojs.po index 1253b771b0..70d8fd5350 100644 --- a/openassessment/conf/locale/vi/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/vi/LC_MESSAGES/djangojs.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Le Minh Tri , 2020\n" "Language-Team: Vietnamese (http://app.transifex.com/open-edx/edx-platform/language/vi/)\n" diff --git a/openassessment/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/zh_CN/LC_MESSAGES/djangojs.po index 29fb8ecd9f..8f3bb858a5 100644 --- a/openassessment/conf/locale/zh_CN/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/zh_CN/LC_MESSAGES/djangojs.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: jsgang , 2015,2017,2021\n" "Language-Team: Chinese (China) (http://app.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" diff --git a/openassessment/conf/locale/zh_TW/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/zh_TW/LC_MESSAGES/djangojs.po index 75a8a9e2a6..c129064c6f 100644 --- a/openassessment/conf/locale/zh_TW/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/zh_TW/LC_MESSAGES/djangojs.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-01 18:36+0000\n" +"POT-Creation-Date: 2023-10-22 18:36+0000\n" "PO-Revision-Date: 2014-06-11 13:04+0000\n" "Last-Translator: Mose Chen , 2017\n" "Language-Team: Chinese (Taiwan) (http://app.transifex.com/open-edx/edx-platform/language/zh_TW/)\n" diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index 8e9a0405ea..e12576f7cb 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -26,28 +26,28 @@ class AssessmentScoreSerializer(Serializer): possible = IntegerField(source="points_possible", required=False) +class AssessmentCriterionSerializer(Serializer): + """ + returns: + { + name: (String) Name of the criterion + selectedOption: (String) Label of the selected option + selectedPoints: (Int) Points awarded for selected option + feedback: (String) Feedback for the selected option + } + """ + name = CharField(source="criterion.name") + selectedOption = CharField(source="option.label") + selectedPoints = IntegerField(source="option.points") + feedback = CharField() + + class AssessmentDataSerializer(Serializer): """ Assessment data serializer """ - optionsSelected = SerializerMethodField() - criterionFeedback = SerializerMethodField() - overallFeedback = SerializerMethodField() - - def get_optionsSelected(self, instance): - result = {} - for part in instance['parts']: - result[part['option']['name']] = part['option']['label'] - return result - - def get_overallFeedback(self, instance): - return instance['feedback'] - - def get_criterionFeedback(self, instance): - result = {} - for part in instance['parts']: - result[part['criterion']['name']] = part['feedback'] - return result + overallFeedback = CharField(source="feedback") + assessmentCriterions = AssessmentCriterionSerializer(source="parts", many=True) class AssessmentStepSerializer(Serializer): diff --git a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py index 7cb694214e..816b7f63cc 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py @@ -4,6 +4,7 @@ import json from unittest.mock import patch +from django.test import TestCase from openassessment.fileupload.api import FileUpload from openassessment.xblock.test.base import ( PEER_ASSESSMENTS, @@ -17,6 +18,9 @@ AssessmentResponseSerializer, AssessmentStepSerializer, AssessmentGradeSerializer, + AssessmentScoreSerializer, + AssessmentDataSerializer, + AssessmentCriterionSerializer, ) @@ -272,3 +276,109 @@ def test_peer_assement_steps(self, xblock): ).data self.assertEqual(serialize_peer["stepScore"], peer["stepScore"]) self.assertEqual(serialize_peer["assessment"], serialize_peer["assessment"]) + + @scenario("data/grade_scenario.xml", user_id="Alan") + def test_assessment_step_score(self, xblock): + submission_text = ["Foo", "Bar"] + submission = self.create_test_submission( + xblock, submission_text=submission_text + ) + + self.submit_staff_assessment(xblock, submission, STAFF_GOOD_ASSESSMENT) + + context = {"response": submission, "step": "staff"} + # When I load my response + data = AssessmentGradeSerializer(xblock.api_data, context=context).data + + # I get the appropriate response + self.assertEqual(context["step"], data["effectiveAssessmentType"]) + + step_score = AssessmentScoreSerializer( + xblock.api_data.staff_assessment_data.assessment, context=context + ).data + + self.assertEqual(data["staff"]["stepScore"], step_score) + + @scenario("data/grade_scenario.xml", user_id="Alan") + def test_assessment_step_assessment_data(self, xblock): + submission_text = ["Foo", "Bar"] + submission = self.create_test_submission( + xblock, submission_text=submission_text + ) + + self.submit_staff_assessment(xblock, submission, STAFF_GOOD_ASSESSMENT) + + context = {"response": submission, "step": "staff"} + # When I load my response + data = AssessmentGradeSerializer(xblock.api_data, context=context).data + + # I get the appropriate response + self.assertEqual(context["step"], data["effectiveAssessmentType"]) + + assessment_data = AssessmentDataSerializer( + xblock.api_data.staff_assessment_data.assessment, context=context + ).data + + self.assertEqual(data["staff"]["assessment"], assessment_data) + + +class TestAssessmentScoreSerializer(TestCase): + """ + Test for AssessmentScoreSerializer + """ + + def test_assessment_score(self): + score = AssessmentScoreSerializer({ + "points_earned": 5, + "points_possible": 10, + }).data + self.assertEqual(score["earned"], 5) + self.assertEqual(score["possible"], 10) + + +class TestAssessmentCriterionSerializer(TestCase): + """ + Test for AssessmentCriterionSerializer + """ + + def test_assessment_criterion(self): + criterion = AssessmentCriterionSerializer({ + "criterion": { + "name": "Foo", + }, + "option": { + "label": "Bar", + "points": 5, + }, + "feedback": "Baz", + }).data + self.assertEqual(criterion["name"], "Foo") + self.assertEqual(criterion["selectedOption"], "Bar") + self.assertEqual(criterion["selectedPoints"], 5) + self.assertEqual(criterion["feedback"], "Baz") + + +class TestAssessmentDataSerializer(TestCase): + """ + Test for AssessmentDataSerializer + """ + + def test_assessment_data(self): + assessment_data = AssessmentDataSerializer({ + "feedback": "Foo", + "parts": [ + { + "criterion": { + "name": "Bar", + }, + "option": { + "label": "Baz", + "points": 5, + }, + "feedback": "Buzz", + }, + ], + }).data + + self.assertEqual(assessment_data["overallFeedback"], "Foo") + self.assertEqual(len(assessment_data["assessmentCriterions"]), 1) From 31359deb582ee81308bac8aea14d0a9b1adfab27 Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Tue, 24 Oct 2023 14:46:05 -0400 Subject: [PATCH 16/27] refactor: BFF contract updates (round 2) (#2085) * refactor: combine assessment/submission endpoints New get_learner_data endpoint covers both modes, while internally routing to the correct view / step / jump step * refactor: move team info to step info * refactor: move team file uploads to submission * refactor: move response data up a level Also included a refactor to make draft / complete submission serializer inputs similar. * refactor: update assessment response hierarchy --- .../ui_mixins/mfe/assessment_serializers.py | 132 +++++++----------- openassessment/xblock/ui_mixins/mfe/mixin.py | 2 - .../ui_mixins/mfe/page_context_serializer.py | 4 +- .../ui_mixins/mfe/submission_serializers.py | 2 +- .../mfe/test_assessment_serializers.py | 52 ++----- .../mfe/test_page_context_serializer.py | 32 ++--- 6 files changed, 77 insertions(+), 147 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index e12576f7cb..0a289127f5 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -54,6 +54,7 @@ class AssessmentStepSerializer(Serializer): """ Assessment step serializer """ + stepScore = AssessmentScoreSerializer(source="*") assessment = AssessmentDataSerializer(source="*") @@ -66,9 +67,45 @@ class SubmissionFileSerializer(Serializer): fileIndex = IntegerField(source="file_index") -class SubmittedResponseSerializer(Serializer): +class AssessmentGradeSerializer(Serializer): """ - Data for a submitted response + Given we want to load an assessment response, + gather the appropriate response and serialize. + + Data same shape as Submission, but coming from different sources. + + Returns: + { + effectiveAssessmentType: String + self: AssessmentStepSerializer + staff: AssessmentStepSerializer + peers: AssessmentStepSerializer[] + } + """ + + effectiveAssessmentType = SerializerMethodField() + self = AssessmentStepSerializer(source="self_assessment_data.assessment") + staff = AssessmentStepSerializer(source="staff_assessment_data.assessment") + peers = AssessmentStepSerializer( + source="peer_assessment_data.assessments", many=True + ) + + def get_effectiveAssessmentType(self, instance): # pylint: disable=unused-argument + """ + Get effective assessment type + """ + return self.context["step"] + + +class AssessmentResponseSerializer(Serializer): + """ + Given we want to load an assessment response, + gather the appropriate response and serialize. + + Data same shape as Submission, but coming from different sources. + + Args: + * Response - All assessment responses have the same data Returns: { @@ -76,7 +113,7 @@ class SubmittedResponseSerializer(Serializer): [ (String) Matched with prompts ], - uploaded_files: (Array [Object]) + uploadedFiles: (Array [Object]) [ { fileUrl: (URL) S3 location @@ -85,12 +122,21 @@ class SubmittedResponseSerializer(Serializer): fileSize: (Bytes?) fileIndex: (Integer, positive) } - ] + ], + teamUploadedFiles: Null } """ textResponses = SerializerMethodField() uploadedFiles = SerializerMethodField() + teamUploadedFiles = NullField(source="*") + + def __init__(self, instance=None, *args, **kwargs): # pylint: disable=keyword-arg-before-vararg + # Very weird workaround to control serialization for None input as data + # since DRF doesn't run to_representation when None is passed as data + if instance is None: + self.fields = {} + super().__init__(instance, *args, **kwargs) def get_textResponses(self, instance): # An empty response has a different format from a saved response @@ -121,81 +167,3 @@ def get_uploadedFiles(self, instance): files.append(file_data) return [SubmissionFileSerializer(file).data for file in files] - - -class AssessmentGradeSerializer(Serializer): - """ - Given we want to load an assessment response, - gather the appropriate response and serialize. - - Data same shape as Submission, but coming from different sources. - - Returns: - { - effectiveAssessmentType: String - self: AssessmentStepSerializer - staff: AssessmentStepSerializer - peers: AssessmentStepSerializer[] - } - """ - effectiveAssessmentType = SerializerMethodField() - self = AssessmentStepSerializer(source="self_assessment_data.assessment") - staff = AssessmentStepSerializer(source="staff_assessment_data.assessment") - peers = AssessmentStepSerializer(source="peer_assessment_data.assessments", many=True) - - def get_effectiveAssessmentType(self, instance): # pylint: disable=unused-argument - """ - Get effective assessment type - """ - return self.context["step"] - - -class AssessmentResponseSerializer(Serializer): - """ - Given we want to load an assessment response, - gather the appropriate response and serialize. - - Data same shape as Submission, but coming from different sources. - - Returns: - { - // Null for Assessments - hasSubmitted: None - hasCancelled: None - hasReceivedGrade: None - teamInfo: None - - // The actual response to view - response: (Object) - { - textResponses: (Array [String]) - [ - (String) Matched with prompts - ], - uploadedFiles: (Array [Object]) - [ - { - fileUrl: (URL) S3 location - fileDescription: (String) - fileName: (String) - fileSize: (Bytes?) - fileIndex: (Integer, positive) - } - ] - } - """ - - hasSubmitted = NullField(source="*") - hasCancelled = NullField(source="*") - hasReceivedGrade = NullField(source="*") - teamInfo = NullField(source="*") - - response = SerializerMethodField() - - def get_response(self, instance): # pylint: disable=unused-argument - # Response is passed in through context, so we don't have to fetch it - # in multiple locations. - response = self.context.get("response") - if not response: - return {} - return SubmittedResponseSerializer(response).data diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index 4feaf509f8..f3e27096a0 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -79,7 +79,6 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument # Determine which mode we are viewing in, since data comes from different sources if workflow_step or jump_step == "submission": has_submitted = self.workflow_data.has_submitted - # View our submitted response if has_submitted: serializer_context.update({"view": "submission"}) @@ -87,7 +86,6 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument # View our draft response else: serializer_context.update({"view": "draft"}) - # View the selected assessment step else: serializer_context.update({"view": "assessment"}) diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index 6c0280263e..d1c214ba93 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -340,6 +340,7 @@ def get_response(self, instance): workflow_step = self.context["step"] active_step = jump_to_step or workflow_step + # Fetch the response for the given step if active_step == "training": response = instance.student_training_data.example elif active_step == "peer": @@ -349,9 +350,8 @@ def get_response(self, instance): else: raise Exception(f"Bad step name: {active_step}") - self.context["response"] = response + return AssessmentResponseSerializer(response).data - return AssessmentResponseSerializer(instance.api_data, context=self.context).data else: raise Exception("Missing view context for page") diff --git a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py index 1c7d627967..52d0897f61 100644 --- a/openassessment/xblock/ui_mixins/mfe/submission_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/submission_serializers.py @@ -1,8 +1,8 @@ """ MFE Serializers related to submissions """ # pylint: disable=abstract-method +from rest_framework.fields import BooleanField from rest_framework.serializers import ( - BooleanField, IntegerField, Serializer, CharField, diff --git a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py index 816b7f63cc..57a85cf5a8 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py @@ -33,22 +33,16 @@ class TestAssessmentResponseSerializer(XBlockHandlerTestCase, SubmissionTestMixi maxDiff = None @scenario("data/basic_scenario.xml", user_id="Alan") - def test_no_response(self, xblock): - # Given we are asking for assessment data too early (still on submission step) - context = {"response": None, "step": "submission"} + def test_no_response(self, xblock): # pylint: disable=unused-argument + # Given we don't have a response to serialize + response = None # When I load my response - data = AssessmentResponseSerializer(xblock.api_data, context=context).data + data = AssessmentResponseSerializer(response).data # I get the appropriate response expected_response = {} - self.assertDictEqual(expected_response, data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(data["hasSubmitted"]) - self.assertIsNone(data["hasCancelled"]) - self.assertIsNone(data["hasReceivedGrade"]) - self.assertIsNone(data["teamInfo"]) + self.assertDictEqual(expected_response, data) @scenario("data/basic_scenario.xml", user_id="Alan") def test_response(self, xblock): @@ -57,23 +51,17 @@ def test_response(self, xblock): submission = self.create_test_submission( xblock, submission_text=submission_text ) - context = {"response": submission, "step": "self"} # When I load my response - data = AssessmentResponseSerializer(xblock.api_data, context=context).data + data = AssessmentResponseSerializer(submission).data # I get the appropriate response expected_response = { "textResponses": submission_text, "uploadedFiles": None, + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(data["hasSubmitted"]) - self.assertIsNone(data["hasCancelled"]) - self.assertIsNone(data["hasReceivedGrade"]) - self.assertIsNone(data["teamInfo"]) + self.assertDictEqual(expected_response, data) @scenario("data/file_upload_scenario.xml", user_id="Alan") def test_files_empty(self, xblock): @@ -82,23 +70,17 @@ def test_files_empty(self, xblock): submission = self.create_test_submission( xblock, submission_text=submission_text ) - context = {"response": submission, "step": "self"} # When I load my response - data = AssessmentResponseSerializer(xblock.api_data, context=context).data + data = AssessmentResponseSerializer(submission).data # I get the appropriate response expected_response = { "textResponses": submission_text, "uploadedFiles": None, + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(data["hasSubmitted"]) - self.assertIsNone(data["hasCancelled"]) - self.assertIsNone(data["hasReceivedGrade"]) - self.assertIsNone(data["teamInfo"]) + self.assertDictEqual(expected_response, data) def _mock_file(self, xblock, student_item_dict=None, **file_data): """Turn mock file data into a FileUpload for testing""" @@ -148,8 +130,7 @@ def test_files(self, xblock, mock_get_files): ) # When I load my response - context = {"response": submission, "step": "self"} - data = AssessmentResponseSerializer(xblock.api_data, context=context).data + data = AssessmentResponseSerializer(submission).data # I get the appropriate response (test URLs use usage ID) expected_url = f"Alan/edX/Enchantment_101/April_1/{xblock.scope_ids.usage_id}" @@ -171,14 +152,9 @@ def test_files(self, xblock, mock_get_files): "fileIndex": 2, }, ], + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(data["hasSubmitted"]) - self.assertIsNone(data["hasCancelled"]) - self.assertIsNone(data["hasReceivedGrade"]) - self.assertIsNone(data["teamInfo"]) + self.assertDictEqual(expected_response, data) class TestAssessmentGradeSerializer(XBlockHandlerTestCase, SubmitAssessmentsMixin): diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index 0e766eb35e..fafcccdf58 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -90,13 +90,9 @@ def test_student_training(self, xblock): expected_response = { "textResponses": ["This is my answer."], "uploadedFiles": None, + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, response_data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(response_data["hasSubmitted"]) - self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["teamInfo"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/peer_only_scenario.xml", user_id="Alan") def test_peer_response(self, xblock): @@ -125,13 +121,9 @@ def test_peer_response(self, xblock): expected_response = { "textResponses": other_text_responses, "uploadedFiles": None, + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, response_data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(response_data["hasSubmitted"]) - self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["teamInfo"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/peer_only_scenario.xml", user_id="Alan") def test_peer_response_not_available(self, xblock): @@ -146,12 +138,7 @@ def test_peer_response_not_available(self, xblock): # I get the appropriate response expected_response = {} - self.assertDictEqual(expected_response, response_data["response"]) - - # ... along with these always-none fields assessments - self.assertIsNone(response_data["hasSubmitted"]) - self.assertIsNone(response_data["hasCancelled"]) - self.assertIsNone(response_data["teamInfo"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/staff_grade_scenario.xml", user_id="Alan") def test_staff_response(self, xblock): @@ -164,7 +151,7 @@ def test_staff_response(self, xblock): # Then I get an empty object expected_response = {} - self.assertDictEqual(expected_response, response_data["response"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/staff_grade_scenario.xml", user_id="Alan") def test_waiting_response(self, xblock): @@ -177,7 +164,7 @@ def test_waiting_response(self, xblock): # Then I get an empty object expected_response = {} - self.assertDictEqual(expected_response, response_data["response"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/self_assessment_scenario.xml", user_id="Alan") def test_done_response(self, xblock): @@ -190,7 +177,7 @@ def test_done_response(self, xblock): # Then I get an empty object expected_response = {} - self.assertDictEqual(expected_response, response_data["response"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") def test_jump_to_peer_response(self, xblock): @@ -218,8 +205,9 @@ def test_jump_to_peer_response(self, xblock): expected_response = { "textResponses": other_text_responses, "uploadedFiles": None, + "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, response_data["response"]) + self.assertDictEqual(expected_response, response_data) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") def test_jump_to_bad_step(self, xblock): From 081db7115b7e2f4b07b0e51213354bafc920817b Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Wed, 25 Oct 2023 10:34:34 -0400 Subject: [PATCH 17/27] feat: disable MFE views for unsupported use-cases (#2090) * feat: disable MFE views for unsupported use-cases Currently: team assignments, reordered assessment steps --- .../conf/locale/en/LC_MESSAGES/django.po | 2 +- .../conf/locale/en/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/eo/LC_MESSAGES/django.po | 2 +- .../conf/locale/eo/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/es_AR/LC_MESSAGES/django.mo | Bin 7549 -> 8372 bytes openassessment/xblock/openassessmentblock.py | 43 ++++++++++++++- .../test/data/assessment_steps_reordered.xml | 49 ++++++++++++++++++ .../xblock/test/test_openassessment.py | 26 ++++++++-- 8 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 openassessment/xblock/test/data/assessment_steps_reordered.xml diff --git a/openassessment/conf/locale/en/LC_MESSAGES/django.po b/openassessment/conf/locale/en/LC_MESSAGES/django.po index 64c9e41bd0..53f5fb7dca 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 13:27+0000\n" +"POT-Creation-Date: 2023-10-24 17:18+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po index 9ad8259f99..512756348c 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 13:27+0000\n" +"POT-Creation-Date: 2023-10-24 17:18+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/django.po b/openassessment/conf/locale/eo/LC_MESSAGES/django.po index 1649b6a72a..113dc5016e 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 13:27+0000\n" +"POT-Creation-Date: 2023-10-24 17:18+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po index 6486d5fa68..67dbe069eb 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 13:27+0000\n" +"POT-Creation-Date: 2023-10-24 17:18+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/es_AR/LC_MESSAGES/django.mo b/openassessment/conf/locale/es_AR/LC_MESSAGES/django.mo index 7aa7a1be49459ef314937c1ddc22eb566fee7220..7142d36ae5c5749d152131f0358915a981eba4b0 100644 GIT binary patch delta 2782 zcmZwITWl0n9LMof+6skAxk)KrINT}<6j5%1a%&3;xD+iE5!C7Kfv)cEEHkrQV$248 zQ3Hu#DJ1p9CX(1#eOZVxF~Mkj@Is=-m>7+cU^J2#6Qc$%M8Ch?sV0Pz{`YfccIM3g z{Lh)~m6d1K6~CEO*KcT#5;qZzwZ;_j?|MFHmq!~j7XQE-ux^YoQ*b)!co9yc%2^g8Jz}Be2IGIMdZ)?82bzA`@e7|)^l(p-ii~kJwD!! zx_>{;z=NoSPNBv-jR)}!)OD@QYK5k{fKEFn9PYp&>_9WFdSNGOfX%21b)#mqAC+mx2XRh#}fyXlK@i-NA-CX=0SK|a7^Cexg42#OJgN_F3L9NYhRK^)pLPxNYar}Kh zvUcV)D#79S{8{AByw8We{~R^$SNJ$yK#jkS58bz|iTWq#?Bc{G9KvDz6<6XQ>2Alb zQJLRKy;Z4p)B_Tz&9)siqilTsDP)<=Gx7POIEUi_dGW;F&poQ#Eo@v&h_Sg>8uKxnpRONoa6IjE6_S#9* zxI;*Vi{>mHmfO68D$OU=FU*&yfxkoT`hRc+)^bv7Hyd@|Jk)?IP$lg^iwT@nL!wAg z%yHI1*S(75WX@o%YIB~BO7&^%_o#vXLd~$Ah1Y|oqDtM0`hFqmzU8O~Y(Y(+7xmUW zi3c!5-G2#r0nDHH05-6Zy0tbvbbi8N)S3)X$0S}vZKjP(TLV0XO29{!&m2I#_s8P% z1E@_qh${6kYU$45X}p9={6$+$WB`l0VTcZu;^(m1G#iy%RII!nTR5-;37SR3Nh8!W);EG zRho9Xeg|$P*q4=eeI~9Z+6k@iV&ZzD^23D>5xWSrd#jj47o7(QZ6vjMRZJ&79QQ|< zOJ_lRump9l)_0`cL1%4g|LEqHd+6OoXmM{N_7G~*N`s?Ynzne|Zl`_Fg?T?0y0Bax zeX^#Qi(Fu%K4dN7N#1S@T+%Nuo_J5qgn)V%To`#_HTiOK z($Z1I`*Ts?rwU1DGko!1*-0p+?2~;i@JE&)#T9u<$r@-0_7|MZyC9p6(!qO!p-p&Hoxg04}i|#z7<8tw2x^8NyS=z-uvEIJGDUYmjx@tmRknBqzs7#1u yNV312EnS*yw_0b@Ic^M9hf3i+O_L21d8)*<$6?h*R))&x;gyw02c@2yTmJ=E^{{XN delta 2035 zcmYM#TWAzl9LMqhCRYi&&9HO6Yx)Ju#;d{B&tmn5*k^eGIj ziWF=s9YsY^&{E>%$qj8E6bT}>2o@1<52h3v1*HulzIZ{uzuBW6_CKF9b7sz*^FL?U z-g&QTy#8qTpix?gkBEOW%sf2z0S8J?#4HO>V*&Q!NcPCLH%efD^!4BehJb}g7hr{u{J0C6bc>NP40xKP40b>kM)gKemcbfISAqh5Rl`Pl_`eifCGdl`Z<+8?4i{vS8s zQ`8HZxJl2oVk5R;175&$7|A35tEu#Iw?>@BL8&Q5y|@Cksiq)(TD`lz3RyK<=dQP6 z8RtpVKn`Ir5oZtn9O6Bw{#!_gmbNuY{>M=Hh709*0=33huoUm02Jiwaa0FXko3IA8 z`O>8^8#RF4u6@62KY|IapTZda5`Dy1Z2?Gz$nzd0kzwApgP=xOy0h89!D)j3N^8dsQ#~`GTZOk2e3fj{~#5;Aj~i| z@)+uCD8(*JpgK5-Y+O5!%diidFpmxKAGYEqT*=O24)!YsFUH`-Nb+m|`9kfbuIu|B z#tu{p^HHfSMy*vPY9=kH7jHt{mqZftu4wiexY|@cC2E7(`@;gN+7~L?7s^}<;b{h% z?J8mdq0gs|m`o&yw}m7Hv(WisLVJX9*c9S(LaA0MA;t%_^dSz~pemY#GChNsM^HRl z&T%%eg7}!2PVgTTl%*V%YGq|*aK-FP)IRu($aUAWla<6iX zR1&lNzDQxwOlnnx7F%U)8Y}dlM2b@Jp+APg$z(^;f1MRe)o0zv@Mq_aPR+{g&h($< zU-N6D-{&mdys>>t=jNU9C0pB4x1zP7RH7h}k-9yqJu}r9YYO|1$G-OW$IIRTrvA0% diff --git a/openassessment/xblock/openassessmentblock.py b/openassessment/xblock/openassessmentblock.py index 5cf0641964..eb2e506b54 100644 --- a/openassessment/xblock/openassessmentblock.py +++ b/openassessment/xblock/openassessmentblock.py @@ -600,10 +600,12 @@ def student_view(self, context=None): # pylint: disable=unused-argument if model["name"] == "leaderboard": leaderboard_model = model + use_mfe_views = self.mfe_views_enabled and self.mfe_views_supported + # All data we intend to pass to the front end. context_dict = { "leaderboard_modal": leaderboard_model, - "mfe_views": self.mfe_views_enabled, + "mfe_views": use_mfe_views, "prompts": self.prompts, "prompts_type": self.prompts_type, "rubric_assessments": ui_models, @@ -615,6 +617,45 @@ def student_view(self, context=None): # pylint: disable=unused-argument template = get_template("openassessmentblock/base.html") return self._create_fragment(template, context_dict, initialize_js_func='OpenAssessmentBlock') + @property + def uses_default_assessment_order(self): + """ + Determine if our steps have been reordered (omission of steps is fine) + """ + last_step_index = 0 + for assessment_step in self.assessment_steps: + step_index = self.VALID_ASSESSMENT_TYPES.index(assessment_step) + + if step_index < last_step_index: + return False + last_step_index = step_index + + return True + + @property + def mfe_views_supported(self): + """ + Currently, there are some unsupported use-cases for ORA MFE views. + + Unsupported use-cases: + 1) Team assignments + 2) Assignments with reordered assessment steps + + Returns: + - False if we are in one of these unsupported configurations. + - True otherwise. + """ + + # Team assessments are currently unsupported + if self.is_team_assignment(): + return False + + # Assessment step reordering is currently unsupported + if not self.uses_default_assessment_order: + return False + + return True + def ora_blocks_listing_view(self, context=None): """This view is used in the Open Response Assessment tab in the LMS Instructor Dashboard to display all available course ORA blocks. diff --git a/openassessment/xblock/test/data/assessment_steps_reordered.xml b/openassessment/xblock/test/data/assessment_steps_reordered.xml new file mode 100644 index 0000000000..2430415926 --- /dev/null +++ b/openassessment/xblock/test/data/assessment_steps_reordered.xml @@ -0,0 +1,49 @@ + + Open Assessment Test + + + Given the state of the world today, what do you think should be done to combat poverty? + + + Given the state of the world today, what do you think should be done to combat pollution? + + + + + 𝓒𝓸𝓷𝓬𝓲𝓼𝓮 + How concise is it? + + + + + + Form + How well-formed is it? + + + + + + + + + + diff --git a/openassessment/xblock/test/test_openassessment.py b/openassessment/xblock/test/test_openassessment.py index 86e3ebc17f..9d8f7ff26d 100644 --- a/openassessment/xblock/test/test_openassessment.py +++ b/openassessment/xblock/test/test_openassessment.py @@ -67,7 +67,7 @@ def assert_is_closed( @ddt.ddt class TestOpenAssessment(XBlockHandlerTestCase): - """Test Open Asessessment Xblock functionality""" + """Test Open Assessment XBlock functionality""" TIME_ZONE_FN_PATH = 'openassessment.xblock.utils.user_data.get_user_preferences' @@ -194,7 +194,7 @@ def test__create_ui_models__leaderboard(self, xblock): @scenario('data/basic_scenario.xml') def test__create_ui_models__no_leaderboard_if_teams_enabled(self, xblock): - # do not show leaderboard in teams ORAS, even if leaderboard_show is set. + # do not show leaderboard in teams ORAs, even if leaderboard_show is set. xblock.leaderboard_show = 10 xblock.teams_enabled = True models = xblock._create_ui_models() # pylint: disable=protected-access @@ -366,7 +366,7 @@ def test_load_student_view_with_dates(self, time_zone, expected_date): def _set_up_start_date(self, start_date): """ - Helper function to set up start date for xblocks + Helper function to set up start date for XBlocks """ xblock = self.load_scenario('data/basic_scenario.xml') xblock.start = start_date @@ -386,7 +386,7 @@ def _set_up_days_early_for_beta(self, xblock, days_early): def _set_up_end_date(self, end_date): """ - Helper function to set up end date for xblocks + Helper function to set up end date for XBlocks """ xblock = self.load_scenario('data/basic_scenario.xml') xblock.due = end_date @@ -705,6 +705,24 @@ def test_custom_file_upload_loads_file_allow_list(self, xblock): """ self.assertEqual(xblock.white_listed_file_types, ["pdf"]) + @ddt.data(True, False) + @scenario('data/basic_scenario.xml') + def test_mfe_views_supported__teams(self, xblock, mock_teams_assignment): + # Given I'm on / not on a team assignment + xblock.is_team_assignment = Mock(return_value=mock_teams_assignment) + + # When I see if MFE views are supported + # Then they are unsupported for team assignments + expected_supported = not mock_teams_assignment + self.assertEqual(xblock.mfe_views_supported, expected_supported) + + @scenario('data/assessment_steps_reordered.xml') + def test_mfe_views_supported__rearranged_steps(self, xblock): + # Given this ORA has rearranged our assessment steps + # When I see if MFE views are supported + # Then they are unsupported for team assignments + self.assertFalse(xblock.mfe_views_supported) + class TestDates(XBlockHandlerTestCase): """ Test Assessment Dates. """ From f990a2b0faec50fb98e9ad1a469febbeb4d8168d Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Wed, 25 Oct 2023 12:22:55 -0400 Subject: [PATCH 18/27] feat: refactor legacy assessment actions and add assessment mfe bff handler (#2074) * refactor: legacy peer assessment handler and api action * refactor: legacy self assessment api handler * refactor: legacy staff assessment handler and api action * refactor: legacy student training handler and api action * refactor: legacy ui mixins folder structure * refactor: peer review uuid matching * feat: mfe handler to submit assessment * test: add tests and style cleanup for mfe assessment handler * feat: get_active_assessment peer api function * feat: auto-pull peer unless jumping --- openassessment/assessment/api/peer.py | 30 +++ openassessment/assessment/test/test_peer.py | 99 ++++++++++ .../conf/locale/en/LC_MESSAGES/django.po | 6 +- .../conf/locale/en/LC_MESSAGES/djangojs.po | 2 +- .../conf/locale/eo/LC_MESSAGES/django.mo | Bin 136705 -> 136524 bytes .../conf/locale/eo/LC_MESSAGES/django.po | 7 +- .../conf/locale/eo/LC_MESSAGES/djangojs.po | 2 +- .../staffgrader/staff_grader_mixin.py | 29 ++- .../tests/test_staff_grader_mixin.py | 63 ++++-- .../xblock/apis/assessments/errors.py | 17 ++ .../apis/assessments/peer_assessment_api.py | 122 ++++++++++++ .../apis/assessments/self_assessment_api.py | 78 +++++++- .../apis/assessments/staff_assessment_api.py | 134 ++++++++++--- .../apis/assessments/student_training_api.py | 60 +++++- openassessment/xblock/apis/workflow_api.py | 2 +- openassessment/xblock/test/test_peer.py | 12 +- openassessment/xblock/test/test_self.py | 5 +- openassessment/xblock/test/test_staff.py | 4 +- openassessment/xblock/test/test_submission.py | 6 +- .../xblock/ui_mixins/legacy/handlers_mixin.py | 183 ++++++++++++++++-- .../legacy/peer_assessments/actions.py | 134 ------------- .../legacy/self_assessments/__init__.py | 0 .../legacy/self_assessments/actions.py | 75 ------- .../legacy/{submissions => }/serializers.py | 0 .../legacy/staff_assessments/__init__.py | 0 .../legacy/staff_assessments/actions.py | 101 ---------- .../legacy/student_training/__init__.py | 0 .../legacy/student_training/actions.py | 88 --------- .../ui_mixins/legacy/submissions/__init__.py | 0 .../{peer_assessments => views}/__init__.py | 0 .../views.py => views/peer.py} | 0 .../views.py => views/self.py} | 0 .../views.py => views/staff.py} | 0 .../views.py => views/submission.py} | 0 .../views.py => views/training.py} | 0 .../xblock/ui_mixins/legacy/views_mixin.py | 10 +- .../ui_mixins/mfe/assessment_serializers.py | 10 + .../ui_mixins/mfe/constants/error_codes.py | 2 + .../mfe/constants/handler_suffixes.py | 2 + openassessment/xblock/ui_mixins/mfe/mixin.py | 75 ++++++- .../ui_mixins/mfe/page_context_serializer.py | 8 +- .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 152 ++++++++++++++- .../mfe/test_page_context_serializer.py | 49 ++++- 43 files changed, 1065 insertions(+), 502 deletions(-) create mode 100644 openassessment/xblock/apis/assessments/errors.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/peer_assessments/actions.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/self_assessments/__init__.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/self_assessments/actions.py rename openassessment/xblock/ui_mixins/legacy/{submissions => }/serializers.py (100%) delete mode 100644 openassessment/xblock/ui_mixins/legacy/staff_assessments/__init__.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/staff_assessments/actions.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/student_training/__init__.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/student_training/actions.py delete mode 100644 openassessment/xblock/ui_mixins/legacy/submissions/__init__.py rename openassessment/xblock/ui_mixins/legacy/{peer_assessments => views}/__init__.py (100%) rename openassessment/xblock/ui_mixins/legacy/{peer_assessments/views.py => views/peer.py} (100%) rename openassessment/xblock/ui_mixins/legacy/{self_assessments/views.py => views/self.py} (100%) rename openassessment/xblock/ui_mixins/legacy/{staff_assessments/views.py => views/staff.py} (100%) rename openassessment/xblock/ui_mixins/legacy/{submissions/views.py => views/submission.py} (100%) rename openassessment/xblock/ui_mixins/legacy/{student_training/views.py => views/training.py} (100%) diff --git a/openassessment/assessment/api/peer.py b/openassessment/assessment/api/peer.py index c2af56bb6b..a2947a985e 100644 --- a/openassessment/assessment/api/peer.py +++ b/openassessment/assessment/api/peer.py @@ -687,6 +687,36 @@ def get_submitted_assessments(submission_uuid, limit=None): raise PeerAssessmentInternalError(error_message) from ex +def get_active_assessment_submission(submission_uuid): + """ + Gets the current active submission being assessed, or None if there is + no active assessment. This will not find a new submission to assess, for + that, call `get_submission_to_assess`. + """ + workflow = PeerWorkflow.get_by_submission_uuid(submission_uuid) + + if not workflow: + raise PeerAssessmentWorkflowError( + "A Peer Assessment Workflow does not exist for the student " + "with submission UUID {}".format(submission_uuid) + ) + + if workflow.is_cancelled: + return None + + active_assessment = workflow.find_active_assessments() + if not active_assessment: + return None + + try: + return sub_api.get_submission(active_assessment.submission_uuid) + except sub_api.SubmissionNotFoundError as ex: + error_message = "Could not find a submission with the uuid %s for student %s in the peer workflow." + error_message_args = (active_assessment.submission_uuid, workflow.student_id) + logger.exception(error_message, error_message_args[0], error_message_args[1]) + raise PeerAssessmentWorkflowError(error_message % error_message_args) from ex + + def get_submission_to_assess(submission_uuid, graded_by, peek=False): """Get a submission to peer evaluate. diff --git a/openassessment/assessment/test/test_peer.py b/openassessment/assessment/test/test_peer.py index c9a880bbfd..741e8605b5 100644 --- a/openassessment/assessment/test/test_peer.py +++ b/openassessment/assessment/test/test_peer.py @@ -13,6 +13,7 @@ from submissions import api as sub_api from openassessment.assessment.api import peer as peer_api +from openassessment.assessment.errors.peer import PeerAssessmentWorkflowError from openassessment.assessment.models import ( Assessment, AssessmentFeedback, @@ -2054,6 +2055,104 @@ def test_flexible_peer_grading_enabled(self, block_setting, course_override, exp ) assert result == expected_flexible + def test_get_active_assessment(self): + """ + Test for behavior of get_active_assessment + """ + # Three learners and submissions + alice_sub, _ = self._create_student_and_submission('alice', 'alice sub', steps=['peer']) + bob_sub, _ = self._create_student_and_submission('bob', 'bob sub', steps=['peer']) + carlos_sub, _ = self._create_student_and_submission('carlos', 'carlos sub', steps=['peer']) + + # No one has any active assessment currently + assert peer_api.get_active_assessment_submission(alice_sub['uuid']) is None + assert peer_api.get_active_assessment_submission(bob_sub['uuid']) is None + assert peer_api.get_active_assessment_submission(carlos_sub['uuid']) is None + + # Alice requests a peer to grade and is assigned bob + sub = peer_api.get_submission_to_assess(alice_sub['uuid'], 3) + assert sub['uuid'] == bob_sub['uuid'] + + # Alice's active assessment is now Bob, and Bob is unaffected + assert peer_api.get_active_assessment_submission(alice_sub['uuid'])['uuid'] == bob_sub['uuid'] + assert peer_api.get_active_assessment_submission(bob_sub['uuid']) is None + + # Alice assesses Bob and then should have no active assessment + peer_api.create_assessment( + alice_sub['uuid'], + 'alice', + ASSESSMENT_DICT['options_selected'], + ASSESSMENT_DICT['criterion_feedback'], + ASSESSMENT_DICT['overall_feedback'], + RUBRIC_DICT, + 3 + ) + assert peer_api.get_active_assessment_submission(alice_sub['uuid']) is None + + # Alice requests a new peer to assess and gets Carlos, who is now her active assessment + sub = peer_api.get_submission_to_assess(alice_sub['uuid'], 3) + assert sub['uuid'] == carlos_sub['uuid'] + assert peer_api.get_active_assessment_submission(alice_sub['uuid'])['uuid'] == carlos_sub['uuid'] + + # Assess Carlos, active assessment is now None + peer_api.create_assessment( + alice_sub['uuid'], + 'alice', + ASSESSMENT_DICT['options_selected'], + ASSESSMENT_DICT['criterion_feedback'], + ASSESSMENT_DICT['overall_feedback'], + RUBRIC_DICT, + 3 + ) + assert peer_api.get_active_assessment_submission(alice_sub['uuid']) is None + + # There are no more peers to assess, and the returned None does not affect the active assessment + assert peer_api.get_submission_to_assess(alice_sub['uuid'], 3) is None + assert peer_api.get_active_assessment_submission(alice_sub['uuid']) is None + + def test_get_active_assessment_cancelled(self): + # Two learners and submissions + alice_sub, _ = self._create_student_and_submission('alice', 'alice sub', steps=['peer']) + bob_sub, _ = self._create_student_and_submission('bob', 'bob sub', steps=['peer']) + + # Alice requests a peer to grade and is assigned bob + sub = peer_api.get_submission_to_assess(alice_sub['uuid'], 3) + assert sub['uuid'] == bob_sub['uuid'] + + # Alice is then cancelled, so then her active assessment is None + workflow_api.cancel_workflow( + alice_sub['uuid'], "cancel", "1", STEP_REQUIREMENTS, COURSE_SETTINGS + ) + assert peer_api.get_active_assessment_submission(alice_sub['uuid']) is None + + def test_get_active_assessment_nonexistant(self): + # If we request the active assessment submission for a nonexistant workflow, + # raise an error + with self.assertRaises(PeerAssessmentWorkflowError): + peer_api.get_active_assessment_submission('nonexistant-uuid') + + def test_get_active_assessment_error(self): + # Two learners and submissions + alice_sub, _ = self._create_student_and_submission('alice', 'alice sub', steps=['peer']) + bob_sub, bob_item = self._create_student_and_submission('bob', 'bob sub', steps=['peer']) + + # Alice requests a peer to grade and is assigned bob + sub = peer_api.get_submission_to_assess(alice_sub['uuid'], 3) + assert sub['uuid'] == bob_sub['uuid'] + + # Delete bob's submission to induce an error + sub_api.reset_score( + bob_item['student_id'], + bob_item['course_id'], + bob_item['item_id'], + clear_state=True, + emit_signal=False + ) + + # Expected error is raised + with self.assertRaises(PeerAssessmentWorkflowError): + peer_api.get_active_assessment_submission(alice_sub['uuid']) + class PeerWorkflowTest(CacheResetTest): """ diff --git a/openassessment/conf/locale/en/LC_MESSAGES/django.po b/openassessment/conf/locale/en/LC_MESSAGES/django.po index 53f5fb7dca..cc454b3a33 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/django.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 17:18+0000\n" +"POT-Creation-Date: 2023-10-25 14:38+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" @@ -2434,10 +2434,6 @@ msgstr "" msgid "Successfully updated OpenAssessment XBlock" msgstr "" -#: xblock/ui_mixins/legacy/submissions/file_actions.py:71 -msgid "Files metadata could not be saved." -msgstr "" - #: xblock/utils/data_conversion.py:315 msgid "You must provide options selected in the assessment." msgstr "" diff --git a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po index 512756348c..561a792a25 100644 --- a/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/en/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 17:18+0000\n" +"POT-Creation-Date: 2023-10-25 14:38+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/django.mo b/openassessment/conf/locale/eo/LC_MESSAGES/django.mo index 6e62cc5d7628e3f23441c8dd49f8e2e5e60eb2b6..b29b55f0fc7a92cabe748850f3d3be0a48af9e21 100644 GIT binary patch delta 10408 zcmY+}2V51$7Qo?I6hXy;9Z>`UMO3hh1q;|kMFGVUd%+GOcD?rAI~FXl#S*b#OEhYt zQKPXC6HDy9VJvwuw!Ht@nfQGB^YG1?-MeLWW_Is&+*a4qn_V5(^JHG6SZ-NL6+ypT zN{w?;s*IP^Dpf8(sX?qOkDaMsS4yez)H|0^>M2ge5tvj~sd)SY$6=QsKF9WV@I86! z^4h2hN(HdL$cjqsR?4A*iTFirRtHpgpy+f%87n74zH!udXBGNQ<%?+Wwp6FEL%sZ0eAr~Vcoh) zwa3C?)Zq~1pK2VgR85?TSMenF#q}IjPSm}=ZlRv|nmnq3QunY?L#3W!P$Q)tb9_~# zu~IM5rHN7*_!j?zkD4mQw(2IAYjH&Z%{VA|U~{Fo3u-WC#}v$rn=wCbM>*kR7>GVC zl*)z?#x^MRUC~jH!Ym3oaJ|`Jm+=thrT!%P;Wd;ibc*CEZ~#`oz4!tjV7d2`)8pdii)h*4%4wa`eR6I-BcaXnS2_`3C}V4 z3X~nLMfv;|q@SuZQ=fs-0)LtHZf%r0OiX@2XbkrR8Dk9xnghh#PaBl%}m}2<-|u~K^%wqF&T@YV><a!?Ua?N-jtCK%R zx%YwesG-;bOXH6ijIVGG`gYLkcVPf|=`WNjj?pNcbtuY-tUZvV-=g6yLHO$^iUwM6$D{PPQ zxdAAhdMdi$dX!tR4W)(mptRWeUS|A1prQm7uTf?u&p5q711v_~0j23jVJ4h{jd2Fb z6{bd-Xm<_h!aPn`Ei&vHVDAg2~V-0+O zazNj{O5Mkrm__n_x&;DJb{vXw;Kt~RZ7>u&qqJy>S-;&up)M5%u@?S=(v-FO>nmu9 z(g|CmG;L3m31uwaz(p8{Ndxq}u^MxbA4R#x=Zv?}h5R*E#P=vC>L@o*Us+9*D;b7z zK!2l7wN=Z{RyE=l^iUmH7fYKsuPxF7eA zXJlaF1X{%6Hciw|y@HeUfd^nH>r+uqJOdA5aqgE~@hv=zZc}t0bDW`2p9-(3`b4^; zT*+4`XZQl8Nh?p&eV{FRl8?lqxWv?_VHo*uCNDf)AFw8tq`nsh;2iuG_u*j~|4B1+ zFRwCFcdoX`KQ)X$3(U5#8QZuEr7y(H(a(T*l$QGvqwxfG#-ek% zC>(>`Fkl`RA>)501t*%)b-uo**%#<}zyrP6&a_1P0?hl+K)=t7?ydSdinZ$rR+Fl7hu?FUpRuU=4hY#jxBWeJdi-hkUScG0OJ) zP@4Jz%B^^djWBev9?p|dZuJtB_1DlLoyB{Jp20dA7o(i<&&H3~iacnk{t7h?U1_oR zSebg~WqSD4z$o&r_$%%~xzbt7b>Dh~)yRYB!Idy>1??||l~jb_1c7SFPh}d zaS;B61F_Ey`4DNI+_*dZ_vXwo*vho^`$rKeC`(Bg7|#X zt@IE4+d<(mAJ|Uqrc896R9?q0d^cx|8GC6;e1Cv>9n%ldi`o9GqckCT)G=P&+0oP! zoCL<6ly9}nil=B*+=~Y><|p0jgJm=H_Pw6#?N|Q6^vwaT zzEEm42Oj!T=Y{^GZ{co~PFnIWJ=K4K)yW5An)HV46edv7;|&MGM@G-Tc~K;9hH}r- zF%*N}>h1btF!?HMfoE|H7JH|gJO#Ons>6FO2Hii7tALB}#=c!LLxQM0dl6OLRsI9>me1uK0c2S3=dQq5B)UxO5SNH{a zZZEyz0E{R90c&FAVwQcvgN!S14fV%SZe^UerM|<5C@r$d$FhH0s#x4o&$*D}_$~E& zO6XgW=qPEaAym9Uxiwj|Kvq1$)|jun?qq$jFZq6qL;nhv{rH@X zvE(mNI#bh%mi?YT4`mdcLuq0s#;~+pbCga!1C#J3&XC!-HG@BrirXl|sA3hp;RKWk z-Y^*zR62{3ry-2|iYc&bVqj%l?V>CQ4IIYH!(JEYdNY{0Vl!;0}5woQD%Qfx9?` z`nb-P{aF74Wxw6JIP^VU-9*$3Ad+1wH1-~J`g`;t$qo<|zQ1I-f4{!milMjj0O|}DvlV31K^w#(M zIPRxDZy!tT#WN@^IH|9mYPX|w-b+Tme)@#tu{QN-SO*<{QjlR+rN4GE$_Brp4;C0; zsc9I3VKn7Yls@A;NFT5$N=q~}&O~`?o<|uaZ4xbY1n=MqTt8Tkwy-2yhk8drCXn4j zEY%j@qCCx_hjKtn#m@K&<>?kZ%(8zU*oZQd{f#oAY#pvGKEkr!f|p`X>JQ^AEICp) zeHtDhPZ-55$;9|8GupDB)4z??XEt-3rM_l^`r|DgwM@k*>j)e{{xdpaDKuVasoA&| z$4X1}i4H?~AJ~Ii@Fi}< zlw`*LObQK_S@!?Yq~jX$Ny{y@8cVLwWebCsoz($u%{ z7_R@)Qg^ZMMkX?h+@f#o^sn`S!?){+>dAJ-znuB(RG!;x=(oeNf7!UZo9DFbAkDJh z(*yQfDwXZ7<2Iagz_Qozb21+w=Ow5-#ZZ!6)5P zw^)A_yRrX+zghNg$3BU zUqKSeyb%0QKgFh@H1$L5id`S+dwC4y@f`P9_wLI$j6C{@Zn-lk+t+)l-=sF;MtT01 ze5S|yS!~P(V>0x;K7rEdhCkPx#`h0BgZ+f^3KsW5pRmhI{f?K6`=~GT%CdiQxrfsE z*1guxlIwrzTRh~Aeg}Mm$qqJ1``c3A^T8G$bZ5%@QTP7ua0&ID|ItsyHz=cHo^rCs ze?`m5eql*KnGe=s9lVXwg1$~p_KU|5lv{BMrQRu%liJO3W6*Joifk@U_RHrvlpV#m zI@wpS07sLz%Ic(E^MP|Xi2PU%Cv}@VB&U=8`t6y=Ny&b08aL#1vfqOH<#Vzpwlevh zl*M{RvAs;@?uuLavPAuD&O3 zQ1-ypn3G^W`@cmx?k}e1J?@qJ@6SdDN!DW=Mw<20}YbqyxkG~R*ZX~W0WI024n-2$~k15MKrU83dr?LBo z6lMB$W!+trnY8I=pP5RT`Nkfuf3i;I33<*eCzzk)StHl47nxRN$xT#bWly3R<^EF1 zGL~GHq9`w`J?xAZ3>+%k<8$Jo+0LxCzfGl*_)^aUQZb|3%SZm+l;itRkxpEqViwVe zav3a$FHn{tgnUm-r0x|qz%Nl2PuZT3Win=9F`|j7OQ(F4@(khxWm#@eo{P8scl~y~ z{o+xJmF0*lRAon5rr}{zE=S&+$VF5#bzfsRk&75d$YVB~s6&({mxV`#DvrB}nUot7 zjt3;ODNHAL6xctn@xr5yP~Q&ayPPc7h}Pt?EWwo+XlD#hl;=4QQFVf7Pc$;?{=%U| z3U&8TX4GWL?#SX$y-8%bPZTBA5=qpJ!;3^Vv!0^;$UTbfBw?9Bgt2}D!IN7RAVv^> z+iUshg|aVYH>^PPBV>v{hg~sN?*C6Db%=k=hq7QpQ%;~>mI=f=yTmC|ca`{om_%J+ z;y6*!tQW=-@-&nmE#%c}l-W;LTtNIt-AN)ycD9~^Gj1aCQvS4%PbZm#pD&xq-(`o?{3FS-j8>OX4rYR?4S|XM`-Js5?Z+ zl0fm3)ZUtkX|_S9~hboU9*YJ}cFiiAchONG5u)t|{&$>QgR8bfheci`;`2RAj?} zn2C_3s!__3l(Q16iA3_L#IKac5DAo{u{#k#`7qIz^0z3<4vpGPU2n=?;3h0hETSyO z|FmqB4-x~Z=|W7Qe2ut5$kGMN68(vKrmiOLV%^VpkT^{gA?6aZh+f3!O9_%#>R#(g zhy6m4m82VSotVhVrFx}WWrFQSGyJW;d!8b#+O6h-1WJ zVw=4k*MEmZmOh$Ke_K#G!$uP^1Z$f$1<=`)gy5JyYJ#wznxSB$iVSAS#)4yC}y{o`e4`BTZpGrkQdf zY(PvQ9GOk!18G|BrtJLB)kAMZY%`|T;{Tbz@=a(3LwpM9}n`N>ks z6D#FYYO<43^-D^vQq9UMHJo+LF_QX&eo9TEzCp{YHEn!#rOLCv0X3A`qm)A}sA(5eSS_W7u;K%L;0y5qN~K``Kz4*5u#@blj#8~K z1Bak{T}~J$;sDHEPpO^kXAm|a_i8|n(I_WcsG)WNe#!BbTO*|wvSJsm$Iu`Sf=}@} zhBsC!0;>lrm5Fnae<~`3R>Jjo6Ypa@9^$BSqJE*eg(l!T^7t^N9%5uurCwlIGmgRW zRn6u~y+N-QO1;GVEtUEmEiRL7)qAwKqM+8?2J+xG>>OvKEAGYYcpN?O6v_$T#tK-c ztx_%+Z5)D9pNNja6uzX82M?JI&Kj>`0qXB#8T<|93X8R)U*I&Xju-GXI<;471inK# zkpUf)Du@%X1g4oFKa?vD#NyZ-Kf@T4k48E16fBIX=z%-Y3mvB@NK-#XxsucLq?v;LRwvwh}7eLB-#f=xv(QBSAH6$h3=rI zjQ>{@ic^s%ik^*rSO}Y-bgl@LFT|q^qwywBMrpa_C_CPSa>a+y8}FmElv5ww+x<~G zcQ8t4?u@lKzKWwz9n-KVUPfA1y+FCw&HJ)3c0{?-%~)2}V+t0aqqyQm<8G7|JA%wP zDo2b`>`Jvlxqx((zP2A7a%Gn(u8L|i{zuQ4u4(AOJuo}2M!8k%jk{2W@zGe?Uz+Yb6*8Q%%mztU&QeZXG$hl1A5pf?Jyc(SJ4%anz%uwPw!+&e7gk}I{$4EdJ%>u5P?{Cv zjcf2T@)Ot|uVEYX8?Kvhj4=siyP3w7n2&rr=EcLt^H_lVmhqLT&ptv_4-Kw)OM8d?mmXu4o9H0 zV10UYXPkvC@IE@eqEIPOPrX?v8x;IpsYV!w?zjcz#15bjUP75C-r_XOKTbD!DoS74 zgf6(pcm$=7oWa6)2@BybAIZA5R}jxv#4KerQTErAd^R@5D_9u|P1H@^1RIdgGoE))2%*9?Nk6sPVk7cJ#w#epsNf`qBG$ou z_zqX%_Q|w}MQ5F&pMD*t>H}{^InXnd6Zhjj9mbw07wkD*siWvx+gxTin z;n)o~lkda6GXDE6P>PPMPN5S`8M08{)36jh4|GCr)`z3??nHFMX(ms>qU5VlT4W!} ziTsGtS6-nfX5%WVpf?u8b{N6&RSX3g7ROMYVp&)U-=OT+W3ir^tDqNoJWB7Lg>oy> zjh9fie~Z%8d6wu~Q45=qk3n}lhM|~=4!KuFmg>$DfdS;H#!Dz?oO_wJ4t5}q#Y8-a z&a_xSDsM96LCf{rw?*e? zw<@)b?@g2W_iG9@$)56sr?@E_oo5HrE>76P8Kd8~G$jTcU>)W?LN8|f2gms?`P>uC zg6t>bG>=?N`CfkA^5{LoZNN8p2FDQBAtYe2?ue z=`(iAWZvdLr|=%8a$}ouMTs|bQ)k?y6{(+ciw?>6YTaXQAb*H-6SeXIFE3L6kokb` zokI5SP;VaT-{;#Ovyv5&Pw0%eId2ZKf+OH@?9T@)kTWrr=z3giqM&+~YXTo!o z6LWFbc^Jz6qOmg0akm_5HH8CI_+i9n`pTxFKY12z|TEkt1AP!7mru$p=dqdGGy56yu!YWq8R@Dd0#TctVUIx2hTa-?=0psx<4#3Fj7LQM*zQ=A@ zxrSvwRHk7=@^dJo!r%anNe3P5gvT`qPQRs~oTIi;oiE@CqD7T_WOUwRSPzXv(Y{EMDH%`KU zR=Shz$5!N_t@UtTh*ilyVt%aL#!_1_2z%i(bVyUSXses*E*2(FZl~{I8p=Jpi*i8E z_R?fbSSZ737RvhbcmQ2GSoVx}5~cG^>1e677|=JHGD`2bNFRNVJEJt+8Z3>OxDd;U4@qy990gOlQQ3)UTIrd*WHJI9!XO~@T(2U+^J9tKgd1?84JGu9id*Uv&9 z>d)c~e1X9<<>(>0$@dS}2h2p-@ke9h5tjY*oQ5(=+(ugJ7%sz=GXA@d(!=c!SkEa7FiV4;#!*(kIqX-#l55<8jmVcEytQL+1j@(==g* zKCy#1j6B~=J#!}EOTPaCWrn;pm%bw7zxX`e+1eSCP&(Bvlq=6fnTq}A>m5(U_T<;G z6INJY*}wH1D4psM$^i2^9RL1{SDmGHF z5j!ro?B9GJa3^{43jJ8EyV6o=K?Qah+m*{>hBO%7Q0Tkji`3tD?n57Rb>bkm_4BXjr>A51b<6%E@>P@xC@xD6qbDd6$%-46y2BSb-qde2)$i&#{tbpvzvG_1 zmw)`M=Ybjz^o6uUnJJH=JUjlt0Ic>9=fa>u= z_k~+1<9*6Y{m`lLtG?IcaWnP)uk?1;kr_-)e63%_O1#l0d=M8>-{!6EWcTqf`SN$V z^M(JWpCu{pxy5qeiht^t!EKmIlg9mJsSN6~|D!w8X-p#@`LF(>hjOx?ira7v^>mhIo%N1f zay!{q&!f}ne}UhTU(B!fv$%jZqM(!gHtgf!WKV4O(PBFm zhyAAGMfQuXu>aGj6g^Guj-`qEY*U@MNW3AJmr_}N*Vr>5(}lg{<};S?CSDVX#Aent zB@zi2Vi0xqfB!v1VIdWt79Ufdi46#u(PWuQxjE5{xKA(u>^I;j{It}dkb{tSh2hkP z66c9zvrS{%#=6_YZ$y@ZimpU|l2e2aQHzivvz2;zA!SaoC!1j?FAvh`WRY7Zi`>(3 zc1i!xY)p9_vC7m5-|<};&a!wB<;ZWMBaA{VLKb;=%(P2PM5a!L;-`g4Ofdo4%M(6b zDQ_aCnhpHSI!VJR%M^an)HOurBo$(E*=BOb zET0oHH8V5YO9yPBi)y5)yF@;VawC%;B=1DI1hzpZoWE@Q3bDv+OVR$n9)2P(Ph2H_rtW)`NvjaCkMcda|FX=(A}BMM zEMIHXa_Z9wd8s^0$o6;4IuFVxh|4Ay63At#jH66>4fY~O3W8N?&XKM@yX z{QFX9Kzv&2uz@VCFw&Gake8ucgSbSzCqGS$rz}%z9R7u}1QMeO`6X16`fmtXc=xcE zw;KC%rQH8v6l4BVd6#lcHolMYZomW3o<=|XXPYXN^P3%3r5r-EBwvOx*v_o`gFK7) zw0uT=KN1U*hy@&9@m{Htup&;vFya{T6}dNYnvl1iS41|-?{ESk%W{qCNxdx3HL5+i z2jy-=8nK)F3T`ypQM4Dw04feplzCj1QiQyz$dXAkA^wqsWenT)F+1o%KFY486XKu5 zP?LXV{KRp-<4-K4;zwL>_Ce~f|LetSDrS&XC;C&C=X?;R5aE>NWz>ndPDqRKmZkC$ zvJ@x2C-xF~sN01_iK_(fH1<*ekD786HIs=p#1Xmww^=d5tUPIN&ToH{4>IO7^<7N9 zn>@qRb;Ux|x5S4;Tgt&^JF|(JWAbA-mdZS4#WWeuL(Ix=sZ681pQuU{Ag@mxCB~93 zC1mMM1QX{Z`G1xiY?q7rf@b^ilmjV$Nt8F+ugA57<8vy{Q@BW^QhtWDiCM%A;$LD3 zk)3td@Gz$1bm9u-r&tYV6P1XjZaKs9~EB^al}yS zx)DE84kcz23&`E@0a1`BMLrlO5{rnu`@|6Fr;UPqQZn^)mti$7&iDz(^ zsh^I~rYzg_B&v|F##@*lM-o%aHWew$QkT3THY4s(o=j|&6=vydws-hb5kYdxtSF2# z%*w$ykh~c7ASzS#Bia$3W}ELQ%TiBc|7}o;+gKloTd*UsopM>?C6P?b)!#3wicmO0 zg)Ci&7UWBalm#2A?v5\n" "Language-Team: openedx-translation \n" @@ -3081,11 +3081,6 @@ msgstr "" "Süççéssfüllý üpdätéd ÖpénÀsséssmént XBlöçk Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: xblock/ui_mixins/legacy/submissions/file_actions.py -msgid "Files metadata could not be saved." -msgstr "" -"Fïlés métädätä çöüld nöt ßé sävéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєт#" - #: xblock/utils/data_conversion.py msgid "You must provide options selected in the assessment." msgstr "" diff --git a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po index 67dbe069eb..9cfeea421e 100644 --- a/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/openassessment/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-ora2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-24 17:18+0000\n" +"POT-Creation-Date: 2023-10-25 14:38+0000\n" "PO-Revision-Date: 2014-06-04 15:41-0400\n" "Last-Translator: Muhammad Ayub khan \n" "Language-Team: openedx-translation \n" diff --git a/openassessment/staffgrader/staff_grader_mixin.py b/openassessment/staffgrader/staff_grader_mixin.py index 38653c83c0..d413b0a4b0 100644 --- a/openassessment/staffgrader/staff_grader_mixin.py +++ b/openassessment/staffgrader/staff_grader_mixin.py @@ -12,7 +12,7 @@ from submissions.api import get_student_ids_by_submission_uuid, get_submission from submissions.errors import SubmissionInternalError, SubmissionNotFoundError, SubmissionRequestError, SubmissionError from submissions.team_api import get_team_ids_by_team_submission_uuid, get_team_submission - +from openassessment.assessment.errors.staff import StaffAssessmentError from openassessment.assessment.models.base import Assessment, AssessmentPart from openassessment.assessment.models.staff import StaffWorkflow, TeamStaffWorkflow from openassessment.data import map_anonymized_ids_to_usernames, OraSubmissionAnswerFactory, VersionNotFoundException @@ -27,6 +27,7 @@ TeamSubmissionListSerializer, ) from openassessment.xblock.staff_area_mixin import require_course_staff +from openassessment.xblock.apis.assessments.staff_assessment_api import do_staff_assessment, do_team_staff_assessment log = logging.getLogger(__name__) @@ -450,9 +451,23 @@ def submit_staff_assessment(self, submission_uuid, data, suffix=''): # pylint: 'msg': String/Empty - error string, if failure occurred } """ - if self.is_team_assignment(): - success, err_msg = self.do_team_staff_assessment(data, team_submission_uuid=submission_uuid) - else: - success, err_msg = self.do_staff_assessment(data) - - return {'success': success, 'msg': err_msg} + try: + args = ( + submission_uuid, + data['options_selected'], + data['criterion_feedback'], + data['overall_feedback'], + data.get('assess_type', 'regrade'), + self.config_data, + self.staff_data, + ) + if self.is_team_assignment(): + do_team_staff_assessment(*args, team_submission_uuid=submission_uuid) + else: + do_staff_assessment(*args) + except StaffAssessmentError: + return { + 'success': False, + 'msg': self.config_data.translate('Your team assessment could not be submitted.') + } + return {'success': True, 'msg': ''} diff --git a/openassessment/staffgrader/tests/test_staff_grader_mixin.py b/openassessment/staffgrader/tests/test_staff_grader_mixin.py index 808514e813..10a112f9ae 100644 --- a/openassessment/staffgrader/tests/test_staff_grader_mixin.py +++ b/openassessment/staffgrader/tests/test_staff_grader_mixin.py @@ -1,16 +1,18 @@ """ Tests for Staff Grader mixin """ +import copy from datetime import timedelta import json from unittest.mock import Mock, patch from uuid import uuid4 from freezegun import freeze_time +from openassessment.assessment.errors.staff import StaffAssessmentError from openassessment.staffgrader.models.submission_lock import SubmissionGradingLock from openassessment.tests.factories import UserFactory -from openassessment.xblock.test.base import XBlockHandlerTestCase, scenario +from openassessment.xblock.test.base import XBlockHandlerTestCase, scenario, STAFF_GOOD_ASSESSMENT @freeze_time("1969-07-20T22:56:00-04:00") @@ -273,37 +275,74 @@ def test_batch_delete_submission_locks(self, xblock): ).exists() @patch('openassessment.staffgrader.staff_grader_mixin.get_submission') + @patch('openassessment.staffgrader.staff_grader_mixin.do_staff_assessment') @scenario('data/basic_scenario.xml', user_id="staff") - def test_submit_staff_assessment(self, xblock, _): + def test_submit_staff_assessment(self, xblock, mock_do_assessment, _): """Simple connectivity and routing test for submit staff assessment""" - xblock.xmodule_runtime = Mock(user_is_staff=True) + xblock.xmodule_runtime = Mock(user_is_staff=True, anonymous_student_id=self.staff_user_id) xblock.is_team_assignment = Mock(return_value=False) - xblock.do_staff_assessment = Mock(return_value=(True, '')) - request_data = {'submission_uuid': self.test_submission_uuid, 'foo': 'bar'} + request_data = copy.deepcopy(STAFF_GOOD_ASSESSMENT) + request_data['submission_uuid'] = self.test_submission_uuid response = self.request(xblock, 'submit_staff_assessment', json.dumps(request_data), response_format='json') - xblock.do_staff_assessment.assert_called_once_with(request_data) + mock_do_assessment.assert_called_once() + assert len(mock_do_assessment.call_args.args) == 7 + assert mock_do_assessment.call_args.args[0:5] == ( + self.test_submission_uuid, + request_data['options_selected'], + request_data['criterion_feedback'], + request_data['overall_feedback'], + request_data['assess_type'], + ) + assert not mock_do_assessment.call_args.kwargs + self.assertDictEqual(response, { 'success': True, 'msg': '' }) @patch('openassessment.staffgrader.staff_grader_mixin.get_team_submission') + @patch('openassessment.staffgrader.staff_grader_mixin.do_team_staff_assessment') @scenario('data/team_submission.xml', user_id="staff") - def test_submit_team_staff_assessment(self, xblock, _): + def test_submit_team_staff_assessment(self, xblock, mock_do_assessment, _): """Simple connectivity and routing test for submit team staff assessment""" - xblock.xmodule_runtime = Mock(user_is_staff=True) + xblock.xmodule_runtime = Mock(user_is_staff=True, anonymous_student_id=self.staff_user_id) xblock.is_team_assignment = Mock(return_value=True) - xblock.do_team_staff_assessment = Mock(return_value=(True, '')) - request_data = {'submission_uuid': self.test_team_submission_uuid, 'foo': 'bar'} + request_data = copy.deepcopy(STAFF_GOOD_ASSESSMENT) + request_data['submission_uuid'] = self.test_team_submission_uuid response = self.request(xblock, 'submit_staff_assessment', json.dumps(request_data), response_format='json') - xblock.do_team_staff_assessment.assert_called_once_with( - request_data, team_submission_uuid=self.test_team_submission_uuid + mock_do_assessment.assert_called_once() + assert len(mock_do_assessment.call_args.args) == 7 + assert mock_do_assessment.call_args.args[0:5] == ( + self.test_team_submission_uuid, + request_data['options_selected'], + request_data['criterion_feedback'], + request_data['overall_feedback'], + request_data['assess_type'], ) + assert mock_do_assessment.call_args.kwargs['team_submission_uuid'] == self.test_team_submission_uuid + self.assertDictEqual(response, { 'success': True, 'msg': '' }) + + @patch('openassessment.staffgrader.staff_grader_mixin.get_submission') + @patch('openassessment.staffgrader.staff_grader_mixin.do_staff_assessment') + @scenario('data/basic_scenario.xml', user_id="staff") + def test_submit_staff_assessment__error(self, xblock, mock_do_assessment, _): + """Error case for submit_staff_assessment""" + xblock.xmodule_runtime = Mock(user_is_staff=True, anonymous_student_id=self.staff_user_id) + xblock.is_team_assignment = Mock(return_value=False) + mock_do_assessment.side_effect = StaffAssessmentError() + + request_data = copy.deepcopy(STAFF_GOOD_ASSESSMENT) + request_data['submission_uuid'] = self.test_submission_uuid + response = self.request(xblock, 'submit_staff_assessment', json.dumps(request_data), response_format='json') + self.assertDictEqual(response, { + 'success': False, + 'msg': 'Your team assessment could not be submitted.' + }) diff --git a/openassessment/xblock/apis/assessments/errors.py b/openassessment/xblock/apis/assessments/errors.py new file mode 100644 index 0000000000..ac3578f242 --- /dev/null +++ b/openassessment/xblock/apis/assessments/errors.py @@ -0,0 +1,17 @@ +""" +Assessment API Errors +""" + +from openassessment.assessment.errors import AssessmentError + + +class InvalidStateToAssess(AssessmentError): + pass + + +class ReviewerMustHaveSubmittedException(InvalidStateToAssess): + pass + + +class ServerClientUUIDMismatchException(AssessmentError): + pass diff --git a/openassessment/xblock/apis/assessments/peer_assessment_api.py b/openassessment/xblock/apis/assessments/peer_assessment_api.py index c920b78b00..0dcef3c9a7 100644 --- a/openassessment/xblock/apis/assessments/peer_assessment_api.py +++ b/openassessment/xblock/apis/assessments/peer_assessment_api.py @@ -5,8 +5,18 @@ from openassessment.assessment.errors import PeerAssessmentWorkflowError from openassessment.assessment.api import peer as peer_api +from openassessment.assessment.errors.peer import PeerAssessmentInternalError, PeerAssessmentRequestError +from openassessment.workflow.errors import AssessmentWorkflowError +from openassessment.xblock.apis.assessments.errors import ( + ReviewerMustHaveSubmittedException, + ServerClientUUIDMismatchException, +) from openassessment.xblock.utils.data_conversion import create_submission_dict from openassessment.xblock.apis.step_data_api import StepDataAPI +from openassessment.xblock.utils.data_conversion import ( + clean_criterion_feedback, + create_rubric_dict, +) logger = logging.getLogger(__name__) @@ -90,6 +100,10 @@ def is_skipped(self): def student_item(self): return self.config_data.student_item_dict + @property + def must_be_graded_by(self): + return self.assessment['must_be_graded_by'] + def format_submission_for_publish(self, peer_submission): student_item_dict = self.config_data.student_item_dict return { @@ -105,6 +119,15 @@ def get_submission_dict(self, peer_sub): def get_download_urls(self, peer_sub): return self._block.get_download_urls_from_submission(peer_sub) + def get_active_assessment_submission(self): + try: + return peer_api.get_active_assessment_submission( + self.submission_uuid + ) + except PeerAssessmentWorkflowError as err: + logger.exception(err) + return None + def get_peer_submission(self): peer_submission = False try: @@ -118,3 +141,102 @@ def get_peer_submission(self): except PeerAssessmentWorkflowError as err: logger.exception(err) return peer_submission + + def assert_assessed_submission_uuid_matches(self, uuid_client): + submission = self.get_peer_submission() or {} + uuid_server = submission.get("uuid", None) + + if uuid_server != uuid_client: + logger.warning( + "Irrelevant assessment submission: expected '%s', got '%s'", + uuid_server, + uuid_client, + ) + raise ServerClientUUIDMismatchException() + + +def peer_assess( + options_selected, + overall_feedback, + criterion_feedback, + config_data, + workflow_data, + peer_step_data, + assessed_submission_uuid=None, +): + """Place a peer assessment into OpenAssessment system + + Assess a Peer Submission. Performs basic workflow validation to ensure + that an assessment can be performed as this time. + + Args: + `assessed_submission_uuid` (string): The unique identifier for the submission being assessed. + `options_selected` (dict): Dictionary mapping criterion names to option values. + `overall_feedback` (unicode): Written feedback for the submission as a whole. + `criterion_feedback` (unicode): Written feedback per the criteria for the submission. + `config_data`: ORA Config Data object + `workflow_data`: ORA Workflow Data object + `peer_step_data`: ORA Peer Step Data object + + Returns: + None + + Raises: + ReviewerMustHaveSubmittedException + ServerClientUUIDMismatchException + PeerAssessmentRequestError + PeerAssessmentWorkflowError + PeerAssessmentInternalError + AssessmentWorkflowError + """ + scorer_submission_uuid = workflow_data.submission_uuid + if not workflow_data.has_workflow: + raise ReviewerMustHaveSubmittedException() + + if assessed_submission_uuid: + peer_step_data.assert_assessed_submission_uuid_matches(assessed_submission_uuid) + + try: + assessment = peer_api.create_assessment( + scorer_submission_uuid, + config_data.student_item_dict["student_id"], + options_selected, + clean_criterion_feedback( + config_data.rubric_criteria_with_labels, + criterion_feedback, + ), + overall_feedback, + create_rubric_dict( + config_data.prompts, + config_data.rubric_criteria_with_labels, + ), + peer_step_data.must_be_graded_by, + ) + # Emit analytics event... + config_data.publish_assessment_event("openassessmentblock.peer_assess", assessment) + except (PeerAssessmentRequestError, PeerAssessmentWorkflowError): + logger.warning( + "Peer API error for submission UUID %s", + scorer_submission_uuid, + exc_info=True, + ) + raise + except PeerAssessmentInternalError: + logger.exception( + "Peer API internal error for submission UUID: %s", + scorer_submission_uuid, + ) + raise + + # Update both the workflow that the submission we"re assessing + # belongs to, as well as our own (e.g. have we evaluated enough?) + try: + if assessment: + workflow_data.update_workflow_status(assessment['submission_uuid']) + workflow_data.update_workflow_status(scorer_submission_uuid) + except AssessmentWorkflowError: + logger.exception( + "Workflow error occurred when submitting peer assessment for submission %s", + assessed_submission_uuid, + ) + raise diff --git a/openassessment/xblock/apis/assessments/self_assessment_api.py b/openassessment/xblock/apis/assessments/self_assessment_api.py index 6764b10d97..334731586a 100644 --- a/openassessment/xblock/apis/assessments/self_assessment_api.py +++ b/openassessment/xblock/apis/assessments/self_assessment_api.py @@ -1,11 +1,22 @@ """ External API for ORA Self Assessment data """ +import logging from submissions import api as submission_api from openassessment.assessment.api import self as self_api +from openassessment.assessment.errors.self import SelfAssessmentInternalError, SelfAssessmentRequestError +from openassessment.workflow.errors import AssessmentWorkflowInternalError, AssessmentWorkflowRequestError +from openassessment.xblock.apis.assessments.errors import ReviewerMustHaveSubmittedException from openassessment.xblock.apis.step_data_api import StepDataAPI -from openassessment.xblock.utils.data_conversion import create_submission_dict +from openassessment.xblock.utils.data_conversion import ( + clean_criterion_feedback, + create_rubric_dict, + create_submission_dict, +) + + +logger = logging.getLogger(__name__) class SelfAssessmentAPI(StepDataAPI): @@ -65,3 +76,68 @@ def rubric_criteria_with_labels(self): @property def prompts(self): return self.config_data.rubric_criteria + + +def self_assess( + options_selected, + criterion_feedback, + overall_feedback, + config_data, + workflow_data, + self_step_data +): + """ + Create a self-assessment for a submission. + + Args: + `options_selected` (dict): Dictionary mapping criterion names to option values. + `criterion_feedback` (unicode): Written feedback per the criteria for the submission. + `overall_feedback` (unicode): Written feedback for the submission as a whole. + `config_data`: ORA Config Data object + `workflow_data`: ORA Workflow Data object + `self_step_data`: ORA Self Step Data object + + Returns: None + + Raises: + ReviewerMustHaveSubmittedException + SelfAssessmentRequestError + AssessmentWorkflowRequestError + SelfAssessmentInternalError + AssessmentWorkflowInternalError + """ + submission_uuid = self_step_data.submission_uuid + + if not workflow_data.has_workflow: + raise ReviewerMustHaveSubmittedException() + + try: + assessment = self_api.create_assessment( + submission_uuid, + self_step_data.student_item_dict["student_id"], + options_selected, + clean_criterion_feedback( + config_data.rubric_criteria_with_labels, + criterion_feedback, + ), + overall_feedback, + create_rubric_dict( + config_data.prompts, + config_data.rubric_criteria_with_labels, + ), + ) + config_data.publish_assessment_event("openassessmentblock.self_assess", assessment) + # After we've created the self-assessment, we need to update the workflow. + workflow_data.update_workflow_status() + except ( + SelfAssessmentRequestError, + AssessmentWorkflowRequestError, + SelfAssessmentInternalError, + AssessmentWorkflowInternalError + ): + logger.warning( + "An error occurred while submitting a self assessment for the submission %s", + submission_uuid, + exc_info=True, + ) + raise diff --git a/openassessment/xblock/apis/assessments/staff_assessment_api.py b/openassessment/xblock/apis/assessments/staff_assessment_api.py index 173694649d..5e2c031170 100644 --- a/openassessment/xblock/apis/assessments/staff_assessment_api.py +++ b/openassessment/xblock/apis/assessments/staff_assessment_api.py @@ -1,15 +1,19 @@ """ External API for ORA Staff Assessment data """ +import logging from submissions import team_api as team_sub_api - from openassessment.assessment.api import staff as staff_api, teams as teams_api +from openassessment.assessment.errors.staff import StaffAssessmentError +from openassessment.workflow import api as workflow_api, team_api as team_workflow_api from openassessment.xblock.apis.step_data_api import StepDataAPI from openassessment.xblock.utils.data_conversion import ( clean_criterion_feedback, create_rubric_dict, ) +logger = logging.getLogger(__name__) + class StaffAssessmentAPI(StepDataAPI): @property @@ -42,36 +46,110 @@ def rubric_dict(self): def assessment(self): return staff_api.get_assessment(self.workflow_data.workflow.get("submission_uuid")) - def create_team_assessment(self, data): - team_submission = team_sub_api.get_team_submission_from_individual_submission( - data["submission_uuid"] - ) - return ( - teams_api.create_assessment( - team_submission["team_submission_uuid"], - self.student_id, - data["options_selected"], - clean_criterion_feedback( - self.config_data.rubric_criteria, data["criterion_feedback"] - ), - data["overall_feedback"], - self.rubric_dict, + @staticmethod + def staff_assessment_exists(submission_uuid): + return staff_api.get_latest_staff_assessment(submission_uuid) is not None + + +def staff_assess( + submission_uuid, + options_selected, + criterion_feedback, + overall_feedback, + assess_type, + config_data, + staff_step_data, +): + """ + Create a staff assessment from a team or individual submission. + """ + if config_data.is_team_assignment(): + do_assessment_fn = do_team_staff_assessment + else: + do_assessment_fn = do_staff_assessment + do_assessment_fn( + submission_uuid, + options_selected, + criterion_feedback, + overall_feedback, + assess_type, + config_data, + staff_step_data, + ) + + +def do_staff_assessment( + submission_uuid, + options_selected, + criterion_feedback, + overall_feedback, + assess_type, + config_data, + staff_step_data, +): + """ + Create a staff assessment from a staff submission. + """ + try: + assessment = staff_api.create_assessment( + submission_uuid, + staff_step_data.student_id, + options_selected, + clean_criterion_feedback( + config_data.rubric_criteria, + criterion_feedback, ), - team_submission["team_submission_uuid"], + overall_feedback, + staff_step_data.rubric_dict, + ) + config_data.publish_assessment_event("openassessmentblock.staff_assess", assessment, type=assess_type) + is_regrade = assess_type == 'regrade' + workflow_api.update_from_assessments(submission_uuid, None, {}, override_submitter_requirements=is_regrade) + except StaffAssessmentError: + logger.warning( + "An error occurred while submitting a staff assessment for the submission %s", + submission_uuid, + exc_info=True, ) + raise + - def create_assessment(self, data): - return staff_api.create_assessment( - data["submission_uuid"], - self.student_id, - data["options_selected"], +# TODO: do_team_staff_assessment_from_individual vs _from_team +def do_team_staff_assessment( + individual_submission_uuid, + options_selected, + criterion_feedback, + overall_feedback, + assess_type, + config_data, + staff_step_data, + team_submission_uuid=None, +): + if team_submission_uuid is None: + team_submission = team_sub_api.get_team_submission_from_individual_submission(individual_submission_uuid) + team_submission_uuid = team_submission['team_submission_uuid'] + try: + assessment = teams_api.create_assessment( + team_submission_uuid, + staff_step_data.student_id, + options_selected, clean_criterion_feedback( - self.config_data.rubric_criteria, data["criterion_feedback"] + config_data.rubric_criteria, criterion_feedback ), - data["overall_feedback"], - self.rubric_dict, + overall_feedback, + staff_step_data.rubric_dict, ) - - @staticmethod - def staff_assessment_exists(submission_uuid): - return staff_api.get_latest_staff_assessment(submission_uuid) is not None + config_data.publish_assessment_event("openassessmentblock.staff_assess", assessment[0], type=assess_type) + is_regrade = assess_type == "regrade" + team_workflow_api.update_from_assessments( + team_submission_uuid, + override_submitter_requirements=is_regrade + ) + except StaffAssessmentError: + logger.warning( + "An error occurred while submitting a team assessment for (%s, %s)", + individual_submission_uuid, + team_submission_uuid, + exc_info=True, + ) + raise diff --git a/openassessment/xblock/apis/assessments/student_training_api.py b/openassessment/xblock/apis/assessments/student_training_api.py index a850cbdc9a..ee690e0689 100644 --- a/openassessment/xblock/apis/assessments/student_training_api.py +++ b/openassessment/xblock/apis/assessments/student_training_api.py @@ -1,11 +1,15 @@ """ External API for ORA Student Training data """ + +import logging from openassessment.assessment.api.student_training import ( get_num_completed, get_training_example, + assess_training_example, ) - +from openassessment.assessment.errors.student_training import StudentTrainingError +from openassessment.workflow.errors import AssessmentWorkflowError from openassessment.xblock.utils.data_conversion import ( convert_training_examples_list_to_dict, create_submission_dict, @@ -13,6 +17,9 @@ from openassessment.xblock.apis.step_data_api import StepDataAPI +logger = logging.getLogger(__name__) + + class StudentTrainingAPI(StepDataAPI): def __init__(self, block): super().__init__(block, "student-training") @@ -155,3 +162,54 @@ def _parse_example(self, example): {}, f"Improperly formatted example, cannot render student training. Example: {example}", ) + + +def training_assess( + options_selected, + config_data, + workflow_data, +): + """ + Compare the scores given by the student with those given by the course author. + If they match, update the training workflow. The client can then reload this + step to view the next essay or the completed step. + + Args: + options_selected: (dict) Mapping of criterion name to selected option name + config_data: ConfigDataApi Object + workflow_data: WorkflowDataApi Object + + Returns: + (dict) Mapping of criterion name to defined "correct" option name, for any criterion in options_selected + that does not match the defined answers + + Raises: + StudentTrainingError + AssessmentWorkflowError + Exception + """ + # Check the student's scores against the course author's scores. + # This implicitly updates the student training workflow (which example essay is shown) + # as well as the assessment workflow (training/peer/self steps). + submission_uuid = workflow_data.submission_uuid + try: + corrections = assess_training_example(submission_uuid, options_selected) + config_data.publish_event( + "openassessment.student_training_assess_example", + { + "submission_uuid": submission_uuid, + "options_selected": options_selected, + "corrections": corrections, + }, + ) + except StudentTrainingError: + msg = "Could not check learner training scores for the learner with submission UUID %s" + logger.warning(msg, submission_uuid, exc_info=True) + raise + + try: + workflow_data.update_workflow_status() + except AssessmentWorkflowError: + logger.exception("Could not update workflow status for submission uuid %s", submission_uuid) + raise + return corrections diff --git a/openassessment/xblock/apis/workflow_api.py b/openassessment/xblock/apis/workflow_api.py index 53932bfacc..621ca9de95 100644 --- a/openassessment/xblock/apis/workflow_api.py +++ b/openassessment/xblock/apis/workflow_api.py @@ -76,7 +76,7 @@ def submission_uuid(self): @property def workflow_requirements(self): - return self._block.workflow_requirements + return self._block.workflow_requirements() @property def status(self): diff --git a/openassessment/xblock/test/test_peer.py b/openassessment/xblock/test/test_peer.py index d67f717fd3..3ac600f222 100644 --- a/openassessment/xblock/test/test_peer.py +++ b/openassessment/xblock/test/test_peer.py @@ -129,7 +129,9 @@ def _sally_and_hal_grade_each_other_helper(self, xblock): @scenario('data/peer_assessment_scenario.xml', user_id='Bob') def test_peer_assess_before_submission(self, xblock): # Submit a peer assessment without a submission - resp = self.request(xblock, 'peer_assess', json.dumps(self.ASSESSMENT), response_format='json') + assessment = copy.deepcopy(self.ASSESSMENT) + assessment['submission_uuid'] = 'some-uuid' + resp = self.request(xblock, 'peer_assess', json.dumps(assessment), response_format='json') self.assertEqual(resp['success'], False) self.assertGreater(len(resp['msg']), 0) @@ -140,7 +142,9 @@ def test_peer_assess_without_leasing_submission(self, xblock): # Attempt to assess a peer without first leasing their submission # (usually occurs by rendering the peer assessment step) - resp = self.request(xblock, 'peer_assess', json.dumps(self.ASSESSMENT), response_format='json') + assessment = copy.deepcopy(self.ASSESSMENT) + assessment['submission_uuid'] = 'some-uuid' + resp = self.request(xblock, 'peer_assess', json.dumps(assessment), response_format='json') self.assertEqual(resp['success'], False) self.assertGreater(len(resp['msg']), 0) @@ -786,13 +790,13 @@ def test_peer_assess_rubric_option_mismatch(self, xblock): expect_failure=True ) - @mock.patch('openassessment.assessment.api.peer') + @mock.patch('openassessment.xblock.apis.assessments.peer_assessment_api.peer_api') @scenario('data/peer_assessment_scenario.xml', user_id='Bob') def test_peer_api_request_error(self, xblock, mock_api): mock_api.create_assessment.side_effect = peer_api.PeerAssessmentRequestError self._submit_peer_assessment(xblock, "Sally", "Bob", self.ASSESSMENT, expect_failure=True) - @mock.patch('openassessment.assessment.api.peer') + @mock.patch('openassessment.xblock.apis.assessments.peer_assessment_api.peer_api') @scenario('data/peer_assessment_scenario.xml', user_id='Bob') def test_peer_api_internal_error(self, xblock, mock_api): mock_api.create_assessment.side_effect = peer_api.PeerAssessmentInternalError diff --git a/openassessment/xblock/test/test_self.py b/openassessment/xblock/test/test_self.py index 4fcdcd376b..a11e56bb45 100644 --- a/openassessment/xblock/test/test_self.py +++ b/openassessment/xblock/test/test_self.py @@ -145,8 +145,7 @@ def test_self_assess_api_error(self, xblock): # Submit a self-assessment # Simulate an error and expect a failure response - with mock.patch('openassessment.xblock.ui_mixins.legacy.self_assessments.actions.self_api') as mock_api: - mock_api.SelfAssessmentRequestError = self_api.SelfAssessmentRequestError + with mock.patch('openassessment.xblock.apis.assessments.self_assessment_api.self_api') as mock_api: mock_api.create_assessment.side_effect = self_api.SelfAssessmentRequestError resp = self.request(xblock, 'self_assess', json.dumps(self.ASSESSMENT), response_format='json') @@ -425,7 +424,7 @@ def test_retrieve_api_error(self, xblock): xblock.get_workflow_info = mock.Mock(return_value={'status': 'self'}) # Simulate an error from the submission API - with mock.patch('openassessment.xblock.ui_mixins.legacy.self_assessments.actions.self_api') as mock_api: + with mock.patch('openassessment.xblock.apis.assessments.self_assessment_api.self_api') as mock_api: mock_api.get_assessment.side_effect = self_api.SelfAssessmentRequestError resp = self.request(xblock, 'render_self_assessment', json.dumps({})) diff --git a/openassessment/xblock/test/test_staff.py b/openassessment/xblock/test/test_staff.py index fd826a7569..6322fc7cde 100644 --- a/openassessment/xblock/test/test_staff.py +++ b/openassessment/xblock/test/test_staff.py @@ -163,7 +163,7 @@ def test_staff_grade_templates_no_peer(self, xblock): class TestStaffAssessment(StaffAssessmentTestBase): """ Test Staff Assessment Workflow. """ - @patch('openassessment.xblock.ui_mixins.legacy.staff_assessments.views.staff_api.create_assessment') + @patch('openassessment.xblock.ui_mixins.legacy.views.staff.staff_api.create_assessment') @scenario('data/self_assessment_scenario.xml', user_id='Bob') def test_staff_assess_handler_missing_id(self, xblock, mock_create_assessment): self.set_staff_access(xblock) @@ -266,7 +266,7 @@ def test_assessment_error(self, xblock): assessment = copy.deepcopy(STAFF_GOOD_ASSESSMENT) assessment['submission_uuid'] = submission['uuid'] - with patch('openassessment.xblock.ui_mixins.legacy.staff_assessments.views.staff_api') as mock_api: + with patch('openassessment.xblock.ui_mixins.legacy.views.staff.staff_api') as mock_api: # Simulate a error mock_api.create_assessment.side_effect = staff_api.StaffAssessmentRequestError resp = self.request(xblock, 'staff_assess', json.dumps(STAFF_GOOD_ASSESSMENT), response_format='json') diff --git a/openassessment/xblock/test/test_submission.py b/openassessment/xblock/test/test_submission.py index 27236ad702..f42401f0ff 100644 --- a/openassessment/xblock/test/test_submission.py +++ b/openassessment/xblock/test/test_submission.py @@ -29,7 +29,7 @@ from openassessment.xblock.apis.submissions import submissions_actions from openassessment.xblock.utils.data_conversion import create_submission_dict, prepare_submission_for_serialization from openassessment.xblock.openassessmentblock import OpenAssessmentBlock -from openassessment.xblock.ui_mixins.legacy.submissions.views import get_team_submission_context +from openassessment.xblock.ui_mixins.legacy.views.submission import get_team_submission_context from openassessment.xblock.workflow_mixin import WorkflowMixin from openassessment.xblock.test.test_team import MockTeamsService, MOCK_TEAM_ID @@ -623,7 +623,7 @@ def test_get_team_context_exceptions(self, xblock): self.assertEqual(context, {}) logger.check_present( ( - 'openassessment.xblock.ui_mixins.legacy.submissions.views', + 'openassessment.xblock.ui_mixins.legacy.views.submission', 'ERROR', '{}: Teams service is unavailable'.format( xblock.location, @@ -638,7 +638,7 @@ def test_get_team_context_exceptions(self, xblock): self.assertEqual(context, {}) logger.check_present( ( - 'openassessment.xblock.ui_mixins.legacy.submissions.views', + 'openassessment.xblock.ui_mixins.legacy.views.submission', 'ERROR', '{}: User associated with anonymous_user_id {} can not be found.'.format( xblock.location, diff --git a/openassessment/xblock/ui_mixins/legacy/handlers_mixin.py b/openassessment/xblock/ui_mixins/legacy/handlers_mixin.py index 350386385f..5e201c4bcd 100644 --- a/openassessment/xblock/ui_mixins/legacy/handlers_mixin.py +++ b/openassessment/xblock/ui_mixins/legacy/handlers_mixin.py @@ -4,9 +4,29 @@ from xblock.core import XBlock from submissions import api as submissions_api - +from openassessment.assessment.errors.peer import ( + PeerAssessmentInternalError, + PeerAssessmentRequestError, + PeerAssessmentWorkflowError, +) +from openassessment.assessment.errors.self import SelfAssessmentInternalError, SelfAssessmentRequestError +from openassessment.assessment.errors.staff import StaffAssessmentInternalError, StaffAssessmentRequestError +from openassessment.assessment.errors.student_training import StudentTrainingError from openassessment.fileupload.exceptions import FileUploadError +from openassessment.workflow.errors import ( + AssessmentWorkflowError, + AssessmentWorkflowInternalError, + AssessmentWorkflowRequestError +) +from openassessment.xblock.apis.assessments.errors import ( + ReviewerMustHaveSubmittedException, + ServerClientUUIDMismatchException, +) from openassessment.xblock.apis.submissions import submissions_actions +from openassessment.xblock.apis.assessments.peer_assessment_api import peer_assess +from openassessment.xblock.apis.assessments.self_assessment_api import self_assess +from openassessment.xblock.apis.assessments.staff_assessment_api import staff_assess +from openassessment.xblock.apis.assessments.student_training_api import training_assess from openassessment.xblock.apis.submissions.errors import ( AnswerTooLongException, DeleteNotAllowed, @@ -20,11 +40,7 @@ UnsupportedFileTypeException ) from openassessment.xblock.staff_area_mixin import require_course_staff -from openassessment.xblock.ui_mixins.legacy.peer_assessments.actions import peer_assess -from openassessment.xblock.ui_mixins.legacy.self_assessments.actions import self_assess -from openassessment.xblock.ui_mixins.legacy.staff_assessments.actions import do_staff_assessment, staff_assess -from openassessment.xblock.ui_mixins.legacy.student_training.actions import training_assess -from openassessment.xblock.ui_mixins.legacy.submissions.serializers import SaveFilesDescriptionRequestSerializer +from openassessment.xblock.ui_mixins.legacy.serializers import SaveFilesDescriptionRequestSerializer from openassessment.xblock.utils.data_conversion import verify_assessment_parameters logger = logging.getLogger(__name__) @@ -199,26 +215,167 @@ def remove_uploaded_file(self, data, suffix=""): # pylint: disable=unused-argum @XBlock.json_handler @verify_assessment_parameters def peer_assess(self, data, suffix=""): # pylint: disable=unused-argument - return peer_assess(self.api_data, data) + """Place a peer assessment into OpenAssessment system + + Assess a Peer Submission. Performs basic workflow validation to ensure + that an assessment can be performed as this time. + + Args: + data (dict): A dictionary containing information required to create + a new peer assessment. This dict should have the following attributes: + `submission_uuid` (string): The unique identifier for the submission being assessed. + `options_selected` (dict): Dictionary mapping criterion names to option values. + `overall_feedback` (unicode): Written feedback for the submission as a whole. + `criterion_feedback` (unicode): Written feedback per the criteria for the submission. + + Returns: + Dict with keys "success" (bool) indicating success/failure. + and "msg" (unicode) containing additional information if an error occurs. + """ + try: + peer_assess( + data['options_selected'], + data['overall_feedback'], + data['criterion_feedback'], + self.config_data, + self.workflow_data, + self.peer_assessment_data(), + assessed_submission_uuid=data['submission_uuid'], + ) + except ReviewerMustHaveSubmittedException: + return { + 'success': False, + 'msg': self.config_data.translate( + 'You must submit a response before you can perform a peer assessment.' + ) + } + except ServerClientUUIDMismatchException: + return { + 'success': False, + 'msg': self.config_data.translate( + 'This feedback has already been submitted or the submission has been cancelled.' + ) + } + except (PeerAssessmentRequestError, PeerAssessmentWorkflowError, PeerAssessmentInternalError): + return { + 'success': False, + 'msg': self.config_data.translate('Your peer assessment could not be submitted.') + } + except AssessmentWorkflowError: + return {'success': False, 'msg': self.config_data.translate('Could not update workflow status.')} + else: + return {"success": True, "msg": ""} @XBlock.json_handler @verify_assessment_parameters def self_assess(self, data, suffix=""): # pylint: disable=unused-argument - return self_assess(self.api_data, data) + """ + Create a self-assessment for a submission. + + Args: + data (dict): Must have the following keys: + options_selected (dict): Dictionary mapping criterion names to option values. + + Returns: + Dict with keys "success" (bool) indicating success/failure + and "msg" (unicode) containing additional information if an error occurs. + """ + def failure_response(reason): + return {'success': False, 'msg': self.config_data.translate(reason)} + + try: + self_assess( + data['options_selected'], + data['criterion_feedback'], + data['overall_feedback'], + self.config_data, + self.workflow_data, + self.self_data, + ) + except ReviewerMustHaveSubmittedException: + return failure_response('You must submit a response before you can perform a self-assessment.') + except ( + SelfAssessmentRequestError, + AssessmentWorkflowRequestError, + SelfAssessmentInternalError, + AssessmentWorkflowInternalError + ): + return failure_response('Your self assessment could not be submitted.') + else: + return {'success': True, 'msg': ''} @XBlock.json_handler def training_assess(self, data, suffix=""): # pylint: disable=unused-argument - return training_assess(self.api_data, data) + """ + Compare the scores given by the student with those given by the course author. + If they match, update the training workflow. The client can then reload this + step to view the next essay or the completed step. + + Currently, we return a boolean indicating whether the student assessed correctly + or not. However, the student training API provides the exact criteria that the student + scored incorrectly, as well as the "correct" options for those criteria. + In the future, we may expose this in the UI to provide more detailed feedback. + + Args: + data (dict): Must have the following keys: + options_selected (dict): Dictionary mapping criterion names to option values. + + Returns: + Dict with keys: + * "success" (bool) indicating success or error + * "msg" (unicode) containing additional information if an error occurs. + * "correct" (bool) indicating whether the student scored the assessment correctly. + + """ + def failure_response(message): + return {"success": False, "msg": self.config_data.translate(message)} + + if "options_selected" not in data: + return failure_response("Missing options_selected key in request.") + if not isinstance(data["options_selected"], dict): + return failure_response("options_selected must be a dictionary.") + + try: + corrections = training_assess(data['options_selected'], self.config_data, self.workflow_data) + except StudentTrainingError: + return failure_response("Your scores could not be checked.") + except AssessmentWorkflowError: + return failure_response("Could not update workflow status.") + except Exception: # pylint: disable=broad-except + return failure_response("An unexpected error occurred.") + + return { + "success": True, + "msg": "", + "corrections": corrections, + } @XBlock.json_handler @require_course_staff("STUDENT_INFO") @verify_assessment_parameters def staff_assess(self, data, suffix=""): # pylint: disable=unused-argument - return staff_assess(self.api_data, data) + """ + Create a staff assessment for a team or individual submission. + """ + def failure_response(reason): + return {'success': False, 'msg': self.config_data.translate(reason)} + + if 'submission_uuid' not in data: + return failure_response('The submission ID of the submission being assessed was not found.') - # NOTE - Temporary surfacing - def do_staff_assessment(self, data): - return do_staff_assessment(self.api_data, data) + try: + staff_assess( + data['submission_uuid'], + data['options_selected'], + data['criterion_feedback'], + data['overall_feedback'], + data.get('assess_type', 'regrade'), + self.config_data, + self.staff_data, + ) + except (StaffAssessmentRequestError, StaffAssessmentInternalError): + return failure_response('Your team assessment could not be submitted.') + return {'success': True, 'msg': ''} # Utils diff --git a/openassessment/xblock/ui_mixins/legacy/peer_assessments/actions.py b/openassessment/xblock/ui_mixins/legacy/peer_assessments/actions.py deleted file mode 100644 index 11fdd8bb9a..0000000000 --- a/openassessment/xblock/ui_mixins/legacy/peer_assessments/actions.py +++ /dev/null @@ -1,134 +0,0 @@ -"""Collection of JSON handlers for legacy view""" -import logging - -from openassessment.assessment.errors import ( - PeerAssessmentInternalError, - PeerAssessmentRequestError, - PeerAssessmentWorkflowError, -) -from openassessment.workflow.errors import AssessmentWorkflowError - -from openassessment.xblock.utils.data_conversion import ( - clean_criterion_feedback, - create_rubric_dict, -) - -logger = logging.getLogger(__name__) # pylint: disable=invalid-name - -messages = { - "must_submit": "You must submit a response before you can perform a peer assessment.", - "already_submitted": "This feedback has already been submitted or the submission has been cancelled.", - "could_not_submit": "Your peer assessment could not be submitted.", - "could_not_update": "Could not update workflow status.", - "could_not_load": "Could not load peer assessment.", -} - - -def create_peer_assessment(api_data, data): - # Import is placed here to avoid model import at project startup. - from openassessment.assessment.api import peer as peer_api - - config_data = api_data.config_data - submission_uuid = api_data.workflow_data.submission_uuid - peer_assessment_data = api_data.peer_assessment_data() - - # Create the assessment - assessment = peer_api.create_assessment( - submission_uuid, - peer_assessment_data.student_item["student_id"], - data["options_selected"], - clean_criterion_feedback( - config_data.rubric_criteria_with_labels, - data["criterion_feedback"], - ), - data["overall_feedback"], - create_rubric_dict( - config_data.prompts, - config_data.rubric_criteria_with_labels, - ), - peer_assessment_data.assessment["must_be_graded_by"], - ) - - return assessment - - -def peer_assess(api_data, data, suffix=""): # pylint: disable=unused-argument - """Place a peer assessment into OpenAssessment system - - Assess a Peer Submission. Performs basic workflow validation to ensure - that an assessment can be performed as this time. - - Args: - data (dict): A dictionary containing information required to create - a new peer assessment. This dict should have the following attributes: - `submission_uuid` (string): The unique identifier for the submission being assessed. - `options_selected` (dict): Dictionary mapping criterion names to option values. - `overall_feedback` (unicode): Written feedback for the submission as a whole. - `criterion_feedback` (unicode): Written feedback per the criteria for the submission. - - Returns: - Dict with keys "success" (bool) indicating success/failure. - and "msg" (unicode) containing additional information if an error occurs. - - """ - translate = api_data.config_data.translate - submission_uuid = api_data.workflow_data.submission_uuid - - def failure_response(reason): - return {"success": False, "msg": translate(reason)} - - if submission_uuid is None: - return failure_response(messages["must_submit"]) - - step_data = api_data.peer_assessment_data() - submission = step_data.get_peer_submission() or {} - uuid_server = submission.get("uuid", None) - uuid_client = data.get("submission_uuid", None) - - if uuid_server != uuid_client: - logger.warning( - "Irrelevant assessment submission: expected '%s', got '%s'", - uuid_server, - uuid_client, - ) - return failure_response(messages["already_submitted"]) - - if step_data.assessment: - try: - assessment = create_peer_assessment(api_data, data) - # Emit analytics event... - api_data.config_data.publish_assessment_event("openassessmentblock.peer_assess", assessment) - except (PeerAssessmentRequestError, PeerAssessmentWorkflowError): - logger.warning( - "Peer API error for submission UUID %s", - submission_uuid, - exc_info=True, - ) - return failure_response(messages["could_not_submit"]) - except PeerAssessmentInternalError: - logger.exception( - "Peer API internal error for submission UUID: %s", - submission_uuid, - ) - return failure_response(messages["could_not_submit"]) - - # Update both the workflow that the submission we"re assessing - # belongs to, as well as our own (e.g. have we evaluated enough?) - try: - update = api_data.workflow_data.update_workflow_status - if assessment: - update(submission_uuid=assessment["submission_uuid"]) - update() - except AssessmentWorkflowError: - logger.exception( - "Workflow error occurred when submitting peer assessment for submission %s", - submission_uuid, - ) - return failure_response(messages["could_not_update"]) - - # Temp kludge until we fix JSON serialization for datetime - assessment["scored_at"] = str(assessment["scored_at"]) - - return {"success": True, "msg": ""} - - return failure_response(messages["could_not_load"]) diff --git a/openassessment/xblock/ui_mixins/legacy/self_assessments/__init__.py b/openassessment/xblock/ui_mixins/legacy/self_assessments/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openassessment/xblock/ui_mixins/legacy/self_assessments/actions.py b/openassessment/xblock/ui_mixins/legacy/self_assessments/actions.py deleted file mode 100644 index 480600e880..0000000000 --- a/openassessment/xblock/ui_mixins/legacy/self_assessments/actions.py +++ /dev/null @@ -1,75 +0,0 @@ -""" A mixin for self Assessments. """ -import logging - -from openassessment.assessment.api import self as self_api -from openassessment.workflow import api as workflow_api - -from openassessment.xblock.utils.data_conversion import ( - clean_criterion_feedback, - create_rubric_dict, -) - -logger = logging.getLogger(__name__) # pylint: disable=invalid-name - -messages = { - "must_submit": "You must submit a response before you can perform a self-assessment.", - "could_not_submit": "Your self assessment could not be submitted.", -} - - -def self_assess(api_data, data, suffix=""): # pylint: disable=unused-argument - """ - Create a self-assessment for a submission. - - Args: - data (dict): Must have the following keys: - options_selected (dict): Dictionary mapping criterion names to option values. - - Returns: - Dict with keys "success" (bool) indicating success/failure - and "msg" (unicode) containing additional information if an error occurs. - """ - # Import is placed here to avoid model import at project startup. - translate = api_data.config_data.translate - submission_uuid = api_data.submission_data.submission_uuid - - def failure_response(reason): - return {"success": False, "msg": translate(reason)} - - if submission_uuid is None: - return failure_response(messages["must_submit"]) - - step_data = api_data.self_assessment_data - try: - assessment = self_api.create_assessment( - step_data.submission_uuid, - step_data.student_item_dict["student_id"], - data["options_selected"], - clean_criterion_feedback(step_data.rubric_criteria, data["criterion_feedback"]), - data["overall_feedback"], - create_rubric_dict(step_data.prompts, step_data.rubric_criteria_with_labels), - ) - api_data.config_data.publish_assessment_event("openassessmentblock.self_assess", assessment) - # After we've created the self-assessment, we need to update the workflow. - api_data.workflow_data.update_workflow_status() - except ( - self_api.SelfAssessmentRequestError, - workflow_api.AssessmentWorkflowRequestError, - ): - logger.warning( - "An error occurred while submitting a self assessment for the submission %s", - submission_uuid, - exc_info=True, - ) - return failure_response(messages["could_not_submit"]) - except ( - self_api.SelfAssessmentInternalError, - workflow_api.AssessmentWorkflowInternalError, - ): - logger.exception( - "An error occurred while submitting a self assessment for the submission %s", - submission_uuid, - ) - return failure_response(messages["could_not_submit"]) - else: - return {"success": True, "msg": ""} diff --git a/openassessment/xblock/ui_mixins/legacy/submissions/serializers.py b/openassessment/xblock/ui_mixins/legacy/serializers.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/submissions/serializers.py rename to openassessment/xblock/ui_mixins/legacy/serializers.py diff --git a/openassessment/xblock/ui_mixins/legacy/staff_assessments/__init__.py b/openassessment/xblock/ui_mixins/legacy/staff_assessments/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openassessment/xblock/ui_mixins/legacy/staff_assessments/actions.py b/openassessment/xblock/ui_mixins/legacy/staff_assessments/actions.py deleted file mode 100644 index 8d1113c53f..0000000000 --- a/openassessment/xblock/ui_mixins/legacy/staff_assessments/actions.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -A mixin for staff grading. -""" - - -import logging - -from openassessment.assessment.errors import ( - StaffAssessmentInternalError, - StaffAssessmentRequestError, -) -from openassessment.workflow import api as workflow_api, team_api as team_workflow_api - -logger = logging.getLogger(__name__) # pylint: disable=invalid-name - - -def do_staff_assessment(api_data, data): - """ - Create a staff assessment from a staff submission. - """ - config_data = api_data.config_data - translate = config_data.translate - step_data = api_data.staff_assessment_data - if "submission_uuid" not in data: - return False, translate("The submission ID of the submission being assessed was not found.") - try: - assessment = step_data.create_assessment(data) - assess_type = data.get("assess_type", "regrade") - config_data.publish_assessment_event("openassessmentblock.staff_assess", assessment, type=assess_type) - workflow_api.update_from_assessments( - assessment["submission_uuid"], - None, - {}, - override_submitter_requirements=(assess_type == "regrade"), - ) - except StaffAssessmentRequestError: - logger.warning( - "An error occurred while submitting a staff assessment for the submission %s", - data["submission_uuid"], - exc_info=True, - ) - msg = translate("Your staff assessment could not be submitted.") - return False, msg - except StaffAssessmentInternalError: - logger.exception( - "An error occurred while submitting a staff assessment for the submission %s", - data["submission_uuid"], - ) - msg = translate("Your staff assessment could not be submitted.") - return False, msg - return True, "" - - -def do_team_staff_assessment(api_data, data, team_submission_uuid=None): - """ - Teams version of do_staff_assessment. - Providing the team_submission_uuid removes lookup of team submission from individual submission_uuid. - """ - config_data = api_data.config_data - translate = config_data.translate - step_data = api_data.staff_assessment_data - if "submission_uuid" not in data and team_submission_uuid is None: - return False, translate("The submission ID of the submission being assessed was not found.") - try: - assessment, team_submission_uuid = step_data.create_team_assessment(data) - assess_type = data.get("assess_type", "regrade") - config_data.publish_assessment_event("openassessmentblock.staff_assess", assessment[0], type=assess_type) - team_workflow_api.update_from_assessments( - team_submission_uuid, - override_submitter_requirements=(assess_type == "regrade"), - ) - - except StaffAssessmentRequestError: - logger.warning( - "An error occurred while submitting a team assessment for the submission %s", - data["submission_uuid"], - exc_info=True, - ) - msg = translate("Your team assessment could not be submitted.") - return False, msg - except StaffAssessmentInternalError: - logger.exception( - "An error occurred while submitting a team assessment for the submission %s", - data["submission_uuid"], - ) - msg = translate("Your team assessment could not be submitted.") - return False, msg - - return True, "" - - -def staff_assess(api_data, data, suffix=""): # pylint: disable=unused-argument - """ - Create a staff assessment from a team or individual submission. - """ - if api_data.config_data.is_team_assignment(): - success, err_msg = do_team_staff_assessment(api_data, data) - else: - success, err_msg = do_staff_assessment(api_data, data) - - return {"success": success, "msg": err_msg} diff --git a/openassessment/xblock/ui_mixins/legacy/student_training/__init__.py b/openassessment/xblock/ui_mixins/legacy/student_training/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openassessment/xblock/ui_mixins/legacy/student_training/actions.py b/openassessment/xblock/ui_mixins/legacy/student_training/actions.py deleted file mode 100644 index 82fc4f853b..0000000000 --- a/openassessment/xblock/ui_mixins/legacy/student_training/actions.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -Student training step in the OpenAssessment XBlock. -""" -import logging - -from openassessment.assessment.api import student_training -from openassessment.workflow.errors import AssessmentWorkflowError - -logger = logging.getLogger(__name__) # pylint: disable=invalid-name - -messages = { - "missing_selected": "Missing options_selected key in request.", - "selected_must_be_dict": "options_selected must be a dictionary.", - "could_not_check": "Your scores could not be checked.", - "unexpected_error": "An unexpected error occurred.", - "could_not_update": "Could not update workflow status.", -} - - -def training_assess(api_data, data): - """ - Compare the scores given by the student with those given by the course author. - If they match, update the training workflow. The client can then reload this - step to view the next essay or the completed step. - - Currently, we return a boolean indicating whether the student assessed correctly - or not. However, the student training API provides the exact criteria that the student - scored incorrectly, as well as the "correct" options for those criteria. - In the future, we may expose this in the UI to provide more detailed feedback. - - Args: - data (dict): Must have the following keys: - options_selected (dict): Dictionary mapping criterion names to option values. - - Returns: - Dict with keys: - * "success" (bool) indicating success or error - * "msg" (unicode) containing additional information if an error occurs. - * "correct" (bool) indicating whether the student scored the assessment correctly. - - """ - - translate = api_data.config_data.translate - submission_uuid = api_data.workflow_data.submission_uuid - - def failure_response(reason_key): - return {"success": False, "msg": translate(messages[reason_key])} - - if "options_selected" not in data: - return failure_response("missing_selected") - if not isinstance(data["options_selected"], dict): - return failure_response("selected_must_be_dict") - - # Check the student's scores against the course author's scores. - # This implicitly updates the student training workflow (which example essay is shown) - # as well as the assessment workflow (training/peer/self steps). - try: - corrections = student_training.assess_training_example(submission_uuid, data["options_selected"]) - api_data.config_data.publish_event( - "openassessment.student_training_assess_example", - { - "submission_uuid": submission_uuid, - "options_selected": data["options_selected"], - "corrections": corrections, - }, - ) - except student_training.StudentTrainingRequestError: - msg = ("Could not check learner training scores for the learner with submission UUID {uuid}").format( - uuid=submission_uuid - ) - logger.warning(msg, exc_info=True) - - return failure_response("could_not_check") - except student_training.StudentTrainingInternalError: - return failure_response("could_not_check") - except Exception: # pylint: disable=broad-except - return failure_response("unexpected_error") - else: - try: - api_data.workflow_data.update_workflow_status() - except AssessmentWorkflowError: - logger.exception(translate(messages["could_not_update"])) - return failure_response("could_not_update") - return { - "success": True, - "msg": "", - "corrections": corrections, - } diff --git a/openassessment/xblock/ui_mixins/legacy/submissions/__init__.py b/openassessment/xblock/ui_mixins/legacy/submissions/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openassessment/xblock/ui_mixins/legacy/peer_assessments/__init__.py b/openassessment/xblock/ui_mixins/legacy/views/__init__.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/peer_assessments/__init__.py rename to openassessment/xblock/ui_mixins/legacy/views/__init__.py diff --git a/openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/views/peer.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/peer_assessments/views.py rename to openassessment/xblock/ui_mixins/legacy/views/peer.py diff --git a/openassessment/xblock/ui_mixins/legacy/self_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/views/self.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/self_assessments/views.py rename to openassessment/xblock/ui_mixins/legacy/views/self.py diff --git a/openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py b/openassessment/xblock/ui_mixins/legacy/views/staff.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/staff_assessments/views.py rename to openassessment/xblock/ui_mixins/legacy/views/staff.py diff --git a/openassessment/xblock/ui_mixins/legacy/submissions/views.py b/openassessment/xblock/ui_mixins/legacy/views/submission.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/submissions/views.py rename to openassessment/xblock/ui_mixins/legacy/views/submission.py diff --git a/openassessment/xblock/ui_mixins/legacy/student_training/views.py b/openassessment/xblock/ui_mixins/legacy/views/training.py similarity index 100% rename from openassessment/xblock/ui_mixins/legacy/student_training/views.py rename to openassessment/xblock/ui_mixins/legacy/views/training.py diff --git a/openassessment/xblock/ui_mixins/legacy/views_mixin.py b/openassessment/xblock/ui_mixins/legacy/views_mixin.py index ac8fbf2526..37cc1e3669 100644 --- a/openassessment/xblock/ui_mixins/legacy/views_mixin.py +++ b/openassessment/xblock/ui_mixins/legacy/views_mixin.py @@ -4,11 +4,11 @@ from xblock.core import XBlock -from .peer_assessments.views import render_peer_assessment, peer_path_and_context -from .self_assessments.views import render_self_assessment, self_path_and_context -from .staff_assessments.views import render_staff_assessment, staff_path_and_context -from .student_training.views import render_student_training, training_path_and_context -from .submissions.views import render_submission, get_submission_path, get_submission_context +from .views.peer import render_peer_assessment, peer_path_and_context +from .views.self import render_self_assessment, self_path_and_context +from .views.staff import render_staff_assessment, staff_path_and_context +from .views.training import render_student_training, training_path_and_context +from .views.submission import render_submission, get_submission_path, get_submission_context class LegacyViewsMixin: diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index 0a289127f5..885c5f5b2d 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -9,6 +9,8 @@ SerializerMethodField, URLField, Serializer, + DictField, + BooleanField, ) from openassessment.xblock.ui_mixins.mfe.serializer_utils import NullField @@ -167,3 +169,11 @@ def get_uploadedFiles(self, instance): files.append(file_data) return [SubmissionFileSerializer(file).data for file in files] + + +class AssessmentSubmitRequestSerializer(Serializer): + """" Serializer for validating request shape """ + optionsSelected = DictField(child=CharField(), allow_empty=True) + criterionFeedback = DictField(child=CharField(), allow_empty=True) + overallFeedback = CharField(allow_blank=True) + continueGrading = BooleanField(required=False, default=False) diff --git a/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py b/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py index 66a3b91100..47672fb669 100644 --- a/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py +++ b/openassessment/xblock/ui_mixins/mfe/constants/error_codes.py @@ -16,4 +16,6 @@ UNABLE_TO_GENERATE_UPLOAD_URL = "ERR_UNABLE_TO_GENERATE_UPLOAD_URL" TOO_MANY_UPLOADS = "ERR_TOO_MANY_UPLOADS" UNSUPPORTED_FILETYPE = "ERR_UNSUPPORTED_FILETYPE" +TRAINING_ANSWER_INCORRECT = "ERR_TRAINING_INCORRECT" +INVALID_STATE_TO_ASSESS = "ERR_INVALID_STATE_FOR_ASSESSMENT" FILE_NOT_FOUND = "ERR_FILE_NOT_FOUND" diff --git a/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py b/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py index ea0bb065fb..aec7048893 100644 --- a/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py +++ b/openassessment/xblock/ui_mixins/mfe/constants/handler_suffixes.py @@ -4,4 +4,6 @@ SUBMISSION_SUBMIT = 'submit' FILE_ADD = 'add' FILE_DELETE = 'delete' +ASSESSMENT_SUBMIT = 'submit' +ASSESSMENT_GET_PEER = 'get_peer' FILE_UPLOAD_CALLBACK = 'upload_response' diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index f3e27096a0..bf7edb85c1 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -6,7 +6,12 @@ from xblock.core import XBlock from xblock.exceptions import JsonHandlerError from openassessment.fileupload.exceptions import FileUploadError - +from openassessment.assessment.errors import AssessmentError +from openassessment.workflow.errors import AssessmentWorkflowError +from openassessment.xblock.apis.assessments.errors import InvalidStateToAssess +from openassessment.xblock.apis.assessments.peer_assessment_api import peer_assess +from openassessment.xblock.apis.assessments.self_assessment_api import self_assess +from openassessment.xblock.apis.assessments.student_training_api import training_assess from openassessment.xblock.apis.submissions import submissions_actions from openassessment.xblock.apis.submissions.errors import ( AnswerTooLongException, @@ -20,6 +25,7 @@ SubmitInternalError, UnsupportedFileTypeException ) +from openassessment.xblock.ui_mixins.mfe.assessment_serializers import AssessmentSubmitRequestSerializer from openassessment.xblock.ui_mixins.mfe.constants import error_codes, handler_suffixes from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import OraBlockInfoSerializer from openassessment.xblock.ui_mixins.mfe.page_context_serializer import PageDataSerializer @@ -288,3 +294,70 @@ def get_learner_submission_data(self): 'response': response, 'file_data': file_data, } + + def _assessment_submit_handler(self, data): + serializer = AssessmentSubmitRequestSerializer(data=data) + if not serializer.is_valid(): + raise OraApiException(400, error_codes.INCORRECT_PARAMETERS, serializer.errors) + data = serializer.validated_data + peer_data = self.peer_assessment_data(data['continueGrading']) + try: + if peer_data.continue_grading or self.workflow_data.is_peer: + peer_assess( + data['optionsSelected'], + data['overallFeedback'], + data['criterionFeedback'], + self.config_data, + self.workflow_data, + peer_data, + ) + elif self.workflow_data.is_self: + self_assess( + data['optionsSelected'], + data['criterionFeedback'], + data['overallFeedback'], + self.config_data, + self.workflow_data, + self.self_data + ) + elif self.workflow_data.is_training: + corrections = training_assess( + data['optionsSelected'], + self.config_data, + self.workflow_data, + ) + if corrections: + raise OraApiException(400, error_codes.TRAINING_ANSWER_INCORRECT, corrections) + else: + raise InvalidStateToAssess() + except InvalidStateToAssess as e: + # This catches the error we explicitly raise, as well as any that may be raised from within + # the assessment logic itself + context = { + 'student_item': self.config_data.student_item_dict, + 'workflow': self.workflow_data.workflow, + } + raise OraApiException(400, error_codes.INVALID_STATE_TO_ASSESS, context) from e + except (AssessmentError, AssessmentWorkflowError) as e: + raise OraApiException(500, error_codes.INTERNAL_EXCEPTION, str(e)) from e + + def _assessment_get_peer_handler(self): + # Call get_peer_submission to grab a new peer submission + self.peer_assessment_data().get_peer_submission() + + # Then, just return page data + serializer_context = { + "view": "assessment", + "step": "peer", + } + page_context = PageDataSerializer(self, context=serializer_context) + return page_context.data + + @XBlock.json_handler + def assessment(self, data, suffix=""): + if suffix == handler_suffixes.ASSESSMENT_SUBMIT: + return self._assessment_submit_handler(data) + elif suffix == handler_suffixes.ASSESSMENT_GET_PEER: + return self._assessment_get_peer_handler() + else: + raise OraApiException(404, error_codes.UNKNOWN_SUFFIX) diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index d1c214ba93..345a951ca4 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -344,7 +344,13 @@ def get_response(self, instance): if active_step == "training": response = instance.student_training_data.example elif active_step == "peer": - response = instance.peer_assessment_data().get_peer_submission() + if workflow_step == "peer": + # If we are on the peer step, grab a submission automatically + response = instance.peer_assessment_data().get_peer_submission() + elif jump_to_step == "peer": + # If we are jumping to the peer step grab any existing assessments but + # don't get a new one automatically + response = instance.peer_assessment_data().get_active_assessment_submission() elif active_step in ("self", "staff", "ai", "waiting", "done"): response = None else: diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index f1cda5c951..437b513334 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -1,14 +1,20 @@ """ Tests for XBlock handlers for the ORA MFE BFF """ +from collections import namedtuple from contextlib import contextmanager import json -from unittest.mock import Mock, patch +from unittest.mock import Mock, PropertyMock, patch +from uuid import uuid4 import ddt from django.contrib.auth import get_user_model from submissions import api as submission_api from submissions import team_api as submission_team_api + +from openassessment.assessment.errors.base import AssessmentError +from openassessment.xblock.apis.assessments.peer_assessment_api import PeerAssessmentAPI +from openassessment.xblock.apis.workflow_api import WorkflowAPI from openassessment.fileupload.api import FileUpload from openassessment.fileupload.exceptions import FileUploadError from openassessment.tests.factories import SharedFileUploadFactory, UserFactory @@ -55,6 +61,11 @@ def mock_get_url(self, expected_file_urls=None): DEFAULT_DRAFT_VALUE = {'response': {'text_responses': ['hi']}} DEFAULT_SUBMIT_VALUE = {'response': {'text_responses': ['Hello World', 'Goodbye World']}} DEFAULT_DELETE_FILE_VALUE = {'fileIndex': 1} + DEFAULT_ASSESSMENT_SUBMIT_VALUE = { + 'optionsSelected': {'ferocity': 'fine', 'color': 'blue', 'element': 'volcano'}, + 'criterionFeedback': {'ferocity': 'rawr!', 'color': ':)', 'element': 'i prefer lead'}, + 'overallFeedback': 'i have no strong feelings', + } def request_create_submission(self, xblock, payload=None): if payload is None: @@ -115,6 +126,26 @@ def request_file_callback(self, xblock, payload): response_format='response' ) + def request_assessment_submit(self, xblock, payload=None): + if payload is None: + payload = self.DEFAULT_ASSESSMENT_SUBMIT_VALUE + return super().request( + xblock, + 'assessment', + json.dumps(payload), + suffix=handler_suffixes.ASSESSMENT_SUBMIT, + response_format='response' + ) + + def request_assessment_get_peer(self, xblock): + return super().request( + xblock, + 'assessment', + '{}', + suffix=handler_suffixes.ASSESSMENT_GET_PEER, + response_format='response' + ) + def assert_error_response(response, status_code, error_code, context=''): assert response.status_code == status_code @@ -731,3 +762,122 @@ def test_faliure(self, xblock): assert resp.status_code == 200 mock_get_download_url.assert_not_called() mock_delete_file.assert_called_once_with(4) + + +AssessMocks = namedtuple('AssessMocks', ['self', 'training', 'peer']) + + +@ddt.ddt +class AssessmentSubmitTest(MFEHandlersTestBase): + + STATUSES = ['cancelled', 'done', 'waiting', 'self', 'training', 'peer'] + + @contextmanager + def mock_workflow_status(self, return_value): + with patch.object(WorkflowAPI, 'status', new_callable=PropertyMock) as m: + m.return_value = return_value + yield m + + @contextmanager + def mock_continue_grading(self, return_value): + with patch.object(PeerAssessmentAPI, 'continue_grading', new_callable=PropertyMock) as m: + m.return_value = return_value + yield m + + @contextmanager + def mock_assess_functions(self, self_kwargs=None, training_kwargs=None, peer_kwargs=None): + self_kwargs = self_kwargs or {} + training_kwargs = training_kwargs or {'return_value': None} + peer_kwargs = peer_kwargs or {} + + base_path = 'openassessment.xblock.ui_mixins.mfe.mixin.' + with patch(base_path + 'self_assess', **self_kwargs) as mock_self: + with patch(base_path + 'training_assess', **training_kwargs) as mock_training: + with patch(base_path + 'peer_assess', **peer_kwargs) as mock_peer: + yield AssessMocks(mock_self, mock_training, mock_peer) + + @ddt.data( + {}, + { + 'criterionFeedback': {}, + 'overallFeedback': '', + }, + { + 'optionsSelected': ['this is a list'], + 'criterionFeedback': 67, + 'overallFeedback': '', + } + ) + @scenario("data/basic_scenario.xml") + def test_incorrect_params(self, xblock, payload): + resp = self.request_assessment_submit(xblock, payload) + assert resp.status_code == 400 + assert resp.json['error']['error_code'] == error_codes.INCORRECT_PARAMETERS + + @ddt.data(None, 'cancelled', 'done', 'ai') + @scenario("data/basic_scenario.xml") + def test_not_allowed_step_error(self, xblock, status): + with self.mock_workflow_status(status): + resp = self.request_assessment_submit(xblock) + assert resp.status_code == 400 + assert resp.json['error']['error_code'] == error_codes.INVALID_STATE_TO_ASSESS + + @ddt.unpack + @ddt.data( + ('self', True, False, False), + ('training', False, True, False), + ('peer', False, False, True) + ) + @scenario("data/basic_scenario.xml") + def test_assess(self, xblock, step, expect_self, expect_training, expect_peer): + with self.mock_workflow_status(step): + with self.mock_assess_functions() as assess_mocks: + resp = self.request_assessment_submit(xblock) + assert resp.status_code == 200 + assert assess_mocks.self.called == expect_self + assert assess_mocks.training.called == expect_training + assert assess_mocks.peer.called == expect_peer + + @ddt.data(None, 'cancelled', 'waiting', 'self', 'training', 'done') + @scenario("data/basic_scenario.xml") + def test_continue_grading(self, xblock, step): + with self.mock_assess_functions() as assess_mocks: + with self.mock_workflow_status(step): + with self.mock_continue_grading(True): + resp = self.request_assessment_submit(xblock) + + assert resp.status_code == 200 + assess_mocks.self.assert_not_called() + assess_mocks.training.assert_not_called() + assess_mocks.peer.assert_called() + + @ddt.data('self', 'training', 'peer') + @scenario("data/basic_scenario.xml") + def test_assess_error(self, xblock, step): + error = AssessmentError("there was a problem") + with self.mock_workflow_status(step): + with self.mock_assess_functions(**{step + '_kwargs': {'side_effect': error}}): + resp = self.request_assessment_submit(xblock) + assert_error_response(resp, 500, error_codes.INTERNAL_EXCEPTION, str(error)) + + @scenario("data/basic_scenario.xml") + def test_training_assess_corrections(self, xblock): + corrections = {'ferocity': 'sublime', 'element': 'hydrogen'} + with self.mock_workflow_status('training'): + with self.mock_assess_functions(training_kwargs={'return_value': corrections}): + resp = self.request_assessment_submit(xblock) + + assert_error_response(resp, 400, error_codes.TRAINING_ANSWER_INCORRECT, corrections) + + +class AssessmentGetPeerTest(MFEHandlersTestBase): + + @scenario("data/basic_scenario.xml") + def test_get_peer(self, xblock): + with patch.object(PeerAssessmentAPI, 'get_peer_submission') as mock_get_peer: + with patch('openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer') as mock_serializer: + mock_serializer().data = str(uuid4()) + resp = self.request_assessment_get_peer(xblock) + assert resp.status_code == 200 + assert resp.json == mock_serializer().data + mock_get_peer.assert_called() diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index fafcccdf58..5c5382bbd2 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -2,15 +2,13 @@ Tests for PageDataSerializer """ from copy import deepcopy - from json import dumps, loads from unittest import TestCase from unittest.case import skip from unittest.mock import Mock, patch +import ddt from openassessment.fileupload.api import TeamFileDescriptor from openassessment.xblock.apis.submissions.submissions_actions import create_team_submission - - from openassessment.xblock.test.base import ( PEER_ASSESSMENTS, SELF_ASSESSMENT, @@ -57,6 +55,7 @@ def test_assessment_view(self, xblock, mock_submission_serializer, mock_assessme mock_submission_serializer.assert_not_called() +@ddt.ddt class TestPageDataSerializerAssessment(XBlockHandlerTestCase, SubmitAssessmentsMixin): """ Test for PageDataSerializer: Assessment view @@ -94,8 +93,9 @@ def test_student_training(self, xblock): } self.assertDictEqual(expected_response, response_data) + @ddt.data(True, False) @scenario("data/peer_only_scenario.xml", user_id="Alan") - def test_peer_response(self, xblock): + def test_peer_response(self, xblock, request_peer): student_item = xblock.get_student_item_dict() # Given responses available for peer grading @@ -113,11 +113,15 @@ def test_peer_response(self, xblock): text_responses = ["Answer A", "Answer B"] self.create_test_submission(xblock, student_item=student_item, submission_text=text_responses) + # ... and I do or do not have a submission assigned to me for grading + if request_peer: + xblock.peer_assessment_data().get_peer_submission() + # When I load my response self.context = {"view": "assessment", "step": "peer"} response_data = PageDataSerializer(xblock, context=self.context).data["response"] - # I get the appropriate response + # I get my current assessment, if I had one, and if I didn't, one is assigned to me expected_response = { "textResponses": other_text_responses, "uploadedFiles": None, @@ -180,7 +184,7 @@ def test_done_response(self, xblock): self.assertDictEqual(expected_response, response_data) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") - def test_jump_to_peer_response(self, xblock): + def test_jump_to_peer_response__no_active_assessment(self, xblock): student_item = xblock.get_student_item_dict() # Given responses available for peer grading @@ -199,7 +203,36 @@ def test_jump_to_peer_response(self, xblock): # When I try to jump back to that step self.context = {"view": "assessment", "step": "done"} self.context["jump_to_step"] = "peer" - response_data = PageDataSerializer(xblock, context=self.context).data["response"] + response_data = PageDataSerializer(xblock, context=self.context).data + + # I recieve an empty response because I have not yet requested a submission to assess + self.assertDictEqual({}, response_data["response"]) + + @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") + def test_jump_to_peer_response__active_assessment(self, xblock): + student_item = xblock.get_student_item_dict() + + # Given responses available for peer grading + other_student_item = deepcopy(student_item) + other_student_item["student_id"] = "Joan" + other_text_responses = ["Answer 1", "Answer 2"] + self.create_test_submission( + xblock, + student_item=other_student_item, + submission_text=other_text_responses, + ) + + # ... and I have completed the peer step of an ORA + self.create_submission_and_assessments(xblock, self.SUBMISSION, self.PEERS, PEER_ASSESSMENTS, None) + + # ... and I have been assigned a peer submission to review + sub = xblock.peer_assessment_data().get_peer_submission() + self.assertIsNotNone(sub) + + # When I try to jump back to that step + self.context = {"view": "assessment", "step": "done"} + self.context["jump_to_step"] = "peer" + response_data = PageDataSerializer(xblock, context=self.context).data # Then I can continue to receive peer responses to grade expected_response = { @@ -207,7 +240,7 @@ def test_jump_to_peer_response(self, xblock): "uploadedFiles": None, "teamUploadedFiles": None, } - self.assertDictEqual(expected_response, response_data) + self.assertDictEqual(expected_response, response_data["response"]) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") def test_jump_to_bad_step(self, xblock): From ca965ed856503ae3b64c0a4f7694e0273a057ff4 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Wed, 25 Oct 2023 15:58:37 -0400 Subject: [PATCH 19/27] feat: add cancellation info to progress serializer (#2093) * feat: add fields to serializer * test: add test for cancelled submission * fix: cancelled submissions map to active state of submission --- .../apis/submissions/submissions_api.py | 14 +++++ .../ui_mixins/mfe/page_context_serializer.py | 4 +- .../xblock/ui_mixins/mfe/serializer_utils.py | 1 + .../mfe/test_page_context_serializer.py | 63 ++++++++++++++++++- 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/openassessment/xblock/apis/submissions/submissions_api.py b/openassessment/xblock/apis/submissions/submissions_api.py index 56d7f2aeb2..6ec949be74 100644 --- a/openassessment/xblock/apis/submissions/submissions_api.py +++ b/openassessment/xblock/apis/submissions/submissions_api.py @@ -47,6 +47,20 @@ def cancellation_info(self): else: return self.workflow_data.get_workflow_cancellation_info(self.submission_uuid) + def _safe_get_cancellation_info_field(self, field): + cancellation_info = self.cancellation_info + if cancellation_info is None: + return None + return cancellation_info.get(field) + + @property + def cancelled_by(self): + return self._safe_get_cancellation_info_field('cancelled_by') + + @property + def cancelled_at(self): + return self._safe_get_cancellation_info_field('cancelled_at') + @property def has_received_final_grade(self): return self.workflow and self.workflow["status"] == "done" diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index 345a951ca4..fb95ea9c1a 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -8,6 +8,7 @@ from rest_framework.fields import ValidationError, CharField from rest_framework.serializers import ( BooleanField, + DateTimeField, IntegerField, Serializer, SerializerMethodField, @@ -142,7 +143,8 @@ class SubmissionStepInfoSerializer(ClosedInfoSerializer): hasSubmitted = BooleanField(source="has_submitted") hasCancelled = BooleanField(source="has_been_cancelled", default=False) - + cancelledBy = CharField(source="cancelled_by") + cancelledAt = DateTimeField(source="cancelled_at") teamInfo = SerializerMethodField() def get_teamInfo(self, instance): diff --git a/openassessment/xblock/ui_mixins/mfe/serializer_utils.py b/openassessment/xblock/ui_mixins/mfe/serializer_utils.py index 6bf57c4485..f201400f27 100644 --- a/openassessment/xblock/ui_mixins/mfe/serializer_utils.py +++ b/openassessment/xblock/ui_mixins/mfe/serializer_utils.py @@ -15,6 +15,7 @@ "waiting": "waiting", "staff": "staff", "done": "done", + "cancelled": "submission", } diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index 5c5382bbd2..f9058c8e8b 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -5,10 +5,12 @@ from json import dumps, loads from unittest import TestCase from unittest.case import skip -from unittest.mock import Mock, patch +from unittest.mock import Mock, PropertyMock, patch import ddt from openassessment.fileupload.api import TeamFileDescriptor +from openassessment.workflow.api import cancel_workflow from openassessment.xblock.apis.submissions.submissions_actions import create_team_submission +from openassessment.xblock.apis.submissions.submissions_api import SubmissionAPI from openassessment.xblock.test.base import ( PEER_ASSESSMENTS, SELF_ASSESSMENT, @@ -287,6 +289,8 @@ def test_submission(self, xblock): "closedReason": None, "hasSubmitted": False, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "peer": None, @@ -319,6 +323,8 @@ def test_student_training(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "studentTraining": { @@ -362,6 +368,8 @@ def test_student_training_due(self, xblock): "closedReason": "pastDue", "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "studentTraining": { @@ -405,6 +413,8 @@ def test_student_training_not_yet_available(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "studentTraining": { @@ -448,6 +458,8 @@ def test_peer_assessment(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "peer": { @@ -462,6 +474,47 @@ def test_peer_assessment(self, xblock): self.assertNestedDictEquals(expected_data, progress_data) + @scenario("data/peer_only_scenario.xml", user_id="Alan") + def test_peer_assessment__cancelled(self, xblock): + # Given I am on the peer step and then get cancelled + submission = self.create_test_submission(xblock) + staff_id, staff_username = 'staff12341234', 'Staff 1234' + cancel_workflow(submission['uuid'], "Test Cancel", staff_id, {}, {}) + + mock_cancellation_info = { + "cancelled_by": staff_username, + "cancelled_at": "2023-10-25T10:27:04.432546", + } + mock_get_cancellation_info = PropertyMock(return_value=mock_cancellation_info) + with patch.object(SubmissionAPI, 'cancellation_info', new_callable=mock_get_cancellation_info): + # When I ask for progress + context = {"step": "peer"} + progress_data = ProgressSerializer(xblock, context=context).data + + # Then I get the expected shapes + expected_data = { + "activeStepName": "submission", + "hasReceivedFinalGrade": False, + "receivedGrades": { + "peer": {}, + "staff": {}, + }, + "stepInfo": { + "submission": { + "closed": False, + "closedReason": None, + "hasSubmitted": True, + "hasCancelled": True, + "cancelledAt": mock_cancellation_info["cancelled_at"], + "cancelledBy": staff_username, + "teamInfo": {}, + }, + "peer": None, + }, + } + + self.assertNestedDictEquals(expected_data, progress_data) + @scenario("data/self_only_scenario.xml", user_id="Alan") def test_self_assessment(self, xblock): # Given I am on the self step @@ -485,6 +538,8 @@ def test_self_assessment(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "self": { @@ -520,6 +575,8 @@ def test_self_assessment_closed(self, xblock): "closedReason": "pastDue", "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "peer": None, @@ -556,6 +613,8 @@ def test_self_assessment_not_available(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": {}, }, "peer": None, @@ -601,6 +660,8 @@ def test_team_assignment(self, xblock): "closedReason": None, "hasSubmitted": True, "hasCancelled": False, + "cancelledAt": None, + "cancelledBy": None, "teamInfo": { "teamName": "Red Squadron", "teamUsernames": ["Red Leader", "Red Two", "Red Five"], From 4f6784c346fd0045896a04802cf0700b34ed6edb Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Thu, 26 Oct 2023 12:10:11 -0400 Subject: [PATCH 20/27] fix: fix getting has submitted info (#2096) --- openassessment/xblock/ui_mixins/mfe/mixin.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index bf7edb85c1..dcc06d342b 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -84,9 +84,8 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument # Determine which mode we are viewing in, since data comes from different sources if workflow_step or jump_step == "submission": - has_submitted = self.workflow_data.has_submitted # View our submitted response - if has_submitted: + if self.submission_data.has_submitted: serializer_context.update({"view": "submission"}) # View our draft response From 3e08062852ae2faf49c508dd8501914ebe06d73d Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Mon, 30 Oct 2023 12:39:58 -0400 Subject: [PATCH 21/27] fix: data routing tests & fixes (#2098) * refactor: delete unused file * fix: raise response correctly * fix: correct step check for submissions view * fix: jump step logic * test: add get_learner_data tests * docs: fix some docstring typos * docs: add info for PageDataSerializer args/context --- openassessment/xblock/test/base.py | 2 +- openassessment/xblock/ui_mixins/mfe/mixin.py | 29 ++- .../ui_mixins/mfe/page_context_serializer.py | 9 + .../xblock/ui_mixins/mfe/serializers.py | 223 ------------------ .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 117 ++++++++- 5 files changed, 140 insertions(+), 240 deletions(-) delete mode 100644 openassessment/xblock/ui_mixins/mfe/serializers.py diff --git a/openassessment/xblock/test/base.py b/openassessment/xblock/test/base.py index c3a408584e..163e356da2 100644 --- a/openassessment/xblock/test/base.py +++ b/openassessment/xblock/test/base.py @@ -240,7 +240,7 @@ def request( raise NotImplementedError(f"Response format '{response_format}' not supported") def assert_assessment_event_published(self, xblock, event_name, assessment, **kwargs): - """ Checks assessment event published successfuly. """ + """ Checks assessment event published successfully. """ parts_list = [] for part in assessment["parts"]: # Some assessment parts do not include point values, diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index dcc06d342b..c00b07060d 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -76,14 +76,15 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument if jump_step: jumpable_steps = ("submission", "peer", "grades") if jump_step not in jumpable_steps: - return JsonHandlerError(404, f"Invalid jump to step: {jump_step}") + raise JsonHandlerError(404, f"Invalid jump to step: {jump_step}") if self._can_jump_to_step(workflow_step, jump_step): serializer_context.update({"jump_to_step": suffix}) else: - return JsonHandlerError(400, f"Cannot jump to step: {jump_step}") + raise JsonHandlerError(400, f"Cannot jump to step: {jump_step}") # Determine which mode we are viewing in, since data comes from different sources - if workflow_step or jump_step == "submission": + if workflow_step == "submission" or jump_step == "submission": + # View our submitted response if self.submission_data.has_submitted: serializer_context.update({"view": "submission"}) @@ -91,7 +92,8 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument # View our draft response else: serializer_context.update({"view": "draft"}) - # View the selected assessment step + + # View the current assessment step else: serializer_context.update({"view": "assessment"}) @@ -101,17 +103,24 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument def _can_jump_to_step(self, workflow_step, jump_step): """ A helper to determine if we can jump to a step or not """ - if jump_step == workflow_step: - return True - - jump_step_to_workflow_step = { + step_name_mappings = { "submission": "submission", "peer": "peer", "grades": "done" } - jump_step_name = jump_step_to_workflow_step[jump_step] - step_status = self.workflow_data.status_details.get(jump_step_name, {}) + workflow_step_to_jump_to = step_name_mappings[jump_step] + + # Can always "jump" to submission + if workflow_step_to_jump_to == "submission": + return True + + # Can always "jump" to the step you're on + if jump_step == workflow_step: + return True + + # Can jump to a step you've completed + step_status = self.workflow_data.status_details.get(workflow_step_to_jump_to, {}) return step_status.get("complete", False) def _submission_draft_handler(self, data): diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index fb95ea9c1a..1ac04a2efa 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -298,6 +298,15 @@ class PageDataSerializer(Serializer): Data for rendering a page in the ORA MFE Requires context to differentiate between Assessment and Submission views + + Args: + * ORA XBlock (self) + + Context: + * step - The Workflow step + * view - One of "submission" when drafting / viewing a submission or "assessment" + assessing responses / viewing grades. + * jump_to_step (Optional) - Allowing user to jump back to view a previous step. """ requires_context = True diff --git a/openassessment/xblock/ui_mixins/mfe/serializers.py b/openassessment/xblock/ui_mixins/mfe/serializers.py deleted file mode 100644 index 6ce4a6341e..0000000000 --- a/openassessment/xblock/ui_mixins/mfe/serializers.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -Serializers for ORA's BFF. - -These are the response shapes that power the MFE implementation of the ORA UI. -""" -# pylint: disable=abstract-method - -from rest_framework.serializers import ( - BooleanField, - DateTimeField, - IntegerField, - Serializer, - CharField, - ListField, - SerializerMethodField, -) - - -class CharListField(ListField): - child = CharField() - - -class IsRequiredField(BooleanField): - """ - Utility for checking if a field is "required" to reduce repeated code. - """ - - def to_representation(self, value): - return value == "required" - - -class TextResponseConfigSerializer(Serializer): - enabled = SerializerMethodField() - required = IsRequiredField(source="text_response") - editorType = CharField(source="text_response_editor") - allowLatexPreview = BooleanField(source="allow_latex") - - def get_enabled(self, block): - return block.text_response is not None - - -class FileResponseConfigSerializer(Serializer): - enabled = SerializerMethodField() - required = IsRequiredField(source="file_upload_response") - fileUploadLimit = SerializerMethodField() - allowedExtensions = CharListField(source="get_allowed_file_types_or_preset") - blockedExtensions = CharListField(source="FILE_EXT_BLACK_LIST") - fileTypeDescription = CharField(source="file_upload_type") - - def get_enabled(self, block): - return block.file_upload_response is not None - - def get_fileUploadLimit(self, block): - if not block.allow_multiple_files: - return 1 - return block.MAX_FILES_COUNT - - -class TeamsConfigSerializer(Serializer): - enabled = BooleanField(source="is_team_assignment") - teamsetName = SerializerMethodField() - - def get_teamsetName(self, block): - if block.teamset_config is not None: - return block.teamset_config.name - return None - - -class SubmissionConfigSerializer(Serializer): - startDatetime = DateTimeField(source="submission_start") - endDatetime = DateTimeField(source="submission_due") - - textResponseConfig = TextResponseConfigSerializer(source="*") - fileResponseConfig = FileResponseConfigSerializer(source="*") - - teamsConfig = TeamsConfigSerializer(source="*") - - -class RubricFeedbackConfigSerializer(Serializer): - description = CharField(source="rubric_feedback_prompt") # is this this field? - defaultText = CharField(source="rubric_feedback_default_text") - - -class RubricCriterionOptionSerializer(Serializer): - name = CharField() - label = CharField() - points = IntegerField() - description = CharField(source="explanation") - - -class RubricCriterionSerializer(Serializer): - name = CharField(source="label") - description = CharField(source="prompt") - feedbackEnabled = SerializerMethodField() - feedbackRequired = IsRequiredField(source="feedback") - options = RubricCriterionOptionSerializer(many=True) - - @staticmethod - def _feedback(criterion): - # Feedback is disabled as a default - return criterion.get("feedback", "disabled") - - def get_feedbackEnabled(self, criterion): - # Feedback can be specified as optional or required - return self._feedback(criterion) != "disabled" - - -class RubricConfigSerializer(Serializer): - showDuringResponse = BooleanField(source="show_rubric_during_response") - feedbackConfig = RubricFeedbackConfigSerializer(source="*") - criteria = RubricCriterionSerializer( - many=True, source="rubric_criteria_with_labels" - ) - - -class SelfSettingsSerializer(Serializer): - required = BooleanField(default=True) - - startTime = DateTimeField(source="start") - endTime = DateTimeField(source="due") - - -class PeerSettingsSerializer(Serializer): - required = BooleanField(default=True) - - startTime = DateTimeField(source="start") - endTime = DateTimeField(source="due") - - minNumberToGrade = IntegerField(source="must_grade") - minNumberToBeGradedBy = IntegerField(source="must_be_graded_by") - - enableFlexibleGrading = BooleanField( - source="enable_flexible_grading", required=False - ) - - -class AssessmentStepSettingsSerializer(Serializer): - """ - Generic Assessments step, where we just need to know if the step is - required given the ora.rubric_assessments source. - """ - - required = BooleanField(default=True) - - def _get_step(self, rubric_assessments, step_name): - """Get the assessment step config for a given step_name""" - for step in rubric_assessments: - if step["name"] == step_name: - return step - return None - - def __init__(self, *args, **kwargs): - self.step_name = kwargs.pop("step_name") - super().__init__(*args, **kwargs) - - def to_representation(self, instance): - assessment_step = self._get_step(instance, self.step_name) - - # Special handling for the peer step which includes extra fields - if assessment_step and self.step_name == "peer-assessment": - return PeerSettingsSerializer(assessment_step).data - elif assessment_step and self.step_name == "self-assessment": - return SelfSettingsSerializer(assessment_step).data - - # If we didn't find a step, it is not required - if assessment_step is None: - assessment_step = {"required": False} - - return super().to_representation(assessment_step) - - -class AssessmentStepsSettingsSerializer(Serializer): - training = AssessmentStepSettingsSerializer( - step_name="student-training", source="rubric_assessments" - ) - peer = AssessmentStepSettingsSerializer( - step_name="peer-assessment", source="rubric_assessments" - ) - # Workaround to allow reserved keyword in serializer key - vars()["self"] = AssessmentStepSettingsSerializer( - step_name="self-assessment", source="rubric_assessments" - ) - staff = AssessmentStepSettingsSerializer( - step_name="staff-assessment", source="rubric_assessments" - ) - - -class AssessmentStepsSerializer(Serializer): - order = SerializerMethodField() - settings = AssessmentStepsSettingsSerializer(source="*") - - def get_order(self, block): - return [step["name"] for step in block.rubric_assessments] - - -class LeaderboardConfigSerializer(Serializer): - enabled = SerializerMethodField() - numberOfEntries = IntegerField(source="leaderboard_show") - - def get_enabled(self, block): - return block.leaderboard_show > 0 - - -class OraBlockInfoSerializer(Serializer): - """ - Main serializer for statically-defined ORA Block information - """ - - title = CharField() - prompts = SerializerMethodField(source="*") - baseAssetUrl = SerializerMethodField(source="*") - - submissionConfig = SubmissionConfigSerializer(source="*") - assessmentSteps = AssessmentStepsSerializer(source="*") - rubricConfig = RubricConfigSerializer(source="*") - leaderboardConfig = LeaderboardConfigSerializer(source="*") - - def get_baseAssetUrl(self, block): - # pylint: disable=protected-access - return block.get_base_url_path_for_course_assets(block.course.id) - - def get_prompts(self, block): - return [prompt["description"] for prompt in block.prompts] diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index 437b513334..62499e3bf1 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -9,6 +9,7 @@ import ddt from django.contrib.auth import get_user_model +from mock import MagicMock from submissions import api as submission_api from submissions import team_api as submission_team_api @@ -33,7 +34,7 @@ UnsupportedFileTypeException ) from openassessment.xblock.apis.submissions.file_api import FileAPI -from openassessment.xblock.test.base import XBlockHandlerTestCase, scenario +from openassessment.xblock.test.base import SubmissionTestMixin, XBlockHandlerTestCase, scenario from openassessment.xblock.test.test_staff_area import NullUserService, UserStateService from openassessment.xblock.test.test_submission import COURSE_ID, setup_mock_team from openassessment.xblock.test.test_team import MOCK_TEAM_ID, MockTeamsService @@ -41,6 +42,14 @@ from openassessment.xblock.ui_mixins.mfe.submission_serializers import DraftResponseSerializer, SubmissionSerializer +class MockSerializer(MagicMock): + """ Hack to get JSON-serializable response from serializer """ + + @property + def data(self): + return {} + + class MFEHandlersTestBase(XBlockHandlerTestCase): def setUp(self): @@ -78,12 +87,14 @@ def request_create_submission(self, xblock, payload=None): response_format='response' ) - def request_learner_submission_info(self, xblock): + def request_get_learner_data(self, xblock, suffix=None): return super().request( xblock, - 'get_block_learner_submission_data', - '', - response_format='response' + 'get_learner_data', + "{}", + request_method="POST", + response_format='response', + suffix=suffix, ) def request_save_draft(self, xblock, payload=None): @@ -156,7 +167,7 @@ def assert_error_response(response, status_code, error_code, context=''): def create_student_and_submission(student, course, item, answer, xblock=None): - """ Creats a student and submission for tests. """ + """ Creates a student and submission for tests. """ submission = submission_api.create_submission( { 'student_id': student, @@ -184,6 +195,100 @@ def assert_called_once_with_helper(mock, expected_first_arg, expected_additional assert not mock.call_args.kwargs +@ddt.ddt +class GetLearnerDataRoutingTest(MFEHandlersTestBase, SubmissionTestMixin): + """ Tests for routing / validation on get_learner_data """ + + @patch("openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer") + @scenario("data/basic_scenario.xml") + def test_start_submission(self, xblock, mock_serializer): + # Given we haven't started a submission + mock_serializer.return_value = MockSerializer() + + # When I ask for learner data + _ = self.request_get_learner_data(xblock) + + # Then I get submission + expected_context = { + "step": "submission", + "view": "draft", + } + mock_serializer.assert_called_once_with(xblock, context={**expected_context}) + + @patch("openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer") + @scenario("data/basic_scenario.xml") + def test_bad_jump_step(self, xblock, mock_serializer): + # Given any state + mock_serializer.return_value = MockSerializer() + + # When I try to jump to a bad step + response = self.request_get_learner_data(xblock, suffix="asdf") + + # Then I get an error and don't return data + mock_serializer.assert_not_called() + + expected_status = 404 + self.assertEqual(expected_status, response.status_code) + + expected_body = {'error': 'Invalid jump to step: asdf'} + self.assertDictEqual(expected_body, json.loads(response.body)) + + @ddt.data("peer", "grades") + @patch("openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer") + @scenario("data/basic_scenario.xml") + def test_jump_to_inaccessible_step(self, xblock, inaccessible_step, mock_serializer): + # Given I'm on an early step + mock_serializer.return_value = MockSerializer() + + # When I try to jump to a step I can't access + response = self.request_get_learner_data(xblock, suffix=inaccessible_step) + + # Then I get an error and don't return data + mock_serializer.assert_not_called() + + expected_status = 400 + self.assertEqual(expected_status, response.status_code) + + expected_body = {'error': f'Cannot jump to step: {inaccessible_step}'} + self.assertDictEqual(expected_body, json.loads(response.body)) + + @patch("openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer") + @scenario("data/basic_scenario.xml", user_id="Alice") + def test_assessment_step(self, xblock, mock_serializer): + # Given I've completed my submission + self.create_test_submission(xblock) + mock_serializer.return_value = MockSerializer() + + # When I try to load my data + _ = self.request_get_learner_data(xblock, suffix=None) + + # Then I am routed to the correct assessment step + expected_context = { + "step": "self", + "view": "assessment", + } + mock_serializer.assert_called_once_with(xblock, context={**expected_context}) + + @patch("openassessment.xblock.ui_mixins.mfe.mixin.PageDataSerializer") + @scenario("data/basic_scenario.xml", user_id="Alice") + def test_jump_back_to_submission_step(self, xblock, mock_serializer): + # Given I've completed my submission + # xblock.get_student_item + self.create_test_submission(xblock) + mock_serializer.return_value = MockSerializer() + + # When I try to jump back to submission + _ = self.request_get_learner_data(xblock, suffix="submission") + + # Then I am routed to the correct view + expected_context = { + "step": "self", + "jump_to_step": "submission", + "view": "submission", + } + mock_serializer.assert_called_once_with(xblock, context={**expected_context}) + + class GetLearnerSubmissionDataIndividualSubmissionTest(MFEHandlersTestBase): maxDiff = None From 9ce6bfd66a7cc01a70f274ef0852b7602b3438e2 Mon Sep 17 00:00:00 2001 From: Leangseu Kim Date: Thu, 26 Oct 2023 16:21:16 -0400 Subject: [PATCH 22/27] chore: update assessment criterions shape --- .../ui_mixins/mfe/assessment_serializers.py | 8 ++------ .../mfe/test_assessment_serializers.py | 18 ++++-------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index 885c5f5b2d..ee2847d8c8 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -32,15 +32,11 @@ class AssessmentCriterionSerializer(Serializer): """ returns: { - name: (String) Name of the criterion - selectedOption: (String) Label of the selected option - selectedPoints: (Int) Points awarded for selected option + selectedOption: (Int) Order of the selected option feedback: (String) Feedback for the selected option } """ - name = CharField(source="criterion.name") - selectedOption = CharField(source="option.label") - selectedPoints = IntegerField(source="option.points") + selectedOption = IntegerField(source="option.order_num") feedback = CharField() diff --git a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py index 57a85cf5a8..03518810fd 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py @@ -319,18 +319,12 @@ class TestAssessmentCriterionSerializer(TestCase): def test_assessment_criterion(self): criterion = AssessmentCriterionSerializer({ - "criterion": { - "name": "Foo", - }, "option": { - "label": "Bar", - "points": 5, + "order_num": 3, }, "feedback": "Baz", }).data - self.assertEqual(criterion["name"], "Foo") - self.assertEqual(criterion["selectedOption"], "Bar") - self.assertEqual(criterion["selectedPoints"], 5) + self.assertEqual(criterion["selectedOption"], 3) self.assertEqual(criterion["feedback"], "Baz") @@ -344,14 +338,10 @@ def test_assessment_data(self): "feedback": "Foo", "parts": [ { - "criterion": { - "name": "Bar", - }, "option": { - "label": "Baz", - "points": 5, + "order_num": 3, }, - "feedback": "Buzz", + "feedback": "Baz", }, ], }).data From 28afca2dbd403594f243dabdddd90d4dfb8dd413 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Tue, 31 Oct 2023 17:03:51 -0400 Subject: [PATCH 23/27] feat: split peer assessments into peer and unused peer (#2100) * fix: change key from peers to peer * feat: split peer assessments into peer and unused peer * style: comments --- openassessment/assessment/models/peer.py | 31 +++++++-- .../apis/assessments/peer_assessment_api.py | 14 ++++ openassessment/xblock/apis/grades_api.py | 8 ++- .../ui_mixins/mfe/assessment_serializers.py | 31 ++++++++- .../mfe/test_assessment_serializers.py | 65 ++++++++++++++++--- 5 files changed, 130 insertions(+), 19 deletions(-) diff --git a/openassessment/assessment/models/peer.py b/openassessment/assessment/models/peer.py index f7d5743f3b..838c53d778 100644 --- a/openassessment/assessment/models/peer.py +++ b/openassessment/assessment/models/peer.py @@ -523,6 +523,16 @@ class PeerWorkflowItem(models.Model): # This WorkflowItem was used to determine the final score for the Workflow. scored = models.BooleanField(default=False) + @classmethod + def _get_assessments(cls, submission_uuid, scored): + return Assessment.objects.filter( + pk__in=[ + item.assessment.pk for item in PeerWorkflowItem.objects.filter( + submission_uuid=submission_uuid, scored=scored + ) + ] + ) + @classmethod def get_scored_assessments(cls, submission_uuid): """ @@ -533,15 +543,22 @@ def get_scored_assessments(cls, submission_uuid): Returns: QuerySet of Assessment objects. + """ + return cls._get_assessments(submission_uuid, True) + @classmethod + def get_unscored_assessments(cls, submission_uuid): """ - return Assessment.objects.filter( - pk__in=[ - item.assessment.pk for item in PeerWorkflowItem.objects.filter( - submission_uuid=submission_uuid, scored=True - ) - ] - ) + Return all unscored assessments for a given submission. + + Args: + submission_uuid (str): The UUID of the submission. + + Returns: + QuerySet of Assessment objects. + + """ + return cls._get_assessments(submission_uuid, False) @classmethod def get_bulk_scored_assessments(cls, submission_uuids): diff --git a/openassessment/xblock/apis/assessments/peer_assessment_api.py b/openassessment/xblock/apis/assessments/peer_assessment_api.py index 0dcef3c9a7..5a33e217ef 100644 --- a/openassessment/xblock/apis/assessments/peer_assessment_api.py +++ b/openassessment/xblock/apis/assessments/peer_assessment_api.py @@ -6,6 +6,8 @@ from openassessment.assessment.errors import PeerAssessmentWorkflowError from openassessment.assessment.api import peer as peer_api from openassessment.assessment.errors.peer import PeerAssessmentInternalError, PeerAssessmentRequestError +from openassessment.assessment.models.peer import PeerWorkflowItem +from openassessment.assessment.serializers.base import serialize_assessments from openassessment.workflow.errors import AssessmentWorkflowError from openassessment.xblock.apis.assessments.errors import ( ReviewerMustHaveSubmittedException, @@ -38,6 +40,18 @@ def assessment(self): def assessments(self): return peer_api.get_assessments(self.submission_uuid) + @property + def scored_assessments(self): + return serialize_assessments(PeerWorkflowItem.get_scored_assessments(self.submission_uuid)) + + @property + def unscored_assessments(self): + return serialize_assessments(PeerWorkflowItem.get_unscored_assessments(self.submission_uuid)) + + @property + def peer_grade(self): + return self._block.grades_data.peer_score + @property def continue_grading(self): return self._continue_grading and self.workflow_data.is_peer_complete diff --git a/openassessment/xblock/apis/grades_api.py b/openassessment/xblock/apis/grades_api.py index 243efe47fa..8f107a7a1e 100644 --- a/openassessment/xblock/apis/grades_api.py +++ b/openassessment/xblock/apis/grades_api.py @@ -47,7 +47,13 @@ def peer_score(self): } """ submission_uuid = self._get_submission_uuid() - peer_requirements = self._block.workflow_requirements()["peer"] + if submission_uuid is None: + return None + + peer_requirements = self._block.workflow_requirements().get('peer') + if peer_requirements is None: + return None + course_settings = self._block.get_course_workflow_settings() peer_score = peer_api.get_score( diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index ee2847d8c8..6b922d5e1e 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -57,6 +57,32 @@ class AssessmentStepSerializer(Serializer): assessment = AssessmentDataSerializer(source="*") +class PeerAssessmentsSerializer(Serializer): + """ + Assessment step serializer for peer step + """ + + stepScore = AssessmentScoreSerializer(source='peer_grade') + assessments = AssessmentDataSerializer( + source="scored_assessments", + many=True, + allow_empty=True + ) + + +class UnweightedPeerAssessmentsSerializer(Serializer): + """ + Assessment step serializer for peer step + """ + + stepScore = NullField(source='*') + assessments = AssessmentDataSerializer( + source="unscored_assessments", + many=True, + allow_empty=True + ) + + class SubmissionFileSerializer(Serializer): fileUrl = URLField(source="file_key") fileDescription = CharField(source="file_description") @@ -84,9 +110,8 @@ class AssessmentGradeSerializer(Serializer): effectiveAssessmentType = SerializerMethodField() self = AssessmentStepSerializer(source="self_assessment_data.assessment") staff = AssessmentStepSerializer(source="staff_assessment_data.assessment") - peers = AssessmentStepSerializer( - source="peer_assessment_data.assessments", many=True - ) + peer = PeerAssessmentsSerializer(source="peer_assessment_data") + peerUnweighted = UnweightedPeerAssessmentsSerializer(source="peer_assessment_data") def get_effectiveAssessmentType(self, instance): # pylint: disable=unused-argument """ diff --git a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py index 03518810fd..aaba2f5619 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py @@ -5,6 +5,7 @@ from unittest.mock import patch from django.test import TestCase +from openassessment.workflow import api as workflow_api from openassessment.fileupload.api import FileUpload from openassessment.xblock.test.base import ( PEER_ASSESSMENTS, @@ -157,6 +158,58 @@ def test_files(self, xblock, mock_get_files): self.assertDictEqual(expected_response, data) +class TestPeerSplit(XBlockHandlerTestCase, SubmitAssessmentsMixin): + ASSESSMENT = { + 'options_selected': {'𝓒𝓸𝓷𝓬𝓲𝓼𝓮': 'ﻉซƈﻉɭɭﻉกՇ', 'Form': 'Fair'}, + 'criterion_feedback': {}, + 'overall_feedback': "" + } + + @scenario("data/grade_scenario.xml", user_id="Bernard") + def test_scored_unscored(self, xblock): + student_item = xblock.get_student_item_dict() + submission = self.create_test_submission( + xblock, student_item=student_item, submission_text=self.SUBMISSION + ) + + other_learners = ['u1', 'u2', 'u3', 'u4'] + # Create submissions from other users + scorer_subs = self.create_peer_submissions( + student_item, other_learners, self.SUBMISSION + ) + + # All four assess the target learner even though we only need two + for scorer_sub, scorer_name in list(zip(scorer_subs, other_learners)): + self.create_peer_assessment( + scorer_sub, + scorer_name, + submission, + self.ASSESSMENT, + xblock.rubric_criteria, + 2, + ) + + # Have the target learner submit one assessment so they can recieve a grade, and update their status + self.create_peer_assessment(submission, 'Bernard', scorer_subs[0], self.ASSESSMENT, xblock.rubric_criteria, 2) + workflow_api.update_from_assessments( + submission['uuid'], + {'peer': {'must_be_graded_by': 2, 'must_grade': 1}}, + {} + ) + + context = {"response": submission, "step": "peer"} + + # When I load my response + data = AssessmentGradeSerializer(xblock.api_data, context=context).data + + # I get the appropriate response + self.assertEqual(context["step"], data["effectiveAssessmentType"]) + self.assertEqual(data["peer"]["stepScore"], {'earned': 5, 'possible': 6}) + self.assertEqual(len(data["peer"]["assessments"]), 2) + self.assertIsNone(data["peerUnweighted"]["stepScore"]) + self.assertEqual(len(data["peerUnweighted"]["assessments"]), 2) + + class TestAssessmentGradeSerializer(XBlockHandlerTestCase, SubmitAssessmentsMixin): ASSESSMENT = { 'options_selected': {'𝓒𝓸𝓷𝓬𝓲𝓼𝓮': 'ﻉซƈﻉɭɭﻉกՇ', 'Form': 'Fair'}, @@ -228,7 +281,7 @@ def test_peer_assement_steps(self, xblock): graded_by = xblock.get_assessment_module("peer-assessment")["must_be_graded_by"] for scorer_sub, scorer_name, assessment in list( zip(scorer_subs, self.PEERS, PEER_ASSESSMENTS) - )[:-1]: + ): self.create_peer_assessment( scorer_sub, scorer_name, @@ -245,13 +298,9 @@ def test_peer_assement_steps(self, xblock): # I get the appropriate response self.assertEqual(context["step"], data["effectiveAssessmentType"]) - for i in range(len(data["peers"])): - peer = data["peers"][i] - serialize_peer = AssessmentStepSerializer( - xblock.api_data.peer_assessment_data().assessments[i], context=context - ).data - self.assertEqual(serialize_peer["stepScore"], peer["stepScore"]) - self.assertEqual(serialize_peer["assessment"], serialize_peer["assessment"]) + self.assertEqual(data["peer"], {'stepScore': None, 'assessments': []}) + self.assertIsNone(data["peerUnweighted"]['stepScore']) + self.assertEqual(len(data["peerUnweighted"]['assessments']), len(self.PEERS)) @scenario("data/grade_scenario.xml", user_id="Alan") def test_assessment_step_score(self, xblock): From bea8ccd6e540b4a3fef3869b9e1460fbbe93c8f9 Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Thu, 2 Nov 2023 10:47:57 -0400 Subject: [PATCH 24/27] refactor: update assessments formats (#2106) * refactor: update assessments data format Frontend now uses a data format which differs from how we store assessments in the backend. Had to create a bunch of extra serializers to handle these different views and directions of data transformation. Ideally there is follow-up work here to minimize the number of one-off serializers and consolidate some of that logic. --- .../ui_mixins/mfe/assessment_serializers.py | 87 +++++++++++++++++-- openassessment/xblock/ui_mixins/mfe/mixin.py | 26 +++--- .../mfe/test_assessment_serializers.py | 25 +++++- .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 19 +++- 4 files changed, 135 insertions(+), 22 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py index 6b922d5e1e..e525037001 100644 --- a/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/assessment_serializers.py @@ -9,7 +9,6 @@ SerializerMethodField, URLField, Serializer, - DictField, BooleanField, ) from openassessment.xblock.ui_mixins.mfe.serializer_utils import NullField @@ -30,7 +29,9 @@ class AssessmentScoreSerializer(Serializer): class AssessmentCriterionSerializer(Serializer): """ - returns: + Serialize assessment criterion values from DB representation to frontend data structure. + + Returns: { selectedOption: (Int) Order of the selected option feedback: (String) Feedback for the selected option @@ -42,10 +43,16 @@ class AssessmentCriterionSerializer(Serializer): class AssessmentDataSerializer(Serializer): """ - Assessment data serializer + Serialize assessment data from DB representation to frontend data structure. + + Returns: + { + criteria: [ AssessmentCriterionSerializer ] + overallFeedback: (String / Empty) + } """ overallFeedback = CharField(source="feedback") - assessmentCriterions = AssessmentCriterionSerializer(source="parts", many=True) + criteria = AssessmentCriterionSerializer(source="parts", many=True) class AssessmentStepSerializer(Serializer): @@ -192,9 +199,73 @@ def get_uploadedFiles(self, instance): return [SubmissionFileSerializer(file).data for file in files] -class AssessmentSubmitRequestSerializer(Serializer): - """" Serializer for validating request shape """ - optionsSelected = DictField(child=CharField(), allow_empty=True) - criterionFeedback = DictField(child=CharField(), allow_empty=True) +class MfeAssessmentCriterionSerializer(Serializer): + """ + Frontend's view of rubric criterion values for an assessment + + { + selectedOption: (Int) Order of the selected option + feedback: (String / Empty) Feedback for the selected option + } + """ + selectedOption = IntegerField() + feedback = CharField() + + +class MfeAssessmentDataSerializer(Serializer): + """ + Frontend's view of Assessment Data. + + criteria: [ MfeAssessmentCriterion ], + overallFeedback: (String / Empty) Feedback for the Assessment + """ + criteria = MfeAssessmentCriterionSerializer(many=True) overallFeedback = CharField(allow_blank=True) + + +class AssessmentSubmitRequestSerializer(MfeAssessmentDataSerializer): + """" + Serializer for validating request shape and unpacking data for assessment APIs. + + Args: Data in the form + { + criteria: [ + // Rubric criterion + { + selectedOption: (Int) Order of the selected option + feedback: (String / Empty) Feedback for the selected option + } + ... + ], + overallFeedback: (String / Empty) + } + """ + continueGrading = BooleanField(required=False, default=False) + + def to_legacy_format(self, xblock): + """ + Converts given assessment format to format needed for submitting an assessment: + + >>> options_selected = {"clarity": "Very clear", "precision": "Somewhat precise"} + >>> criterion_feedback = {"clarity": "I thought this essay was very clear."} + >>> feedback = "Your submission was thrilling." + """ + options_selected = {} + criterion_feedback = {} + + for i, criterion_data in enumerate(self.data['criteria']): + + # Look up the name and value for each given rubric selection + criterion_name = xblock.rubric_criteria[i]['name'] + selected_value = xblock.rubric_criteria[i]['options'][criterion_data['selectedOption']]['name'] + options_selected[criterion_name] = selected_value + + # Attach feedback for the criterion + criterion_feedback[criterion_name] = criterion_data['feedback'] + + return { + "options_selected": options_selected, + "criterion_feedback": criterion_feedback, + "feedback": self.data["overallFeedback"] + } diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index c00b07060d..5e020569b9 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -25,7 +25,10 @@ SubmitInternalError, UnsupportedFileTypeException ) -from openassessment.xblock.ui_mixins.mfe.assessment_serializers import AssessmentSubmitRequestSerializer +from openassessment.xblock.ui_mixins.mfe.assessment_serializers import ( + AssessmentSubmitRequestSerializer, + MfeAssessmentDataSerializer, +) from openassessment.xblock.ui_mixins.mfe.constants import error_codes, handler_suffixes from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import OraBlockInfoSerializer from openassessment.xblock.ui_mixins.mfe.page_context_serializer import PageDataSerializer @@ -307,30 +310,30 @@ def _assessment_submit_handler(self, data): serializer = AssessmentSubmitRequestSerializer(data=data) if not serializer.is_valid(): raise OraApiException(400, error_codes.INCORRECT_PARAMETERS, serializer.errors) - data = serializer.validated_data - peer_data = self.peer_assessment_data(data['continueGrading']) + assessment_data = serializer.to_legacy_format(self) + peer_data = self.peer_assessment_data(serializer.data['continueGrading']) try: if peer_data.continue_grading or self.workflow_data.is_peer: peer_assess( - data['optionsSelected'], - data['overallFeedback'], - data['criterionFeedback'], + assessment_data['options_selected'], + assessment_data['feedback'], + assessment_data['criterion_feedback'], self.config_data, self.workflow_data, peer_data, ) elif self.workflow_data.is_self: self_assess( - data['optionsSelected'], - data['criterionFeedback'], - data['overallFeedback'], + assessment_data['options_selected'], + assessment_data['criterion_feedback'], + assessment_data['feedback'], self.config_data, self.workflow_data, self.self_data ) elif self.workflow_data.is_training: corrections = training_assess( - data['optionsSelected'], + assessment_data['options_selected'], self.config_data, self.workflow_data, ) @@ -349,6 +352,9 @@ def _assessment_submit_handler(self, data): except (AssessmentError, AssessmentWorkflowError) as e: raise OraApiException(500, error_codes.INTERNAL_EXCEPTION, str(e)) from e + # Return assessment data for the frontend + return MfeAssessmentDataSerializer(data).data + def _assessment_get_peer_handler(self): # Call get_peer_submission to grab a new peer submission self.peer_assessment_data().get_peer_submission() diff --git a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py index aaba2f5619..2452b5e0ab 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py +++ b/openassessment/xblock/ui_mixins/mfe/test_assessment_serializers.py @@ -22,6 +22,7 @@ AssessmentScoreSerializer, AssessmentDataSerializer, AssessmentCriterionSerializer, + AssessmentSubmitRequestSerializer, ) @@ -396,4 +397,26 @@ def test_assessment_data(self): }).data self.assertEqual(assessment_data["overallFeedback"], "Foo") - self.assertEqual(len(assessment_data["assessmentCriterions"]), 1) + self.assertEqual(len(assessment_data["criteria"]), 1) + + +class TestAssessmentSubmitRequestSerializer(TestCase): + """ + Test for AssessmentSubmitRequestSerializer + """ + + def test_assessment_data(self): + assessment_submit_request_data = AssessmentSubmitRequestSerializer({ + "criteria": [ + { + "selectedOption": 3, + "feedback": "Baz", + } + ], + "overallFeedback": "Foo", + "continueGrading": True, + }).data + + self.assertEqual(assessment_submit_request_data["overallFeedback"], "Foo") + self.assertEqual(len(assessment_submit_request_data["criteria"]), 1) + self.assertTrue(assessment_submit_request_data["continueGrading"]) diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index 62499e3bf1..1da8815737 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -70,10 +70,23 @@ def mock_get_url(self, expected_file_urls=None): DEFAULT_DRAFT_VALUE = {'response': {'text_responses': ['hi']}} DEFAULT_SUBMIT_VALUE = {'response': {'text_responses': ['Hello World', 'Goodbye World']}} DEFAULT_DELETE_FILE_VALUE = {'fileIndex': 1} + DEFAULT_ASSESSMENT_SUBMIT_VALUE = { - 'optionsSelected': {'ferocity': 'fine', 'color': 'blue', 'element': 'volcano'}, - 'criterionFeedback': {'ferocity': 'rawr!', 'color': ':)', 'element': 'i prefer lead'}, - 'overallFeedback': 'i have no strong feelings', + "criteria": [ + { + "selectedOption": 2, + "feedback": "rawr!", + }, + { + "selectedOption": 0, + "feedback": ":)", + }, + { + "selectedOption": 1, + "feedback": "i prefer lead", + } + ], + "overallFeedback": "i have no strong feelings", } def request_create_submission(self, xblock, payload=None): From 6f8f5c157f0fde384fac5d0edac462198d7a7817 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 2 Nov 2023 11:26:59 -0400 Subject: [PATCH 25/27] feat: add response to self and done steps (#2104) * feat: add response to self and done step views * docs: fix some comments --------- Co-authored-by: nsprenkle --- .../ui_mixins/mfe/page_context_serializer.py | 5 ++- .../mfe/test_page_context_serializer.py | 31 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index 1ac04a2efa..013cbb5a9e 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -362,7 +362,10 @@ def get_response(self, instance): # If we are jumping to the peer step grab any existing assessments but # don't get a new one automatically response = instance.peer_assessment_data().get_active_assessment_submission() - elif active_step in ("self", "staff", "ai", "waiting", "done"): + elif active_step in ("self", "done"): + learner_submission_data = instance.get_learner_submission_data() + return SubmissionSerializer(learner_submission_data).data + elif active_step in ("staff", "ai", "waiting"): response = None else: raise Exception(f"Bad step name: {active_step}") diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index f9058c8e8b..ebc6cfa9b6 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -175,14 +175,19 @@ def test_waiting_response(self, xblock): @scenario("data/self_assessment_scenario.xml", user_id="Alan") def test_done_response(self, xblock): # Given I'm on the done step - self.create_submission_and_assessments(xblock, self.SUBMISSION, [], [], SELF_ASSESSMENT) + submission_text = ["Danger", "Will Robinson"] + self.create_submission_and_assessments(xblock, submission_text, [], [], SELF_ASSESSMENT) # When I load my response self.context = {"view": "assessment", "step": "done"} response_data = PageDataSerializer(xblock, context=self.context).data["response"] - # Then I get an empty object - expected_response = {} + # Then I get my response back + expected_response = { + "textResponses": submission_text, + "uploadedFiles": [], + "teamUploadedFiles": None, + } self.assertDictEqual(expected_response, response_data) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") @@ -207,7 +212,7 @@ def test_jump_to_peer_response__no_active_assessment(self, xblock): self.context["jump_to_step"] = "peer" response_data = PageDataSerializer(xblock, context=self.context).data - # I recieve an empty response because I have not yet requested a submission to assess + # I receive an empty response because I have not yet requested a submission to assess self.assertDictEqual({}, response_data["response"]) @scenario("data/grade_scenario_peer_only.xml", user_id="Bernard") @@ -259,6 +264,24 @@ def test_jump_to_bad_step(self, xblock): with self.assertRaises(Exception): _ = PageDataSerializer(xblock, context=self.context).data + @scenario("data/self_only_scenario.xml", user_id="Alan") + def test_self_response(self, xblock): + # Given I am on the self grading step + submission_text = ["This is MYYYYYY submissionnninoinoioin", "also this"] + self.create_test_submission(xblock, submission_text=submission_text) + + # When I load my response + self.context = {"view": "assessment", "step": "self"} + response_data = PageDataSerializer(xblock, context=self.context).data["response"] + + # I get my response back + expected_response = { + "textResponses": submission_text, + "uploadedFiles": [], + "teamUploadedFiles": None, + } + self.assertDictEqual(expected_response, response_data) + class TestPageContextProgress(XBlockHandlerTestCase, SubmitAssessmentsMixin): # Show full dict diffs From fae1c976850aa091a01c7424808c5550cad1959c Mon Sep 17 00:00:00 2001 From: jansenk Date: Wed, 1 Nov 2023 15:21:14 -0400 Subject: [PATCH 26/27] fix: remove unused code --- openassessment/xblock/ui_mixins/mfe/mixin.py | 11 +---- .../ui_mixins/mfe/page_context_serializer.py | 42 ---------------- .../xblock/ui_mixins/mfe/test_mfe_mixin.py | 2 +- .../mfe/test_page_context_serializer.py | 48 ------------------- 4 files changed, 3 insertions(+), 100 deletions(-) diff --git a/openassessment/xblock/ui_mixins/mfe/mixin.py b/openassessment/xblock/ui_mixins/mfe/mixin.py index 5e020569b9..d38e501291 100644 --- a/openassessment/xblock/ui_mixins/mfe/mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/mixin.py @@ -86,16 +86,9 @@ def get_learner_data(self, data, suffix=""): # pylint: disable=unused-argument raise JsonHandlerError(400, f"Cannot jump to step: {jump_step}") # Determine which mode we are viewing in, since data comes from different sources + # View submission, submitted or draft if workflow_step == "submission" or jump_step == "submission": - - # View our submitted response - if self.submission_data.has_submitted: - serializer_context.update({"view": "submission"}) - - # View our draft response - else: - serializer_context.update({"view": "draft"}) - + serializer_context.update({"view": "submission"}) # View the current assessment step else: serializer_context.update({"view": "assessment"}) diff --git a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py index 013cbb5a9e..924c25e33a 100644 --- a/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/page_context_serializer.py @@ -34,43 +34,6 @@ class AssessmentScoreSerializer(Serializer): possible = IntegerField(source="points_possible", required=False) -class ReceivedGradesSerializer(Serializer): - """ - Received grades for each of the applicable graded steps - Returns: - { - self: (Assessment score object) - peer: (Assessment score object) - staff: (Assessment score object) - } - """ - - self = AssessmentScoreSerializer(source="grades.self_score") - peer = AssessmentScoreSerializer(source="grades.peer_score") - staff = AssessmentScoreSerializer(source="grades.staff_score") - - def to_representation(self, instance): - """ - Hook output to remove steps that are not part of the assignment. - - Grades are not released for steps until all steps are completed. - """ - step_names = ["self", "peer", "staff"] - - # NOTE - cache this so we don't update the workflow - configured_steps = instance.status_details.keys() - is_done = instance.is_done - - for step in step_names: - if step not in configured_steps: - self.fields.pop(step) - - if not is_done: - return {field: {} for field in self.fields} - - return super().to_representation(instance) - - class ClosedInfoSerializer(Serializer): """Serialize closed info from a given assessment step API""" @@ -273,16 +236,11 @@ class ProgressSerializer(Serializer): { // What step are we on? An index to the configuration from ORA config call. activeStepName: (String) one of ["submission", "studentTraining", "peer", "self", "staff", "done] - - hasReceivedFinalGrade: (Bool) // In effect, is the ORA complete? - receivedGrades: (Object) Staff grade data, when there is a completed staff grade. activeStepInfo: (Object) Specific info for the active step } """ activeStepName = SerializerMethodField() - hasReceivedFinalGrade = BooleanField(source="workflow_data.is_done") - receivedGrades = ReceivedGradesSerializer(source="workflow_data") stepInfo = StepInfoSerializer(source="*") def get_activeStepName(self, instance): diff --git a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py index 1da8815737..e959776690 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py +++ b/openassessment/xblock/ui_mixins/mfe/test_mfe_mixin.py @@ -224,7 +224,7 @@ def test_start_submission(self, xblock, mock_serializer): # Then I get submission expected_context = { "step": "submission", - "view": "draft", + "view": "submission", } mock_serializer.assert_called_once_with(xblock, context={**expected_context}) diff --git a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py index ebc6cfa9b6..34788d3177 100644 --- a/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py +++ b/openassessment/xblock/ui_mixins/mfe/test_page_context_serializer.py @@ -304,8 +304,6 @@ def test_submission(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "submission", - "hasReceivedFinalGrade": False, - "receivedGrades": {}, "stepInfo": { "submission": { "closed": False, @@ -335,11 +333,6 @@ def test_student_training(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "studentTraining", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -380,11 +373,6 @@ def test_student_training_due(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "studentTraining", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": True, @@ -425,11 +413,6 @@ def test_student_training_not_yet_available(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "studentTraining", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -470,11 +453,6 @@ def test_peer_assessment(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "peer", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -517,11 +495,6 @@ def test_peer_assessment__cancelled(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "submission", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -550,11 +523,6 @@ def test_self_assessment(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "self", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "self": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -586,12 +554,6 @@ def test_self_assessment_closed(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "self", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "self": {}, - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": True, @@ -624,12 +586,6 @@ def test_self_assessment_not_available(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "self", - "hasReceivedFinalGrade": False, - "receivedGrades": { - "self": {}, - "peer": {}, - "staff": {}, - }, "stepInfo": { "submission": { "closed": False, @@ -673,10 +629,6 @@ def test_team_assignment(self, xblock): # Then I get the expected shapes expected_data = { "activeStepName": "staff", - "hasReceivedFinalGrade": False, - "receivedGrades": { - # NOTE - Teams actually have a different step type that should go here - }, "stepInfo": { "submission": { "closed": False, From c8341c66532537170c0f4ed1d6d9e5fbfecf7dbe Mon Sep 17 00:00:00 2001 From: nsprenkle Date: Mon, 6 Nov 2023 13:22:12 -0500 Subject: [PATCH 27/27] chore: bump version numbers to 6.0.0 Major version bump since we are adding new dual-ui which seems major enough to require a major version bump. --- openassessment/__init__.py | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openassessment/__init__.py b/openassessment/__init__.py index 625d402e2c..e0ec6036e3 100644 --- a/openassessment/__init__.py +++ b/openassessment/__init__.py @@ -2,4 +2,4 @@ Initialization Information for Open Assessment Module """ -__version__ = '5.5.6' +__version__ = '6.0.0' diff --git a/package-lock.json b/package-lock.json index 2f8cf875d2..1da5032650 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "edx-ora2", - "version": "5.4.0", + "version": "6.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "edx-ora2", - "version": "5.4.0", + "version": "6.0.0", "dependencies": { "@edx/frontend-build": "^6.1.1", "@edx/paragon": "^20.9.2", diff --git a/package.json b/package.json index e74811a393..d622df935c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "edx-ora2", - "version": "5.5.6", + "version": "6.0.0", "repository": "https://github.com/openedx/edx-ora2.git", "dependencies": { "@edx/frontend-build": "^6.1.1",