From 9687b59f7e2a76ec54c8d9c98e1b0bb9d961894e Mon Sep 17 00:00:00 2001 From: davivcu Date: Sat, 13 Mar 2021 10:28:03 +0100 Subject: [PATCH 001/143] tests --- configuration/conf.json | 2 +- configuration/multiwoz.json | 68 ++++++++++++++++++++++++++++++++++ configuration/unipi_model.json | 34 ++++++++--------- web/server/annotator_config.py | 19 ++++++++-- web/server/matilda_app.py | 25 ++++++++++--- 5 files changed, 120 insertions(+), 28 deletions(-) create mode 100644 configuration/multiwoz.json diff --git a/configuration/conf.json b/configuration/conf.json index ab6596c..d48f915 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -2,7 +2,7 @@ "app": { "address":"0.0.0.0", "port":5000, - "annotation_models":["unipi_model.json","lida_model.json"] + "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json"] }, "database": { "name": "matilda", diff --git a/configuration/multiwoz.json b/configuration/multiwoz.json new file mode 100644 index 0000000..9e9d17b --- /dev/null +++ b/configuration/multiwoz.json @@ -0,0 +1,68 @@ +{ + + "text": { + "description" : "The user's query", + "label_type" : "string", + "required" : true + }, + + + "dialog_act": { + + "description" : "Type of dialogue act", + "label_type" : "multilabel_classification", + "required" : false, + "labels" :[ + "sys_greet", + "sys_inform_basic", + "sys_inform_proactive", + "sys_request", + "sys_select", + "sys_deny", + "usr_greet", + "usr_inform_basic", + "usr_inform_proactive", + "usr_request", + "usr_select", + "usr_deny" + ] + }, + + "metadata": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_name", + "company_size", + "location", + "contact", + "other" + ] + + }, + + "global_slot": { + + "description" : "General info related to the dialogue", + "label_type" : "multilabel_global_string", + "required" : false, + "labels" : [ + "result", + "goal" + ] + + } + + } diff --git a/configuration/unipi_model.json b/configuration/unipi_model.json index 70bfa7c..3c8065a 100644 --- a/configuration/unipi_model.json +++ b/configuration/unipi_model.json @@ -1,11 +1,27 @@ { + "global_slot": { + + "description" : "General info related to the dialogue", + "label_type" : "multilabel_global_string", + "required" : false, + "labels" : [ + "result" + ] + }, + "usr": { "description" : "The user's query", "label_type" : "string", "required" : true }, + "sys": { + "description" : "The system's response", + "label_type" : "string", + "required" : true + }, + "Dialogue_act": { "description" : "Type of dialogue act", @@ -62,24 +78,6 @@ ] - }, - - "global_slot": { - - "description" : "General info related to the dialogue", - "label_type" : "multilabel_global_string", - "required" : false, - "labels" : [ - "result" - ] - - }, - - - "sys": { - "description" : "The system's response", - "label_type" : "string", - "required" : true } } diff --git a/web/server/annotator_config.py b/web/server/annotator_config.py index 1c81328..f2d2d45 100644 --- a/web/server/annotator_config.py +++ b/web/server/annotator_config.py @@ -123,9 +123,9 @@ def validate_dialogue(annotation_style, dialogue: List[Dict[str, Any]]) -> Union print(message, turn) return message except: - print("dialogue",i,"in list couldn't validate with the current annotation style model") - return - + message = "ERROR4: dialogue "+str(i)+" in list couldn't validate with the current annotation style model" + print(message) + return message return dialogue @@ -366,3 +366,16 @@ def agreement_classification_score(listOfClassifications, totalLabels): "multilabel_classification_string" : None, "multilabel_global_string" : None } + + +def convert_to_format(dialogue): + turnList = [] + metaTags = {} + turnList.append(metaTags) + for element in dialogue: + if ((element == "log") and (type(dialogue[element]) == list)): + for turn in dialogue[element]: + turnList.append(turn) + else: + turnList[0][element] = dialogue[element] + return turnList diff --git a/web/server/matilda_app.py b/web/server/matilda_app.py index a80b576..f727a4b 100644 --- a/web/server/matilda_app.py +++ b/web/server/matilda_app.py @@ -747,12 +747,25 @@ def handle_post_of_collections(mode, destination, id=None): annotationStyle = Configuration.annotation_styles[0] values["annotationStyle"] = annotationStyle - for dialogueName, dialogue in values["document"].items(): - validation = Configuration.validate_dialogue(annotationStyle, dialogue) - if ((type(validation) is str) and (validation.startswith("ERROR"))): - print("Validation for",dialogueName," failed with "+annotationStyle) - response = {"status":"error","error":" Dialogue "+dialogueName+": "+str(validation)} - return jsonify( response ) + if (type(values["document"])) == list: + rebuiltDocument = {} + for document in values["document"]: + for dialogueName, dialogue in document.items(): + dialogue = convert_to_format(dialogue) + validation = Configuration.validate_dialogue(annotationStyle, dialogue) + if ((type(validation) is str) and (validation.startswith("ERROR"))): + print("Validation for",dialogueName," failed with "+annotationStyle) + #response = {"status":"error","error":" Dialogue "+dialogueName+": "+str(validation)} + #return jsonify( response ) + rebuiltDocument[dialogueName] = dialogue + values["document"] = rebuiltDocument + else: + for dialogueName, dialogue in values["document"].items(): + validation = Configuration.validate_dialogue(annotationStyle, dialogue) + if ((type(validation) is str) and (validation.startswith("ERROR"))): + print("Validation for",dialogueName," failed with "+annotationStyle) + response = {"status":"error","error":" Dialogue "+dialogueName+": "+str(validation)} + return jsonify( response ) #check for same id check = DatabaseManagement.readDatabase("dialogues_collections", { "id":id }) From 57ef412fa679b9b8276b192dbf1ad798a8762497 Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 16 Mar 2021 13:41:37 +0100 Subject: [PATCH 002/143] switched to development --- configuration/conf.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/conf.json b/configuration/conf.json index d48f915..01c9578 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -1,11 +1,11 @@ { "app": { "address":"0.0.0.0", - "port":5000, + "port":5008, "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json"] }, "database": { - "name": "matilda", + "name": "matilda_development", "legacy_configuration": { "address": "localhost", "port": 27017, From 88eea5446b36f8447f6e22078a500198447d42df Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 16 Mar 2021 13:42:17 +0100 Subject: [PATCH 003/143] switched to development --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index bdeca34..03c1b04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: ports: - 27017:27017 matilda: - image: davivcu/matilda:beta + image: davivcu/matilda:multimodel volumes: - ./configuration:/configuration restart: always From 3412b2aae2518d81061faf98f832f5d4ee9d6ab7 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Thu, 18 Mar 2021 19:09:40 +0100 Subject: [PATCH 004/143] Update login_components.js --- web/server/gui/source/components/login_components.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/server/gui/source/components/login_components.js b/web/server/gui/source/components/login_components.js index f329b4f..07a44f0 100644 --- a/web/server/gui/source/components/login_components.js +++ b/web/server/gui/source/components/login_components.js @@ -54,6 +54,7 @@ Vue.component("login-view", {
` -}); \ No newline at end of file +}); From 1c1dbd027913811004615cb51b90dff6800c84b1 Mon Sep 17 00:00:00 2001 From: davivcu Date: Fri, 19 Mar 2021 08:42:43 +0100 Subject: [PATCH 005/143] scripts support --- configuration/conf.json | 9 ++++--- web/server/convert_to_format.py | 27 +++++++++++++++++++ web/server/gui/assets/css/main.css | 1 + web/server/gui/index.html | 1 + .../gui/source/components/login_components.js | 1 + web/server/matilda_app.py | 3 ++- 6 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 web/server/convert_to_format.py diff --git a/configuration/conf.json b/configuration/conf.json index 01c9578..236e8f4 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -1,8 +1,11 @@ { "app": { "address":"0.0.0.0", - "port":5008, - "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json"] + "port":5000, + "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json"], + "conversion_scripts": { + "multiwoz.json": { "file": "convertToFormat" } + } }, "database": { "name": "matilda_development", @@ -12,6 +15,6 @@ "username": null, "password": null }, - "optional_uri": "mongodb://mongo:27017/?retryWrites=true&w=majority" + "optional_uri": null } } \ No newline at end of file diff --git a/web/server/convert_to_format.py b/web/server/convert_to_format.py new file mode 100644 index 0000000..bcd7cec --- /dev/null +++ b/web/server/convert_to_format.py @@ -0,0 +1,27 @@ + +class ConversionScripts: + def convert_document_to_format(document,Configuration,annotationStyle): + if (type(document)) == list: + rebuiltDocument = {} + for document in document: + for dialogueName, dialogue in document.items(): + dialogue = ConversionScripts.convert_dialogue_to_format(dialogue) + validation = Configuration.validate_dialogue(annotationStyle, dialogue) + if ((type(validation) is str) and (validation.startswith("ERROR"))): + print("Validation for",dialogueName," failed with "+annotationStyle) + #response = {"status":"error","error":" Dialogue "+dialogueName+": "+str(validation)} + #return jsonify( response ) + rebuiltDocument[dialogueName] = dialogue + return rebuiltDocument + + def convert_dialogue_to_format(dialogue): + turnList = [] + metaTags = {} + turnList.append(metaTags) + for element in dialogue: + if ((element == "log") and (type(dialogue[element]) == list)): + for turn in dialogue[element]: + turnList.append(turn) + else: + turnList[0][element] = dialogue[element] + return turnList \ No newline at end of file diff --git a/web/server/gui/assets/css/main.css b/web/server/gui/assets/css/main.css index 1408b52..5f50ea3 100644 --- a/web/server/gui/assets/css/main.css +++ b/web/server/gui/assets/css/main.css @@ -412,6 +412,7 @@ input:focus { height: 54px; width: 200px; margin: 8px 0 8px 10px; + align-self: baseline; } .logo img { diff --git a/web/server/gui/index.html b/web/server/gui/index.html index bbd6aaa..6304b54 100644 --- a/web/server/gui/index.html +++ b/web/server/gui/index.html @@ -52,6 +52,7 @@ +
DEVELOPMENT VERSION
diff --git a/web/server/gui/source/components/login_components.js b/web/server/gui/source/components/login_components.js index f329b4f..868485a 100644 --- a/web/server/gui/source/components/login_components.js +++ b/web/server/gui/source/components/login_components.js @@ -54,6 +54,7 @@ Vue.component("login-view", {
@@ -604,7 +604,7 @@ Vue.component('classification-global-annotation',{ v-on:mouseover="turnSeparatorWhite()" v-on:mouseout="turnSeparatorGrey()"> - Global Slot + Global Slots

{{guiMessages.selected.annotation_app.expand}} From da2b2bbae7c6a905e93379b54bac8aa05c9214d9 Mon Sep 17 00:00:00 2001 From: davivcu Date: Fri, 19 Mar 2021 19:43:05 +0100 Subject: [PATCH 007/143] slot collapsed if too many --- configuration/conf.json | 2 +- .../gui/source/components/annotation_type_components.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configuration/conf.json b/configuration/conf.json index 236e8f4..f84c945 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -2,7 +2,7 @@ "app": { "address":"0.0.0.0", "port":5000, - "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json"], + "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json", "unipi_v2.json"], "conversion_scripts": { "multiwoz.json": { "file": "convertToFormat" } } diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index 3449eb1..45f530c 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -199,6 +199,10 @@ Vue.component('classification-string-annotation', { created () { if (this.multilabelStringOptions) { adminEventBus.$on("switch_slot_values", this.switchSlotValue); + } else { + if (this.classes.length > 5) { + this.collapsed = true; + } } }, From 62199c34417866f5c0709addb896efa9ba351a7b Mon Sep 17 00:00:00 2001 From: davivcu Date: Mon, 22 Mar 2021 21:23:37 +0100 Subject: [PATCH 008/143] datamanagement view --- configuration/unipi_v2.json | 460 +++++++----------- .../gui/assets/css/annotation_types.css | 1 + .../components/all_dialogues_components.js | 2 +- .../components/datamanagement_components.js | 21 +- web/server/gui/source/utils/languages.js | 9 + 5 files changed, 210 insertions(+), 283 deletions(-) diff --git a/configuration/unipi_v2.json b/configuration/unipi_v2.json index caa2b3e..1fe254b 100644 --- a/configuration/unipi_v2.json +++ b/configuration/unipi_v2.json @@ -1,277 +1,183 @@ -{ - - "sys": { - "description" : "The user's query", - "label_type" : "string", - "required" : true - }, - - "usr": { - "description" : "The user's query", - "label_type" : "string", - "required" : true - }, - - - "sys_inform_basic": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "sys_inform_basic": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "sys_inform_proactive": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "sys_request": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "sys_select": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "usr_greet": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "usr_inform_proactive": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "usr_request": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "usr_select": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "usr_deny": { - - "description" : "Entity's value", - "label_type" : "multilabel_classification_string", - "required" : false, - "labels" : [ - - "job_description", - "contract", - "duties", - "skill", - "past_experience", - "degree", - "age", - "languages", - "area", - "company_name", - "company_size", - "location", - "contact", - "other" - ] - - }, - - "global_slot": { - - "description" : "General info related to the dialogue", - "label_type" : "multilabel_global_string", - "required" : false, - "labels" : [ - "goal" - ] - - } - - } +{ + + "sys": { + "description" : "The user's query", + "label_type" : "string", + "required" : true + }, + + "usr": { + "description" : "The user's query", + "label_type" : "string", + "required" : true + }, + + "greeting": { + + "description" : "Type of dialogue act", + "label_type" : "multilabel_classification", + "required" : false, + "labels" :[ + "sys_greet", + "usr_greet" + ] + }, + + "sys_inform_basic": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_name", + "company_size", + "location", + "contact", + "other" + ] + + }, + + "sys_inform_proactive": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_name", + "company_size", + "location", + "contact", + "other" + ] + + }, + + "sys_request": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location" + ] + + }, + + "usr_inform_proactive": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location", + "other" + ] + + }, + + "usr_request": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "area", + "company_size", + "location" + ] + + }, + + "sys_select": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "usr_select": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "usr_deny": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "global_slot": { + + "description" : "General info related to the dialogue", + "label_type" : "multilabel_global_string", + "required" : false, + "labels" : [ + "result" + ] + + } + + } diff --git a/web/server/gui/assets/css/annotation_types.css b/web/server/gui/assets/css/annotation_types.css index 2274837..22e5685 100644 --- a/web/server/gui/assets/css/annotation_types.css +++ b/web/server/gui/assets/css/annotation_types.css @@ -35,6 +35,7 @@ .soft-text { font-size: 11px; + color: #259af7e0; } .multilabel-string-item-wrapper { diff --git a/web/server/gui/source/components/all_dialogues_components.js b/web/server/gui/source/components/all_dialogues_components.js index 46cd984..329f707 100644 --- a/web/server/gui/source/components/all_dialogues_components.js +++ b/web/server/gui/source/components/all_dialogues_components.js @@ -19,7 +19,7 @@ Vue.component("all-dialogues", { } }, created() { - allDialoguesEventBus.$on( "refresh_dialogue_list", this.getAllDialogueIdsFromServer ) + allDialoguesEventBus.$on( "refresh_dialogue_list", this.getAllDialogueIdsFromServer ); }, mounted () { this.init(); diff --git a/web/server/gui/source/components/datamanagement_components.js b/web/server/gui/source/components/datamanagement_components.js index 9adbe56..2daea4a 100644 --- a/web/server/gui/source/components/datamanagement_components.js +++ b/web/server/gui/source/components/datamanagement_components.js @@ -168,6 +168,10 @@ Vue.component("datamanagement-view", {

{{guiMessages.selected.collection.title}}

+
@@ -176,15 +180,22 @@ Vue.component("datamanagement-view", {
- +

+ Assign annotators to selected collection +

+ +

+ Assign collections to selected annotator +

+ +

+ Select a user or a collection +

diff --git a/web/server/gui/source/utils/languages.js b/web/server/gui/source/utils/languages.js index 1456f32..5f8f0a7 100644 --- a/web/server/gui/source/utils/languages.js +++ b/web/server/gui/source/utils/languages.js @@ -113,6 +113,9 @@ guiMessages = { freeze: "This operation will freeze the collection and notify your work is done and can be reviewed. Do it only when you finished", freezed: "These annotations are freezed and can not be edited until reviewed and unlocked by an administrator", empty:"Empty", + dataManagementTitle:"Select a user or a collection", + collectionToAnnotator:"Assign collections to selected user", + annotatorToCollection:"Assign annotators to selected collection" }, annotation_app: { @@ -362,6 +365,9 @@ guiMessages = { freeze: "Questa operazione bloccherà la collezione e notificherà che hai finito e che le annotazioni sono pronte per la revisione", freezed: "L'annotazione è stata segnalata come completata e quindi non potrà essere modificata fino alla revisione e allo sblocco da parte di un amministratore.", empty:"Vuoto", + dataManagementTitle:"Seleziona un utente o una collezione", + collectionToAnnotator:"Assegna collezioni all'utente selezionato", + annotatorToCollection:"Assegna utenti alla collezione selezionata" }, annotation_app: { turnId: "Id Turno", @@ -609,6 +615,9 @@ guiMessages = { freeze: "Dieser Vorgang friert die Sammlung ein und benachrichtigt Sie, dass Ihre Arbeit erledigt ist und überprüft werden kann. Führen Sie sie erst aus, wenn Sie fertig sind.", freezed: "Diese Anmerkungen sind eingefroren und können erst bearbeitet werden, wenn sie von einem Administrator überprüft und entsperrt wurden", empty: "leer", + dataManagementTitle:"Select a user or a collection", + collectionToAnnotator:"Assign collections to selected annotator", + annotatorToCollection:"Assign users to selected collection" }, annotation_app: { From 5146694450660fbcebc4881186846371bf30b393 Mon Sep 17 00:00:00 2001 From: davivcu Date: Mon, 22 Mar 2021 21:31:54 +0100 Subject: [PATCH 009/143] small fixes --- configuration/unipi_model_v2.json | 183 ++++++++++++++++++++++++++++ web/server/annotator_config.py | 3 +- web/server/gui/assets/css/modal.css | 1 - web/server/gui/index.html | 66 +++++----- 4 files changed, 218 insertions(+), 35 deletions(-) create mode 100644 configuration/unipi_model_v2.json diff --git a/configuration/unipi_model_v2.json b/configuration/unipi_model_v2.json new file mode 100644 index 0000000..1fe254b --- /dev/null +++ b/configuration/unipi_model_v2.json @@ -0,0 +1,183 @@ +{ + + "sys": { + "description" : "The user's query", + "label_type" : "string", + "required" : true + }, + + "usr": { + "description" : "The user's query", + "label_type" : "string", + "required" : true + }, + + "greeting": { + + "description" : "Type of dialogue act", + "label_type" : "multilabel_classification", + "required" : false, + "labels" :[ + "sys_greet", + "usr_greet" + ] + }, + + "sys_inform_basic": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_name", + "company_size", + "location", + "contact", + "other" + ] + + }, + + "sys_inform_proactive": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_name", + "company_size", + "location", + "contact", + "other" + ] + + }, + + "sys_request": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location" + ] + + }, + + "usr_inform_proactive": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location", + "other" + ] + + }, + + "usr_request": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description", + "contract", + "area", + "company_size", + "location" + ] + + }, + + "sys_select": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "usr_select": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "usr_deny": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "job_description" + ] + + }, + + "global_slot": { + + "description" : "General info related to the dialogue", + "label_type" : "multilabel_global_string", + "required" : false, + "labels" : [ + "result" + ] + + } + + } diff --git a/web/server/annotator_config.py b/web/server/annotator_config.py index 252426e..f1a83ad 100644 --- a/web/server/annotator_config.py +++ b/web/server/annotator_config.py @@ -123,9 +123,10 @@ def validate_dialogue(annotation_style, dialogue: List[Dict[str, Any]]) -> Union print(message, turn) return message except: - message = "ERROR4: dialogue "+str(i)+" in list couldn't validate with the current annotation style model" + message = "ERROR4: dialogue in list couldn't validate with the current annotation style model" print(message) return message + return dialogue diff --git a/web/server/gui/assets/css/modal.css b/web/server/gui/assets/css/modal.css index bfc7649..f65a0fd 100644 --- a/web/server/gui/assets/css/modal.css +++ b/web/server/gui/assets/css/modal.css @@ -33,7 +33,6 @@ box-shadow: 0 2px 8px rgba(0, 0, 0, .33); transition: all .3s ease; font-family: Helvetica, Arial, sans-serif; - overflow: scroll; } .modal-header h3 { diff --git a/web/server/gui/index.html b/web/server/gui/index.html index 6304b54..df4cabe 100644 --- a/web/server/gui/index.html +++ b/web/server/gui/index.html @@ -17,21 +17,21 @@ CSS ---------------------------------------------------------------> - - + + - + - - - - - - - - + + + + + + + + @@ -84,33 +84,33 @@ SCRIPTS ============================================= --> - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - + + + + + + From 22c85c822db56e244795f9efb512e4a971d3a3c2 Mon Sep 17 00:00:00 2001 From: davivcu Date: Mon, 22 Mar 2021 21:52:38 +0100 Subject: [PATCH 010/143] datamanagement view --- .../gui/source/components/datamanagement_components.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/server/gui/source/components/datamanagement_components.js b/web/server/gui/source/components/datamanagement_components.js index 2daea4a..9a2df90 100644 --- a/web/server/gui/source/components/datamanagement_components.js +++ b/web/server/gui/source/components/datamanagement_components.js @@ -181,15 +181,15 @@ Vue.component("datamanagement-view", {

- Assign annotators to selected collection + {{guiMessages.selected.collection.annotatorToCollection}}

- Assign collections to selected annotator + {{guiMessages.selected.collection.collectionToAnnotator}}

- Select a user or a collection + {{guiMessages.selected.collection.dataManagementTitle}}

@@ -301,10 +301,11 @@ Vue.component("datamanagement-view", {
{{guiMessages.selected.database.saved}} - {{guiMessages.selected.annotation_app.unsaved}} + + {{guiMessages.selected.annotation_app.unsaved}}
@@ -472,10 +473,10 @@ Vue.component('collection-users-reverse', {
@@ -484,8 +485,9 @@ Vue.component('collection-users-reverse', { {{guiMessages.selected.database.saved}} - {{guiMessages.selected.annotation_app.unsaved}} + + {{guiMessages.selected.annotation_app.unsaved}}
` From 8b0149aef3a42758c292e933a31b9d663b728b09 Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 23 Mar 2021 20:17:17 +0100 Subject: [PATCH 012/143] fix datamanagement view optimization datamanagement view --- .../components/datamanagement_components.js | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/web/server/gui/source/components/datamanagement_components.js b/web/server/gui/source/components/datamanagement_components.js index b0f4c88..4fb2dbf 100644 --- a/web/server/gui/source/components/datamanagement_components.js +++ b/web/server/gui/source/components/datamanagement_components.js @@ -180,24 +180,32 @@ Vue.component("datamanagement-view", {
-

- {{guiMessages.selected.collection.annotatorToCollection}} -

+ -

- {{guiMessages.selected.collection.collectionToAnnotator}} -

+ -

+ -

    From 3d178d8be63d519969e0e27495f8c9d05f82be22 Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 23 Mar 2021 21:07:30 +0100 Subject: [PATCH 013/143] fix datamanagament view fix datamanagement view --- .../components/datamanagement_components.js | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/web/server/gui/source/components/datamanagement_components.js b/web/server/gui/source/components/datamanagement_components.js index 4fb2dbf..60afd0a 100644 --- a/web/server/gui/source/components/datamanagement_components.js +++ b/web/server/gui/source/components/datamanagement_components.js @@ -84,7 +84,7 @@ Vue.component("datamanagement-view", { console.log("Selected collection",this.selectedCollection); this.changesSaved = ""; //refresh from database - this.init(); + //this.init(); }, clicked_active() { @@ -381,13 +381,13 @@ Vue.component('collection-users-reverse', { backend.get_all_users() .then( (response) => { this.allUsers = response; - this.get_user_assignments(); + this.get_user_assignments(this.selectedUser); }); }); }, - get_user_assignments: function() { - search = {"assignedTo":this.selectedUser} + get_user_assignments: function(selectedUser) { + search = {"assignedTo":selectedUser} projection = {"id":1,"gold":1,"assignedTo":1,"lastUpdate":1} backend.get_specific_collections("dialogues_collections",search, projection) .then( (response) => { @@ -395,14 +395,15 @@ Vue.component('collection-users-reverse', { for (collection in response) { this.assignedCollections.push(response[collection].id) } - console.log("Asssigned to",this.selectedUser,this.assignedCollections) + console.log("Asssigned to",selectedUser,this.assignedCollections) } ) }, clicked_user: function(clickedUser) { this.selectedUser = clickedUser; - this.init(); + this.assignedCollections = []; + this.get_user_assignments(clickedUser); }, inspect_entry: function(clickedEntry) { @@ -420,6 +421,18 @@ Vue.component('collection-users-reverse', { console.log("Output array updated",this.allEntriesNamedMetadata[clickedCollection].assignedTo); }, + delete_entry(clickedDialogue) { + let del = confirm(guiMessages.selected.collection.confirmDeleteDialogue); + if (del == true) { + backend.remove_from_collection_async("dialogues_collections", this.entry.id, {"dialogue":clickedDialogue}) + .then( (response) => { + console.log(response); + this.init(); + } + ) + } + }, + save: function() { console.log("Update plan",this.saveTasks); backend.update_multiple_collections_async("dialogues_collections",this.saveTasks) From 17f23433904e356fed4a3a2795b4cf325e9e77f3 Mon Sep 17 00:00:00 2001 From: davivcu Date: Fri, 26 Mar 2021 20:05:56 +0100 Subject: [PATCH 014/143] documentLenght only --- web/server/database.py | 15 +++++++++++++-- .../components/datamanagement_components.js | 6 ++++-- .../source/components/supervision_components.js | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/web/server/database.py b/web/server/database.py index c91335d..f8e9b44 100644 --- a/web/server/database.py +++ b/web/server/database.py @@ -81,6 +81,7 @@ def readDatabase(coll,pairs=None, projection=None): #print(" * Searching in:",coll,"for key '",pairs) entries = {} + documentLengthOnly = False #adds restrictions to the search if pairs is None: @@ -88,17 +89,27 @@ def readDatabase(coll,pairs=None, projection=None): #search with projection of interested fields or simple search if projection is not None: + try: + if projection["document"] == "length": + projection["document"] = 1 + documentLengthOnly = True + except: + pass query = selected_collection.find(pairs,projection) else: query = selected_collection.find(pairs) - #convert objectId into string and gold in true or false - #calculate document length which also is dialogues total number + #operations after the query for line in query: + #convert objectId into string if line.get("_id") is not None: line["_id"] = str(line["_id"]) + #calculate document length which also is dialogues total number if line.get("document") is not None: line["documentLength"] = len(line["document"]) + if documentLengthOnly: + line["document"] = line["documentLength"] + responseObject.append(line) return responseObject diff --git a/web/server/gui/source/components/datamanagement_components.js b/web/server/gui/source/components/datamanagement_components.js index 60afd0a..5db49c9 100644 --- a/web/server/gui/source/components/datamanagement_components.js +++ b/web/server/gui/source/components/datamanagement_components.js @@ -52,7 +52,8 @@ Vue.component("datamanagement-view", { getAllEntriesFromServer() { mainContainer.style.cursor = "progress"; - backend.get_collections_async("dialogues_collections") + projection = {"annotationStyle":1, "assignedTo":1, "description":1, "document":"length", "gold":1, "id":1}; + backend.get_specific_collections("dialogues_collections",{}, projection) .then( (response) => { for (collection in response) { this.allEntriesNamedMetadata[response[collection].id] = response[collection] @@ -369,7 +370,8 @@ Vue.component('collection-users-reverse', { this.allEntriesNamedMetadata = []; this.assignedCollections = []; //get data from server - backend.get_collections_async("dialogues_collections") + projection = {"annotationStyle":1, "assignedTo":1, "description":1, "documentLength":1, "gold":1, "id":1}; + backend.get_specific_collections("dialogues_collections",{}, projection) .then( (response) => { console.log("All collections",response); for (collection in response) { diff --git a/web/server/gui/source/components/supervision_components.js b/web/server/gui/source/components/supervision_components.js index 67f3d46..0a397c6 100644 --- a/web/server/gui/source/components/supervision_components.js +++ b/web/server/gui/source/components/supervision_components.js @@ -67,7 +67,7 @@ Vue.component("supervision-view", { }, getAllCollectionIdsFromServer() { - backend.get_specific_collections("dialogues_collections",{},{"id":1,"gold":1,"assignedTo":1,"document":1} ) + backend.get_specific_collections("dialogues_collections",{},{"id":1,"gold":1,"assignedTo":1, "document":"length"} ) .then( (response) => { console.log(response); this.allCollectionsMetadata = response; From 0e144ab19bf9b8a70d089a14aa1ad458e08f7801 Mon Sep 17 00:00:00 2001 From: davivcu Date: Sat, 27 Mar 2021 20:31:28 +0100 Subject: [PATCH 015/143] new slot annotation view --- configuration/conf.json | 3 - web/server/database.py | 1 + .../gui/assets/css/annotation_types.css | 18 ++- web/server/gui/index.html | 66 +++++----- .../components/annotation_app_components.js | 5 +- .../components/annotation_type_components.js | 120 ++++++++++++++---- 6 files changed, 147 insertions(+), 66 deletions(-) diff --git a/configuration/conf.json b/configuration/conf.json index 12e14c6..8f17ba2 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -3,9 +3,6 @@ "address":"0.0.0.0", "port":5000, "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json", "unipi_model_v2.json"], - "conversion_scripts": { - "multiwoz.json": { "file": "convertToFormat" } - } }, "database": { "name": "matilda_dev", diff --git a/web/server/database.py b/web/server/database.py index f8e9b44..c4efe9a 100644 --- a/web/server/database.py +++ b/web/server/database.py @@ -107,6 +107,7 @@ def readDatabase(coll,pairs=None, projection=None): #calculate document length which also is dialogues total number if line.get("document") is not None: line["documentLength"] = len(line["document"]) + #remove document if only length is requested if documentLengthOnly: line["document"] = line["documentLength"] diff --git a/web/server/gui/assets/css/annotation_types.css b/web/server/gui/assets/css/annotation_types.css index 22e5685..797a9b6 100644 --- a/web/server/gui/assets/css/annotation_types.css +++ b/web/server/gui/assets/css/annotation_types.css @@ -47,6 +47,10 @@ padding-bottom:5px; } +.multilabel-string-item-new-wrapper { + font-size:15px; +} + .multilabel-string-checkbox-container { grid-area: checkboxZone; display: flex; @@ -137,6 +141,15 @@ background-color: #259af7ad !important; } +.multilabel-string-item-selector { + margin-bottom: 5px; + width: 48%; + font-size: 14px; + border-color: rgb(0 0 0 / 17%); + color: rgb(0 0 0 / 91%); + font-family: 'CoreSansNR35Light'; +} + .txt-sel-button { vertical-align: bottom; background: white; @@ -190,18 +203,19 @@ border:1px solid rgba(0,0,0,0.1); margin-top:5px; display:block; + width:-webkit-fill-available; } .global-label { cursor: pointer; + text-transform:capitalize; } .supervision_readonly { pointer-events:none; + opacity:0.7 } - - /******************************** * Info button ********************************/ diff --git a/web/server/gui/index.html b/web/server/gui/index.html index df4cabe..3be8d0c 100644 --- a/web/server/gui/index.html +++ b/web/server/gui/index.html @@ -17,21 +17,21 @@ CSS ---------------------------------------------------------------> - - + + - + - - - - - - - - + + + + + + + + @@ -84,33 +84,33 @@ SCRIPTS ============================================= --> - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - + + + + + + diff --git a/web/server/gui/source/components/annotation_app_components.js b/web/server/gui/source/components/annotation_app_components.js index 6acdabd..8df1600 100644 --- a/web/server/gui/source/components/annotation_app_components.js +++ b/web/server/gui/source/components/annotation_app_components.js @@ -618,7 +618,7 @@ Vue.component('annotations',{ template: ` -
    +
    Current Turn: {{currentId}}
    @@ -641,7 +641,8 @@ Vue.component('annotations',{ v-bind:uniqueName="classString.name" v-bind:classes="classString.params" v-bind:info="classString.info" - v-bind:currentId="currentId"> + v-bind:currentId="currentId" + v-bind:supervision="readOnly">
    diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index 45f530c..b7e46a1 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -182,7 +182,7 @@ Vue.component('classification-annotation',{ Vue.component('classification-string-annotation', { - props: ["classification_strings", "uniqueName", "classes", "info", "confidences","currentId","multilabelStringOptions","accepted"], + props: ["classification_strings", "uniqueName", "classes", "info", "confidences", "currentId", "multilabelStringOptions", "accepted", "supervision"], data () { @@ -192,6 +192,8 @@ Vue.component('classification-string-annotation', { showInfo: false, guiMessages, backup_classification_strings: this.classification_strings, + selectedLabel: "", + filledLabels: [] } }, @@ -200,7 +202,7 @@ Vue.component('classification-string-annotation', { if (this.multilabelStringOptions) { adminEventBus.$on("switch_slot_values", this.switchSlotValue); } else { - if (this.classes.length > 5) { + if (this.supervision == false) { this.collapsed = true; } } @@ -334,20 +336,6 @@ Vue.component('classification-string-annotation', { }, - clearValue: function(event,labelName) { - event.stopPropagation(); - let stringField = event.target.parentNode.parentNode.querySelector("input.multilabel-string-input"); - if (stringField.value == "") { - console.log("empty"); - event.target.checked = false; - return; - } else { - console.log("cleaning"); - stringField.value = ""; - this.updateClassAndString(stringField, labelName); - } - }, - selectWords: function(event,labelName) { annotationAppEventBus.$emit("resume_annotation_tools"); //display feedbacks @@ -432,6 +420,33 @@ Vue.component('classification-string-annotation', { } //TODO: filled labels showed higher in the list? }, + + clearValue: function(event,labelName) { + event.stopPropagation(); + let stringField = event.target.parentNode.parentNode.querySelector("input.multilabel-string-input"); + if (stringField.value == "") { + console.log("empty"); + event.target.checked = false; + //empty output? + this.directUpdateClassAndString("none", labelName); + } else { + console.log("cleaning"); + stringField.value = ""; + this.updateClassAndString(stringField, labelName); + } + }, + + resetLabels(label) { + if ((label == "") && (this.classification_strings.length > 0)) { + let r = confirm("Reset all slot values for "+this.uniqueName+"?"); + if (r == true) { + outEvent = {name: this.uniqueName, data: undefined} + annotationAppEventBus.$emit('classification_string_updated', outEvent); + } + } else if (label == "none") { + this.directUpdateClassAndString("none","none"); + } + } }, @@ -439,17 +454,70 @@ Vue.component('classification-string-annotation', { `
    -
    +
    -
    - {{uniqueName.replace(/_/g, ' ')}}

    - [Click to Expand] -
    +
    +
    + {{uniqueName.replace(/_/g, ' ')}} +
    +
    + + + + + +
    +
    + +
    + +
    + +
    + {{ info }} +
    + +
    + +
    + +
    + + Label: + + + +
    @@ -608,7 +676,7 @@ Vue.component('classification-global-annotation',{ v-on:mouseover="turnSeparatorWhite()" v-on:mouseout="turnSeparatorGrey()"> - Global Slots + Global Slot

    {{guiMessages.selected.annotation_app.expand}} From db58b6d08c7b3e63192d4c05dd291b414d470600 Mon Sep 17 00:00:00 2001 From: davivcu Date: Sat, 27 Mar 2021 22:05:05 +0100 Subject: [PATCH 016/143] new slot annotation view --- web/server/gui/assets/css/annotation_app.css | 7 ++-- .../components/annotation_app_components.js | 3 ++ .../components/annotation_type_components.js | 38 ++++++++++++++++++- web/server/gui/source/utils/languages.js | 3 ++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/web/server/gui/assets/css/annotation_app.css b/web/server/gui/assets/css/annotation_app.css index 43d81aa..db48d1a 100644 --- a/web/server/gui/assets/css/annotation_app.css +++ b/web/server/gui/assets/css/annotation_app.css @@ -35,10 +35,9 @@ overflow: auto; padding: 5px 24px; display: grid; - grid-template: [row1-start] ". . . . . ." 1fr [row1-end] - [row2-start] ". button-section . title-section rate-section status-section" 5fr [row2-end] - [row3-start] ". . . . . ." 1fr [row3-end] - / 0.0fr 0.9fr 0.05fr 1fr 2fr 1fr; + grid-template: [row1-start] ". . . . . . ." 1fr [row1-end] + [row2-start] ". button-section title-section rate-section status-section . switch-button " 5fr [row2-end] + [row3-start] ". . . . . . . " 1fr [row3-end] / 0fr 1fr 1fr 1fr 1fr 1fr 1fr; } diff --git a/web/server/gui/source/components/annotation_app_components.js b/web/server/gui/source/components/annotation_app_components.js index 8df1600..e9eabbe 100644 --- a/web/server/gui/source/components/annotation_app_components.js +++ b/web/server/gui/source/components/annotation_app_components.js @@ -406,6 +406,9 @@ Vue.component('dialogue-menu',{ {{guiMessages.selected.annotation_app.allSaved}} {{guiMessages.selected.annotation_app.unsaved}}
    + + +
    ` }) diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index b7e46a1..a04575b 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -192,6 +192,7 @@ Vue.component('classification-string-annotation', { showInfo: false, guiMessages, backup_classification_strings: this.classification_strings, + slotView: "new", selectedLabel: "", filledLabels: [] } @@ -202,7 +203,7 @@ Vue.component('classification-string-annotation', { if (this.multilabelStringOptions) { adminEventBus.$on("switch_slot_values", this.switchSlotValue); } else { - if (this.supervision == false) { + if ((this.supervision == false) && (this.slotView == "new")){ this.collapsed = true; } } @@ -211,6 +212,7 @@ Vue.component('classification-string-annotation', { methods: { get_confidence : function (id){ + console.log(this.confidences); if (this.confidences){ x = this.confidences[id]; @@ -437,6 +439,8 @@ Vue.component('classification-string-annotation', { }, resetLabels(label) { + console.log(label); + console.log(this.classification_strings); if ((label == "") && (this.classification_strings.length > 0)) { let r = confirm("Reset all slot values for "+this.uniqueName+"?"); if (r == true) { @@ -454,7 +458,7 @@ Vue.component('classification-string-annotation', { `
    -
    +
    @@ -517,6 +521,36 @@ Vue.component('classification-string-annotation', { + + + +
    diff --git a/web/server/gui/source/utils/languages.js b/web/server/gui/source/utils/languages.js index 5f8f0a7..865fd91 100644 --- a/web/server/gui/source/utils/languages.js +++ b/web/server/gui/source/utils/languages.js @@ -131,6 +131,7 @@ guiMessages = { expand: "Click to Expand", noTurn: "No turn selected. Please select one to annotate", rate: "Annotation rate", + switchAnnotationView: "Expanded Slots View", }, resolution_app: { errorId: "Error Id:", @@ -382,6 +383,7 @@ guiMessages = { expand: "Clicca per espandere", noTurn: "Nessun turno selezionato, nessuna modifica effettuata.", rate: "Stima annotazione", + switchAnnotationView: "Visuale Slot-Espansi", }, resolution_app: { errorId: "Id Conflitto:", @@ -633,6 +635,7 @@ guiMessages = { expand: "Klicken zum Erweitern", noTurn: "Keine Runde ausgewählt. Bitte wählen Sie eine zum Kommentieren aus", rate: "Annotation Rate", + switchAnnotationView: "Expanded Slots View", }, resolution_app: { errorId: "Error Id:", From c6d8d00c873a6ced42d160798e3211dc4653190e Mon Sep 17 00:00:00 2001 From: davivcu Date: Sun, 28 Mar 2021 14:03:09 +0200 Subject: [PATCH 017/143] new slot annotation view --- configuration/conf.json | 2 +- .../components/annotation_app_components.js | 2 - .../components/annotation_type_components.js | 49 +++++++++++++++---- .../components/datamanagement_components.js | 2 +- .../gui/source/components/users_components.js | 4 +- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/configuration/conf.json b/configuration/conf.json index 8f17ba2..985fe9e 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -2,7 +2,7 @@ "app": { "address":"0.0.0.0", "port":5000, - "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json", "unipi_model_v2.json"], + "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json", "unipi_model_v2.json"] }, "database": { "name": "matilda_dev", diff --git a/web/server/gui/source/components/annotation_app_components.js b/web/server/gui/source/components/annotation_app_components.js index e9eabbe..b4821db 100644 --- a/web/server/gui/source/components/annotation_app_components.js +++ b/web/server/gui/source/components/annotation_app_components.js @@ -407,8 +407,6 @@ Vue.component('dialogue-menu',{ {{guiMessages.selected.annotation_app.unsaved}}
    - -
    ` }) diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index a04575b..ee4f74e 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -204,7 +204,7 @@ Vue.component('classification-string-annotation', { adminEventBus.$on("switch_slot_values", this.switchSlotValue); } else { if ((this.supervision == false) && (this.slotView == "new")){ - this.collapsed = true; + this.collapsed = "new"; } } }, @@ -212,7 +212,6 @@ Vue.component('classification-string-annotation', { methods: { get_confidence : function (id){ - console.log(this.confidences); if (this.confidences){ x = this.confidences[id]; @@ -231,13 +230,17 @@ Vue.component('classification-string-annotation', { toggleCollapse: function () { - - if (this.collapsed) { - this.collapsed = false; - } else { - this.collapsed = true; - } - + switch(this.collapsed) { + case true: + this.collapsed = "new"; + break; + case "new": + this.collapsed = false; + break; + case false: + this.collapsed = true; + break; + } }, turnSeparatorWhite: function() { @@ -460,6 +463,31 @@ Vue.component('classification-string-annotation', {
    +
    + {{uniqueName.replace(/_/g, ' ')}}

    + [Click to Expand] +
    +
    + +
    + +
    + {{ info }} +
    + +
    + +
    + +
    + + + +
    +
    {{uniqueName.replace(/_/g, ' ')}} @@ -521,7 +549,7 @@ Vue.component('classification-string-annotation', { - + @@ -574,7 +574,7 @@ Vue.component('classification-string-annotation', { @@ -621,7 +621,7 @@ Vue.component('classification-string-annotation', {
    -
    +
    {{labelName}} || {{get_confidence(labelName)}} - + {{labelName}} || {{get_confidence(labelName)}} - + From 7f2ca0f7c029be397731767f51549c6866498af3 Mon Sep 17 00:00:00 2001 From: davivcu Date: Mon, 29 Mar 2021 23:26:46 +0200 Subject: [PATCH 024/143] range with tokens --- .../components/annotation_type_components.js | 2 +- web/server/gui/source/utils/utils.js | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index 128e4ec..21c3abb 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -379,7 +379,7 @@ Vue.component('classification-string-annotation', { let context = event.target.id; //updating let range = getTokenRange(event,text); - activeLabel.value += context.trim()+"["+event.target.selectionStart+","+event.target.selectionEnd+"]["+text+"],"; + activeLabel.value += context.trim()+"["+range+"]["+text+"],"; this.updateClassAndString(activeLabel, labelName); //put all back in place. Two possible parent view: interannotator and annotation annotationAppEventBus.$emit("resume_annotation_tools"); diff --git a/web/server/gui/source/utils/utils.js b/web/server/gui/source/utils/utils.js index 2a8e0f9..b6980ae 100644 --- a/web/server/gui/source/utils/utils.js +++ b/web/server/gui/source/utils/utils.js @@ -203,10 +203,23 @@ function annotation_rate_increment(turnNumber, annotations, turnTot, turnList) { } } -function getTokenRange(utterance,selection) { - console.log(utterance); - console.log(selection); +function getTokenRange(event,selectionText) { + let utterance = event.target.value; + //if selection starts with a space trims it + if (utterance.charAt(event.target.selectionStart) == " ") { + event.target.selectionStart++; + } + if (utterance.charAt(event.target.selectionEnd-1) == " ") { + event.target.selectionEnd--; + } + let utteranceUntilFirstToken = utterance.substr(0,event.target.selectionStart); + let rangeStart = utteranceUntilFirstToken.split(/[\s]/).length; + let utteranceUntilLastToken = utterance.substr(0,event.target.selectionEnd); + let rangeEnd = utteranceUntilLastToken.split(/[\s]/).length; + + let range = rangeStart+","+rangeEnd; + return range } From 2b8f7354548a64d761a22bd0215568445b6a719f Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 30 Mar 2021 00:07:36 +0200 Subject: [PATCH 025/143] range starting from 0 --- web/server/gui/source/utils/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/server/gui/source/utils/utils.js b/web/server/gui/source/utils/utils.js index b6980ae..0c8685a 100644 --- a/web/server/gui/source/utils/utils.js +++ b/web/server/gui/source/utils/utils.js @@ -218,7 +218,7 @@ function getTokenRange(event,selectionText) { let utteranceUntilLastToken = utterance.substr(0,event.target.selectionEnd); let rangeEnd = utteranceUntilLastToken.split(/[\s]/).length; - let range = rangeStart+","+rangeEnd; + let range = (rangeStart-1)+","+(rangeEnd-1); return range } From 2ab9fe3c9ec118becddeacafa9ea3c732fbf654e Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Tue, 30 Mar 2021 11:36:37 +0200 Subject: [PATCH 026/143] Update unipi_model_v2.json --- configuration/unipi_model_v2.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/configuration/unipi_model_v2.json b/configuration/unipi_model_v2.json index 7dce5f9..301a251 100644 --- a/configuration/unipi_model_v2.json +++ b/configuration/unipi_model_v2.json @@ -215,6 +215,19 @@ ] }, + + "sys_deny": { + + "description" : "Entity's value", + "label_type" : "multilabel_classification_string", + "required" : false, + "labels" : [ + + "none", + "job_description" + ] + + }, "async": { From 8f7092120cc2c73731471e8db137545d4a86edb6 Mon Sep 17 00:00:00 2001 From: davivcu Date: Tue, 30 Mar 2021 21:22:12 +0200 Subject: [PATCH 027/143] new annotation rate with slots --- .../components/annotation_app_components.js | 15 ++++++----- .../components/annotation_type_components.js | 3 ++- web/server/gui/source/utils/utils.js | 27 ++----------------- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/web/server/gui/source/components/annotation_app_components.js b/web/server/gui/source/components/annotation_app_components.js index b4821db..150f36d 100644 --- a/web/server/gui/source/components/annotation_app_components.js +++ b/web/server/gui/source/components/annotation_app_components.js @@ -19,7 +19,7 @@ Vue.component("annotation-app", { primaryElementClassName: "primary-turn-input", globalSlotNonEmpty: 0, metaTags: [], - annotatedTurns: [], + annotatedTurns: ["annotated"], annotationRate: '0%', readOnly:false, } @@ -199,9 +199,10 @@ Vue.component("annotation-app", { //turn 0 is meta-tags and global_slot reserved so it's skipped if (this.dCurrentId != 0) { this.allDataSaved = false; - //update annotation rate, slots don't count - if (event.turn != undefined) { - this.update_annotation_rate(event, this.dTurns.length); + //update annotation rate + if (this.annotatedTurns[this.dCurrentId] != "annotated") { + this.update_annotation_rate(); + this.turn_is_annotated(this.dCurrentId); } //update turn utils.update_turn( this.dTurns[this.dCurrentId], event); @@ -217,10 +218,10 @@ Vue.component("annotation-app", { this.annotatedTurns[event] = "annotated"; }, - update_annotation_rate: function(annotations, turnTot) { + update_annotation_rate: function() { let oldValue = Number(this.dTurns[0]["status"].slice(0,-1)); - let increment = Number(utils.annotation_rate_increment(annotations.turn, annotations, turnTot, this.annotatedTurns)); - let newValue = ( Number(oldValue) + Number(increment) ).toFixed(1); + let unitRate = (100 / (this.dTurns.length-1)); + let newValue = ( Number(oldValue) + Number(unitRate) ).toFixed(1); //small adjustments due to decimals removal and exceptions if (newValue >= 98) newValue = 100; else if (newValue < 0) newValue = 0; diff --git a/web/server/gui/source/components/annotation_type_components.js b/web/server/gui/source/components/annotation_type_components.js index 21c3abb..8160630 100644 --- a/web/server/gui/source/components/annotation_type_components.js +++ b/web/server/gui/source/components/annotation_type_components.js @@ -280,6 +280,7 @@ Vue.component('classification-string-annotation', { if (this.classification_strings[classStringTuple][0] == labelName) { console.log(this.classification_strings[classStringTuple][0]); + return this.classification_strings[classStringTuple][1] } @@ -378,7 +379,7 @@ Vue.component('classification-string-annotation', { let labelName = activeLabel.id.split("_input")[0]; let context = event.target.id; //updating - let range = getTokenRange(event,text); + let range = utils.get_token_range(event,text); activeLabel.value += context.trim()+"["+range+"]["+text+"],"; this.updateClassAndString(activeLabel, labelName); //put all back in place. Two possible parent view: interannotator and annotation diff --git a/web/server/gui/source/utils/utils.js b/web/server/gui/source/utils/utils.js index 0c8685a..22a053e 100644 --- a/web/server/gui/source/utils/utils.js +++ b/web/server/gui/source/utils/utils.js @@ -180,30 +180,7 @@ function update_turn(turn, turnData){ update_dict1_from_dict2(turn,temp) } -function annotation_rate_increment(turnNumber, annotations, turnTot, turnList) { - // if turn is not already annotated return the dialogue relative % increment - let unitRate = (100 / (turnTot-1)); - - if (annotations.data != undefined) { - if (annotations.data.length > 0) { - if ((turnList[turnNumber] == undefined) || (turnList[turnNumber] == false) || (turnList[turnNumber] == "annotated")) { - turnList[turnNumber] = true; - return unitRate - } else { - return 0 - } - } else if (annotations.data.length == 0) { - if ((turnList[turnNumber] != undefined) && (turnList[turnNumber] != false)) { - turnList[turnNumber] = false; - return -(unitRate) - } else { - return 0 - } - } - } -} - -function getTokenRange(event,selectionText) { +function get_token_range(event,selectionText) { let utterance = event.target.value; //if selection starts with a space trims it if (utterance.charAt(event.target.selectionStart) == " ") { @@ -230,5 +207,5 @@ utils = get_turn_data : get_turn_data, get_all_turns_data : get_all_turns_data, create_date : create_date, - annotation_rate_increment : annotation_rate_increment + get_token_range : get_token_range } From 677c6a8d6cc2d7835c7b061374b4fe0b3b49d224 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia Date: Thu, 1 Apr 2021 14:09:33 +0200 Subject: [PATCH 028/143] configuration view 1/2 --- .gitignore | 6 ++ configuration/conf.json | 2 +- web/server/gui/assets/css/main.css | 2 +- web/server/gui/assets/css/resolutions_app.css | 4 ++ web/server/gui/index.html | 1 + web/server/gui/source/admin_view.js | 14 +++- .../components/configuration_components.js | 68 +++++++++++++++++++ web/server/gui/source/utils/languages.js | 6 ++ 8 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 web/server/gui/source/components/configuration_components.js diff --git a/.gitignore b/.gitignore index 11d0499..a287540 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ GOLD* John.json /lib pyvenv.cfg +.gitattributes +.gitattributes +db/ +web/github +web/github.pub +web/server/LIDA_ANNOTATIONS/ diff --git a/configuration/conf.json b/configuration/conf.json index 985fe9e..a8ed4e8 100644 --- a/configuration/conf.json +++ b/configuration/conf.json @@ -2,7 +2,7 @@ "app": { "address":"0.0.0.0", "port":5000, - "annotation_models":["unipi_model.json","lida_model.json","multiwoz.json", "unipi_model_v2.json"] + "annotation_models":["unipi_model.json","lida_model.json","unipi_model_v2.json"] }, "database": { "name": "matilda_dev", diff --git a/web/server/gui/assets/css/main.css b/web/server/gui/assets/css/main.css index 921095c..e71748d 100644 --- a/web/server/gui/assets/css/main.css +++ b/web/server/gui/assets/css/main.css @@ -358,7 +358,7 @@ input:focus { .admin-panel { display: grid; - grid-template: [row1-start] "1 2 3 4" [row1-end] / 1fr 1fr 1fr 1fr; + grid-template: [row1-start] "1 2 3 4 5" [row1-end] / 1fr 1fr 1fr 1fr 1fr; padding-top:30px; } diff --git a/web/server/gui/assets/css/resolutions_app.css b/web/server/gui/assets/css/resolutions_app.css index 0d7e402..01a9dac 100644 --- a/web/server/gui/assets/css/resolutions_app.css +++ b/web/server/gui/assets/css/resolutions_app.css @@ -21,6 +21,10 @@ margin-top: 25px; } +#admin_main .inner-wrap { + max-width: 1210px !important; +} + #resolution-app { background-color: #f1f1f3; height: 100%; diff --git a/web/server/gui/index.html b/web/server/gui/index.html index 8ed400d..10cf6f9 100644 --- a/web/server/gui/index.html +++ b/web/server/gui/index.html @@ -106,6 +106,7 @@ + diff --git a/web/server/gui/source/admin_view.js b/web/server/gui/source/admin_view.js index 452a2e9..709e72d 100644 --- a/web/server/gui/source/admin_view.js +++ b/web/server/gui/source/admin_view.js @@ -74,10 +74,16 @@ Vue.component("main-admin-view", { }, switchToAnnotation() { - console.log('--- BACK TO ANNOTATION VIEW ----'); + console.log('--- ANNOTATION VIEW ----'); databaseEventBus.$emit("assignments_selected"); }, + switchToConfiguration() { + console.log('--- CONFIGURATION VIEW ----'); + this.view = 'configuration'; + }, + + open_file(event){ let file = event.target.files[0]; @@ -107,10 +113,12 @@ Vue.component("main-admin-view", { +

    {{guiMessages.selected.admin_panel[1]}}

    {{guiMessages.selected.admin_panel[2]}}

    {{guiMessages.selected.admin_panel[3]}}

    {{guiMessages.selected.admin_panel[0]}}

    +

    {{guiMessages.selected.admin_panel[5]}}

    @@ -143,6 +151,10 @@ Vue.component("main-admin-view", { v-bind:collectionId="displayingCollection" v-bind:dialogueId="displayingDialogue"> + + +
    ` diff --git a/web/server/gui/source/components/configuration_components.js b/web/server/gui/source/components/configuration_components.js new file mode 100644 index 0000000..3679641 --- /dev/null +++ b/web/server/gui/source/components/configuration_components.js @@ -0,0 +1,68 @@ +Vue.component("configuration-view", { + + props: [ + "userName" + ], + + data() { + return { + changesSaved: "", + guiMessages, + showHelpConfig:false, + } + }, + + created() { + }, + + mounted () { + this.init(); + }, + + computed : { + role: function() { + return mainApp.role; + } + }, + + beforeDestroyed() { + console.log("=================================="); + console.log("I am being destroyed"); + }, + // METHODS + methods:{ + init : function(){ + //get configuration infos from server + }, + + go_back: function() { + adminEventBus.$emit("go_back"); + }, + + save() { + //send new configuration + //fields = {"assignedTo":this.selectedCollection.assignedTo}; + //backend.update_collection_async(this.selectedCollection.id,"dialogues_collections",fields) + // .then( (response) => { + //}); + }, + }, + template: + ` +
    +
    +

    {{guiMessages.selected.collection.title}}

    + +
    + + +
    + +
    + +
    +

    Configuration

    +
    +
    + ` +}); diff --git a/web/server/gui/source/utils/languages.js b/web/server/gui/source/utils/languages.js index 865fd91..daf98cb 100644 --- a/web/server/gui/source/utils/languages.js +++ b/web/server/gui/source/utils/languages.js @@ -46,6 +46,7 @@ guiMessages = { wipeCacheConfirm: "This will delete the conflicts file allowing to start conflict resolving anew.", confirmOverwriteUser: "Username already exists, please specify another username or confirm to overwrite existing user", role:"Role", + configPage: "Matilda Configuration", }, lida: { button_fileFormatInfo: "Format Info", @@ -153,6 +154,7 @@ guiMessages = { "Create, edit and assign dialogues collections", "Inspect how annotations are progressing", "Annotate collections assigned to you", + "Configure annotation models, database connection, app environment" ], modal_formatInfo: [ @@ -298,6 +300,7 @@ guiMessages = { confirmOverwriteUser: "L'username scelto esiste già, vuoi sovrascrivere l'utente già esistente?", wipeCacheConfirm: "Questo cancellerà la lista dei conflitti e permetterà di ricominciare la risoluzione da capo", role:"Ruolo", + configPage: "Configurazione di Matilda", }, lida: { button_fileFormatInfo: "Info sui formati", @@ -405,6 +408,7 @@ guiMessages = { "Crea, modifica e assegna le collezioni di dialoghi", "Controlla come sta procedendo il lavoro di annotazione", "Annota le collezioni assegnate a te", + "Configura i modelli di annotazione, la connessione al database, l'ambiente dell'app" ], modal_formatInfo: [ @@ -549,6 +553,7 @@ guiMessages = { wipeCacheConfirm: "Dadurch wird die Konfliktdatei gelöscht, sodass die Konfliktlösung erneut gestartet werden kann.", confirmOverwriteUser: "Benutzername existiert bereits, bitte geben Sie einen anderen Benutzernamen an oder bestätigen Sie, um den vorhandenen Benutzer zu überschreiben", role:"Role", + configPage: "Matilda Configuration", }, lida: { button_fileFormatInfo: "Info formatieren", @@ -657,6 +662,7 @@ guiMessages = { "Dialogsammlungen erstellen, bearbeiten und zuweisen", "Überprüfen Sie, wie die Anmerkungen fortschreiten", "Ihnen zugewiesene Sammlungen kommentieren", + "Configure annotation models, database connection, app environment" ], modal_formatInfo: [ From 20e1e37c7c6475a1fa13bc0a9afd314ca322090e Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia Date: Fri, 2 Apr 2021 08:45:54 +0200 Subject: [PATCH 029/143] configuration view back-end --- .../components/configuration_components.js | 44 ++++++++++++++++--- web/server/gui/source/utils/backend.js | 44 ++++++++++++++++++- web/server/matilda_app.py | 27 ++++++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) diff --git a/web/server/gui/source/components/configuration_components.js b/web/server/gui/source/components/configuration_components.js index 3679641..a9fa491 100644 --- a/web/server/gui/source/components/configuration_components.js +++ b/web/server/gui/source/components/configuration_components.js @@ -9,14 +9,16 @@ Vue.component("configuration-view", { changesSaved: "", guiMessages, showHelpConfig:false, + settings: {"app":{},"database":{}}, + outModels:[], } }, created() { + this.init(); }, mounted () { - this.init(); }, computed : { @@ -32,7 +34,17 @@ Vue.component("configuration-view", { // METHODS methods:{ init : function(){ - //get configuration infos from server + //get configuration info from server + backend.manage_configuration_file() + .then( (response) => { + if (response.status == "done") { + this.settings = response; + this.outModels = this.settings.app.annotation_models; + } else { + alert(response.error); + } + } + ); }, go_back: function() { @@ -40,11 +52,15 @@ Vue.component("configuration-view", { }, save() { - //send new configuration - //fields = {"assignedTo":this.selectedCollection.assignedTo}; - //backend.update_collection_async(this.selectedCollection.id,"dialogues_collections",fields) - // .then( (response) => { - //}); + backend.manage_configuration_file(settings) + .then( (response) => { + if (response.status == "done") { + this.init(); + } else { + alert(response.error); + } + } + ); }, }, template: @@ -62,6 +78,20 @@ Vue.component("configuration-view", {

    Configuration

    +

    Listed annotation models

    +
      + + Aggiungi un nuovo annotation model +
    ` diff --git a/web/server/gui/source/utils/backend.js b/web/server/gui/source/utils/backend.js index c66a9e6..3ae008f 100644 --- a/web/server/gui/source/utils/backend.js +++ b/web/server/gui/source/utils/backend.js @@ -58,6 +58,45 @@ async function annotate_query(query){ * ANNOTATON STYLE RESOURCE ***************************************/ +async function manage_configuration_file(settings){ + + if (settings == undefined) { + + var apiLink = API_BASE+`/configuration_file`; + + try { + var response = await axios.get(apiLink) + + var configurationFile = response.data + console.log("============= CONFIGURATION ==============") + console.log(configurationFile) + return configurationFile + + } catch (error) { + + console.log(error); + response["error"] = error; + return response; + } + + } else { + + var apiLink = API_BASE+`/configuration_file/${settings}`; + + try { + var response = await axios.put(apiLink) + var result = response; + console.log("============= CONFIGURATION MODIFIED ==============") + console.log(result); + return result; + + } catch (error) { + + console.log(error); + } + } +} + async function get_annotation_style_async(collection,id,supervision){ var dialogues = {} @@ -76,9 +115,9 @@ async function get_annotation_style_async(collection,id,supervision){ } try { + var response = await axios.get(apiLink) - dialogueStyle = response.data console.log("============= ANNOTATION CLASSES ==============") console.log(dialogueStyle) @@ -90,7 +129,7 @@ async function get_annotation_style_async(collection,id,supervision){ } -}; +} async function get_registered_annotation_styles(){ @@ -1014,6 +1053,7 @@ backend = write_tag : write_tag, get_annotation_style_async : get_annotation_style_async, get_registered_annotation_styles : get_registered_annotation_styles, + manage_configuration_file : manage_configuration_file, get_all_dialogues_async : get_all_dialogues_async, put_single_dialogue_async : put_single_dialogue_async, diff --git a/web/server/matilda_app.py b/web/server/matilda_app.py index 011576d..d333fa6 100644 --- a/web/server/matilda_app.py +++ b/web/server/matilda_app.py @@ -52,6 +52,33 @@ def welcome(): # FUNCTION HANDLERS ############################################## +@MatildaApp.route('/configuration_file', methods=['GET']) +@MatildaApp.route('/configuration_file/', methods=['PUT']) +def handle_configuration_file(settings=None): + """ + Returns the annotation styles registered in configuration json + """ + responseObject = { "status":"fail" } + + if request.method == "GET": + + for section in Configuration.conf: + responseObject[section] = Configuration.conf[section] + if (type(section)) != str: + for setting in section: + responseObject[setting][section] = setting + + responseObject["status"] = "done"; + + if request.method == "PUT": + + #do something + + responseObject = { "status":"done" } + + return jsonify( responseObject ) + + @MatildaApp.route('//dialogues_metadata',methods=['GET']) @MatildaApp.route('//dialogues_metadata/',methods=['PUT']) def handle_dialogues_metadata_resource(user, id=None): From 948fb363839e92b2ae5310a993fce80f83bd1b79 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Fri, 2 Apr 2021 09:46:13 +0200 Subject: [PATCH 030/143] Update unipi_model_v2.json --- configuration/unipi_model_v2.json | 38 ++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/configuration/unipi_model_v2.json b/configuration/unipi_model_v2.json index 301a251..e6b5503 100644 --- a/configuration/unipi_model_v2.json +++ b/configuration/unipi_model_v2.json @@ -170,6 +170,12 @@ "none", "job_description", "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", "area", "company_size", "location" @@ -202,8 +208,8 @@ ] }, - - "usr_deny": { + + "sys_deny": { "description" : "Entity's value", "label_type" : "multilabel_classification_string", @@ -211,12 +217,22 @@ "labels" : [ "none", - "job_description" + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location" ] }, - - "sys_deny": { + + "usr_deny": { "description" : "Entity's value", "label_type" : "multilabel_classification_string", @@ -224,7 +240,17 @@ "labels" : [ "none", - "job_description" + "job_description", + "contract", + "duties", + "skill", + "past_experience", + "degree", + "age", + "languages", + "area", + "company_size", + "location" ] }, From bb3e0c8780070ac823c0e99bc0cfd7704c17354d Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Fri, 2 Apr 2021 09:44:31 +0200 Subject: [PATCH 031/143] Update languages.js missing term --- web/server/gui/source/utils/languages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/server/gui/source/utils/languages.js b/web/server/gui/source/utils/languages.js index daf98cb..db38134 100644 --- a/web/server/gui/source/utils/languages.js +++ b/web/server/gui/source/utils/languages.js @@ -559,7 +559,7 @@ guiMessages = { button_fileFormatInfo: "Info formatieren", button_delete: "Löschen", button_switch: "Ansicht wechseln", - dreht: "dreht", + turns: "dreht", button_newDialogue: "Neuen Dialog hinzufügen", button_wipeDialogues: "Dialoge löschen", interfaceLanguage: "System Sprache:", From 6c394dfba0f61493b0dde838c561c257d17113a7 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Fri, 2 Apr 2021 15:06:14 +0200 Subject: [PATCH 032/143] annotators or annotator --- .../gui/source/components/supervision_components.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/web/server/gui/source/components/supervision_components.js b/web/server/gui/source/components/supervision_components.js index 0a397c6..7c77193 100644 --- a/web/server/gui/source/components/supervision_components.js +++ b/web/server/gui/source/components/supervision_components.js @@ -118,17 +118,23 @@ Vue.component("supervision-view", { False
    + +
    @@ -586,4 +592,4 @@ Vue.component("supervision-annotation-app", {
` -}); \ No newline at end of file +}); From 3e55ba2dbd6d8f8bd92fa7615f4fe70f79c70133 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia <44603608+davivcu@users.noreply.github.com> Date: Fri, 2 Apr 2021 15:22:18 +0200 Subject: [PATCH 033/143] Update main.css --- web/server/gui/assets/css/main.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/server/gui/assets/css/main.css b/web/server/gui/assets/css/main.css index e71748d..d611173 100644 --- a/web/server/gui/assets/css/main.css +++ b/web/server/gui/assets/css/main.css @@ -275,12 +275,12 @@ input:focus { justify-content: flex-end; align-items: center; text-align: right; - padding-right: 20px; + padding-right: 3px; font-weight: bold; font-family: montserrat; text-transform: uppercase; font-size: 11px; - letter-spacing: 1px; + letter-spacing: 0.5px; background-color: #999; transition: 0.2s; color: white; From b9efce1314f0a5e623706c2940488f66113392c8 Mon Sep 17 00:00:00 2001 From: davivcu Date: Fri, 2 Apr 2021 17:17:34 +0200 Subject: [PATCH 034/143] configuration view back end --- web/server/annotator_config.py | 4 ++++ web/server/gui/source/utils/backend.js | 7 ++++++- web/server/matilda_app.py | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/web/server/annotator_config.py b/web/server/annotator_config.py index f1a83ad..798a86a 100644 --- a/web/server/annotator_config.py +++ b/web/server/annotator_config.py @@ -43,17 +43,21 @@ class Configuration(object): class responsible for configuration and valid annotation structure """ + DEFAULT_PATH = "" + #importing json configuration file try: #docker with open('configuration/conf.json') as json_file: conf = json.load(json_file) __DEFAULT_PATH = "configuration/" + DEFAULT_PATH = __DEFAULT_PATH except: #standalone with open('../../configuration/conf.json') as json_file: conf = json.load(json_file) __DEFAULT_PATH = "../../configuration/" + DEFAULT_PATH = __DEFAULT_PATH # Here the list of annotation model file names annotation_styles = conf["app"]["annotation_models"] diff --git a/web/server/gui/source/utils/backend.js b/web/server/gui/source/utils/backend.js index 3ae008f..c45220c 100644 --- a/web/server/gui/source/utils/backend.js +++ b/web/server/gui/source/utils/backend.js @@ -75,7 +75,12 @@ async function manage_configuration_file(settings){ } catch (error) { console.log(error); - response["error"] = error; + if (response != undefined) { + response["error"] = error; + } else { + response = {} + response["error"] = error; + } return response; } diff --git a/web/server/matilda_app.py b/web/server/matilda_app.py index d333fa6..53932aa 100644 --- a/web/server/matilda_app.py +++ b/web/server/matilda_app.py @@ -68,8 +68,14 @@ def handle_configuration_file(settings=None): for setting in section: responseObject[setting][section] = setting + responseObject["annotationStyles"] = {} + for model in Configuration.annotation_styles: + with open(Configuration.DEFAULT_PATH+model) as style_file: + responseObject["annotationStyles"][model] = json.load(style_file) + responseObject["status"] = "done"; + if request.method == "PUT": #do something From 5eddb09e5cccff8a51263614e8b79a0d24e64394 Mon Sep 17 00:00:00 2001 From: Davide Ivan Cucurnia Date: Sun, 4 Apr 2021 16:07:40 +0200 Subject: [PATCH 035/143] configuration view 2/2 --- web/server/gui/assets/css/database.css | 78 + web/server/gui/assets/css/main.css | 1 - web/server/gui/index.html | 74 +- web/server/gui/lib/axios.min.js | 3 + web/server/gui/lib/vue.js | 11944 ++++++++++++++++ .../components/configuration_components.js | 177 +- .../components/datamanagement_components.js | 2 +- .../components/supervision_components.js | 8 +- web/server/gui/source/utils/backend.js | 36 +- web/server/gui/source/utils/languages.js | 21 +- web/server/matilda_app.py | 74 +- 11 files changed, 12330 insertions(+), 88 deletions(-) create mode 100644 web/server/gui/lib/axios.min.js create mode 100644 web/server/gui/lib/vue.js diff --git a/web/server/gui/assets/css/database.css b/web/server/gui/assets/css/database.css index 8f53353..ed6aaa9 100644 --- a/web/server/gui/assets/css/database.css +++ b/web/server/gui/assets/css/database.css @@ -586,4 +586,82 @@ input[type="password"]:hover { color: #222; padding: 5px; transition: ease 250ms all; +} + +/******************************* +// CONFIGURATION VIEW +*******************************/ + +.annotation-models-list .entry-list-single-item-container { + border-left:5px solid #3a9dd6 !important; + width:75%; + grid-template: [row1-start] "info buttons" [row1-end] / 7fr 3fr; + margin-bottom:2%; +} + +.annotation-models-list .entry-info { + display:block; + padding:1%; + padding-left:4%; +} + +.annotation-models-list .entry-info:hover { + border-left: 3px solid #3a9dd6; +} + +.annotation-models-list .entry-info span { + font-family: 'Montserrat'; + text-transform: uppercase; + font-weight: bold; + font-size: 14px; + align-self: center; +} + +.annotation-models-list .entry-info label { + grid-template: none !important; +} + +.annotation-models-list .edit-dialogue-button, +.annotation-models-list .del-dialogue-button{ + margin-top:0px; + margin-right:4%; + width: 48%; + height: 55%; + place-self: center; + margin-right: 4%; +} + +.entry-buttons { + grid-area: buttons; + display: flex; +} + +.closing-list { + clear:both; +} + +.annotation-style-structure { + overflow-y: scroll; + height: 40em; +} + +.annotation-style-text { + width: 95%; + height: 40em; + background: white !important; + border:1px solid rgb(0 0 0 / 17%); +} + +h4 { + margin-top:10px; + margin-bottom:10px; +} + +h5 { + margin:4px; + padding:0; +} + +h4 span, h5 span { + color: rgb(0 0 0 / 61%); } \ No newline at end of file diff --git a/web/server/gui/assets/css/main.css b/web/server/gui/assets/css/main.css index d611173..3e4e1ce 100644 --- a/web/server/gui/assets/css/main.css +++ b/web/server/gui/assets/css/main.css @@ -264,7 +264,6 @@ input:focus { .int-coll-num-turns:hover { background-color: #999; - transition: 0.2s; color: white; } diff --git a/web/server/gui/index.html b/web/server/gui/index.html index 10cf6f9..5ec4599 100644 --- a/web/server/gui/index.html +++ b/web/server/gui/index.html @@ -17,25 +17,25 @@ CSS ---------------------------------------------------------------> - - + + - + - - - - - - - - + + + + + + + + - - + + @@ -66,7 +66,7 @@
- MATILDA · Copyright © 2020 Wluper Ltd. · Developed in collaboration with University of Pisa + MATILDA v.1.1.15 · Copyright © 2020 Wluper Ltd. · Developed in collaboration with University of Pisa
@@ -84,34 +84,34 @@ SCRIPTS ============================================= --> - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - + + + + + + + diff --git a/web/server/gui/lib/axios.min.js b/web/server/gui/lib/axios.min.js new file mode 100644 index 0000000..fc6c8b6 --- /dev/null +++ b/web/server/gui/lib/axios.min.js @@ -0,0 +1,3 @@ +/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),c.isAxiosError=n(26),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(13),s=n(16),i=n(5),a=n(17),u=n(20),c=n(21),f=n(14);e.exports=function(e){return new Promise(function(t,n){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";d.Authorization="Basic "+btoa(h+":"+m)}var y=a(e.baseURL,e.url);if(l.open(e.method.toUpperCase(),i(y,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l.onreadystatechange=function(){if(l&&4===l.readyState&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var r="getAllResponseHeaders"in l?u(l.getAllResponseHeaders()):null,s=e.responseType&&"text"!==e.responseType?l.response:l.responseText,i={data:s,status:l.status,statusText:l.statusText,headers:r,config:e,request:l};o(t,n,i),l=null}},l.onabort=function(){l&&(n(f("Request aborted",e,"ECONNABORTED",l)),l=null)},l.onerror=function(){n(f("Network Error",e,null,l)),l=null},l.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),n(f(t,e,"ECONNABORTED",l)),l=null},r.isStandardBrowserEnv()){var g=(e.withCredentials||c(y))&&e.xsrfCookieName?s.read(e.xsrfCookieName):void 0;g&&(d[e.xsrfHeaderName]=g)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),r.isUndefined(e.withCredentials)||(l.withCredentials=!!e.withCredentials),e.responseType)try{l.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),n(e),l=null)}),p||(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(14);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(15);e.exports=function(e,t,n,o,s){var i=new Error(e);return r(i,t,n,o,s)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";var r=n(18),o=n(19);e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,s,i={};return e?(r.forEach(e.split("\n"),function(e){if(s=e.indexOf(":"),t=r.trim(e.substr(0,s)).toLowerCase(),n=r.trim(e.substr(s+1)),t){if(i[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?i[t]=(i[t]?i[t]:[]).concat([n]):i[t]=i[t]?i[t]+", "+n:n}}),i):i}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){function n(e,t){return r.isPlainObject(e)&&r.isPlainObject(t)?r.merge(e,t):r.isPlainObject(t)?r.merge({},t):r.isArray(t)?t.slice():t}function o(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(e[o],t[o])}t=t||{};var s={},i=["url","method","data"],a=["headers","auth","proxy","params"],u=["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","timeoutMessage","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","decompress","maxContentLength","maxBodyLength","maxRedirects","transport","httpAgent","httpsAgent","cancelToken","socketPath","responseEncoding"],c=["validateStatus"];r.forEach(i,function(e){r.isUndefined(t[e])||(s[e]=n(void 0,t[e]))}),r.forEach(a,o),r.forEach(u,function(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(void 0,t[o])}),r.forEach(c,function(r){r in t?s[r]=n(e[r],t[r]):r in e&&(s[r]=n(void 0,e[r]))});var f=i.concat(a).concat(u).concat(c),p=Object.keys(e).concat(Object.keys(t)).filter(function(e){return f.indexOf(e)===-1});return r.forEach(p,o),s}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t){"use strict";e.exports=function(e){return"object"==typeof e&&e.isAxiosError===!0}}])}); +//# sourceMappingURL=axios.min.map \ No newline at end of file diff --git a/web/server/gui/lib/vue.js b/web/server/gui/lib/vue.js new file mode 100644 index 0000000..4ef7ff1 --- /dev/null +++ b/web/server/gui/lib/vue.js @@ -0,0 +1,11944 @@ +/*! + * Vue.js v2.6.10 + * (c) 2014-2019 Evan You + * Released under the MIT License. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.Vue = factory()); +}(this, function () { 'use strict'; + + /* */ + + var emptyObject = Object.freeze({}); + + // These helpers produce better VM code in JS engines due to their + // explicitness and function inlining. + function isUndef (v) { + return v === undefined || v === null + } + + function isDef (v) { + return v !== undefined && v !== null + } + + function isTrue (v) { + return v === true + } + + function isFalse (v) { + return v === false + } + + /** + * Check if value is primitive. + */ + function isPrimitive (value) { + return ( + typeof value === 'string' || + typeof value === 'number' || + // $flow-disable-line + typeof value === 'symbol' || + typeof value === 'boolean' + ) + } + + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + function isObject (obj) { + return obj !== null && typeof obj === 'object' + } + + /** + * Get the raw type string of a value, e.g., [object Object]. + */ + var _toString = Object.prototype.toString; + + function toRawType (value) { + return _toString.call(value).slice(8, -1) + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + function isPlainObject (obj) { + return _toString.call(obj) === '[object Object]' + } + + function isRegExp (v) { + return _toString.call(v) === '[object RegExp]' + } + + /** + * Check if val is a valid array index. + */ + function isValidArrayIndex (val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + } + + function isPromise (val) { + return ( + isDef(val) && + typeof val.then === 'function' && + typeof val.catch === 'function' + ) + } + + /** + * Convert a value to a string that is actually rendered. + */ + function toString (val) { + return val == null + ? '' + : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) + ? JSON.stringify(val, null, 2) + : String(val) + } + + /** + * Convert an input value to a number for persistence. + * If the conversion fails, return original string. + */ + function toNumber (val) { + var n = parseFloat(val); + return isNaN(n) ? val : n + } + + /** + * Make a map and return a function for checking if a key + * is in that map. + */ + function makeMap ( + str, + expectsLowerCase + ) { + var map = Object.create(null); + var list = str.split(','); + for (var i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase + ? function (val) { return map[val.toLowerCase()]; } + : function (val) { return map[val]; } + } + + /** + * Check if a tag is a built-in tag. + */ + var isBuiltInTag = makeMap('slot,component', true); + + /** + * Check if an attribute is a reserved attribute. + */ + var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); + + /** + * Remove an item from an array. + */ + function remove (arr, item) { + if (arr.length) { + var index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1) + } + } + } + + /** + * Check whether an object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) + } + + /** + * Create a cached version of a pure function. + */ + function cached (fn) { + var cache = Object.create(null); + return (function cachedFn (str) { + var hit = cache[str]; + return hit || (cache[str] = fn(str)) + }) + } + + /** + * Camelize a hyphen-delimited string. + */ + var camelizeRE = /-(\w)/g; + var camelize = cached(function (str) { + return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) + }); + + /** + * Capitalize a string. + */ + var capitalize = cached(function (str) { + return str.charAt(0).toUpperCase() + str.slice(1) + }); + + /** + * Hyphenate a camelCase string. + */ + var hyphenateRE = /\B([A-Z])/g; + var hyphenate = cached(function (str) { + return str.replace(hyphenateRE, '-$1').toLowerCase() + }); + + /** + * Simple bind polyfill for environments that do not support it, + * e.g., PhantomJS 1.x. Technically, we don't need this anymore + * since native bind is now performant enough in most browsers. + * But removing it would mean breaking code that was able to run in + * PhantomJS 1.x, so this must be kept for backward compatibility. + */ + + /* istanbul ignore next */ + function polyfillBind (fn, ctx) { + function boundFn (a) { + var l = arguments.length; + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + + boundFn._length = fn.length; + return boundFn + } + + function nativeBind (fn, ctx) { + return fn.bind(ctx) + } + + var bind = Function.prototype.bind + ? nativeBind + : polyfillBind; + + /** + * Convert an Array-like object to a real Array. + */ + function toArray (list, start) { + start = start || 0; + var i = list.length - start; + var ret = new Array(i); + while (i--) { + ret[i] = list[i + start]; + } + return ret + } + + /** + * Mix properties into target object. + */ + function extend (to, _from) { + for (var key in _from) { + to[key] = _from[key]; + } + return to + } + + /** + * Merge an Array of Objects into a single Object. + */ + function toObject (arr) { + var res = {}; + for (var i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res + } + + /* eslint-disable no-unused-vars */ + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ + function noop (a, b, c) {} + + /** + * Always return false. + */ + var no = function (a, b, c) { return false; }; + + /* eslint-enable no-unused-vars */ + + /** + * Return the same value. + */ + var identity = function (_) { return _; }; + + /** + * Generate a string containing static keys from compiler modules. + */ + function genStaticKeys (modules) { + return modules.reduce(function (keys, m) { + return keys.concat(m.staticKeys || []) + }, []).join(',') + } + + /** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ + function looseEqual (a, b) { + if (a === b) { return true } + var isObjectA = isObject(a); + var isObjectB = isObject(b); + if (isObjectA && isObjectB) { + try { + var isArrayA = Array.isArray(a); + var isArrayB = Array.isArray(b); + if (isArrayA && isArrayB) { + return a.length === b.length && a.every(function (e, i) { + return looseEqual(e, b[i]) + }) + } else if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime() + } else if (!isArrayA && !isArrayB) { + var keysA = Object.keys(a); + var keysB = Object.keys(b); + return keysA.length === keysB.length && keysA.every(function (key) { + return looseEqual(a[key], b[key]) + }) + } else { + /* istanbul ignore next */ + return false + } + } catch (e) { + /* istanbul ignore next */ + return false + } + } else if (!isObjectA && !isObjectB) { + return String(a) === String(b) + } else { + return false + } + } + + /** + * Return the first index at which a loosely equal value can be + * found in the array (if value is a plain object, the array must + * contain an object of the same shape), or -1 if it is not present. + */ + function looseIndexOf (arr, val) { + for (var i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) { return i } + } + return -1 + } + + /** + * Ensure a function is called only once. + */ + function once (fn) { + var called = false; + return function () { + if (!called) { + called = true; + fn.apply(this, arguments); + } + } + } + + var SSR_ATTR = 'data-server-rendered'; + + var ASSET_TYPES = [ + 'component', + 'directive', + 'filter' + ]; + + var LIFECYCLE_HOOKS = [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated', + 'errorCaptured', + 'serverPrefetch' + ]; + + /* */ + + + + var config = ({ + /** + * Option merge strategies (used in core/util/options) + */ + // $flow-disable-line + optionMergeStrategies: Object.create(null), + + /** + * Whether to suppress warnings. + */ + silent: false, + + /** + * Show production mode tip message on boot? + */ + productionTip: "development" !== 'production', + + /** + * Whether to enable devtools + */ + devtools: "development" !== 'production', + + /** + * Whether to record perf + */ + performance: false, + + /** + * Error handler for watcher errors + */ + errorHandler: null, + + /** + * Warn handler for watcher warns + */ + warnHandler: null, + + /** + * Ignore certain custom elements + */ + ignoredElements: [], + + /** + * Custom user key aliases for v-on + */ + // $flow-disable-line + keyCodes: Object.create(null), + + /** + * Check if a tag is reserved so that it cannot be registered as a + * component. This is platform-dependent and may be overwritten. + */ + isReservedTag: no, + + /** + * Check if an attribute is reserved so that it cannot be used as a component + * prop. This is platform-dependent and may be overwritten. + */ + isReservedAttr: no, + + /** + * Check if a tag is an unknown element. + * Platform-dependent. + */ + isUnknownElement: no, + + /** + * Get the namespace of an element + */ + getTagNamespace: noop, + + /** + * Parse the real tag name for the specific platform. + */ + parsePlatformTagName: identity, + + /** + * Check if an attribute must be bound using property, e.g. value + * Platform-dependent. + */ + mustUseProp: no, + + /** + * Perform updates asynchronously. Intended to be used by Vue Test Utils + * This will significantly reduce performance if set to false. + */ + async: true, + + /** + * Exposed for legacy reasons + */ + _lifecycleHooks: LIFECYCLE_HOOKS + }); + + /* */ + + /** + * unicode letters used for parsing html tags, component names and property paths. + * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * skipping \u10000-\uEFFFF due to it freezing up PhantomJS + */ + var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; + + /** + * Check if a string starts with $ or _ + */ + function isReserved (str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F + } + + /** + * Define a property. + */ + function def (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); + } + + /** + * Parse simple path. + */ + var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); + function parsePath (path) { + if (bailRE.test(path)) { + return + } + var segments = path.split('.'); + return function (obj) { + for (var i = 0; i < segments.length; i++) { + if (!obj) { return } + obj = obj[segments[i]]; + } + return obj + } + } + + /* */ + + // can we use __proto__? + var hasProto = '__proto__' in {}; + + // Browser environment sniffing + var inBrowser = typeof window !== 'undefined'; + var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; + var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase(); + var UA = inBrowser && window.navigator.userAgent.toLowerCase(); + var isIE = UA && /msie|trident/.test(UA); + var isIE9 = UA && UA.indexOf('msie 9.0') > 0; + var isEdge = UA && UA.indexOf('edge/') > 0; + var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android'); + var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios'); + var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; + var isPhantomJS = UA && /phantomjs/.test(UA); + var isFF = UA && UA.match(/firefox\/(\d+)/); + + // Firefox has a "watch" function on Object.prototype... + var nativeWatch = ({}).watch; + + var supportsPassive = false; + if (inBrowser) { + try { + var opts = {}; + Object.defineProperty(opts, 'passive', ({ + get: function get () { + /* istanbul ignore next */ + supportsPassive = true; + } + })); // https://github.com/facebook/flow/issues/285 + window.addEventListener('test-passive', null, opts); + } catch (e) {} + } + + // this needs to be lazy-evaled because vue may be required before + // vue-server-renderer can set VUE_ENV + var _isServer; + var isServerRendering = function () { + if (_isServer === undefined) { + /* istanbul ignore if */ + if (!inBrowser && !inWeex && typeof global !== 'undefined') { + // detect presence of vue-server-renderer and avoid + // Webpack shimming the process + _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'; + } else { + _isServer = false; + } + } + return _isServer + }; + + // detect devtools + var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + + /* istanbul ignore next */ + function isNative (Ctor) { + return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) + } + + var hasSymbol = + typeof Symbol !== 'undefined' && isNative(Symbol) && + typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); + + var _Set; + /* istanbul ignore if */ // $flow-disable-line + if (typeof Set !== 'undefined' && isNative(Set)) { + // use native Set when available. + _Set = Set; + } else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = /*@__PURE__*/(function () { + function Set () { + this.set = Object.create(null); + } + Set.prototype.has = function has (key) { + return this.set[key] === true + }; + Set.prototype.add = function add (key) { + this.set[key] = true; + }; + Set.prototype.clear = function clear () { + this.set = Object.create(null); + }; + + return Set; + }()); + } + + /* */ + + var warn = noop; + var tip = noop; + var generateComponentTrace = (noop); // work around flow check + var formatComponentName = (noop); + + { + var hasConsole = typeof console !== 'undefined'; + var classifyRE = /(?:^|[-_])(\w)/g; + var classify = function (str) { return str + .replace(classifyRE, function (c) { return c.toUpperCase(); }) + .replace(/[-_]/g, ''); }; + + warn = function (msg, vm) { + var trace = vm ? generateComponentTrace(vm) : ''; + + if (config.warnHandler) { + config.warnHandler.call(null, msg, vm, trace); + } else if (hasConsole && (!config.silent)) { + console.error(("[Vue warn]: " + msg + trace)); + } + }; + + tip = function (msg, vm) { + if (hasConsole && (!config.silent)) { + console.warn("[Vue tip]: " + msg + ( + vm ? generateComponentTrace(vm) : '' + )); + } + }; + + formatComponentName = function (vm, includeFile) { + if (vm.$root === vm) { + return '' + } + var options = typeof vm === 'function' && vm.cid != null + ? vm.options + : vm._isVue + ? vm.$options || vm.constructor.options + : vm; + var name = options.name || options._componentTag; + var file = options.__file; + if (!name && file) { + var match = file.match(/([^/\\]+)\.vue$/); + name = match && match[1]; + } + + return ( + (name ? ("<" + (classify(name)) + ">") : "") + + (file && includeFile !== false ? (" at " + file) : '') + ) + }; + + var repeat = function (str, n) { + var res = ''; + while (n) { + if (n % 2 === 1) { res += str; } + if (n > 1) { str += str; } + n >>= 1; + } + return res + }; + + generateComponentTrace = function (vm) { + if (vm._isVue && vm.$parent) { + var tree = []; + var currentRecursiveSequence = 0; + while (vm) { + if (tree.length > 0) { + var last = tree[tree.length - 1]; + if (last.constructor === vm.constructor) { + currentRecursiveSequence++; + vm = vm.$parent; + continue + } else if (currentRecursiveSequence > 0) { + tree[tree.length - 1] = [last, currentRecursiveSequence]; + currentRecursiveSequence = 0; + } + } + tree.push(vm); + vm = vm.$parent; + } + return '\n\nfound in\n\n' + tree + .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm) + ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)") + : formatComponentName(vm))); }) + .join('\n') + } else { + return ("\n\n(found in " + (formatComponentName(vm)) + ")") + } + }; + } + + /* */ + + var uid = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + */ + var Dep = function Dep () { + this.id = uid++; + this.subs = []; + }; + + Dep.prototype.addSub = function addSub (sub) { + this.subs.push(sub); + }; + + Dep.prototype.removeSub = function removeSub (sub) { + remove(this.subs, sub); + }; + + Dep.prototype.depend = function depend () { + if (Dep.target) { + Dep.target.addDep(this); + } + }; + + Dep.prototype.notify = function notify () { + // stabilize the subscriber list first + var subs = this.subs.slice(); + if (!config.async) { + // subs aren't sorted in scheduler if not running async + // we need to sort them now to make sure they fire in correct + // order + subs.sort(function (a, b) { return a.id - b.id; }); + } + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + // The current target watcher being evaluated. + // This is globally unique because only one watcher + // can be evaluated at a time. + Dep.target = null; + var targetStack = []; + + function pushTarget (target) { + targetStack.push(target); + Dep.target = target; + } + + function popTarget () { + targetStack.pop(); + Dep.target = targetStack[targetStack.length - 1]; + } + + /* */ + + var VNode = function VNode ( + tag, + data, + children, + text, + elm, + context, + componentOptions, + asyncFactory + ) { + this.tag = tag; + this.data = data; + this.children = children; + this.text = text; + this.elm = elm; + this.ns = undefined; + this.context = context; + this.fnContext = undefined; + this.fnOptions = undefined; + this.fnScopeId = undefined; + this.key = data && data.key; + this.componentOptions = componentOptions; + this.componentInstance = undefined; + this.parent = undefined; + this.raw = false; + this.isStatic = false; + this.isRootInsert = true; + this.isComment = false; + this.isCloned = false; + this.isOnce = false; + this.asyncFactory = asyncFactory; + this.asyncMeta = undefined; + this.isAsyncPlaceholder = false; + }; + + var prototypeAccessors = { child: { configurable: true } }; + + // DEPRECATED: alias for componentInstance for backwards compat. + /* istanbul ignore next */ + prototypeAccessors.child.get = function () { + return this.componentInstance + }; + + Object.defineProperties( VNode.prototype, prototypeAccessors ); + + var createEmptyVNode = function (text) { + if ( text === void 0 ) text = ''; + + var node = new VNode(); + node.text = text; + node.isComment = true; + return node + }; + + function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) + } + + // optimized shallow clone + // used for static nodes and slot nodes because they may be reused across + // multiple renders, cloning them avoids errors when DOM manipulations rely + // on their elm reference. + function cloneVNode (vnode) { + var cloned = new VNode( + vnode.tag, + vnode.data, + // #7975 + // clone children array to avoid mutating original in case of cloning + // a child. + vnode.children && vnode.children.slice(), + vnode.text, + vnode.elm, + vnode.context, + vnode.componentOptions, + vnode.asyncFactory + ); + cloned.ns = vnode.ns; + cloned.isStatic = vnode.isStatic; + cloned.key = vnode.key; + cloned.isComment = vnode.isComment; + cloned.fnContext = vnode.fnContext; + cloned.fnOptions = vnode.fnOptions; + cloned.fnScopeId = vnode.fnScopeId; + cloned.asyncMeta = vnode.asyncMeta; + cloned.isCloned = true; + return cloned + } + + /* + * not type checking this file because flow doesn't play well with + * dynamically accessing methods on Array prototype + */ + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto); + + var methodsToPatch = [ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' + ]; + + /** + * Intercept mutating methods and emit events + */ + methodsToPatch.forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break + case 'splice': + inserted = args.slice(2); + break + } + if (inserted) { ob.observeArray(inserted); } + // notify change + ob.dep.notify(); + return result + }); + }); + + /* */ + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * In some cases we may want to disable observation inside a component's + * update computation. + */ + var shouldObserve = true; + + function toggleObserving (value) { + shouldObserve = value; + } + + /** + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target + * object's property keys into getter/setters that + * collect dependencies and dispatch updates. + */ + var Observer = function Observer (value) { + this.value = value; + this.dep = new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (Array.isArray(value)) { + if (hasProto) { + protoAugment(value, arrayMethods); + } else { + copyAugment(value, arrayMethods, arrayKeys); + } + this.observeArray(value); + } else { + this.walk(value); + } + }; + + /** + * Walk through all properties and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ + Observer.prototype.walk = function walk (obj) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length; i++) { + defineReactive$$1(obj, keys[i]); + } + }; + + /** + * Observe a list of Array items. + */ + Observer.prototype.observeArray = function observeArray (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + // helpers + + /** + * Augment a target Object or Array by intercepting + * the prototype chain using __proto__ + */ + function protoAugment (target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment a target Object or Array by defining + * hidden properties. + */ + /* istanbul ignore next */ + function copyAugment (target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + */ + function observe (value, asRootData) { + if (!isObject(value) || value instanceof VNode) { + return + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if ( + shouldObserve && + !isServerRendering() && + (Array.isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value._isVue + ) { + ob = new Observer(value); + } + if (asRootData && ob) { + ob.vmCount++; + } + return ob + } + + /** + * Define a reactive property on an Object. + */ + function defineReactive$$1 ( + obj, + key, + val, + customSetter, + shallow + ) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + if ((!getter || setter) && arguments.length === 2) { + val = obj[key]; + } + + var childOb = !shallow && observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter () { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + if (Array.isArray(value)) { + dependArray(value); + } + } + } + return value + }, + set: function reactiveSetter (newVal) { + var value = getter ? getter.call(obj) : val; + /* eslint-disable no-self-compare */ + if (newVal === value || (newVal !== newVal && value !== value)) { + return + } + /* eslint-enable no-self-compare */ + if (customSetter) { + customSetter(); + } + // #7981: for accessor properties without setter + if (getter && !setter) { return } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = !shallow && observe(newVal); + dep.notify(); + } + }); + } + + /** + * Set a property on an object. Adds the new property and + * triggers change notification if the property doesn't + * already exist. + */ + function set (target, key, val) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.length = Math.max(target.length, key); + target.splice(key, 1, val); + return val + } + if (key in target && !(key in Object.prototype)) { + target[key] = val; + return val + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.' + ); + return val + } + if (!ob) { + target[key] = val; + return val + } + defineReactive$$1(ob.value, key, val); + ob.dep.notify(); + return val + } + + /** + * Delete a property and trigger change if necessary. + */ + function del (target, key) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.splice(key, 1); + return + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid deleting properties on a Vue instance or its root $data ' + + '- just set it to null.' + ); + return + } + if (!hasOwn(target, key)) { + return + } + delete target[key]; + if (!ob) { + return + } + ob.dep.notify(); + } + + /** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ + function dependArray (value) { + for (var e = (void 0), i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + if (Array.isArray(e)) { + dependArray(e); + } + } + } + + /* */ + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + */ + var strats = config.optionMergeStrategies; + + /** + * Options with restrictions + */ + { + strats.el = strats.propsData = function (parent, child, vm, key) { + if (!vm) { + warn( + "option \"" + key + "\" can only be used during instance " + + 'creation with the `new` keyword.' + ); + } + return defaultStrat(parent, child) + }; + } + + /** + * Helper that recursively merges two data objects together. + */ + function mergeData (to, from) { + if (!from) { return to } + var key, toVal, fromVal; + + var keys = hasSymbol + ? Reflect.ownKeys(from) + : Object.keys(from); + + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + // in case the object is already observed... + if (key === '__ob__') { continue } + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if ( + toVal !== fromVal && + isPlainObject(toVal) && + isPlainObject(fromVal) + ) { + mergeData(toVal, fromVal); + } + } + return to + } + + /** + * Data + */ + function mergeDataOrFn ( + parentVal, + childVal, + vm + ) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal + } + if (!parentVal) { + return childVal + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn () { + return mergeData( + typeof childVal === 'function' ? childVal.call(this, this) : childVal, + typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal + ) + } + } else { + return function mergedInstanceDataFn () { + // instance merge + var instanceData = typeof childVal === 'function' + ? childVal.call(vm, vm) + : childVal; + var defaultData = typeof parentVal === 'function' + ? parentVal.call(vm, vm) + : parentVal; + if (instanceData) { + return mergeData(instanceData, defaultData) + } else { + return defaultData + } + } + } + } + + strats.data = function ( + parentVal, + childVal, + vm + ) { + if (!vm) { + if (childVal && typeof childVal !== 'function') { + warn( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + + return parentVal + } + return mergeDataOrFn(parentVal, childVal) + } + + return mergeDataOrFn(parentVal, childVal, vm) + }; + + /** + * Hooks and props are merged as arrays. + */ + function mergeHook ( + parentVal, + childVal + ) { + var res = childVal + ? parentVal + ? parentVal.concat(childVal) + : Array.isArray(childVal) + ? childVal + : [childVal] + : parentVal; + return res + ? dedupeHooks(res) + : res + } + + function dedupeHooks (hooks) { + var res = []; + for (var i = 0; i < hooks.length; i++) { + if (res.indexOf(hooks[i]) === -1) { + res.push(hooks[i]); + } + } + return res + } + + LIFECYCLE_HOOKS.forEach(function (hook) { + strats[hook] = mergeHook; + }); + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + function mergeAssets ( + parentVal, + childVal, + vm, + key + ) { + var res = Object.create(parentVal || null); + if (childVal) { + assertObjectType(key, childVal, vm); + return extend(res, childVal) + } else { + return res + } + } + + ASSET_TYPES.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Watchers. + * + * Watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + strats.watch = function ( + parentVal, + childVal, + vm, + key + ) { + // work around Firefox's Object.prototype.watch... + if (parentVal === nativeWatch) { parentVal = undefined; } + if (childVal === nativeWatch) { childVal = undefined; } + /* istanbul ignore if */ + if (!childVal) { return Object.create(parentVal || null) } + { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = {}; + extend(ret, parentVal); + for (var key$1 in childVal) { + var parent = ret[key$1]; + var child = childVal[key$1]; + if (parent && !Array.isArray(parent)) { + parent = [parent]; + } + ret[key$1] = parent + ? parent.concat(child) + : Array.isArray(child) ? child : [child]; + } + return ret + }; + + /** + * Other object hashes. + */ + strats.props = + strats.methods = + strats.inject = + strats.computed = function ( + parentVal, + childVal, + vm, + key + ) { + if (childVal && "development" !== 'production') { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = Object.create(null); + extend(ret, parentVal); + if (childVal) { extend(ret, childVal); } + return ret + }; + strats.provide = mergeDataOrFn; + + /** + * Default strategy. + */ + var defaultStrat = function (parentVal, childVal) { + return childVal === undefined + ? parentVal + : childVal + }; + + /** + * Validate component names + */ + function checkComponents (options) { + for (var key in options.components) { + validateComponentName(key); + } + } + + function validateComponentName (name) { + if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicodeRegExp.source) + "]*$")).test(name)) { + warn( + 'Invalid component name: "' + name + '". Component names ' + + 'should conform to valid custom element name in html5 specification.' + ); + } + if (isBuiltInTag(name) || config.isReservedTag(name)) { + warn( + 'Do not use built-in or reserved HTML elements as component ' + + 'id: ' + name + ); + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + */ + function normalizeProps (options, vm) { + var props = options.props; + if (!props) { return } + var res = {}; + var i, val, name; + if (Array.isArray(props)) { + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + name = camelize(val); + res[name] = { type: null }; + } else { + warn('props must be strings when using array syntax.'); + } + } + } else if (isPlainObject(props)) { + for (var key in props) { + val = props[key]; + name = camelize(key); + res[name] = isPlainObject(val) + ? val + : { type: val }; + } + } else { + warn( + "Invalid value for option \"props\": expected an Array or an Object, " + + "but got " + (toRawType(props)) + ".", + vm + ); + } + options.props = res; + } + + /** + * Normalize all injections into Object-based format + */ + function normalizeInject (options, vm) { + var inject = options.inject; + if (!inject) { return } + var normalized = options.inject = {}; + if (Array.isArray(inject)) { + for (var i = 0; i < inject.length; i++) { + normalized[inject[i]] = { from: inject[i] }; + } + } else if (isPlainObject(inject)) { + for (var key in inject) { + var val = inject[key]; + normalized[key] = isPlainObject(val) + ? extend({ from: key }, val) + : { from: val }; + } + } else { + warn( + "Invalid value for option \"inject\": expected an Array or an Object, " + + "but got " + (toRawType(inject)) + ".", + vm + ); + } + } + + /** + * Normalize raw function directives into object format. + */ + function normalizeDirectives (options) { + var dirs = options.directives; + if (dirs) { + for (var key in dirs) { + var def$$1 = dirs[key]; + if (typeof def$$1 === 'function') { + dirs[key] = { bind: def$$1, update: def$$1 }; + } + } + } + } + + function assertObjectType (name, value, vm) { + if (!isPlainObject(value)) { + warn( + "Invalid value for option \"" + name + "\": expected an Object, " + + "but got " + (toRawType(value)) + ".", + vm + ); + } + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + */ + function mergeOptions ( + parent, + child, + vm + ) { + { + checkComponents(child); + } + + if (typeof child === 'function') { + child = child.options; + } + + normalizeProps(child, vm); + normalizeInject(child, vm); + normalizeDirectives(child); + + // Apply extends and mixins on the child options, + // but only if it is a raw options object that isn't + // the result of another mergeOptions call. + // Only merged options has the _base property. + if (!child._base) { + if (child.extends) { + parent = mergeOptions(parent, child.extends, vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + parent = mergeOptions(parent, child.mixins[i], vm); + } + } + } + + var options = {}; + var key; + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField (key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + */ + function resolveAsset ( + options, + type, + id, + warnMissing + ) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return + } + var assets = options[type]; + // check local registration variations first + if (hasOwn(assets, id)) { return assets[id] } + var camelizedId = camelize(id); + if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } + var PascalCaseId = capitalize(camelizedId); + if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } + // fallback to prototype chain + var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; + if (warnMissing && !res) { + warn( + 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, + options + ); + } + return res + } + + /* */ + + + + function validateProp ( + key, + propOptions, + propsData, + vm + ) { + var prop = propOptions[key]; + var absent = !hasOwn(propsData, key); + var value = propsData[key]; + // boolean casting + var booleanIndex = getTypeIndex(Boolean, prop.type); + if (booleanIndex > -1) { + if (absent && !hasOwn(prop, 'default')) { + value = false; + } else if (value === '' || value === hyphenate(key)) { + // only cast empty string / same name to boolean if + // boolean has higher priority + var stringIndex = getTypeIndex(String, prop.type); + if (stringIndex < 0 || booleanIndex < stringIndex) { + value = true; + } + } + } + // check default value + if (value === undefined) { + value = getPropDefaultValue(vm, prop, key); + // since the default value is a fresh copy, + // make sure to observe it. + var prevShouldObserve = shouldObserve; + toggleObserving(true); + observe(value); + toggleObserving(prevShouldObserve); + } + { + assertProp(prop, key, value, vm, absent); + } + return value + } + + /** + * Get the default value of a prop. + */ + function getPropDefaultValue (vm, prop, key) { + // no default, return undefined + if (!hasOwn(prop, 'default')) { + return undefined + } + var def = prop.default; + // warn against non-factory defaults for Object & Array + if (isObject(def)) { + warn( + 'Invalid default value for prop "' + key + '": ' + + 'Props with type Object/Array must use a factory function ' + + 'to return the default value.', + vm + ); + } + // the raw prop value was also undefined from previous render, + // return previous default value to avoid unnecessary watcher trigger + if (vm && vm.$options.propsData && + vm.$options.propsData[key] === undefined && + vm._props[key] !== undefined + ) { + return vm._props[key] + } + // call factory function for non-Function types + // a value is Function if its prototype is function even across different execution context + return typeof def === 'function' && getType(prop.type) !== 'Function' + ? def.call(vm) + : def + } + + /** + * Assert whether a prop is valid. + */ + function assertProp ( + prop, + name, + value, + vm, + absent + ) { + if (prop.required && absent) { + warn( + 'Missing required prop: "' + name + '"', + vm + ); + return + } + if (value == null && !prop.required) { + return + } + var type = prop.type; + var valid = !type || type === true; + var expectedTypes = []; + if (type) { + if (!Array.isArray(type)) { + type = [type]; + } + for (var i = 0; i < type.length && !valid; i++) { + var assertedType = assertType(value, type[i]); + expectedTypes.push(assertedType.expectedType || ''); + valid = assertedType.valid; + } + } + + if (!valid) { + warn( + getInvalidTypeMessage(name, value, expectedTypes), + vm + ); + return + } + var validator = prop.validator; + if (validator) { + if (!validator(value)) { + warn( + 'Invalid prop: custom validator check failed for prop "' + name + '".', + vm + ); + } + } + } + + var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/; + + function assertType (value, type) { + var valid; + var expectedType = getType(type); + if (simpleCheckRE.test(expectedType)) { + var t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; + } + } else if (expectedType === 'Object') { + valid = isPlainObject(value); + } else if (expectedType === 'Array') { + valid = Array.isArray(value); + } else { + valid = value instanceof type; + } + return { + valid: valid, + expectedType: expectedType + } + } + + /** + * Use function string name to check built-in types, + * because a simple equality check will fail when running + * across different vms / iframes. + */ + function getType (fn) { + var match = fn && fn.toString().match(/^\s*function (\w+)/); + return match ? match[1] : '' + } + + function isSameType (a, b) { + return getType(a) === getType(b) + } + + function getTypeIndex (type, expectedTypes) { + if (!Array.isArray(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1 + } + for (var i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i + } + } + return -1 + } + + function getInvalidTypeMessage (name, value, expectedTypes) { + var message = "Invalid prop: type check failed for prop \"" + name + "\"." + + " Expected " + (expectedTypes.map(capitalize).join(', ')); + var expectedType = expectedTypes[0]; + var receivedType = toRawType(value); + var expectedValue = styleValue(value, expectedType); + var receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += " with value " + expectedValue; + } + message += ", got " + receivedType + " "; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += "with value " + receivedValue + "."; + } + return message + } + + function styleValue (value, type) { + if (type === 'String') { + return ("\"" + value + "\"") + } else if (type === 'Number') { + return ("" + (Number(value))) + } else { + return ("" + value) + } + } + + function isExplicable (value) { + var explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some(function (elem) { return value.toLowerCase() === elem; }) + } + + function isBoolean () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; }) + } + + /* */ + + function handleError (err, vm, info) { + // Deactivate deps tracking while processing error handler to avoid possible infinite rendering. + // See: https://github.com/vuejs/vuex/issues/1505 + pushTarget(); + try { + if (vm) { + var cur = vm; + while ((cur = cur.$parent)) { + var hooks = cur.$options.errorCaptured; + if (hooks) { + for (var i = 0; i < hooks.length; i++) { + try { + var capture = hooks[i].call(cur, err, vm, info) === false; + if (capture) { return } + } catch (e) { + globalHandleError(e, cur, 'errorCaptured hook'); + } + } + } + } + } + globalHandleError(err, vm, info); + } finally { + popTarget(); + } + } + + function invokeWithErrorHandling ( + handler, + context, + args, + vm, + info + ) { + var res; + try { + res = args ? handler.apply(context, args) : handler.call(context); + if (res && !res._isVue && isPromise(res) && !res._handled) { + res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); }); + // issue #9511 + // avoid catch triggering multiple times when nested calls + res._handled = true; + } + } catch (e) { + handleError(e, vm, info); + } + return res + } + + function globalHandleError (err, vm, info) { + if (config.errorHandler) { + try { + return config.errorHandler.call(null, err, vm, info) + } catch (e) { + // if the user intentionally throws the original error in the handler, + // do not log it twice + if (e !== err) { + logError(e, null, 'config.errorHandler'); + } + } + } + logError(err, vm, info); + } + + function logError (err, vm, info) { + { + warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); + } + /* istanbul ignore else */ + if ((inBrowser || inWeex) && typeof console !== 'undefined') { + console.error(err); + } else { + throw err + } + } + + /* */ + + var isUsingMicroTask = false; + + var callbacks = []; + var pending = false; + + function flushCallbacks () { + pending = false; + var copies = callbacks.slice(0); + callbacks.length = 0; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + // Here we have async deferring wrappers using microtasks. + // In 2.5 we used (macro) tasks (in combination with microtasks). + // However, it has subtle problems when state is changed right before repaint + // (e.g. #6813, out-in transitions). + // Also, using (macro) tasks in event handler would cause some weird behaviors + // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109). + // So we now use microtasks everywhere, again. + // A major drawback of this tradeoff is that there are some scenarios + // where microtasks have too high a priority and fire in between supposedly + // sequential events (e.g. #4521, #6690, which have workarounds) + // or even between bubbling of the same event (#6566). + var timerFunc; + + // The nextTick behavior leverages the microtask queue, which can be accessed + // via either native Promise.then or MutationObserver. + // MutationObserver has wider support, however it is seriously bugged in + // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It + // completely stops working after triggering a few times... so, if native + // Promise is available, we will use it: + /* istanbul ignore next, $flow-disable-line */ + if (typeof Promise !== 'undefined' && isNative(Promise)) { + var p = Promise.resolve(); + timerFunc = function () { + p.then(flushCallbacks); + // In problematic UIWebViews, Promise.then doesn't completely break, but + // it can get stuck in a weird state where callbacks are pushed into the + // microtask queue but the queue isn't being flushed, until the browser + // needs to do some other work, e.g. handle a timer. Therefore we can + // "force" the microtask queue to be flushed by adding an empty timer. + if (isIOS) { setTimeout(noop); } + }; + isUsingMicroTask = true; + } else if (!isIE && typeof MutationObserver !== 'undefined' && ( + isNative(MutationObserver) || + // PhantomJS and iOS 7.x + MutationObserver.toString() === '[object MutationObserverConstructor]' + )) { + // Use MutationObserver where native Promise is not available, + // e.g. PhantomJS, iOS7, Android 4.4 + // (#6466 MutationObserver is unreliable in IE11) + var counter = 1; + var observer = new MutationObserver(flushCallbacks); + var textNode = document.createTextNode(String(counter)); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = String(counter); + }; + isUsingMicroTask = true; + } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { + // Fallback to setImmediate. + // Techinically it leverages the (macro) task queue, + // but it is still a better choice than setTimeout. + timerFunc = function () { + setImmediate(flushCallbacks); + }; + } else { + // Fallback to setTimeout. + timerFunc = function () { + setTimeout(flushCallbacks, 0); + }; + } + + function nextTick (cb, ctx) { + var _resolve; + callbacks.push(function () { + if (cb) { + try { + cb.call(ctx); + } catch (e) { + handleError(e, ctx, 'nextTick'); + } + } else if (_resolve) { + _resolve(ctx); + } + }); + if (!pending) { + pending = true; + timerFunc(); + } + // $flow-disable-line + if (!cb && typeof Promise !== 'undefined') { + return new Promise(function (resolve) { + _resolve = resolve; + }) + } + } + + /* */ + + var mark; + var measure; + + { + var perf = inBrowser && window.performance; + /* istanbul ignore if */ + if ( + perf && + perf.mark && + perf.measure && + perf.clearMarks && + perf.clearMeasures + ) { + mark = function (tag) { return perf.mark(tag); }; + measure = function (name, startTag, endTag) { + perf.measure(name, startTag, endTag); + perf.clearMarks(startTag); + perf.clearMarks(endTag); + // perf.clearMeasures(name) + }; + } + } + + /* not type checking this file because flow doesn't play well with Proxy */ + + var initProxy; + + { + var allowedGlobals = makeMap( + 'Infinity,undefined,NaN,isFinite,isNaN,' + + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + + 'require' // for Webpack/Browserify + ); + + var warnNonPresent = function (target, key) { + warn( + "Property or method \"" + key + "\" is not defined on the instance but " + + 'referenced during render. Make sure that this property is reactive, ' + + 'either in the data option, or for class-based components, by ' + + 'initializing the property. ' + + 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', + target + ); + }; + + var warnReservedPrefix = function (target, key) { + warn( + "Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " + + 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + + 'prevent conflicts with Vue internals' + + 'See: https://vuejs.org/v2/api/#data', + target + ); + }; + + var hasProxy = + typeof Proxy !== 'undefined' && isNative(Proxy); + + if (hasProxy) { + var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); + config.keyCodes = new Proxy(config.keyCodes, { + set: function set (target, key, value) { + if (isBuiltInModifier(key)) { + warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); + return false + } else { + target[key] = value; + return true + } + } + }); + } + + var hasHandler = { + has: function has (target, key) { + var has = key in target; + var isAllowed = allowedGlobals(key) || + (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); + if (!has && !isAllowed) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return has || !isAllowed + } + }; + + var getHandler = { + get: function get (target, key) { + if (typeof key === 'string' && !(key in target)) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return target[key] + } + }; + + initProxy = function initProxy (vm) { + if (hasProxy) { + // determine which proxy handler to use + var options = vm.$options; + var handlers = options.render && options.render._withStripped + ? getHandler + : hasHandler; + vm._renderProxy = new Proxy(vm, handlers); + } else { + vm._renderProxy = vm; + } + }; + } + + /* */ + + var seenObjects = new _Set(); + + /** + * Recursively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + */ + function traverse (val) { + _traverse(val, seenObjects); + seenObjects.clear(); + } + + function _traverse (val, seen) { + var i, keys; + var isA = Array.isArray(val); + if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { + return + } + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return + } + seen.add(depId); + } + if (isA) { + i = val.length; + while (i--) { _traverse(val[i], seen); } + } else { + keys = Object.keys(val); + i = keys.length; + while (i--) { _traverse(val[keys[i]], seen); } + } + } + + /* */ + + var normalizeEvent = cached(function (name) { + var passive = name.charAt(0) === '&'; + name = passive ? name.slice(1) : name; + var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first + name = once$$1 ? name.slice(1) : name; + var capture = name.charAt(0) === '!'; + name = capture ? name.slice(1) : name; + return { + name: name, + once: once$$1, + capture: capture, + passive: passive + } + }); + + function createFnInvoker (fns, vm) { + function invoker () { + var arguments$1 = arguments; + + var fns = invoker.fns; + if (Array.isArray(fns)) { + var cloned = fns.slice(); + for (var i = 0; i < cloned.length; i++) { + invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler"); + } + } else { + // return handler return value for single handlers + return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler") + } + } + invoker.fns = fns; + return invoker + } + + function updateListeners ( + on, + oldOn, + add, + remove$$1, + createOnceHandler, + vm + ) { + var name, def$$1, cur, old, event; + for (name in on) { + def$$1 = cur = on[name]; + old = oldOn[name]; + event = normalizeEvent(name); + if (isUndef(cur)) { + warn( + "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), + vm + ); + } else if (isUndef(old)) { + if (isUndef(cur.fns)) { + cur = on[name] = createFnInvoker(cur, vm); + } + if (isTrue(event.once)) { + cur = on[name] = createOnceHandler(event.name, cur, event.capture); + } + add(event.name, cur, event.capture, event.passive, event.params); + } else if (cur !== old) { + old.fns = cur; + on[name] = old; + } + } + for (name in oldOn) { + if (isUndef(on[name])) { + event = normalizeEvent(name); + remove$$1(event.name, oldOn[name], event.capture); + } + } + } + + /* */ + + function mergeVNodeHook (def, hookKey, hook) { + if (def instanceof VNode) { + def = def.data.hook || (def.data.hook = {}); + } + var invoker; + var oldHook = def[hookKey]; + + function wrappedHook () { + hook.apply(this, arguments); + // important: remove merged hook to ensure it's called only once + // and prevent memory leak + remove(invoker.fns, wrappedHook); + } + + if (isUndef(oldHook)) { + // no existing hook + invoker = createFnInvoker([wrappedHook]); + } else { + /* istanbul ignore if */ + if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { + // already a merged invoker + invoker = oldHook; + invoker.fns.push(wrappedHook); + } else { + // existing plain hook + invoker = createFnInvoker([oldHook, wrappedHook]); + } + } + + invoker.merged = true; + def[hookKey] = invoker; + } + + /* */ + + function extractPropsFromVNodeData ( + data, + Ctor, + tag + ) { + // we are only extracting raw values here. + // validation and default values are handled in the child + // component itself. + var propOptions = Ctor.options.props; + if (isUndef(propOptions)) { + return + } + var res = {}; + var attrs = data.attrs; + var props = data.props; + if (isDef(attrs) || isDef(props)) { + for (var key in propOptions) { + var altKey = hyphenate(key); + { + var keyInLowerCase = key.toLowerCase(); + if ( + key !== keyInLowerCase && + attrs && hasOwn(attrs, keyInLowerCase) + ) { + tip( + "Prop \"" + keyInLowerCase + "\" is passed to component " + + (formatComponentName(tag || Ctor)) + ", but the declared prop name is" + + " \"" + key + "\". " + + "Note that HTML attributes are case-insensitive and camelCased " + + "props need to use their kebab-case equivalents when using in-DOM " + + "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"." + ); + } + } + checkProp(res, props, key, altKey, true) || + checkProp(res, attrs, key, altKey, false); + } + } + return res + } + + function checkProp ( + res, + hash, + key, + altKey, + preserve + ) { + if (isDef(hash)) { + if (hasOwn(hash, key)) { + res[key] = hash[key]; + if (!preserve) { + delete hash[key]; + } + return true + } else if (hasOwn(hash, altKey)) { + res[key] = hash[altKey]; + if (!preserve) { + delete hash[altKey]; + } + return true + } + } + return false + } + + /* */ + + // The template compiler attempts to minimize the need for normalization by + // statically analyzing the template at compile time. + // + // For plain HTML markup, normalization can be completely skipped because the + // generated render function is guaranteed to return Array. There are + // two cases where extra normalization is needed: + + // 1. When the children contains components - because a functional component + // may return an Array instead of a single root. In this case, just a simple + // normalization is needed - if any child is an Array, we flatten the whole + // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep + // because functional components already normalize their own children. + function simpleNormalizeChildren (children) { + for (var i = 0; i < children.length; i++) { + if (Array.isArray(children[i])) { + return Array.prototype.concat.apply([], children) + } + } + return children + } + + // 2. When the children contains constructs that always generated nested Arrays, + // e.g.