From d6df44421b6b0b344d34c51a14e02a55010a8275 Mon Sep 17 00:00:00 2001 From: Alberto Sanchez Gonzalez Date: Wed, 26 Apr 2023 12:26:34 +0200 Subject: [PATCH 1/5] feat: add brazilian portuguese language --- locales/pt-BR/messages.po | 132 ++++++++++++++++++++++ locales/pt-BR/messages_po.js | 1 + locales/pt-BR/taotest.rdf.po | 89 +++++++++++++++ views/js/loader/taoTests.min.js.map | 2 +- views/js/loader/taoTestsRunner.min.js.map | 2 +- 5 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 locales/pt-BR/messages.po create mode 100644 locales/pt-BR/messages_po.js create mode 100644 locales/pt-BR/taotest.rdf.po diff --git a/locales/pt-BR/messages.po b/locales/pt-BR/messages.po new file mode 100644 index 00000000..2ebaf0b7 --- /dev/null +++ b/locales/pt-BR/messages.po @@ -0,0 +1,132 @@ +msgid "" +msgstr "" +"Project-Id-Version: tao-3x\n" +"PO-Revision-Date: 2023-04-21 15:46\n" +"Last-Translator: TAO Translation Team \n" +"MIME-Version: 1.0\n" +"Language: pt\n" +"sourceLanguage: en-US\n" +"targetLanguage: en-US\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Basepath: ../../\n" +"X-Poedit-KeywordsList: __\n" +"X-Poedit-SearchPath-0: .\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tao-3x\n" +"X-Crowdin-Project-ID: 582145\n" +"X-Crowdin-Language: pt-BR\n" +"X-Crowdin-File: /taoTests/locales/en-US/messages.po\n" +"X-Crowdin-File-ID: 1717\n" +"Language-Team: Portuguese, Brazilian\n" + +msgid " . \\common_Utils::toPHPVariableString($this->getDescription()) . " +msgstr " . \\common_Utils::toPHPVariableString($this->getDescription()) . " + +msgid " . \\common_Utils::toPHPVariableString($this->getLabel()) . " +msgstr " . \\common_Utils::toPHPVariableString($this->getLabel()) . " + +#, tao-public +msgid "Authoring" +msgstr "Autoria" + +#, tao-public +msgid "Combine a selection of items into tests." +msgstr "Combinar uma seleção de itens em testes." + +#, tao-public +msgid "Copy To" +msgstr "Copiar em" + +#, tao-public +msgid "Delete" +msgstr "Remover" + +#, tao-public +msgid "Duplicate" +msgstr "Duplicar" + +#, tao-public +msgid "Export" +msgstr "Exportar" + +#, tao-public +msgid "Import" +msgstr "Importar" + +msgid "Last updated on %2s" +msgstr "Última atualização em %2s" + +#, tao-public +msgid "Manage Schema" +msgstr "Gerenciar esquema" + +#, tao-public +msgid "Manage tests" +msgstr "Gerenciar testes" + +#, tao-public +msgid "Move" +msgstr "Mover" + +#, tao-public +msgid "Move To" +msgstr "Mover em" + +#, tao-public +msgid "New class" +msgstr "Nova pasta" + +#, tao-public +msgid "New test" +msgstr "Novo teste" + +#, tao-public +msgid "Preview" +msgstr "Visualizar" + +#, tao-public +msgid "Properties" +msgstr "Propriedades" + +msgid "Security plugins" +msgstr "Plugins de segurança" + +msgid "Set of plugins with \\'security\\' category" +msgstr "Conjunto de plugins com \\'security\\'" + +msgid "Test Preview is not installed, please contact to your administrator." +msgstr "Pré-visualização de teste não está instalada, por favor, contate o administrador." + +msgid "Test properties" +msgstr "Propriedades de teste" + +msgid "Test saved" +msgstr "Teste salvo" + +msgid "Test was successfully deleted." +msgstr "O teste foi removido com sucesso." + +#, tao-public +msgid "Tests" +msgstr "Testes" + +#, tao-public +msgid "Tests library" +msgstr "Biblioteca de testes" + +msgid "The Test mode (sequencing, scoring, cumulating, etc.) and layout are also configured here." +msgstr "O modo de teste (sequenciamento, pontuação, acumulação, etc.) e layout também estão configurados aqui." + +msgid "The Tests module allows to combine a selection of Items to a Test." +msgstr "O módulo de testes permite combinar uma seleção de itens para um teste." + +msgid "Unable to delete test." +msgstr "Não foi possível remover o teste." + +msgid "Unable to process your request" +msgstr "Não foi possível processar sua solicitação" + +msgid "You checked out this test %2s ago" +msgstr "Você fez check-out deste teste %2s atrás" + diff --git a/locales/pt-BR/messages_po.js b/locales/pt-BR/messages_po.js new file mode 100644 index 00000000..d3b734ae --- /dev/null +++ b/locales/pt-BR/messages_po.js @@ -0,0 +1 @@ +{" . \\\\common_Utils::toPHPVariableString($this->getDescription()) . ":" . \\\\common_Utils::toPHPVariableString($this->getDescription()) . "," . \\\\common_Utils::toPHPVariableString($this->getLabel()) . ":" . \\\\common_Utils::toPHPVariableString($this->getLabel()) . "," AND ":" E "," and ":" e "," has been deleted successfully":" foi removido com sucesso"," is ":" \u00e9 "," next":" pr\u00f3ximo"," Remove criteria":" Remover crit\u00e9rios"," requires a subgrid adapter":" requer um adaptador de subgrid","%1$s expected but %2$s detected":"%1$s esperado, mas %2$s detectado","%d attempts left before your account is locked.":"%d tentativas restantes antes de sua conta ser bloqueada.","%d day":"%d dia","%d days":"%d dias","%h hour":"%h hora","%h hours":"%h% hora(s)","%i minute":"%i minuto","%i minutes":"%i minutos","%m month":"%m m\u00eas","%m months":"%m meses","%s %s selected":"%s de %s selecionados","%s (%s kb)":"%s (%s kb)","%s Class saved":"Classe %s salva","%s classes":"%s classes","%s Confirmation":"%s Confirma\u00e7\u00e3o","%s could not be released":"%s n\u00e3o p\u00f4de ser lan\u00e7ado","%s created":"%s criado","%s extension(s) to install.":"%s extens\u00e3o(\u00f5es) a instalar.","%s has been deleted":"%s foi exclu\u00eddo","%s has been released":"%s foi publicado","%s instances":"%s inst\u00e2ncia","%s is of a type that cannot be published":"%s \u00e9 de um tipo que n\u00e3o pode ser publicado","%s Locked":"%s Bloqueado","%s\u0022 is not a valid index identifier. It must start with a letter and contain letters, numbers or underscores only":"%s\u0022 n\u00e3o \u00e9 um identificador de \u00edndice v\u00e1lido. Deve come\u00e7ar com uma letra e conter apenas letras, n\u00fameros ou sublinhados","%y year":"%y ano","%y years":"%y anos","(empty)":"(vazio)","... reloading page.":"... atualizando a p\u00e1gina.","7-zip archive":"arquivo 7-zip","Filters<\/del>":"Filtros<\/del>","Options<\/del>":"Op\u00e7\u00f5es<\/del>"," %s <\/strong> has been moved to the background.":" %s <\/strong> foi movido para o plano de fundo.","> Extension %s succesfully installed.":"> Extens\u00e3o %s instalada com sucesso.","> Installation done.":"> Instala\u00e7\u00e3o conclu\u00edda.","a class":"uma classe","A date has to be a Datetime or timestamp":"Uma data deve ser uma do tipo datetime ou timestamp","A fatal error occured during the installation process.":"Ocorreu um erro fatal durante o processo de instala\u00e7\u00e3o.","A maintenance status must have a STATUS: \u0022%s\u0022 or \u0022%s":"Um status de manuten\u00e7\u00e3o deve ter um STATUS: \u0022%s\u0022 ou \u0022%s","A message with further instructions has been sent to your email address: %s":"Uma mensagem com mais instru\u00e7\u00f5es foi enviada para o seu endere\u00e7o de e-mail: %s","AAC audio":"\u00c1udio AAC","About":"Sobre","abs":"abs","Absolute value":"Valor absoluto","AC":"AC","Access Denied":"Acesso Negado","Access denied. Please renew your authentication!":"Acesso negado. Por favor, renove sua autentica\u00e7\u00e3o!","Account status":"Status da conta","Action":"A\u00e7\u00e3o","Action %s - removed %s positions":"A\u00e7\u00e3o %s - removeu %s posi\u00e7\u00f5es","Action `%s` is not configured in the action queue service":"A a\u00e7\u00e3o `%s` n\u00e3o est\u00e1 configurada na fila de tarefas","Action was not executed yet":"A a\u00e7\u00e3o ainda n\u00e3o foi executada","Actions":"A\u00e7\u00f5es","Add":"Adicionar","Add \/ Edit lists":"Adicionar \/ Editar listas","Add a CSV file":"Adicionar arquivo CSV","Add a user":"Adicionar usu\u00e1rio","Add an RDF\/XML file":"Adicionar um arquivo RDF\/XML","Add Consumer":"Adicionar Consumidor","add criteria":"adicionar crit\u00e9rios","Add file(s)":"Adicionar arquivo(s)","Add property":"Adicionar propriedade","Add Provider":"Adicionar provedor","Adding search index for %s":"Adicionando \u00edndice de pesquisa para %s","Adding search index for created resource":"Adicionando \u00edndice de pesquisa para o recurso criado","Adding the new class has failed":"Falha ao adicionar nova classe","Adding the new resource has failed":"Falha ao adicionar o novo recurso","Adding\/updating search index for updated resource":"Adicionando\/atualizando \u00edndice de pesquisa do recurso","Adobe Flash file":"Arquivo Adobe Flash","Advanced search, add filters":"Pesquisa avan\u00e7ada, adicionar filtros","aliases:":"alias:","all":"todos","all audios":"todos os \u00e1udios","All data will be removed in %s":"Todos os dados ser\u00e3o removidos em %s","All fields are required":"Todos os campos s\u00e3o obrigat\u00f3rios","all images":"todas as imagens","All rights reserved.":"Todos os direitos reservados.","all videos":"todos os v\u00eddeos","Allow for all domains":"Permitir para todos os dom\u00ednios","Allow for the following domains":"Permitir para os seguintes dom\u00ednios","Allow to generate publishable versions of deliveries ":"Permitir a gera\u00e7\u00e3o de vers\u00f5es public\u00e1veis de entregas ","Alpha version":"Vers\u00e3o alfa","An email has been sent":"Um e-mail foi enviado","An error occurred during user deletion":"Ocorreu um erro durante a exclus\u00e3o do usu\u00e1rio","An error occurred!":"Ocorreu um erro!","An exception occured while running \u0022%s":"Ocorreu uma exce\u00e7\u00e3o ao executar \u0022%s","an instance":"uma inst\u00e2ncia","Ans":"Ans","Apply":"Aplicar","Apply date range":"Aplicar intervalo de datas","Arc cosine":"Cosseno de arco","Arc sine":"Seno de arco","Arc tangent":"Arco tangente","Archived":"Arquivado","Are you sure to delete the versioned resource?\nThe history will be lost as well.":"Tem certeza que deseja excluir o recurso versionado?\nO hist\u00f3rico tamb\u00e9m ser\u00e1 perdido.","Are you sure you want to delete it?":"Tem a certeza que deseja remover?","Argument check failed: %s":"Falha ao verificar argumento: %s","Arguments %s and %s are mutually exclusive":"Argumentos %s e %s s\u00e3o mutuamente exclusivos","Arguments separator":"Separador de argumentos","array":"array","Assessment Activity":"Atividade da Avalia\u00e7\u00e3o","Assets":"M\u00eddias","Assign":"Atribuir","Assign User to role":"Atribuir fun\u00e7\u00e3o ao usu\u00e1rio","Assign Users":"Atribuir Usu\u00e1rios","Audio Video Interleave":"Intercala\u00e7\u00e3o de \u00e1udio e v\u00eddeo","Author":"Autor","Author Item":"Criar Item","Authoring":"Autoria","auto unlocked in %s":"auto desbloqueado em %s","Available":"Dispon\u00edvel","Available Extensions":"Extens\u00f5es dispon\u00edveis","Back":"Voltar","Back to listing":"Voltar \u00e0 lista","Base-10 logarithm":"Logaritmo na base 10","Beta version":"Vers\u00e3o Beta","Binary operator *":"Operador bin\u00e1rio *","Binary operator +":"Operador bin\u00e1rio +","Binary operator -":"Operador bin\u00e1rio -","Binary operator \/":"Operador bin\u00e1rio \/","Binary operator modulo":"M\u00f3dulo do operador bin\u00e1rio","Bitmap image":"Imagem bitmap","Blueprint":"Planta","Blueprints":"Diagramas","Blueprints library":"Biblioteca de Diagramas","Booklet":"Livraria","Booklets":"Livros","Booklets library":"Biblioteca de Favoritos","boolean":"booleano","Browse folders:":"Navegar em pastas:","Browse...":"Navegar...","C":"C","C file":"Arquivo C","C++ file (.cpp)":"Arquivo C++ (.cpp)","Calc speadsheet (Staroffice)":"Planilha Calc (Staroffice)","Calculator":"Calculadora","Calendar":"Calend\u00e1rio","Cancel":"Cancelar","cancel":"cancelar","cancel the action":"cancelar a\u00e7\u00e3o","Cancelled":"Cancelado","Cannot be edited":"N\u00e3o pode ser editado","Cannot divide by zero":"N\u00e3o \u00e9 poss\u00edvel dividir por 0","Cascading Style Sheets":"Folhas de estilo em cascata","Case sensitive":"Distin\u00e7\u00e3o entre mai\u00fasculas e min\u00fasculas","ceil":"teto","Change password":"Alterar senha","Change the password":"Alterar senha","Change the sign of the current operand":"Alterar o sinal do operador atual","Check all":"Marcar todas","Check All":"Marcar todas","Check-in":"Check-in","choices:":"op\u00e7\u00f5es:","Choose a value...":"Escolha um valor...","Choose export format":"Escolher formato de exporta\u00e7\u00e3o","Choose import format":"Escolha formato da importa\u00e7\u00e3o","class selected":"classe selecionada","Class uri provided is not a valid class.":"A classe uri fornecida n\u00e3o \u00e9 uma classe v\u00e1lida.","Cleaning up tmp space complete":"Limpeza de espa\u00e7o tmp completa","Cleaning up tmp space started":"Limpeza espa\u00e7o tmp iniciado","Clear":"Apagar","Clear All":"Apagar tudo","Clear all data":"Apagar todos os dados","Clear expression":"Apagar express\u00e3o","Clear History":"Limpar Hist\u00f3rico","Clear history":"Limpar hist\u00f3rico","Clear selection":"Apagar sele\u00e7\u00e3o","Clear the date time picker":"Limpar o seletor de data e hora","Clear the stored variables":"Limpar as vari\u00e1veis armazenadas","Click to reload.":"Clique para recarregar.","Close":"Fechar","Close dialog":"Fechar di\u00e1logo","Close message":"Fechar mensagem","Code Version":"Vers\u00e3o do C\u00f3digo","Collecting of abandoned actions in the action queue ...":"Coletando a\u00e7\u00f5es abandonadas na fila de tarefas ...","Column":"Coluna","Combine a selection of items into tests.":"Combinar uma sele\u00e7\u00e3o de itens em testes.","command":"comando","Commands:":"Comandos:","comment...":"coment\u00e1rio...","Commit":"Aplicar","Completed":"Conclu\u00eddo","Completed - Error":"Conclu\u00eddo - Erro","Compressed tar file":"Arquivo tar comprimido","Compute the expression":"Calcular a express\u00e3o","Confirm":"Confirmar","Connect to the TAO platform":"Conectar-se \u00e0 plataforma de TAO","Continue":"Continuar","Copy":"Copiar","Copy to":"Copiar para","Copy To":"Copiar em","Copy to clipboard":"Copiar para \u00e1rea de transfer\u00eancia","cos":"cos","cosh":"cosh","Cosine":"Cosseno","count":"contar","Create":"Criar","Create and design items and exercises.":"Criar e projetar itens e exerc\u00edcios.","Create instance of ":"Criar inst\u00e2ncia de ","Created":"Criado","Creating report ...":"Criando o relat\u00f3rio...","CSP Header settings were saved successfully!":"Configura\u00e7\u00f5es de cabe\u00e7alho CSP foram salvas com sucesso!","CSV":"CSV","CSV file":"Arquivo CSV","CSV Options":"Op\u00e7\u00f5es CSV","Cube root":"Raiz C\u00fabica","Current language":"Idioma atual","Current playback position":"Posi\u00e7\u00e3o atual da reprodu\u00e7\u00e3o","Data imported":"Dados importados","Data imported successfully":"Importado com sucesso","Data imported. Some records are invalid.":"Dados importados. Alguns registros s\u00e3o inv\u00e1lidos.","Data language":"Idioma dos dados","Data Language":"Idioma dos dados","Data not imported. All records are invalid.":"Os dados n\u00e3o importados. Todos os registros s\u00e3o inv\u00e1lidos.","Data source URI":"URI fonte de dados","Database file":"Arquivo de banco de dados","Date":"Data","date range":"per\u00edodo","date time":"data\/hora","date time range":"intervalo de tempo","Default search":"Pesquisa padr\u00e3o","default:":"padr\u00e3o:","Define the default values":"Definir valores padr\u00e3o","Deg":"Deg","Degree":"Grau","Delete":"Remover","Delete Left":"Excluir Esquerda","Delete Right":"Excluir Direita","Delete the term on the left side of the cursor":"Excluir o termo no lado esquerdo do cursor","Delete the term on the right side of the cursor":"Excluir o termo no lado direito do cursor","Deleting search index for %s":"Excluindo \u00edndice de pesquisa para %s","Deliveries":"Entregas","Deliveries library":"Biblioteca de entregas","Demo Sandbox":"Demo Sandbox","Did you mean %s?":"Voc\u00ea quis dizer %s?","Digit 0":"D\u00edgito 0","Digit 1":"D\u00edgito 1","Digit 2":"D\u00edgito 2","Digit 3":"D\u00edgito 3","Digit 4":"D\u00edgito 4","Digit 5":"D\u00edgito 5","Digit 6":"D\u00edgito 6","Digit 7":"D\u00edgito 7","Digit 8":"D\u00edgito 8","Digit 9":"D\u00edgito 9","Disabled %s":"Desativado %s","Do you wish to install the following extension(s):\n%s?":"Voc\u00ea deseja instalar a(s) seguinte(s) extens\u00e3o(s):\n%s?","Document templates (Staroffice)":"Modelos de documentos (Staroffice)","does not match":"n\u00e3o confere","Don\u0027t set":"N\u00e3o definir","Dot":"Ponto","Download":"Download","Download this file":"Download do arquivo","Drag file here":"Arraste o arquivo aqui","Drag files here":"Arraste os arquivos aqui","Drop the files to upload":"Solte o arquivo aqui para fazer o upload","Duplicate":"Duplicar","Edit":"Editar","Edit a user":"Editar usu\u00e1rio","Edit class %s":"Editar classe %s","Edit Instance":"Editar inst\u00e2ncia","Edit Tree":"Editar \u00e1rvore","Element":"Elemento","Element deleted.":"Elemento exclu\u00eddo.","Email":"Email","enabled":"habilitado","Enabled %s":"Habilitado %s","End of document reached. Continuing from the beginning.":"Fim do documento alcan\u00e7ado. Continuando desde o in\u00edcio.","Enhanced metafile":"Metarquivo aprimorado","Enter":"Entrar","Error":"Erro","Error adding search index for %s with message %s":"Erro ao adicionar \u00edndice de pesquisa para %s com mensagem %s","Error during file import":"Erro durante importa\u00e7\u00e3o do arquivo","Error in result":"Erro no resultado","Error in syntax":"Erro na sintaxe","Error in value":"Erro no valor","Error: %s":"Erro: %s","Event Log":"Registro de Eventos","Examples:":"Exemplos:","Exclusive (OR)":"Exclusivo (OU)","Execute":"Executar","Executing task %s failed":"Falha ao executar tarefa %s","exp":"exp","Exponent":"Expoente","Export":"Exportar","Export ":"Exportar ","Export \u0022%s\u0022 in %s":"Exportar \u0022%s\u0022 em %s","Export CSV":"Exportar como CSV","Export failed.":"Falha ao exportar.","Export Irregularities":"Inregularidades de exporta\u00e7\u00e3o","Export Metadata as RDF\/XML file":"Exportar metadados como arquivo RDF\/XML","Export succeeded.":"Exportado com sucesso.","Export Table":"Exportar tabela","Extension \u0022%s\u0022 has been installed":"Extens\u00e3o \u0022%s\u0022 foi instalada","Extensions manager":"Gerenciador de extens\u00f5es","Factorial":"Fatorial","Failed":"Falhou","Failed to delete index for %s":"Falha ao excluir arquivo %s","False":"Falso","Field delimiter":"Delimitador de campo","Field encloser":"Encerrador de campo","Fields must match":"Os campos devem coincidir","File":"Arquivo","File download failed":"O download do arquivo falhou","File name":"Nome do Arquivo","File Properties":"Propriedades do arquivo","file selected":"arquivo selecionado","File Uploader":"Carregador de Arquivos","files selected":"arquivo selecionado","Filter":"filtro","Filter by value":"Filtro por valor","Filtering mode":"Modo de filtragem","First Name":"Primeiro Nome","First page":"Primeira p\u00e1gina","First row column names":"Nome das colunas da primeira linha","Fit to width":"Ajustar \u00e0 largura","Flash video":"V\u00eddeo Flash","floor":"piso","Flowchart-based programming environment & TI Interactive Workbook":"Ambiente de programa\u00e7\u00e3o baseado em fluxograma e TI Interactive Workbook","Forbid for all domains":"Proibir todos os dom\u00ednios","Force HTTPS on this platform":"For\u00e7ar HTTPS nesta plataforma","Force Release":"For\u00e7ar Lan\u00e7amento","Forgot your password?":"Esqueceu sua senha?","Form":"Formul\u00e1rio","Form data not saved.":"Dados do formul\u00e1rio n\u00e3o salvos.","From":"De","Fuzzy Matching":"Fuzzy Matching","generated-value":"valores gerados","Generis Form":"Generis Form","Geogebra data file":"Arquivo de dados Geogebra","Get History":"Obter Hist\u00f3rico","Get the history list":"Obter a lista de hist\u00f3rico","GIF image":"Imagem GIF","Go Back":"Voltar","go back to home page":"retornar a p\u00e1gina inicial","Group test takers according to global features and classifications.":"takers de teste do grupo de acordo com recursos e classifica\u00e7\u00f5es globais.","Groups":"grupos","Groups library":"Biblioteca de grupos","GZip Compressed Archive":"Arquivo Comprimido GZip","Header file with extensionsLabels":"Arquivo de cabe\u00e7alho com extensLabels","Height":"Altura","Help":"Socorro","Hi, %s
You indicated that you have forgotten your TAO password.":"Ol\u00e1, %s
Voc\u00ea indicou que esqueceu a sua senha de TAO.","Hide detailed report":"Ocultar relat\u00f3rio detalhado","Hide password":"Ocultar senha","Highlight all":"Destaque todos","History":"Hist\u00f3rico","hours":"horas","Hyperbolic arc cosine":"Arco cosseno hiperb\u00f3lico","Hyperbolic arc sine":"Arco seno hiperb\u00f3lico","Hyperbolic arc tangent":"Arco tangente hiperb\u00f3lico","Hyperbolic cosine":"Cosseno hiperb\u00f3lico","Hyperbolic sine":"Seno hiperb\u00f3lico","Hyperbolic tangent":"Tangente hiperb\u00f3lica","Hypertext markup language":"Linguagem de marca\u00e7\u00e3o de hipertexto","I understand that this action is permanent.":"Eu entendo que esta a\u00e7\u00e3o n\u00e3o poder\u00e1 ser desfeita.","Identifier":"Identificador","If you do not wish to reset your password, just ignore this email and your password will remain the same.":"Se voc\u00ea n\u00e3o fez esta solicita\u00e7\u00e3o, voc\u00ea pode ignorar este e-mail e sua senha permanecer\u00e1 a mesma.","Implications failed:":"Implica\u00e7\u00f5es falharam:","Import":"Importar","Import ":"Importar ","Import a %s into \u0022%s":"Importar um %s para \u0022%s","Import Completed":"Importa\u00e7\u00e3o Completa","Import failed.":"A importa\u00e7\u00e3o falhou.","Import Metadata from CSV file":"Importar metadados de um arquivo CSV","Import Metadata from RDF file":"Importar Metadados de arquivo RDF","Import succeeded.":"Importa\u00e7\u00e3o bem sucedida.","Imported %1$d\/%2$d. Some records are invalid.":"Importado %1$d\/%2$d. Alguns registros s\u00e3o inv\u00e1lidos.","Imported %d resources":"%d recursos importados","Imported resource \u0022%s":"Recurso importado \u0022%s","impossible to update task status":"imposs\u00edvel atualizar o status da tarefa","In Progress":"Em Progresso","In progress":"Em progresso","Inclusive (AND)":"Inclusivo (E)","Index":"Indexa\u00e7\u00e3o","Index has been deleted for %s":"O \u00edndice foi exclu\u00eddo para %s","Infinity":"Infinito","Injector has to contains a valid \u0022destination\u0022 field.":"Injetor deve conter um campo \u0022destino\u0022 v\u00e1lido.","Injector has to contains a valid \u0022source\u0022 field.":"Injetor deve conter um campo \u0022fonte\u0022 v\u00e1lido.","Inline":"Alinhado","Install":"Instalar","Installation done.":"Instala\u00e7\u00e3o conclu\u00edda.","Installation...":"Instala\u00e7\u00e3o...","Installed Extensions":"Extens\u00f5es Instaladas","Installed Version":"Vers\u00e3o Instalada","Installing extension %s...":"Instalando extens\u00f5es %s...","Instance saved":"Inst\u00e2ncia salva","Interface Language":"Linguagem da Interface","Interface language":"Linguagem da interface","Invalid CSP header.":"Cabe\u00e7alho CSP inv\u00e1lido.","Invalid date range (must be after or the same as: %s)":"Intervalo de data inv\u00e1lido (deve ser depois ou o mesmo de: %s)","Invalid date range (must be after: %s)":"Intervalo de data inv\u00e1lido (deve ser ap\u00f3s: %s)","Invalid date range (must be before or the same as: %s)":"Intervalo de data inv\u00e1lido (deve ser depois ou o mesmo de: %s)","Invalid date range (must be before: %s)":"Intervalo de data inv\u00e1lido (deve ser ap\u00f3s: %s)","Invalid field length":"Tamanho do campo inv\u00e1lido","Invalid field range (maximum value: %s)":"Intervalo de campo inv\u00e1lido (valor m\u00e1ximo: %s)","Invalid field range (minimum value: %1$s, maximum value: %2$s)":"Intervalo de campo inv\u00e1lido (valor m\u00ednimo: %1$s, valor m\u00e1ximo: %2$s)","Invalid field range (minimum value: %s)":"Intervalo de campo inv\u00e1lido (valor m\u00ednimo: %s)","Invalid file size (minimum %1$s bytes, maximum %2$s bytes)":"Tamanho do arquivo inv\u00e1lido (m\u00ednimo de %1$s bytes, m\u00e1ximo de %2$s bytes)","Invalid file type!":"Tipo de arquivo inv\u00e1lido!","Invalid input":"Entrada inv\u00e1lida","Invalid input for function":"Entrada inv\u00e1lida para a fun\u00e7\u00e3o","Invalid JSON config file: %s":"Arquivo JSON de configura\u00e7\u00e3o inv\u00e1lido: %s","Invalid login or password. Please try again.":"Login ou senha inv\u00e1lidos. Por favor tente novamente.","Invalid login or password. Your account has been locked, please contact your administrator.":"Login ou senha inv\u00e1lidos. Sua conta foi bloqueada, por favor, entre em contato com o administrador.","invalid regular expression":"express\u00e3o regular inv\u00e1lida","Invalid values:":"Valor inv\u00e1lido:","Items":"Itens","Items library":"Biblioteca de itens","items per page":"itens por p\u00e1gina","Javascript code":"C\u00f3digo javascript","JPEG image":"imagem JPEG","Label":"T\u00edtulo","Label Path":"Endere\u00e7o do T\u00edtulo","Language":"Idioma","Last attempt before your account is locked.":"\u00daltima tentativa antes de sua conta ser bloqueada.","Last Name":"Sobrenome","Last page":"\u00daltima p\u00e1gina","Last result":"\u00daltimo resultado","Last updated on %2s":"\u00daltima atualiza\u00e7\u00e3o em %2s","Layout":"Layout","Left parenthesis":"Par\u00eantese esquerdo","less than a minute":"menos de um minuto","List":"Lista","List - Multiple choice - Check box":"Lista - M\u00faltipla escolha - Caixa de sele\u00e7\u00e3o","List - Multiple choice - Search input":"Lista - M\u00faltipla escolha - Entrada de pesquisa","List - Single choice - Drop down":"Lista - Simples - Drop down","List - Single choice - Radio button":"Lista - Simples - Radio button","List - Single choice - Search input":"Lista - Simples - Pesquisa","List item URI duplications found":"Duplica\u00e7\u00f5es de item de lista URI encontradas","List values":"Listar valores","Lists":"Listas","Load more":"Carregar mais","Loaded":"Carregado","Loaded at Startup":"Carregado na Inicializa\u00e7\u00e3o","Loading":"Carregando","Loading status":"Carregando status","Loading task status ...":"Carregando status da tarefa...","locked by %s":"bloqueado por %s","Log in":"Entrar","Log Out":"Sair","Login":"Entrar","Login available":"Acesso dispon\u00edvel","Login is already in use.":"Login j\u00e1 est\u00e1 em uso.","Login is empty.":"Login est\u00e1 vazio.","Logout":"Sair","LTI":"LTI","LTI Consumers":"Consumidores LTI","LTI Providers":"Provedores LTI","M4A audio":"\u00e1udio M4A","Main Menu":"Menu Principal","Maintenance service is already installed.":"O servi\u00e7o de manuten\u00e7\u00e3o j\u00e1 est\u00e1 instalado.","Maintenance service must have a persistence option.":"O servi\u00e7o de manuten\u00e7\u00e3o deve ter uma op\u00e7\u00e3o de persist\u00eancia.","Maintenance service was installed. Platform is disabled.":"O servi\u00e7o de manuten\u00e7\u00e3o foi instalado. A plataforma est\u00e1 desativada.","Maintenance service was installed. Platform is enabled.":"O servi\u00e7o de manuten\u00e7\u00e3o foi instalado. Plataforma habilitada.","Maintenance storage driver is not set":"O driver de armazenamento de manuten\u00e7\u00e3o n\u00e3o est\u00e1 definido","Manage Access Rights":"Gerenciar Permiss\u00f5es de Acesso","Manage Assets":"Gerenciar Ativos","Manage class schema":"Gerenciar esquema de classe","Manage data list":"Gerenciar lista de dados","Manage groups":"Gerenciar grupos","Manage items":"Gerenciar itens","Manage Media":"Gerenciar m\u00eddia","Manage Results":"Gerenciar Resultados","Manage roles":"Gerenciar fun\u00e7\u00f5es","Manage Roles and apply them to users.":"Gerenciar Fun\u00e7\u00f5es e aplic\u00e1-las aos usu\u00e1rios.","Manage Schema":"Gerenciar esquema","Manage Test Center":"Gerenciar Centro de Testes","Manage test takers":"Gerenciar candidatos","Manage tests":"Gerenciar testes","Manage users":"Gerenciar usu\u00e1rios","Manage Versioned File":"Gerenciar arquivo versionado","Map the properties to the CSV columns":"Mapear as propriedades das colunas CSV","Maximum selection reached":"Foi atingido o limite de sele\u00e7\u00f5es","Media":"M\u00eddia","Media Manager":"Gerenciador de M\u00eddia","Media Manager extension":"Extens\u00e3o do Media Manager","Media resize along with their container, e.g. 50% means half of the container size not half of the media size.":"Redimensionar a m\u00eddia junto com seu cont\u00eainer, por exemplo, 50% significa metade do tamanho do cont\u00eainer n\u00e3o metade do tamanho da m\u00eddia.","Message":"Mensagem","Messages":"Mensagens","Metadata export is not available for the selected resource.":"Exporta\u00e7\u00e3o de metadados n\u00e3o est\u00e1 dispon\u00edvel para o recurso selecionado.","Microsoft Excel":"Microsoft Excel","Microsoft Excel binary format":"Formato bin\u00e1rio do Microsoft Excel","Microsoft Office Document Imaging":"Imagens de documentos do Microsoft Office","Microsoft Powerpoint":"Microsoft PowerPoint","Microsoft Powerpoint slideshow":"Slideshow do Microsoft Powerpoint","Microsoft Project file":"Arquivo do Microsoft Project","Microsoft Visio file":"Arquivo do Microsoft Visio","Microsoft Word":"Microsoft Word","Microsoft Word template":"Modelo do Microsoft Word","Microsoft Works file":"Arquivo Microsoft Works","Microsoft XPS file":"Arquivo Microsoft XPS","MIME encapsulation of aggregate HTML documents":"Encapsulamento MIME de documentos HTML agregados","Mind mapping software application (free mind open source)":"Aplicativo de software de mapeamento mental (c\u00f3digo aberto livre)","minutes":"minutos","missing config %s for the service %s":"falta a configura\u00e7\u00e3o %s para o servi\u00e7o %s","Missing Parameters":"Par\u00e2metros ausentes","modulo":"m\u00f3dulo","More":"Mais","Move":"Mover","Move Left":"Mover \u00e0 esquerda","Move Right":"Mover \u00e0 direita","Move role":"Mover fun\u00e7\u00e3o","Move the cursor one step on the left":"Mova o cursor um passo \u00e0 esquerda","Move the cursor one step on the right":"Mova o cursor um passo \u00e0 direita","Move To":"Mover em","Move to":"Mover para","Moving this element will replace the properties of the previous class by those of the destination class :":"Mover este elemento ir\u00e1 substituir as propriedades da classe anterior por aquelas da classe de destino :","MP4 video":"V\u00eddeo MP4","MPEG audio":"\u00c1udio MPEG","MPEG video":"V\u00eddeo do MPEG","MPEG-4 audio file":"Arquivos de \u00e1udio MPEG-4","Multiple values delimiter":"Separador de valores m\u00faltiplos","Multiply the value by 10^x":"Multiplique o valor por 10^x","Mute":"Mudo","My custom text translation":"Tradu\u00e7\u00e3o de texto personalizada","My settings":"Minhas configura\u00e7\u00f5es","My settings (%s)":"Minhas configura\u00e7\u00f5es (%s)","Name":"Nome","Natural logarithm":"Logaritmo natural","New blueprint":"Novo diagrama","New booklet":"Novo booklet","New class":"Nova pasta","New delivery":"Nova entrega","New Group":"Novo Grupo","New item":"Novo item","New passage":"Nova passagem","New password":"Nova senha","New role":"Nova fun\u00e7\u00e3o","New test":"Novo teste","New Test Center":"Novo Centro de Testes","New test-taker":"Novo candidato","Next":"Pr\u00f3ximo","Next match":"Pr\u00f3xima Correspond\u00eancia","Next page":"Pr\u00f3xima p\u00e1gina","No":"N\u00e3o","No action specified":"Nenhuma a\u00e7\u00e3o especificada","No client translation bundles updated":"Nenhum pacote de tradu\u00e7\u00e3o de cliente atualizado","No extensions available.":"Nenhuma extens\u00e3o dispon\u00edvel.","no file not found in this location":"nenhum arquivo encontrado neste local","No file selected":"Nenhum arquivo selecionado","No files":"Nenhum arquivo","No item found. Please try other search criteria.":"Nenhum item encontrado. Verifique os crit\u00e9rios de pesquisa.","no label":"sem r\u00f3tulos","No Task yet":"N\u00e3o h\u00e1 tarefas ainda","Node duplication has failed":"Falha ao duplicar n\u00f3","Not enough arguments following: %s":"Argumentos insuficientes: %s","Not enough non-option arguments: got %s, need at least %s":"Argumentos n\u00e3o opcionais insuficientes: obteve %s, precisa de pelo menos %s","Not started":"N\u00e3o iniciado","Nothing imported":"Nada foi importado","Nothing to install !":"Nada para instalar!","Nothing to list!":"Nada para exibir!","Notifications":"Notifica\u00e7\u00f5es","notifications drivers aren\\\\\u0027t persistent. use a persistent database storage driver":"notifica\u00e7\u00f5es drivers n\u00e3o s\u00e3o salvos. use um driver de armazenamento","Nth root":"Raiz en\u00e9sima","number":"n\u00famero","Number of elements":"N\u00famero de elementos","of":"de","Off":"Desligado","Ogg Vorbis audio":"\u00c1udio Ogg Vorbis","Ogg Vorbis video":"V\u00eddeo Ogg Vorbis","OK":"OK","Ok":"Ok","Old Password":"Senha Antiga","On":"Ligado","Only allow for my own domain (%s)":"Permitir apenas meu dom\u00ednio (%s)","Only one of the field must have value %s":"Apenas um dos campos deve ter o valor %s","OpenDocument Database":"Banco de dados OpenDocument","OpenDocument Presentation":"Apresenta\u00e7\u00e3o OpenDocument","OpenDocument spreadsheet document":"Documento de planilha OpenDocument","OpenDocument text document":"Documento de texto OpenDocument","OpenDocument Text Template":"Modelo de Texto OpenDocument","Operated By ":"Operado por ","or":"ou","Outlook on the next Synchronization":"Outlook na pr\u00f3xima Sincroniza\u00e7\u00e3o","Page":"P\u00e1gina","Pascal file (.pas)":"Arquivo Pascal (.pas)","Password":"Senha","Password changed":"Senha Alterada","Password is empty.":"A senha est\u00e1 vazia.","Password reset":"Recuperar senha","Password successfully changed":"Senha alterada com sucesso","Passwords are not matching":"As senhas n\u00e3o coincidem","Pause":"Pausar","PDF file":"Arquivo PDF","Permission denied to write in the selected class":"Permiss\u00e3o negada para escrever na classe selecionada","Plain text":"Texto sem formata\u00e7\u00e3o","Platform Theming":"Tema da plataforma","Play":"Executar","Please confirm deletion":"Confirme a exclus\u00e3o","Please confirm deletion of %s.":"Por favor, confirme a exclus\u00e3o de %s.","Please confirm deletion of user %s":"Por favor, confirme a exclus\u00e3o do usu\u00e1rio %s","Please confirm locking of account %s":"Por favor confirme o bloqueio da conta %s","Please confirm property deletion!":"Por favor confirme a exclus\u00e3o da propriedade!","Please confirm this operation.":"Por favor confirme esta opera\u00e7\u00e3o.","Please confirm unlocking of account %s":"Por favor, confirme o desbloqueio da conta %s","Please contact %s or an administrator to release it":"Por favor contate %s ou um administrador para liber\u00e1-lo","Please contact your administrator.":"Por favor, contate o administrador.","Please contact your system administrator.":"Por favor, contate o administrador do sistema.","Please define your search in the search panel.":"Por favor, defina sua pesquisa no painel de pesquisa.","Please download the track and listen offline.":"Por favor, baixe a faixa e ou\u00e7a offline.","Please download the video and view offline.":"Por favor, baixe o v\u00eddeo e veja offline.","Please give a message to your commit":"Por favor informe o coment\u00e1rio para essa a\u00e7\u00e3o","Please provide a reason":"Por favor, informe um motivo","Please report bugs, ideas, comments or feedback on the TAO Forum":"Por favor, reporte bugs, ideias, coment\u00e1rios ou coment\u00e1rios no F\u00f3rum TAO","Please wait":"Aguarde","Please wait while ...":"Por favor aguarde um instante...","PNG image":"Imagem PNG","Portable Custom Interactions":"Intera\u00e7\u00f5es Personalizadas Port\u00e1teis","Position":"Posi\u00e7\u00e3o","Positionals:":"Posicionais:","Post install processing":"Processamento da p\u00f3s-instala\u00e7\u00e3o","Power of":"Poder de","Power of 10":"Poder de 10","Prepare, publish deliveries sessions.":"Prepare, publique as sess\u00f5es de entregas.","Preparing installation...":"Preparando a instala\u00e7\u00e3o...","Preview":"Visualizar","Previous":"Anterior","Previous match":"Combina\u00e7\u00e3o anterior","Previous page":"P\u00e1gina anterior","Proceed":"Prosseguir","Proctorio Review":"Revis\u00e3o do Proctorio","Properties":"Propriedades","Provided URL is not valid":"A URL fornecida n\u00e3o \u00e9 v\u00e1lida","Publish":"Publicar","Publish the test":"Publicar o teste","Queued":"Na fila","Quicktime video":"V\u00eddeo Quicktime","Rad":"Rad","Radian":"Radianos","random":"aleat\u00f3rio","Random value":"Valor aleat\u00f3rio","Range field is required":"O campo Intervalo \u00e9 obrigat\u00f3rio","RAR archive":"Arquivo RAR","RDF":"RDF","RealMedia file":"Arquivo RealMedia","Record and manage test takers.":"Registre e gerencie os candidatos.","Refresh":"Atualizar","Regenerate":"Regenerar","Release":"Lan\u00e7ar","Releasing the lock might cause the work in progress by %s to be lost.":"Liberar a trava pode fazer com que o trabalho em andamento por %s seja perdido.","Reload":"Recarregar","Remind":"Lembrar","Remind Last":"Lembrar \u00faltimo","Remind the last value":"Lembrar o \u00faltimo valor","Remind the next expression in the history":"Lembrar a pr\u00f3xima express\u00e3o na hist\u00f3ria","Remind the previous expression in the history":"Lembrar a pr\u00f3xima express\u00e3o na hist\u00f3ria","Remind the recorded value":"Lembrar o valor gravado","Remote Lists":"Listas Remotas","Remove":"Excluir","Remove criteria":"Remover crit\u00e9rios","Remove Message":"Remover Mensagem","Remove this file":"Remover esse arquivo","Removed %s directories":"%s diret\u00f3rios removidos","Removed %s files":"%s arquivos removidos","Removing: %s":"Removendo: %s","Rename":"Renomear","Repeat new password":"Repita a nova senha","Repeat password":"Repita a senha","Request a password reset via Email.":"Solicitar redefini\u00e7\u00e3o de senha por e-mail.","require notification ID":"requer notifica\u00e7\u00e3o ID","required":"obrigat\u00f3rio","required length":"comprimento obrigat\u00f3rio","Requires":"Obrigat\u00f3rio","Reset":"Redefinir","Reset the range values":"Redefinir os valores de intervalo","Resource":"Recurso","Resource copied":"Recurso copiado","Resource deleted":"Recurso exclu\u00eddo","Resource Identifier":"Identificador do Recurso","Resource Identifier could not be copied to the clipboard":"Identificador do recurso n\u00e3o p\u00f4de ser copiado para a \u00e1rea de transfer\u00eancia","Resource Identifier has been copied to the clipboard":"Identificador do Recurso foi copiado para a \u00e1rea de transfer\u00eancia","Resource not imported due to multiple super classes":"Recurso n\u00e3o foi importado devido a m\u00faltiplas super classes","Resource not imported due to multiple types":"Recurso n\u00e3o importado devido a m\u00faltiplos tipos","Resource saved":"Recursos salvos","resources":"recursos","Resources moved":"Recursos movidos","Resources successfully indexed":"Recursos indexados com sucesso","Resources was not indexed":"Os recursos n\u00e3o foram indexados","Responsive mode":"Modo responsivo","Restore sound":"Restaurar som","Results":"Resultados","Results library":"Biblioteca de resultados","Results Monitoring":"Monitoramento de Resultados","Return to sign in page":"Retornar para a p\u00e1gina de login","Rich Text Format file":"Formato de arquivo Rich Text","Right click the tree to manage your lists":"Clique com o bot\u00e3o direito na \u00e1rvore para gerenciar suas listas","Right parenthesis":"Par\u00eanteses direito","Role saved":"Fun\u00e7\u00e3o salva","Roles":"Fun\u00e7\u00f5es","Roles library":"Biblioteca de fun\u00e7\u00f5es","round":"rodada","Round to closest whole number":"Arredondar para o n\u00famero inteiro mais pr\u00f3ximo","Round to lower whole number":"Arredondar para baixo n\u00famero inteiro","Round to upper whole number":"Arredondar para cima n\u00famero inteiro","Row %s":"Linha %s","Running task %s":"Executando a tarefa: %s","Save":"Salvar","Saved.":"Salvo.","Scientific Calculator":"Calculadora cient\u00edfica","Scope":"Escopo","Search":"Pesquisa","Search %s":"Buscar %s","Search by properties":"Pesquisa por propriedades","Search sub-classes":"Pesquisar sub-classes","second":"segundo","seconds":"segundos","Security":"Seguran\u00e7a","Security plugins":"Plugins de seguran\u00e7a","Security settings":"Op\u00e7\u00f5es de seguran\u00e7a","select":"selecionar","Select":"Selecionar","Select a class":"Selecione uma classe","Select a destination":"Selecione um destino","Select a language":"Selecione um idioma","Select loaded %s":"Selecionar %s carregado","Select this file":"Selecione este arquivo","select...":"selecionar...","Selected":"Selecionado","Selected file:":"Selecione um arquivo:","Selection saved successfully":"Sele\u00e7\u00e3o salva com sucesso","self-locked":"autobloqueado","Set of plugins with \\\\\u0027security\\\\\u0027 category":"Conjunto de plugins com \\\\\u0027security\\\\\u0027","Set the trigonometric function to work in degrees":"Defina a fun\u00e7\u00e3o trigonom\u00e9trica para funcionar em graus","Set the trigonometric function to work in radians":"Defina a fun\u00e7\u00e3o trigonom\u00e9trica para trabalhar em radianos","Settings":"Confirgura\u00e7\u00f5es","Settings updated":"Configura\u00e7\u00f5es atualizadas","Show detailed report":"Mostrar relat\u00f3rio detalhado","Show password":"Mostrar senha","Sibelius music notation":"Nota\u00e7\u00e3o musical do Sibelius","Sign change":"Mudar sinal","sin":"seno","Sine":"Seno","sinh":"sinh","Size":"Tamanho","Some resources have not been moved: %s":"Alguns recursos n\u00e3o foram movidos: %s","Something unexpected happened.":"Algo inesperado aconteceu.","Sources that can embed this platform in an iFrame":"Fontes que podem incorporar essa plataforma em um iFrame","Square root":"Raiz quadrada","Start of document reached. Continuing from the end.":"In\u00edcio do documento alcan\u00e7ado. Continuando do final.","Status":"Status","Status of":"Status de","Store":"Armazenar","Store the value a variable":"Armazenar o valor de uma vari\u00e1vel","Storing digital video data on a computer game":"Armazenando dados de v\u00eddeo digitais em uma partida de computador","string":"string","Submit":"Enviar","Success":"Sucesso","Successfully cloned instance as %s":"Inst\u00e2ncia clonada com sucesso como %s","Successfully deleted %s":"Exclu\u00eddo com sucesso %s","Successfully imported \u0022%s":"Importado com sucesso \u0022%s","Successfully imported %s tripples":"%s tripples foram importados com sucesso","Successfully imported class \u0022%s":"Classe importada com sucesso \u0022%s","Successfully updated %s client translation bundles":"%s pacotes de tradu\u00e7\u00e3o de cliente atualizados com sucesso","Supported export formats":"Formatos de exporta\u00e7\u00e3o suportados","SVG image":"Imagem SVG","Syntax error":"Erro de sintaxe","Tagged image file":"Arquivo de imagem marcados","tan":"tan","Tangent":"Tangente","tanh":"tanh","Tao Default Theme":"Tema Padr\u00e3o do Tao","TAO Home":"TAO In\u00edcio","TAO Login":"TAO Login","TAO platform is already on live mode since %s":"Plataforma TAO j\u00e1 est\u00e1 ativa desde %s","TAO platform is already on maintenance mode since %s":"Plataforma TAO j\u00e1 est\u00e1 em modo de manuten\u00e7\u00e3o desde %s","TAO platform is live since %s.":"Plataforma TAO est\u00e1 ativa desde %s.","TAO platform is now live. It was in maintenance since %s":"A plataforma de TAO est\u00e1 ativa. Estava em manuten\u00e7\u00e3o desde %s","TAO platform is now under maintenance. It was in maintenance since %s":"Plataforma TAO agora est\u00e1 em manuten\u00e7\u00e3o. Estava em manuten\u00e7\u00e3o desde %s","TAO platform is under maintenance since %s":"Plataforma TAO est\u00e1 em manuten\u00e7\u00e3o desde %s","Task %s has been cancelled, message was not processed.":"Tarefa %s foi cancelada, mensagem n\u00e3o foi processada.","task created":"tarefa criada","Task Listing":"Listas de Tarefas","Task Name":"Nome da tarefa","Task not found":"Tarefa n\u00e3o encontrada","Task not returned any report.":"Tarefa n\u00e3o retornou nenhum relat\u00f3rio.","Task Queue":"Lista de tarefas","taskqueue":"taskqueue","Term":"Termo","Test center contains test taker and groups and are administer by a proctor":"Centro de testes cont\u00e9m taker e grupos de teste e s\u00e3o administrados por um perfil","Test Center List":"Lista Central de Teste","Test Centers":"Centros de teste","Test Preview is not installed, please contact to your administrator.":"Pr\u00e9-visualiza\u00e7\u00e3o de teste n\u00e3o est\u00e1 instalada, por favor, contate o administrador.","Test properties":"Propriedades de teste","Test saved":"Teste salvo","Test takers library":"Biblioteca de candidatos","Test was successfully deleted.":"O teste foi removido com sucesso.","Test-takers":"Candidatos","Tests":"Testes","Tests library":"Biblioteca de testes","TeX file":"Arquivo TeX","Text - Long - Box":"Texto Longo - Caixa","Text - Long - HTML editor":"Texto - Longo - Editor HTML","Text - Short - Field":"Texto - Curto - Campo","Text document file format (Staroffice)":"Formato de arquivo de documento de texto (Staroffice)","The action will be applied to":"A a\u00e7\u00e3o ser\u00e1 aplicada em","The action will be applied to the following":"A a\u00e7\u00e3o ser\u00e1 aplicada para os seguintes","The action will not be applied to ":"A a\u00e7\u00e3o n\u00e3o ser\u00e1 aplicada em ","The action will not be applied to the following":"A a\u00e7\u00e3o n\u00e3o ser\u00e1 aplicada para os seguintes","The column ":"A coluna ","The following criteria are not applicable to the selected class and have been removed from the search":"Os seguintes crit\u00e9rios n\u00e3o s\u00e3o aplic\u00e1veis \u00e0 classe selecionada e foram removidos da pesquisa","The format of this field is not valid.":"O formato deste campo n\u00e3o \u00e9 v\u00e1lido.","The imported file is not properly UTF-8 encoded.":"O arquivo importado n\u00e3o \u00e9 codificado corretamente em UTF-8.","The index identifier should not be empty":"O identificador de \u00edndice n\u00e3o deve estar vazio","The lock has been released":"O bloqueio foi liberado","The properties of the source class will be replaced by those of the destination class. This might result in a loss of metadata. Continue anyway?":"As propriedades da classe de origem ser\u00e3o substitu\u00eddas por aquelas da classe de destino. Isto pode resultar em perda de metadados. Continuar mesmo assim?","The server has sent an empty response":"O servidor enviou uma resposta vazia","The Test mode (sequencing, scoring, cumulating, etc.) and layout are also configured here.":"O modo de teste (sequenciamento, pontua\u00e7\u00e3o, acumula\u00e7\u00e3o, etc.) e layout tamb\u00e9m est\u00e3o configurados aqui.","The Tests module allows to combine a selection of Items to a Test.":"O m\u00f3dulo de testes permite combinar uma sele\u00e7\u00e3o de itens para um teste.","The uploaded file is too large (maximum %s bytes)":"O arquivo enviado \u00e9 muito grande (m\u00e1ximo %s bytes)","The value for the property \u0022%s\u0022 must be unique.":"O valor para a propriedade \u0022%s\u0022 deve ser \u00fanico.","The value of this field must be a valid date format, e.g. YYYY-MM-DD":"O valor deste campo deve ser um formato de data v\u00e1lido, por exemplo AAAA-MM-DD","The value of this field must be an integer":"O valor deste campo deve ser um n\u00famero inteiro","The value of this field must be numeric":"O valor deste campo deve ser num\u00e9rico","There is nothing to list!":"N\u00e3o h\u00e1 nada para listar!","This %s is currently checked out":"Este %s est\u00e1 atualmente check-out","This field is required":"Este campo \u00e9 obrigat\u00f3rio","This field is too long":"Este campo \u00e9 muito longo","This field is too short":"Este campo \u00e9 muito curto","This is not a valid email address.":"Este n\u00e3o \u00e9 um endere\u00e7o de e-mail v\u00e1lido.","this is required":"campo obrigat\u00f3rio","This Login is already in use":"Login j\u00e1 est\u00e1 em uso","This media cannot be played!":"Esta m\u00eddia n\u00e3o pode ser reproduzida!","This or one of %s must have a value":"Este ou um dos %s devem ter um valor","This password reset link is no longer valid. It may have already been used. If you still wish to reset your password please request a new link":"Este link de redefini\u00e7\u00e3o de senha n\u00e3o \u00e9 mais v\u00e1lido. Ele pode ter j\u00e1 sido usado. Se voc\u00ea ainda deseja redefinir sua senha, solicite um novo link","This resource is locked":"Este recurso est\u00e1 bloqueado","This role is still given to one or more users. Please remove the role to these users first.":"Esta fun\u00e7\u00e3o ainda \u00e9 dado a um ou mais usu\u00e1rios. Por favor, remova a primeira fun\u00e7\u00e3o para esses usu\u00e1rios.","This should equal %s":"Isto deve ser igual a %s","This should not equal %s":"Isto n\u00e3o deve ser igual a %s","time":"hora","Time zone":"Fuso hor\u00e1rio","Title":"T\u00edtulo","to":"para","To reset your password, click the link below, or paste it into your browser. You will then be prompted to create a new password.":"Para redefinir sua senha, clique no link abaixo ou cole-o no seu navegador. Em seguida, ser\u00e1 solicitado a criar uma nova senha.","to translate":"para traduzir","Toggle multiple\/single selection":"Alternar sele\u00e7\u00e3o m\u00faltipla\/\u00fanica","Toggle the date time picker":"Alternar o seletor de data e hora","Tokenizer":"Tokenizer","Too many non-option arguments: got %s, maximum of %s":"Muitos argumentos n\u00e3o-op\u00e7\u00e3o: obteve %s, m\u00e1ximo de %s","Too many suggestions match your query. Only a few are listed":"Muitas sugest\u00f5es correspondem \u00e0 sua consulta. Somente algumas est\u00e3o listadas","Tools":"Ferramentas","Total duration":"Dura\u00e7\u00e3o total","Total:":"Total:","Translate":"Traduzir","Translate to":"Traduzir para","Translation parameters":"Par\u00e2metros de tradu\u00e7\u00e3o","Translation saved":"Tradu\u00e7\u00e3o salva","Transport Layer Security":"Seguran\u00e7a de Camada de Transporte","Tree - Multiple node choice ":"\u00c1rvore - M\u00faltipla escolha de n\u00f3 ","Tree values":"Valores da \u00e1rvore","Trees":"\u00c1rvores","True":"Verdadeiro","trunc":"trunc","Type":"Tipo","Type your search":"Digite sua pesquisa","Unable to access your account?":"N\u00e3o foi poss\u00edvel acessar sua conta?","Unable to change passwords in demo mode":"N\u00e3o foi poss\u00edvel alterar a senha em modo de demonstra\u00e7\u00e3o","Unable to copy the resource":"N\u00e3o \u00e9 poss\u00edvel copiar o recurso","Unable to delete %s":"N\u00e3o foi poss\u00edvel excluir %s","Unable to delete test.":"N\u00e3o foi poss\u00edvel remover o teste.","Unable to delete the selected resource":"N\u00e3o \u00e9 poss\u00edvel excluir o recurso selecionado","Unable to delete the selected resources":"N\u00e3o foi poss\u00edvel excluir os recursos selecionados","Unable to move the resources":"N\u00e3o \u00e9 poss\u00edvel mover recursos","Unable to open file %s":"N\u00e3o foi poss\u00edvel abrir o arquivo %s","Unable to process your request":"N\u00e3o foi poss\u00edvel processar sua solicita\u00e7\u00e3o","Unable to release the lock":"Imposs\u00edvel liberar o bloqueio","Unable to remove the property.":"N\u00e3o \u00e9 poss\u00edvel remover a propriedade.","Unable to save resource.":"N\u00e3o foi poss\u00edvel salvar o recurso.","unable to search into notification.":"n\u00e3o \u00e9 poss\u00edvel pesquisar na notifica\u00e7\u00e3o.","Unable to send the password reset request":"N\u00e3o foi poss\u00edvel enviar a solicita\u00e7\u00e3o de recupera\u00e7\u00e3o de senha","Unable to update the asset service":"N\u00e3o \u00e9 poss\u00edvel atualizar o servi\u00e7o","Unable to upload file":"N\u00e3o foi poss\u00edvel enviar o arquivo","Unable to upload file %s : %s":"N\u00e3o foi poss\u00edvel enviar o arquivo %s : %s","Unary operator +":"Operador Un\u00e1rio +","Unary operator -":"Operador Un\u00e1rio -","Uncheck all":"Desmarcar todos","Uncheck All":"Desmarcar todos","Undefined amount of the pages for pagination":"Valor indefinido das p\u00e1ginas para pagina\u00e7\u00e3o","Undefined amount of the totalPages for pagination":"Quantidade indefinida de p\u00e1ginas totais para pagina\u00e7\u00e3o","Undo":"Desfazer","Unexpected error. Please contact administrator":"Ocorreu um erro inesperado. Por favor, contate o administrador do sistema","Uninstall of %s failed":"Falha ao desinstalar de %s","Uninstalled %s":"%s desinstalado","UNIX Compressed Archive File":"Arquivo de Compress\u00e3o UNIX","unknown":"desconhecido","Unknown Error":"Erro desconhecido","unkown task id %s":"id tarefa desconhecido %s","Update":"Atualizar","Update ID : %s":"Atualizar o ID : %s","Updating search index":"Atualizando \u00edndice de busca","Upload":"Enviar","Upload into:":"Enviar para:","URI Path":"URI Path","Usage: ImportRdf RDF_FILE [MODEL_ID]":"Uso: ImportRdf RDF_FILE [MODEL_ID]","USAGE: please provide a valid extension id as second parameter":"USO: Por favor, forne\u00e7a um ID de extens\u00e3o v\u00e1lido como segundo par\u00e2metro","USAGE: please provide a valid service name as first parameter":"USO: Por favor, forne\u00e7a um nome de servi\u00e7o v\u00e1lido como primeiro par\u00e2metro","USAGE: please provide the service name as first parameter":"USO: por favor, forne\u00e7a o nome de servi\u00e7o como primeiro par\u00e2metro","Use a term":"Utilizar um termo","Use a variable":"Utilizar uma vari\u00e1vel","Use default value":"Utilizar valor padr\u00e3o","User":"Usu\u00e1rio","User %s can not be locked":"O usu\u00e1rio %s n\u00e3o pode ser bloqueado","User %s can not be unlocked":"O usu\u00e1rio %s n\u00e3o pode ser desbloqueado","User %s successfully locked":"Usu\u00e1rio %s bloqueado com sucesso","User %s successfully unlocked":"Usu\u00e1rio %s desbloqueado com sucesso","User added":"Usu\u00e1rio adicionado","User deleted successfully":"Usu\u00e1rio exclu\u00eddo com sucesso","User deletion not permitted on a demo instance":"Exclus\u00e3o de usu\u00e1rio n\u00e3o permitida em uma inst\u00e2ncia de demonstra\u00e7\u00e3o","User not found":"Usu\u00e1rio n\u00e3o encontrado","User saved":"Usu\u00e1rio salvo","User Settings":"Configura\u00e7\u00f5es de Usu\u00e1rio","Users":"Usu\u00e1rios","Validation for field \u0027%s\u0027 has failed. Language does not exist in the system":"Valida\u00e7\u00e3o do campo \u0027%s\u0027 falhou. Idioma n\u00e3o existe no sistema","Validation for field \u0027%s\u0027 has failed. List of values expected":"Valida\u00e7\u00e3o do campo \u0027%s\u0027 falhou. Lista de valores esperados","Validation for field \u0027%s\u0027 has failed. Should not be empty":"Valida\u00e7\u00e3o do campo \u0027%s\u0027 falhou. N\u00e3o deve estar vazio","Validation for field \u0027%s\u0027 has failed. Valid role expected. Given: %s":"Valida\u00e7\u00e3o para o campo \u0027%s\u0027 falhou. Fun\u00e7\u00e3o v\u00e1lida esperada. Dado: %s","Validation for field \u0027%s\u0027 has failed. Valid URI expected":"Falha na valida\u00e7\u00e3o do campo \u0027.%s\u0027. URI v\u00e1lido esperado","Validation for field \u0027%s\u0027 has failed. Valid URI expected. Given: %s":"A valida\u00e7\u00e3o do campo \u0027%s\u0027 falhou. URI v\u00e1lido esperado. Dado: %s","Value ellipsis":"Elipses de valor","Value of E":"Valor de E","Value of PI":"Valor do PI","Variable":"Vari\u00e1vel","Variable %s":"Vari\u00e1vel %s","Version":"Vers\u00e3o","View":"Visualizar","View and format the collected results.":"Visualizar e formatar os resultados coletados.","View report":"Visualizar relat\u00f3rio","View resources as a list":"Ver recursos como uma lista","View resources as a tree":"Ver recursos como uma \u00e1rvore","View Tree":"Ver \u00c1rvore","Wait is over":"Espera acabou","Waiting":"Aguardando","WAV audio":"\u00c1udio WAV","WebM audio":"\u00c1udio WebM","WebM video":"WebM v\u00eddeo","Whole number part":"Parte n\u00famero inteiro","Width":"Largura","Windows help file":"Arquivo de ajuda do Windows","Windows Media audio":"\u00c1udio do Windows Media","Windows Media file (metafile)":"Arquivo de m\u00eddia Windows (metafile)","Windows Media video":"\u00c1udio do Windows Media","Wrap image left":"Ajustar imagem \u00e0 direita","Wrap image right":"Ajustar imagem \u00e0 direita","Write Document":"Escrever Documento","Wrong or missing parameter extension, module or action":"Extens\u00e3o de par\u00e2metro errada ou ausente","Wrong parameter shownExtension":"Par\u00e2metro errado shownExtension","XML Editor":"Editor XML","XML file":"Arquivo XML","xmlEdit":"xmlEdit","Yes":"Sim","You are encountering a prolonged connectivity loss.":"Voc\u00ea est\u00e1 enfrentando uma perda de conectividade prolongada.","You are not allowed to write in the class %s":"Voc\u00ea n\u00e3o tem permiss\u00e3o para escrever na classe %s","You are not authorised to remove this lock":"Voc\u00ea n\u00e3o est\u00e1 autorizado a remover este bloqueio","You cannot delete the root node":"Voc\u00ea n\u00e3o pode remover o n\u00f3 ra\u00edz","You cannot move the selected resources in the class %s":"Voc\u00ea n\u00e3o pode mover os recursos selecionados para a classe %s","You checked out this test %2s ago":"Voc\u00ea fez check-out deste teste %2s atr\u00e1s","You currently have no access to the platform":"Atualmente voc\u00ea n\u00e3o tem acesso \u00e0 plataforma","You do not have the required rights to edit this resource.":"Voc\u00ea n\u00e3o tem permiss\u00e3o para editar este recurso.","You have been locked due to too many failed login attempts. ":"Voc\u00ea foi bloqueado devido a muitas tentativas de login. ","You have been logged out. Please login again":"A sua sess\u00e3o foi encerrada. Por favor, inicie sess\u00e3o novamente","You must activate JavaScript in your browser to run this application.":"Voc\u00ea deve ativar JavaScript no seu navegador para executar este aplicativo.","Your account has been locked, please contact your administrator.":"Sua conta foi bloqueada, por favor, contate o administrador.","Your browser does not meet the technical requirements to run TAO.":"Seu navegador n\u00e3o atende aos requisitos t\u00e9cnicos para executar o TAO.","Your browser does not support copying to the clipboard":"Seu navegador n\u00e3o suporta copiar para a \u00e1rea de transfer\u00eancia","Your browser doesn\u2019t support the audio player.":"Seu navegador n\u00e3o suporta o reprodutor de \u00e1udio.","Your browser doesn\u2019t support the video player.":"Seu navegador n\u00e3o suporta o reprodutor de v\u00eddeo.","Your mail":"Seu e-mail","Your TAO Password":"Sua senha TAO","ZIP archive":"Arquivo ZIP"} \ No newline at end of file diff --git a/locales/pt-BR/taotest.rdf.po b/locales/pt-BR/taotest.rdf.po new file mode 100644 index 00000000..975af9eb --- /dev/null +++ b/locales/pt-BR/taotest.rdf.po @@ -0,0 +1,89 @@ +msgid "" +msgstr "" +"Project-Id-Version: tao-3x\n" +"PO-Revision-Date: 2023-04-21 15:46\n" +"Last-Translator: TAO Translation Team \n" +"MIME-Version: 1.0\n" +"Language: pt\n" +"sourceLanguage: en-US\n" +"targetLanguage: en-US\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: tao-3x\n" +"X-Crowdin-Project-ID: 582145\n" +"X-Crowdin-Language: pt-BR\n" +"X-Crowdin-File: /taoTests/locales/en-US/taotest.rdf.po\n" +"X-Crowdin-File-ID: 1719\n" +"Language-Team: Portuguese, Brazilian\n" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#Test +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Test" +msgstr "Teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#Test +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Test" +msgstr "Teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestContent +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Test Content" +msgstr "Conteúdo do teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestContent +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Test Content" +msgstr "Conteúdo do teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestTestModel +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Test Model" +msgstr "Modelo do teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestTestModel +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Test Model" +msgstr "Modelo do teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestModelImplementation +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Testmodel implementation" +msgstr "Implementação do testmodel" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestModelImplementation +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Implementation of the test model" +msgstr "Implementação do modelo de teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestsManagerRole +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Tests Manager" +msgstr "Gerente de testes" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestsManagerRole +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "The Tests Manager Role" +msgstr "A função Gerenciador de Testes" + +# http://www.tao.lu/Ontologies/TAOItem.rdf#TestAuthor +msgctxt "http://www.w3.org/2000/01/rdf-schema#label" +msgid "Test Author" +msgstr "Autor de teste" + +# http://www.tao.lu/Ontologies/TAOItem.rdf#TestAuthor +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "The Test Author Role" +msgstr "Função do Autor de Teste" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestModelImplementation +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Testmodel implementation" +msgstr "Implementação do testmodel" + +# http://www.tao.lu/Ontologies/TAOTest.rdf#TestsManagerRole +msgctxt "http://www.w3.org/2000/01/rdf-schema#comment" +msgid "Tests Manager" +msgstr "Gerente de testes" + diff --git a/views/js/loader/taoTests.min.js.map b/views/js/loader/taoTests.min.js.map index 2c948d82..e516fc52 100644 --- a/views/js/loader/taoTests.min.js.map +++ b/views/js/loader/taoTests.min.js.map @@ -1 +1 @@ -{"version":3,"mappings":"AAmBAA,kDACA,aACA,OACA,OACA,+BACA,SACA,oCACA,CACA,CACA,CACA,GCTAA,qCACA,SACA,UACA,SACA,sBACA,wBACA,cACA,UACAC,EACAC,QACAC,OACAC,sBACAC,iBACA,CACA,aAYA,2CAEA,MADAC,+CACAF,wBACAG,2BACAC,qBACAC,yBACAR,uCACAS,yDACA,EACA,GACAD,gBACA,yCACA,GACAA,wBACA,gCACA,EACA,CAEA,6EACA,gCACA,wEAEA,QACA,EACA,GCpDAT,2CACA,SACA,OACA,wBACA,MACA,cACA,cACA,6BACA,SACA,0EACA,aAEA,yDAEAW,uEACAL,wBACAM,wBACAC,YACAC,YACAC,oCACA,iBAEAL,iCACAM,8BACAJ,iBACAK,YACAC,kBACAC,4FACA,EACA,EACA,GC1BAnB,6CACA,SACA,UACA,SACA,iBACA,iCACA,aAEA,OAMAoB,aAEAd,wBACAe,4CACAA,gBACAA,sDACAC,uBAGAC,+BACAC,wBACA,EACA,CACA,CACA,GCjDAxB,uDACAA,MCFA","names":["define","_","context","module","providerLoaderFactory","providerRegistry","config","addList","load","then","previewerFactory","binder","previewerConfig","readOnly","fullPage","pluginsOptions","uri","catch","logger","feedback","start","previewAction","actions","$","lock"],"sources":["../controller/routes.js","../previewer/factory.js","../controller/tests/action.js","../controller/tests/editTest.js","module-create.js","/github/workspace/tao/views/build/config-wrap-end-default.js"],"sourcesContent":["/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2014-2020 (original work) Open Assessment Technologies SA\n */\n\n//@see http://forge.taotesting.com/projects/tao/wiki/Front_js\ndefine('taoTests/controller/routes',[],function(){\n 'use strict';\n return {\n 'Tests' : {\n 'deps' : 'controller/tests/action',\n 'actions' : {\n 'editTest' : 'controller/tests/editTest'\n }\n }\n };\n});\n\n","/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2020 (original work) Open Assessment Technologies SA ;\n */\n/**\n * @author Hanna Dzmitryieva \n */\ndefine('taoTests/previewer/factory',[\n 'lodash',\n 'context',\n 'module',\n 'core/providerLoader',\n 'core/providerRegistry',\n 'core/logger'\n], function (\n _,\n context,\n module,\n providerLoaderFactory,\n providerRegistry\n) {\n 'use strict';\n\n /**\n * Loads and display the test previewer\n * @param {String} type - The type of previewer\n * @param {String} uri - The URI of the test to load\n * @param {Object} [config] - Some config entries\n * @param {String} [config.fullPage] - Force the previewer to occupy the full window.\n * @param {String} [config.readOnly] - Do not allow to modify the previewed test.\n * @param {Object} [config.previewers] - Optionally load static adapters. By default take them from the module's config.\n * @returns {Promise}\n */\n function previewerFactory(type, uri, config) {\n config = _.defaults(config || {}, module.config());\n return providerLoaderFactory()\n .addList(config.previewers)\n .load(context.bundle)\n .then(function (providers) {\n _.forEach(providers, function (provider) {\n previewerFactory.registerProvider(provider.name, provider);\n });\n })\n .then(function () {\n return previewerFactory.getProvider(type);\n })\n .then(function (provider) {\n return provider.init(uri, config);\n });\n }\n\n return providerRegistry(previewerFactory, function validateProvider(provider) {\n if (!_.isFunction(provider.init)) {\n throw new TypeError('The previewer provider MUST have a init() method');\n }\n return true;\n });\n});\n\n","/*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2014 - 2020 (original work) Open Assessment Techniologies SA\n *\n */\ndefine('taoTests/controller/tests/action',[\n 'lodash',\n 'i18n',\n 'layout/actions/binder',\n 'uri',\n 'ui/feedback',\n 'core/logger',\n 'taoTests/previewer/factory',\n 'module'\n], function(_, __, binder, uri, feedback, loggerFactory, previewerFactory, module){\n 'use strict';\n\n const logger = loggerFactory('taoTests/controller/action');\n\n binder.register('testPreview', function testPreview(actionContext) {\n const config = module.config();\n const previewerConfig = _.omit({\n readOnly: false,\n fullPage: true,\n pluginsOptions: config.pluginsOptions\n }, _.isUndefined);\n\n previewerFactory(config.provider,\n uri.decode(actionContext.uri),\n previewerConfig)\n .catch(err => {\n logger.error(err);\n feedback().error(__('Test Preview is not installed, please contact to your administrator.'));\n });\n });\n});\n\n","/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA;\n */\n\n/**\n * Test edition controller\n *\n */\ndefine('taoTests/controller/tests/editTest',[\n 'jquery',\n 'ui/lock',\n 'module',\n 'layout/actions',\n],\tfunction($, lock, module, actions){\n 'use strict';\n\n return {\n\n\n /**\n * Controller's entrypoint\n */\n start(){\n\n const config = module.config();\n const previewAction = actions.getBy('test-preview');\n if (previewAction) {\n previewAction.state.disabled = !config.isPreviewEnabled;\n actions.updateState();\n }\n\n $('#lock-box').each(function() {\n lock($(this)).register();\n });\n }\n };\n});\n\n","\ndefine(\"taoTests/loader/taoTests.bundle\", function(){});\n","define(\"taoTests/loader/taoTests.min\", [\"taoItems/loader/taoItems.min\"], function(){});\n"]} \ No newline at end of file +{"version":3,"mappings":"AAmBAA,kDACA,aACA,OACA,OACA,+BACA,SACA,oCACA,CACA,CACA,CACA,GCTAA,qCACA,SACA,UACA,SACA,sBACA,wBACA,cACA,UACAC,EACAC,QACAC,OACAC,sBACAC,iBACA,CACA,aAYA,2CAEA,MADAC,+CACAF,wBACAG,2BACAC,qBACAC,yBACAR,uCACAS,yDACA,EACA,GACAD,gBACA,yCACA,GACAA,wBACA,gCACA,EACA,CAEA,6EACA,gCACA,wEAEA,QACA,EACA,GCpDAT,2CACA,SACA,OACA,wBACA,MACA,cACA,cACA,6BACA,SACA,0EACA,aAEA,yDAEAW,uEACAL,wBACAM,wBACAC,YACAC,YACAC,oCACA,iBAEAL,iCACAM,8BACAJ,iBACAK,YACAC,kBACAC,4FACA,EACA,EACA,GC1BAnB,6CACA,SACA,UACA,SACA,iBACA,iCACA,aAEA,OAMAoB,aAEAd,wBACAe,4CACAA,gBACAA,sDACAC,uBAGAC,+BACAC,wBACA,EACA,CACA,CACA,GCjDAxB,uDACAA,MCFA","names":["define","_","context","module","providerLoaderFactory","providerRegistry","config","addList","load","then","previewerFactory","binder","previewerConfig","readOnly","fullPage","pluginsOptions","uri","catch","logger","feedback","start","previewAction","actions","$","lock"],"sources":["../controller/routes.js","../previewer/factory.js","../controller/tests/action.js","../controller/tests/editTest.js","module-create.js","/home/alberto/workspace/oat/taocloud-ami-luoss/tao/views/build/config-wrap-end-default.js"],"sourcesContent":["/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2014-2020 (original work) Open Assessment Technologies SA\n */\n\n//@see http://forge.taotesting.com/projects/tao/wiki/Front_js\ndefine('taoTests/controller/routes',[],function(){\n 'use strict';\n return {\n 'Tests' : {\n 'deps' : 'controller/tests/action',\n 'actions' : {\n 'editTest' : 'controller/tests/editTest'\n }\n }\n };\n});\n\n","/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2020 (original work) Open Assessment Technologies SA ;\n */\n/**\n * @author Hanna Dzmitryieva \n */\ndefine('taoTests/previewer/factory',[\n 'lodash',\n 'context',\n 'module',\n 'core/providerLoader',\n 'core/providerRegistry',\n 'core/logger'\n], function (\n _,\n context,\n module,\n providerLoaderFactory,\n providerRegistry\n) {\n 'use strict';\n\n /**\n * Loads and display the test previewer\n * @param {String} type - The type of previewer\n * @param {String} uri - The URI of the test to load\n * @param {Object} [config] - Some config entries\n * @param {String} [config.fullPage] - Force the previewer to occupy the full window.\n * @param {String} [config.readOnly] - Do not allow to modify the previewed test.\n * @param {Object} [config.previewers] - Optionally load static adapters. By default take them from the module's config.\n * @returns {Promise}\n */\n function previewerFactory(type, uri, config) {\n config = _.defaults(config || {}, module.config());\n return providerLoaderFactory()\n .addList(config.previewers)\n .load(context.bundle)\n .then(function (providers) {\n _.forEach(providers, function (provider) {\n previewerFactory.registerProvider(provider.name, provider);\n });\n })\n .then(function () {\n return previewerFactory.getProvider(type);\n })\n .then(function (provider) {\n return provider.init(uri, config);\n });\n }\n\n return providerRegistry(previewerFactory, function validateProvider(provider) {\n if (!_.isFunction(provider.init)) {\n throw new TypeError('The previewer provider MUST have a init() method');\n }\n return true;\n });\n});\n\n","/*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2014 - 2020 (original work) Open Assessment Techniologies SA\n *\n */\ndefine('taoTests/controller/tests/action',[\n 'lodash',\n 'i18n',\n 'layout/actions/binder',\n 'uri',\n 'ui/feedback',\n 'core/logger',\n 'taoTests/previewer/factory',\n 'module'\n], function(_, __, binder, uri, feedback, loggerFactory, previewerFactory, module){\n 'use strict';\n\n const logger = loggerFactory('taoTests/controller/action');\n\n binder.register('testPreview', function testPreview(actionContext) {\n const config = module.config();\n const previewerConfig = _.omit({\n readOnly: false,\n fullPage: true,\n pluginsOptions: config.pluginsOptions\n }, _.isUndefined);\n\n previewerFactory(config.provider,\n uri.decode(actionContext.uri),\n previewerConfig)\n .catch(err => {\n logger.error(err);\n feedback().error(__('Test Preview is not installed, please contact to your administrator.'));\n });\n });\n});\n\n","/**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA;\n */\n\n/**\n * Test edition controller\n *\n */\ndefine('taoTests/controller/tests/editTest',[\n 'jquery',\n 'ui/lock',\n 'module',\n 'layout/actions',\n],\tfunction($, lock, module, actions){\n 'use strict';\n\n return {\n\n\n /**\n * Controller's entrypoint\n */\n start(){\n\n const config = module.config();\n const previewAction = actions.getBy('test-preview');\n if (previewAction) {\n previewAction.state.disabled = !config.isPreviewEnabled;\n actions.updateState();\n }\n\n $('#lock-box').each(function() {\n lock($(this)).register();\n });\n }\n };\n});\n\n","\ndefine(\"taoTests/loader/taoTests.bundle\", function(){});\n","define(\"taoTests/loader/taoTests.min\", [\"taoItems/loader/taoItems.min\"], function(){});\n"]} \ No newline at end of file diff --git a/views/js/loader/taoTestsRunner.min.js.map b/views/js/loader/taoTestsRunner.min.js.map index 04e181fd..ffff40b2 100644 --- a/views/js/loader/taoTestsRunner.min.js.map +++ b/views/js/loader/taoTestsRunner.min.js.map @@ -1 +1 @@ -{"version":3,"mappings":"AACAA,MCDA,+FAEAC,sEACAC,gIAoBAC,yBACA,UACA,aACA,UACA,SACA,QACA,CAYAC,gDAEA,iBAEA,GAEAJ,MC/CA,yDA0CA,6BACA,gBAIA,MAHAK,wCACAC,iBACA,GACAA,GACA,CAdA,+CAgBA,wBAEA,GAEAN,MCtDA,0FAEAC,sEACAM,kIAwBA,yCAEAC,qBACA,GAEA,aAEA,GAEAR,MCpCA,kJAiCA,sCAkDA,gCACAS,gCAEAC,wCACAC,cACAC,MACAC,eACAC,gBACAC,8BACAC,qCACA,EAEA,mCACAJ,gFAGAK,mBACA,QAGAC,eACAC,+BAGAlB,4CACA,gEACAmB,mDACA,EACA,CAEA,uCACAX,gCAEAY,wCACAV,cACAC,MACAC,eACAS,eACAR,gBACAC,8BACAC,qCACA,EAEA,mCACAJ,gFAGAK,mBACA,EAGAM,sCAEAC,MADAb,aAEAC,MACAE,gBACAC,8BACAC,qCACA,EACAS,2BACAD,gCACAV,gBACAQ,cACA,GAEAE,kCACAV,gBACAQ,aACAT,UACA,KACAD,gBACAA,kBAEA,mCACAA,+DAGAK,oBAEA,QAGAC,oBAIAjB,gDACA,gEACAmB,mDACA,GAEAnB,+CACA,gEACAmB,kDACA,IAXAM,mBAYA,IA/IAT,UAWAU,aATAC,UAEAC,SAEAC,kBAUAC,0BAEAC,WAMAC,uCACAN,cACAO,8BAGAd,uEAEA,MADAO,yBACAO,6BACA,EACA,EAMAC,qCACAR,iBACA,EAyGA,kFACA,gDA4KA,MArKAV,WAaAmB,wBAEA,2BACA,iDAGA,kDACA,gDAGA,GAEA,EAFAnC,gBACAoC,eACA,UACA,oEAGA,kBASA,GARApC,+DACAiB,uCAGAjB,6DACAiB,qCAGA,oDACA,yFAIAc,SACAb,0BAEA,MAKA,GAJAlB,qDACAiB,6BAGA,kDACA,kDAIAc,SACAN,mBAEA,CAGA,MADAE,oBACA,IACA,EAMAU,6BACA,2CACA,+BACA,EACA,EAMAC,+BACA,aACA,EAMAC,0BACAP,oCAEAF,gCAGA,MAFAF,mBACAC,2BACAW,8BACA,EACA,EACA,EAMAC,uBACA,qCACAT,oCACAF,gCACA,uDAEA,MADAF,UACAY,+CACAE,gBACA,EACA,EACA,EACA,EACA,EACA,EAMAC,uBACA,2CACA,0DACA3C,wBACA4B,iBACAC,2BAGA7B,+BAEA+B,UACA,EACA,EACA,EAOAa,qBAmBA,MAlBAb,YAEA/B,oCACAQ,gCAEAqC,gDACA1B,6BACA,EAEAnB,2CAEAA,0CAEAA,qCACA,GAEA4B,SACAC,kBACAG,oCACA,qDACA,EACA,CACA,EACAhB,QACA,CAjWAhB,sEACA8C,+FACAC,wFAoBAC,4BACAC,4BA4UA,2BAEA,GAEAlD,MCzWA,mLAuCA,yCAuEA,6BACA,kFACAyB,6BAGA,4BACAxB,+BAIA0C,6CAHAA,SAIA,CACA,CASA,2BACA,iBAQA,MANA1C,wCACAA,8BACAkD,gCAEA,GAEAjB,sBACA,CAQA,0BACAd,2BACA,IAzGAA,QAKAgC,WAXAC,0EACAC,sEAeAC,YAKAC,QACAC,QACAC,SACAC,UACAC,UACAC,UACA,EAKA,kBAKA,8DAMAzD,YAMA0D,MAMAC,cAMAC,UAmtBA,MAzpBA5C,oBAUAqC,OAcA,MAbAL,cACAA,iCAIAnD,0CACA,wDACAsD,gCACA,GAEAU,gMACA,sGACA,sBACA,IACA,EAUAN,SAIA,MAHAM,+DACA,4DACA,sBACA,IACA,EAWAC,kBAIA,MAHAD,iDACA,qKACA,sBACA,IACA,EAWAE,6BAIA,MAHAF,sDACA,4EACA,sBACA,IACA,EAUAG,oBAKA,MAJAH,6CACAI,sCACA,kCACA,sBACA,IACA,EASAC,qBAOA,MANA,wCACAL,6CACA,uEACA,sBAGA,IACA,EASAM,oBAOA,MANA,wCACAN,4CACA,sEACA,sBAGA,IACA,EASAL,SAIA,MAHAK,+DACA,4CACA,sBACA,IACA,EASAvB,QAIA,MAHAuB,6DACA,0CACA,sBACA,IACA,EASAJ,UAQA,MAPAI,iEACA,SACA,sBAEA,aACA,gFACA,sBACA,IACA,EAMAO,YACA,iBACA,EAWAC,aACA,mCACA,EAMAC,aACA,cACA,EAOAC,gBACA,oBACA,EAWAC,mBACA,oCACA,EAUAC,4BACA,oCACA,4CAEA,6BACA,gCAEA,CAEA,QACA,EAOAC,gBAKA,MAJA1E,cACAA,+CAGAA,UACA,EAOA2E,WACA,WACA,qCACA,iEAGAjB,oCACAA,qDACAA,mCACA,CAEA,YACA,EAOAkB,mBAKA,MAJA,2DACAjB,qDAGAA,aACA,EAOAkB,eAKA,MAJA,mDACAjB,6CAGAA,SACA,EASAkB,qBACA,4CAEAC,iDAIA,mCAHAjD,4GAIA,EAQAkD,eACA,oBACA,EAUAC,sBACA,sCACA,kDAIA,MADA7B,uBACA,IACA,EASA8B,yBACA,UAMA,MAJArF,6CACAsF,qDAGA,OACA,EAYAC,gCACA,WASA,MANAC,QADA,mCACAvD,4DAEA+B,gDAGAwB,0BACAA,MACA,EAWAC,2BACA,uCACA,wEAGA,wDACA,EAYAC,kCACA,uCACA,wEASA,MANAtB,2CACAuB,UACAlC,SACAmC,WACA,EACAxB,mCACA,IACA,EAOAyB,cACA,6CACA,EAQAC,sBAKA,MAJA3C,wCACAA,oCAGA,IACA,EAMA4C,iBACA,gDACA,EAOAC,4BAKA,MAJA7C,2CACAA,0CAGA,IACA,EAMA8C,aACA,4CACA,EAOAC,oBAKA,MAJA/C,uCACAA,kCAGA,IACA,EAMAgD,gBASA,MARAhD,cACAnD,sCACAmD,8CAEAA,gCAIAA,UACA,EAQAiD,kBACApG,6BACAgE,2BAIA,kCACA,KACA,EAQAqC,sBACArG,iCACAgE,+BAIA,sCACA,KACA,EASAsC,2BACAtG,6BACAgE,oCAIA,2CACA,KACA,EAUAuC,gCACAvG,6BACAgE,yCAIA,yCACA,KACA,EAQAwC,gBACAxG,6BACAgE,yBAIA,yBACA,KACA,EAOAyC,cACAzG,8BACA,uBAKAiC,mBAJA,0BACA+B,uBAOA,wBACA,2CAGA,KACA,EAOA0C,eACA1G,+BACA,wBACA,0BACAgE,uBAGA/B,mBAIA,6BACA,4CAGA,KACA,EAUA0E,+BACA3G,gCACAgE,wCAIA,wCACA,KACA,CAEA,GACA7C,4BACA,0BACA,6CACAgC,YACAA,mBAGAhD,gBACA0D,WACAC,mBACAC,cACA,GACA5C,MACA,CAvzBAnB,sEACA4G,mHACAC,iJACAC,sJAuzBA,kFAEA,0CACA,yFAGA,QACA,GAEA,aAEA,GAEA/G,MCz0BA,qPAsCA,wCAkBA,2BACA,oDAGA,MADAgH,oBACAC,YACA,CAQA,+BACA,gCAMA,MAJAC,mBACAC,mCAGAA,IACA,CAaA,4CAEA,oEACA,sBACAC,iCACA,CACA,GAGA,4CACAC,gCAEAC,iCACAA,mBAGAA,IACAC,aAEAzD,+CACAnB,uBAEA,EACA,EACA,CAWA,0BACA,aACA6E,eACAC,+BACA,QAEAC,oDAIAC,wDAKA,MAFAD,gBAEAE,0BACAC,iBACAjH,SACA,EACA,wBAEA,iCACAiH,eACAjH,SACA,EACA,GAlBAsB,qFAmBA,IAhHA4B,sDACAgE,eACAd,mBACAe,iDAEAC,4CAEAC,mCACAf,eACAQ,eACAQ,qCAsjBA,MAzcApE,mBAOAqE,6BACAtG,kDACAsF,4BASA,MARAD,yBAEAjH,8BACAA,kBACAkH,aAEA,GAEA,IACA,EASAiB,qCAKA,MAJAhF,cACA0E,2BAGAO,8BACA,EASA5E,2BAOA,oDACA,EAQAI,2BAKA,2CAIA,GAFA6D,eAEAY,oBACA,4CACA,+BACAC,kDACA,CAEAD,oBACAE,gBACAC,qBACA,GACAC,iBACAH,aACAE,sBAEA9F,SAEA,EACA,EAEA,EACA,EAMAyD,uCACA,qBACA,EAOAuC,+BAMA,MALA,oBACAT,gBACA,2BAGA,IACA,EAQAU,uCAMA,MALA,mBACAV,gBACA,mCAGA,IACA,EAMAW,6BACA,mBACA,EAMAC,+BACA,mBACA,EASAC,sDACA,2EACA,EAMAC,2CACA,mBACA,EAMAC,2CACA,2BACA,EAMAC,2CACA,oBAEAxB,cAIAY,sBACAA,yDACArI,6CACAsI,sDAEAA,aACAA,4CACAY,+BACAA,+BAEA,4BACAA,yBACA,mCACAA,iBACAA,+CACA,0BACA,2CACAxG,qBACA,gBACA,iBAEA4E,uDAGAA,+EAEA,IAGAe,qBAhCApG,qFAiCA,EASAkH,uCACA,qCACA,kDAGA,0BACA,+DAQA,MALA,4DACAC,0CACA,GACAX,cACA,mCACA,IACA,EAQAY,oCACA,kEACA,iDACA,EACA,EAQAC,yDAKA,MAJAtJ,0BACAA,gCAGA,IACA,EAUA6F,mCAKA,8BACA,EAOAE,yCAKA,iCACA,EAOAE,iCAKA,6BACA,EAUAsD,yDAKA,mDACA,EAWAC,+DAOA,mEACA,EAUAC,qCAMA,qCACA,EAYAC,0DAQA,kEACA,EAYAC,mEAQA,uEACA,EAWAC,gDAQA,8CACA,CACA,GAEAC,qCACAhG,0BACA,0BACAA,iBACA,GAEAA,6CACA,0CACA,uCACAiG,uCAEA9J,+CACA+J,YACAlG,iDAEAA,wCAEA,GAGAuC,MACA,GACA8B,oCACArE,yCACAA,4BACAiG,wCACAjG,kBAGAuC,MACA,GACAsB,4CACAtF,aACA4H,yCACA,gCACA,CACA,GACAnG,KACA,CAtmBA7D,sEACAoH,0FACA6C,8GACArD,mHACAC,iJACAqD,gKACAL,gIAmBAM,cACAC,gBA8kBAvG,qCAEA,YAEA,GAEA9D,MChnBA,wSA8CA,sCACAsK,qEACAC,gFASAC,uCACAC,2EACAC,8CAEA,uDACA,2FAGA,6FACAC,mFACAD,OACA,CACA,EAMAE,cACAxJ,SACA,8EACA,sDACA,EAEAyJ,aACA,kFACA,iGACAF,+EACAE,WACA,CACA,EAEAtC,eACA,oFACA,kEACA,EAEAzE,QACA,6EACA,oDACA,EAEAP,UACA,sEACA,2DACA,CAEA,EAMA,MAJAgH,iBACAO,uDAGA5I,sDACA,kDACA4I,2EACA,+GACA,iEACAA,sEACA,CACA,qBACA,EACA,CACA,CACAA,6FAEA,wFAEA,KADAA,qFACAxD,GACA,EACA,CA7HAyD,kIACAC,uIACAC,6HACA1C,6HACAnH,+FACA0C,0FACA+G,mHAmBA,qDAsGA,8BAEA,GAEA7K,MCrIA,2DA4BA,iBAMAyD,qBAEA,qCAGAd,SAEA,EACA,EAOAkB,2BAEA,qCAGAlB,SAEA,EACA,EAQAmD,mCAEA,qCAGAnD,SAEA,EACA,EAOAqD,yCAEA,qCAGArD,SAEA,EACA,EASA8G,yCAEA,qCAGA9G,SAEA,EACA,EASA+G,2BAEA,qCAGA/G,SAEA,EACA,EAWAgH,iCAEA,qCAGAhH,SAEA,EACA,EAUAiH,yCAEA,qCAGAjH,SAEA,EACA,EAWAkH,+BAEA,qCAGAlH,SAEA,EACA,CACA,EAEA,kBAEA,GAEA3C,MCzLA,+MAeA,mDACA,gCACA,gCACA,CA0BA,2CACA,qEACA,iEAEA,2BACA,+FAGA,2EACA,kIAGA,QACA,CASA,kCACAc,sEACAwC,iEAEA,0CACA,6BAGA,6CACA,2CAEA,0EACA,4CAGA,wDACA,iDAEA,CAEA,QACA,CAiBA,qCACA4H,uEACA5H,iEACA6H,mFACA/J,YACAmC,WAEA,cACA,0FAGA6H,wCAKA,iCAMAC,gBACA,gCACA,EAMAC,YACA,aACA,CAEA,8CAEA,6EACAC,2BACAhI,yBAGA,uBACA,WACA,wCACA,0BACA,oEACAiI,0BACA,GACAC,qFACAC,8CACAA,iEAGAA,IACA,4BACAtK,wFACAnB,aACA,qDACA,EACA,4DACA,2BACA,wCAEA,MADAmB,aACAuK,UACA,8BACA,yBACA,GACA,mCACA,CA1KA1L,sEACA2L,8GACAC,kIACAb,uIACAc,mHAEA,mFAKA,MAJA,kCACAC,+CAGA,0CACA,GAgKA,6BAEA,GAEA/L,MClLA,gHAgFA,uDAIAgM,UAHAC,cACAC,aACAC,kBAOAC,uDACAnM,yBACAoM,iEASA,MAPAL,UADAM,0CACAA,OAGAC,cAGAzB,wDACAwB,sBACA,GAGApK,yCACA,EAEA,qBACA,kFAQA,OAOAsK,sCAGA,uCACAvM,yCACAkM,6BAEA,EAEA,wBACA,sEAOA,MAJAlM,mCACAgM,2BAGAG,8CACA,cAQA,MALAK,WADAC,UACAC,iCAEAA,mDAGAF,wCACAG,0CAEAC,gCACA,2CACA,EAOA,OAMAnD,8BACA,yCACA,EAMAoD,mCACAJ,WACAvH,8CACA,mDAKA,MAJAyH,wBACAlB,uCAGAA,GACA,KACA,GAEAvG,sBAEA,EAQA4H,oCAEA,MADAC,eACA7H,wCACA,EAOA8H,oCAEA,MADAD,eACA7H,qCACA,EAMA+H,6BACAF,eAEAN,UACAvH,8CACAlF,sCACA2M,sBACAzH,2BAEA,EACA,GAEAA,mBAEA,CACA,CACA,EACA,EACA,EASAgI,4CAKA,MAJAlN,kCACAiM,0BAGA,IACA,EAQAkB,2EACAjE,WACAkE,eACA,2EAMA,MALApN,uEACA6K,oGACAuC,gBAGAA,WACA,gCACAH,OACA/D,0BAIA,EACA,EAMAmE,sDACAnE,WACAoE,2CACA,6DACA,4BACA,EACA,GACA,oDACA,iDACA,EACA,EAQAC,4DAEA,MADArB,8BACA,IACA,EAQAsB,0CACA,oCACA,EAQAC,8CAKA,MAJAzN,0CACAkM,8BAGA,IACA,EAMAwB,yBACA,6CACA,2DACAjB,WACAC,8DACA,kCACA,GAGAA,oCACA,qCACA,qBACA,EACA,EAMAiB,qDACA,8CACA,CACA,CACA,CAjWA3N,sEACA0M,0FACA5B,qIAyBAD,8DAQA+C,8DAKAtB,OACAuB,kBAEAC,uBAEA,EAUA1B,oEACA,iDACA,8CACA,sDACA,EACA,uDACApM,8CACAsM,iBAGAA,aACA,EACA,EAgSA,sBAEA,GCtWAvM,6DACAA,MCFA","names":["define","_","areaBroker$1","requireAreas","areaBroker","defaultObjects","map","pluginFactory","hostName","eventNs","probeHandler","now","data","id","type","timestamp","timezone","overseer","probe","collectLatencyEvent","runner","startHandler","marker","stopHandler","last","args","collectEvent","queueStorage","probes","queue","immutableQueue","writing","started","getStorage","Promise","resetStorage","add","name","getQueue","getProbes","push","storage","flush","resolve","start","stop","removeHandler","moment","uuid","timeZone","slice","execStack","dataHolder","pluginFactories","config","plugins","states","init","ready","render","finish","destroy","proxy","probeOverseer","testStore","providerRun","loadItem","renderItem","unloadItem","itemStates","disableItem","enableItem","getConfig","getOptions","getPlugins","getPlugin","getPluginsConfig","getPluginConfig","getAreaBroker","getProxy","getProbeOverseer","getTestStore","getPluginStore","loadedStore","getState","setState","getPersistentState","state","setPersistentState","stored","getItemState","setItemState","loaded","disabled","getTestData","setTestData","getTestContext","setTestContext","getTestMap","setTestMap","getDataHolder","next","previous","jump","skip","exit","pause","resume","timeout","eventifier","providerRegistry","dataHolderFactory","extraCallParams","mergedParams","middlewares","list","middleware","async","err","reject","command","params","initialized","delegateProxy","applyMiddlewares","status","testDataHolder","proxyAdapter","initConfig","tokenHandler","onlineStatus","use","install","delegate","communicatorPromise","communicator","then","destroyCommunicator","catch","setOnline","setOffline","isOnline","isOffline","isConnectivityError","getTokenHandler","hasCommunicator","getCommunicator","self","channel","communicatorInstance","send","addCallActionParams","sendVariables","callTestAction","getItem","submitItem","callItemAction","telemetry","connectivity","response","msg","wrapper","delegator","tokenHandlerFactory","_defaults","_slice","providers","loadFromBundle","loadAndRegisterProvider","providersToLoad","target","loadedProviders","registration","itemRunner","logger","loggerFactory","providerLoader","pluginLoader","container","template","validateTestRunnerConfiguration","getOption","getRunner","results","renderTo","runnerConfig","acc","destroying","component","runnerFactory","Handlebars","helpers","testMode","storeNames","volatiles","changeTracking","isStoreModeUnified","selectStoreMode","result","modes","getStore","loadStore","isUnified","store","keyPattern","storeKey","getItems","setItem","trackChange","removeItem","clear","setVolatile","clearVolatileIfStoreChange","shouldClear","clearVolatileStores","clearing","startChangeTracking","hasChanges","resetChanges","remove","getStorageIdentifier","legacyPrefixes","unified","fragmented"],"sources":["/github/workspace/tao/views/build/config-wrap-start-default.js","../runner/areaBroker.js","../runner/dataHolder.js","../runner/plugin.js","../runner/probeOverseer.js","../runner/runner.js","../runner/proxy.js","../runner/providerLoader.js","../runner/proxy/sample.js","../runner/runnerComponent.js","../runner/testStore.js","module-create.js","/github/workspace/tao/views/build/config-wrap-end-default.js"],"sourcesContent":["\n","define('taoTests/runner/areaBroker',['lodash', 'ui/areaBroker'], function (_, areaBroker$1) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n areaBroker$1 = areaBroker$1 && Object.prototype.hasOwnProperty.call(areaBroker$1, 'default') ? areaBroker$1['default'] : areaBroker$1;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technlogies SA\n *\n */\n var requireAreas = ['content', //where the content is renderer, for example an item\n 'toolbox', //the place to add arbitrary tools, like a zoom, a comment box, etc.\n 'navigation', //the navigation controls like next, previous, skip\n 'control', //the control center of the test, progress, timers, etc.\n 'header', //the area that could contains the test titles\n 'panel' //a panel to add more advanced GUI (item review, navigation pane, etc.)\n ];\n /**\n * Creates an area broker with the required areas for the test runner.\n *\n * @see ui/areaBroker\n *\n * @param {jQueryElement|HTMLElement|String} $container - the main container\n * @param {Object} mapping - keys are the area names, values are jQueryElement\n * @returns {broker} the broker\n * @throws {TypeError} without a valid container\n */\n\n var areaBroker = _.partial(areaBroker$1, requireAreas);\n\n return areaBroker;\n\n});\n\n","define('taoTests/runner/dataHolder',[],function () { 'use strict';\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technlogies SA\n *\n */\n\n /**\n * Holds the test runner data.\n *\n * @example\n * var holder = holder();\n * holder.get('testMap');\n *\n * @author Bertrand Chevrier \n */\n\n /**\n * @type {String[]} the list of default objects to create\n */\n const defaultObjects = ['testContext', 'testMap'];\n /**\n * Creates a new data holder,\n * with default entries.\n *\n * @returns {Map} the holder\n */\n\n function dataHolderFactory() {\n var map = new Map();\n defaultObjects.forEach(function (entry) {\n map.set(entry, {});\n });\n return map;\n }\n\n return dataHolderFactory;\n\n});\n\n","define('taoTests/runner/plugin',['lodash', 'core/plugin'], function (_, pluginFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n pluginFactory = pluginFactory && Object.prototype.hasOwnProperty.call(pluginFactory, 'default') ? pluginFactory['default'] : pluginFactory;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n /**\n * A pluginFactory configured for the test runner\n * @returns {Function} the preconfigured plugin factory\n */\n\n var plugin = _.partialRight(pluginFactory, {\n //alias getHost to getTestRunner\n hostName: 'testRunner'\n });\n\n return plugin;\n\n});\n\n","define('taoTests/runner/probeOverseer',['lodash', 'moment', 'lib/uuid', 'lib/moment-timezone.min'], function (_, moment, uuid, momentTimezone_min) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n moment = moment && Object.prototype.hasOwnProperty.call(moment, 'default') ? moment['default'] : moment;\n uuid = uuid && Object.prototype.hasOwnProperty.call(uuid, 'default') ? uuid['default'] : uuid;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technlogies SA\n *\n */\n var timeZone = moment.tz.guess();\n var slice = Array.prototype.slice;\n /**\n * Create the overseer intance\n * @param {runner} runner - a instance of a test runner\n * @returns {probeOverseer} the new probe overseer\n * @throws TypeError if something goes wrong\n */\n\n function probeOverseerFactory(runner) {\n // the created instance\n var overseer; // the list of registered probes\n\n var probes = []; //temp queue\n\n var queue = []; //immutable queue which will not be flushed\n\n var immutableQueue = [];\n /**\n * @type {Storage} to store the collected events\n */\n\n var queueStorage;\n /**\n * @type {Promise} Promises chain to avoid write collisions\n */\n\n var writing = Promise.resolve(); //is the overseer started\n\n var started = false;\n /**\n * Get the storage instance\n * @returns {Promise} that resolves with the storage\n */\n\n var getStorage = function getStorage() {\n if (queueStorage) {\n return Promise.resolve(queueStorage);\n }\n\n return runner.getTestStore().getStore('test-probe').then(function (newStorage) {\n queueStorage = newStorage;\n return Promise.resolve(queueStorage);\n });\n };\n /**\n * Unset the storage instance\n */\n\n\n var resetStorage = function resetStorage() {\n queueStorage = null;\n };\n /**\n * Register the collection event of a probe against a runner\n * @param {Object} probe - a valid probe\n */\n\n\n function collectEvent(probe) {\n var eventNs = `.probe-${probe.name}`; //event handler registered to collect data\n\n var probeHandler = function probeHandler() {\n var now = moment();\n var data = {\n id: uuid(12, 16),\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(slice.call(arguments)));\n }\n\n overseer.push(data);\n }; //fallback\n\n\n if (probe.latency) {\n return collectLatencyEvent(probe);\n }\n\n _.forEach(probe.events, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(probeHandler, eventName));\n });\n }\n\n function collectLatencyEvent(probe) {\n var eventNs = `.probe-${probe.name}`; //start event handler registered to collect data\n\n var startHandler = function startHandler() {\n var now = moment();\n var data = {\n id: uuid(12, 16),\n marker: 'start',\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(slice.call(arguments)));\n }\n\n overseer.push(data);\n }; //stop event handler registered to collect data\n\n\n var stopHandler = function stopHandler() {\n var now = moment();\n var last;\n var data = {\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n var args = slice.call(arguments);\n last = _.findLast(immutableQueue, {\n type: probe.name,\n marker: 'start'\n });\n\n if (last && !_.findLast(immutableQueue, {\n type: probe.name,\n marker: 'end',\n id: last.id\n })) {\n data.id = last.id;\n data.marker = 'end';\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(args));\n }\n\n overseer.push(data);\n }\n }; //fallback\n\n\n if (!probe.latency) {\n return collectEvent(probe);\n }\n\n _.forEach(probe.startEvents, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(startHandler, eventName));\n });\n\n _.forEach(probe.stopEvents, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(stopHandler, eventName));\n });\n } //argument validation\n\n\n if (!_.isPlainObject(runner) || !_.isFunction(runner.init) || !_.isFunction(runner.on)) {\n throw new TypeError('Please set a test runner');\n }\n /**\n * @typedef {probeOverseer}\n */\n\n\n overseer = {\n /**\n * Add a new probe\n * @param {Object} probe\n * @param {String} probe.name - the probe name\n * @param {Boolean} [probe.latency = false] - simple or latency mode\n * @param {String[]} [probe.events] - the list of events to listen (simple mode)\n * @param {String[]} [probe.startEvents] - the list of events to mark the start (lantency mode)\n * @param {String[]} [probe.stopEvents] - the list of events to mark the end (latency mode)\n * @param {Function} [probe.capture] - lambda fn to define the data context, it receive the test runner and the event parameters\n * @returns {probeOverseer} chains\n * @throws TypeError if the probe is not well formatted\n */\n add: function add(probe) {\n // probe structure strict validation\n if (!_.isPlainObject(probe)) {\n throw new TypeError('A probe is a plain object');\n }\n\n if (!_.isString(probe.name) || _.isEmpty(probe.name)) {\n throw new TypeError('A probe must have a name');\n }\n\n if (_.where(probes, {\n name: probe.name\n }).length > 0) {\n throw new TypeError('A probe with this name is already regsitered');\n }\n\n if (probe.latency) {\n if (_.isString(probe.startEvents) && !_.isEmpty(probe.startEvents)) {\n probe.startEvents = [probe.startEvents];\n }\n\n if (_.isString(probe.stopEvents) && !_.isEmpty(probe.stopEvents)) {\n probe.stopEvents = [probe.stopEvents];\n }\n\n if (!probe.startEvents.length || !probe.stopEvents.length) {\n throw new TypeError('Latency based probes must have startEvents and stopEvents defined');\n } //if already started we register the events on addition\n\n\n if (started) {\n collectLatencyEvent(probe);\n }\n } else {\n if (_.isString(probe.events) && !_.isEmpty(probe.events)) {\n probe.events = [probe.events];\n }\n\n if (!_.isArray(probe.events) || probe.events.length === 0) {\n throw new TypeError('A probe must define events');\n } //if already started we register the events on addition\n\n\n if (started) {\n collectEvent(probe);\n }\n }\n\n probes.push(probe);\n return this;\n },\n\n /**\n * Get the time entries queue\n * @returns {Promise} with the data in parameterj\n */\n getQueue: function getQueue() {\n return getStorage().then(function (storage) {\n return storage.getItem('queue');\n });\n },\n\n /**\n * Get the list of defined probes\n * @returns {Object[]} the probes collection\n */\n getProbes: function getProbes() {\n return probes;\n },\n\n /**\n * Push a time entry to the queue\n * @param {Object} entry - the time entry\n */\n push: function push(entry) {\n getStorage().then(function (storage) {\n //ensure the queue is pushed to the store consistently and atomically\n writing = writing.then(function () {\n queue.push(entry);\n immutableQueue.push(entry);\n return storage.setItem('queue', queue);\n });\n });\n },\n\n /**\n * Flush the queue and get the entries\n * @returns {Promise} with the data in parameter\n */\n flush: function flush() {\n return new Promise(function (resolve) {\n getStorage().then(function (storage) {\n writing = writing.then(function () {\n return storage.getItem('queue').then(function (flushed) {\n queue = [];\n return storage.setItem('queue', queue).then(function () {\n resolve(flushed);\n });\n });\n });\n });\n });\n },\n\n /**\n * Start the probes\n * @returns {Promise} once started\n */\n start: function start() {\n return getStorage().then(function (storage) {\n return storage.getItem('queue').then(function (savedQueue) {\n if (_.isArray(savedQueue)) {\n queue = savedQueue;\n immutableQueue = savedQueue;\n }\n\n _.forEach(probes, collectEvent);\n\n started = true;\n });\n });\n },\n\n /**\n * Stop the probes\n * Be carefull, stop will also clear the store and the queue\n * @returns {Promise} once stopped\n */\n stop: function stop() {\n started = false;\n\n _.forEach(probes, function (probe) {\n var eventNs = `.probe-${probe.name}`;\n\n var removeHandler = function removeHandler(eventName) {\n runner.off(eventName + eventNs);\n };\n\n _.forEach(probe.startEvents, removeHandler);\n\n _.forEach(probe.stopEvents, removeHandler);\n\n _.forEach(probe.events, removeHandler);\n });\n\n queue = [];\n immutableQueue = [];\n return getStorage().then(function (storage) {\n return storage.removeItem('queue').then(resetStorage);\n });\n }\n };\n return overseer;\n }\n\n return probeOverseerFactory;\n\n});\n\n","define('taoTests/runner/runner',['lodash', 'core/eventifier', 'core/providerRegistry', 'taoTests/runner/dataHolder'], function (_, eventifier, providerRegistry, dataHolderFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;\n providerRegistry = providerRegistry && Object.prototype.hasOwnProperty.call(providerRegistry, 'default') ? providerRegistry['default'] : providerRegistry;\n dataHolderFactory = dataHolderFactory && Object.prototype.hasOwnProperty.call(dataHolderFactory, 'default') ? dataHolderFactory['default'] : dataHolderFactory;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2015-2020 (original work) Open Assessment Technologies SA ;\n */\n /**\n * Builds an instance of the QTI test runner\n *\n * @param {String} providerName\n * @param {Function[]} pluginFactories\n * @param {Object} config\n * @param {String} config.serviceCallId - the identifier of the test session\n * @param {String} [config.testDefinition] - the identifier of the test definition\n * @param {String} [config.testCompilation] - the identifier of the compiled test\n * @param {Object} config.options - the test runner configuration options\n * @param {Object} config.options.plugins - the plugins configuration\n * @param {jQueryElement} [config.renderTo] - the dom element that is going to holds the test content (item, rubick, etc)\n * @returns {runner}\n */\n\n function testRunnerFactory(providerName) {\n let pluginFactories = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n /**\n * @type {Object} The test runner instance\n */\n let runner;\n /**\n * @type {Map} Contains the test runner data\n */\n\n let dataHolder;\n /**\n * @type {Object} the registered plugins\n */\n\n const plugins = {};\n /**\n * @type {Object} the test of the runner\n */\n\n const states = {\n init: false,\n ready: false,\n render: false,\n finish: false,\n destroy: false\n };\n /**\n * @type {Object} keeps the states of the items\n */\n\n let itemStates = {};\n /**\n * The selected test runner provider\n */\n\n const provider = testRunnerFactory.getProvider(providerName);\n /**\n * Keep the area broker instance\n * @see taoTests/runner/areaBroker\n */\n\n let areaBroker;\n /**\n * Keep the proxy instance\n * @see taoTests/runner/proxy\n */\n\n let proxy;\n /**\n * Keep the instance of the probes overseer\n * @see taoTests/runner/probeOverseer\n */\n\n let probeOverseer;\n /**\n * Keep the instance of a testStore\n * @see taoTests/runner/testStore\n */\n\n let testStore;\n /**\n * Run a method of the provider (by delegation)\n *\n * @param {String} method - the method to run\n * @param {...} args - rest parameters given to the provider method\n * @returns {Promise} so provider can do async stuffs\n */\n\n function providerRun(method) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n return new Promise(resolve => {\n if (!_.isFunction(provider[method])) {\n return resolve();\n }\n\n return resolve(provider[method].apply(runner, args));\n });\n }\n /**\n * Run a method in all plugins\n *\n * @param {String} method - the method to run\n * @returns {Promise} once that resolve when all plugins are done\n */\n\n\n function pluginRun(method) {\n var execStack = [];\n\n _.forEach(runner.getPlugins(), plugin => {\n if (_.isFunction(plugin[method])) {\n execStack.push(plugin[method]());\n }\n });\n\n return Promise.all(execStack);\n }\n /**\n * Trigger error event\n * @param {Error|String} err - the error\n * @fires runner#error\n */\n\n\n function reportError(err) {\n runner.trigger('error', err);\n }\n /**\n * Defines the test runner\n *\n * @type {runner}\n */\n\n\n runner = eventifier({\n /**\n * Initialize the runner\n * - instantiate the plugins\n * - provider init\n * - plugins init\n * - call render\n * @fires runner#init\n * @returns {runner} chains\n */\n init() {\n if (!dataHolder) {\n dataHolder = this.getDataHolder();\n } //instantiate the plugins first\n\n\n _.forEach(pluginFactories, pluginFactory => {\n const plugin = pluginFactory(runner, this.getAreaBroker());\n plugins[plugin.getName()] = plugin;\n });\n\n providerRun('install').then(_.partial(providerRun, 'loadPersistentStates')).then(_.partial(pluginRun, 'install')).then(_.partial(providerRun, 'init')).then(_.partial(pluginRun, 'init')).then(() => {\n this.setState('init', true).off('init.internal').after('init.internal', () => this.render()).trigger('init');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Render the runner\n * - provider render\n * - plugins render\n * @fires runner#render\n * @fires runner#ready\n * @returns {runner} chains\n */\n render() {\n providerRun('render').then(() => pluginRun('render')).then(() => {\n this.setState('ready', true).trigger('render').trigger('ready');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Load an item\n * - provider loadItem, resolve or return the itemData\n * - plugins loadItem\n * - call renderItem\n * @param {*} itemRef - something that let you identify the item to load\n * @fires runner#loaditem\n * @returns {runner} chains\n */\n loadItem(itemRef) {\n providerRun('loadItem', itemRef).then(itemData => {\n this.setItemState(itemRef, 'loaded', true).off('loaditem.internal').after('loaditem.internal', () => this.renderItem(itemRef, itemData)).trigger('loaditem', itemRef, itemData);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Render an item\n * - provider renderItem\n * - plugins renderItem\n * @param {Object} itemRef\n * @param {Object} itemData - the loaded item data\n * @fires runner#renderitem\n * @returns {runner} chains\n */\n renderItem(itemRef, itemData) {\n providerRun('renderItem', itemRef, itemData).then(() => {\n this.setItemState(itemRef, 'ready', true).trigger('renderitem', itemRef, itemData);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Unload an item (for example to destroy the item)\n * - provider unloadItem\n * - plugins unloadItem\n * @param {*} itemRef - something that let you identify the item to unload\n * @fires runner#unloaditem\n * @returns {runner} chains\n */\n unloadItem(itemRef) {\n providerRun('unloadItem', itemRef).then(() => {\n itemStates = _.omit(itemStates, itemRef);\n this.trigger('unloaditem', itemRef);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Disable an item\n * - provider disableItem\n * @param {*} itemRef - something that let you identify the item\n * @fires runner#disableitem\n * @returns {runner} chains\n */\n disableItem(itemRef) {\n if (!this.getItemState(itemRef, 'disabled')) {\n providerRun('disableItem', itemRef).then(() => {\n this.setItemState(itemRef, 'disabled', true).trigger('disableitem', itemRef);\n }).catch(reportError);\n }\n\n return this;\n },\n\n /**\n * Enable an item\n * - provider enableItem\n * @param {*} itemRef - something that let you identify the item\n * @fires runner#disableitem\n * @returns {runner} chains\n */\n enableItem(itemRef) {\n if (this.getItemState(itemRef, 'disabled')) {\n providerRun('enableItem', itemRef).then(() => {\n this.setItemState(itemRef, 'disabled', false).trigger('enableitem', itemRef);\n }).catch(reportError);\n }\n\n return this;\n },\n\n /**\n * When the test is terminated\n * - provider finish\n * - plugins finsh\n * @fires runner#finish\n * @returns {runner} chains\n */\n finish() {\n providerRun('finish').then(() => pluginRun('finish')).then(() => {\n this.setState('finish', true).trigger('finish');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Flushes the runner\n * - provider flush\n * - plugins flush\n * @fires runner#flush\n * @returns {runner} chains\n */\n flush() {\n providerRun('flush').then(() => pluginRun('flush')).then(() => {\n this.setState('flush', true).trigger('flush');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Destroy\n * - provider destroy\n * - plugins destroy\n * @fires runner#destroy\n * @returns {runner} chains\n */\n destroy() {\n providerRun('destroy').then(() => pluginRun('destroy')).then(() => {\n if (proxy) {\n return proxy.destroy();\n }\n }).then(() => {\n this.setTestContext({}).setTestMap({}).setState('destroy', true).trigger('destroy');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Get the whole test runner configuration\n * @returns {Object} the config\n */\n getConfig() {\n return config || {};\n },\n\n /**\n * Get the options from the configuration parameters, (feature flags, parameter values, etc.)\n *\n * Alias to getConfig().options\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @returns {Object} the configuration options\n */\n getOptions() {\n return this.getConfig().options || {};\n },\n\n /**\n * Get the runner pugins\n * @returns {plugin[]} the plugins\n */\n getPlugins() {\n return plugins;\n },\n\n /**\n * Get a plugin\n * @param {String} name - the plugin name\n * @returns {plugin} the plugin\n */\n getPlugin(name) {\n return plugins[name];\n },\n\n /**\n * Get the configuration of the plugins\n *\n * Alias to getConfig().options.plugins\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @returns {Object} the configuration options\n */\n getPluginsConfig() {\n return this.getOptions().plugins || {};\n },\n\n /**\n * Get the configuration of a given plugin\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @param {String} pluginName - the name of the plugin\n * @returns {Object} the configuration options of the plugin\n */\n getPluginConfig(pluginName) {\n if (pluginName && plugins[pluginName]) {\n const pluginsConfig = this.getPluginsConfig();\n\n if (pluginsConfig[pluginName]) {\n return pluginsConfig[pluginName];\n }\n }\n\n return {};\n },\n\n /**\n * Get the area broker, load it if not present\n *\n * @returns {areaBroker} the areaBroker\n */\n getAreaBroker() {\n if (!areaBroker) {\n areaBroker = provider.loadAreaBroker.call(this);\n }\n\n return areaBroker;\n },\n\n /**\n * Get the proxy, load it if not present\n *\n * @returns {proxy} the proxy\n */\n getProxy() {\n if (!proxy) {\n if (!_.isFunction(provider.loadProxy)) {\n throw new Error('The provider does not have a loadProxy method');\n }\n\n proxy = provider.loadProxy.call(this);\n proxy.on('error', error => this.trigger('error', error));\n proxy.install(this.getDataHolder());\n }\n\n return proxy;\n },\n\n /**\n * Get the probeOverseer, and load it if not present\n *\n * @returns {probeOverseer} the probe overseer\n */\n getProbeOverseer() {\n if (!probeOverseer && _.isFunction(provider.loadProbeOverseer)) {\n probeOverseer = provider.loadProbeOverseer.call(this);\n }\n\n return probeOverseer;\n },\n\n /**\n * Get the testStore, and load it if not present\n *\n * @returns {testStore} the testStore instance\n */\n getTestStore() {\n if (!testStore && _.isFunction(provider.loadTestStore)) {\n testStore = provider.loadTestStore.call(this);\n }\n\n return testStore;\n },\n\n /**\n * Get a plugin store.\n * It's a convenience method that calls testStore.getStore\n * @param {String} name - the name of store, usually the plugin name.\n *\n * @returns {Promise} the plugin store\n */\n getPluginStore(name) {\n const loadedStore = this.getTestStore();\n\n if (!loadedStore || !_.isFunction(loadedStore.getStore)) {\n return Promise.reject(new Error('Please configure a testStore via loadTestStore to be able to get a plugin store'));\n }\n\n return this.getTestStore().getStore(name);\n },\n\n /**\n * Check a runner state\n *\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n */\n getState(name) {\n return !!states[name];\n },\n\n /**\n * Define a runner state\n *\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {runner} chains\n * @throws {TypeError} if the state name is not a valid string\n */\n setState(name, active) {\n if (!_.isString(name) || _.isEmpty(name)) {\n throw new TypeError('The state must have a name');\n }\n\n states[name] = !!active;\n return this;\n },\n\n /**\n * Checks a runner persistent state\n * - provider getPersistentState\n *\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n */\n getPersistentState(name) {\n let state;\n\n if (_.isFunction(provider.getPersistentState)) {\n state = provider.getPersistentState.call(runner, name);\n }\n\n return !!state;\n },\n\n /**\n * Defines a runner persistent state\n * - provider setPersistentState\n *\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {Promise} Returns a promise that:\n * - will be resolved once the state is fully stored\n * - will be rejected if any error occurs or if the state name is not a valid string\n */\n setPersistentState(name, active) {\n let stored;\n\n if (!_.isString(name) || _.isEmpty(name)) {\n stored = Promise.reject(new TypeError('The state must have a name'));\n } else {\n stored = providerRun('setPersistentState', name, !!active);\n }\n\n stored.catch(reportError);\n return stored;\n },\n\n /**\n * Check an item state\n *\n * @param {*} itemRef - something that let you identify the item\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n *\n * @throws {TypeError} if there is no itemRef nor name\n */\n getItemState(itemRef, name) {\n if (_.isEmpty(itemRef) || _.isEmpty(name)) {\n throw new TypeError('The state is identified by an itemRef and a name');\n }\n\n return !!(itemStates[itemRef] && itemStates[itemRef][name]);\n },\n\n /**\n * Check an item state\n *\n * @param {*} itemRef - something that let you identify the item\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {runner} chains\n *\n * @throws {TypeError} if there is no itemRef nor name\n */\n setItemState(itemRef, name, active) {\n if (_.isEmpty(itemRef) || _.isEmpty(name)) {\n throw new TypeError('The state is identified by an itemRef and a name');\n }\n\n itemStates[itemRef] = itemStates[itemRef] || {\n loaded: false,\n ready: false,\n disabled: false\n };\n itemStates[itemRef][name] = !!active;\n return this;\n },\n\n /**\n * Get the test data/definition\n * @deprecated\n * @returns {Object} the test data\n */\n getTestData() {\n return dataHolder && dataHolder.get('testData');\n },\n\n /**\n * Set the test data/definition\n * @deprecated\n * @param {Object} testData - the test data\n * @returns {runner} chains\n */\n setTestData(testData) {\n if (dataHolder && _.isPlainObject(testData)) {\n dataHolder.set('testData', testData);\n }\n\n return this;\n },\n\n /**\n * Get the test context/state\n * @returns {Object} the test context\n */\n getTestContext() {\n return dataHolder && dataHolder.get('testContext');\n },\n\n /**\n * Set the test context/state\n * @param {Object} testContext - the context to set\n * @returns {runner} chains\n */\n setTestContext(testContext) {\n if (dataHolder && _.isPlainObject(testContext)) {\n dataHolder.set('testContext', testContext);\n }\n\n return this;\n },\n\n /**\n * Get the test items map\n * @returns {Object} the test map\n */\n getTestMap() {\n return dataHolder && dataHolder.get('testMap');\n },\n\n /**\n * Set the test items map\n * @param {Object} testMap - the map to set\n * @returns {runner} chains\n */\n setTestMap(testMap) {\n if (dataHolder && _.isPlainObject(testMap)) {\n dataHolder.set('testMap', testMap);\n }\n\n return this;\n },\n\n /**\n * Get the data holder\n * @returns {dataHolder}\n */\n getDataHolder() {\n if (!dataHolder) {\n if (_.isFunction(provider.loadDataHolder)) {\n dataHolder = provider.loadDataHolder.call(this);\n } else {\n dataHolder = dataHolderFactory();\n }\n }\n\n return dataHolder;\n },\n\n /**\n * Move next alias\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n next(scope) {\n if (_.isFunction(provider.next)) {\n return providerRun('next', scope);\n } //backward compat\n\n\n this.trigger('move', 'next', scope);\n return this;\n },\n\n /**\n * Move previous alias\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n previous(scope) {\n if (_.isFunction(provider.previous)) {\n return providerRun('previous', scope);\n } //backward compat\n\n\n this.trigger('move', 'previous', scope);\n return this;\n },\n\n /**\n * Move to alias\n * @param {String|Number} position - where to jump\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n jump(position, scope) {\n if (_.isFunction(provider.jump)) {\n return providerRun('jump', position, scope);\n } //backward compat\n\n\n this.trigger('move', 'jump', scope, position);\n return this;\n },\n\n /**\n * Skip alias\n * @param {String|*} [scope] - the movement scope\n * @param {String|*} [direction] - next/previous/jump\n * @param {Number|*} [ref] - the item ref\n * @fires runner#skip\n * @returns {runner} chains\n */\n skip(scope, direction, ref) {\n if (_.isFunction(provider.skip)) {\n return providerRun('skip', scope, direction, ref);\n } //backward compat\n\n\n this.trigger('skip', scope, direction, ref);\n return this;\n },\n\n /**\n * Exit the test\n * @param {String|*} [why] - reason the test is exited\n * @fires runner#exit\n * @returns {runner} chains\n */\n exit(why) {\n if (_.isFunction(provider.exit)) {\n return providerRun('exit', why);\n } //backward compat\n\n\n this.trigger('exit', why);\n return this;\n },\n\n /**\n * Pause the current execution\n * @fires runner#pause\n * @returns {runner} chains\n */\n pause() {\n if (_.isFunction(provider.pause)) {\n if (!this.getState('pause')) {\n this.setState('pause', true);\n return providerRun('pause');\n }\n\n return Promise.resolve();\n } //backward compat\n\n\n if (!this.getState('pause')) {\n this.setState('pause', true).trigger('pause');\n }\n\n return this;\n },\n\n /**\n * Resume a paused test\n * @fires runner#pause\n * @returns {runner} chains\n */\n resume() {\n if (_.isFunction(provider.resume)) {\n if (this.getState('pause')) {\n this.setState('pause', false);\n return providerRun('resume');\n }\n\n return Promise.resolve();\n } //backward compat\n\n\n if (this.getState('pause') === true) {\n this.setState('pause', false).trigger('resume');\n }\n\n return this;\n },\n\n /**\n * Notify a test timeout\n * @param {String} scope - The scope where the timeout occurred\n * @param {String} ref - The reference to the place where the timeout occurred\n * @param {Object} [timer] - The timer's descriptor, if any\n * @fires runner#timeout\n * @returns {runner} chains\n */\n timeout(scope, ref, timer) {\n if (_.isFunction(provider.timeout)) {\n return providerRun('timeout', scope, ref, timer);\n } //backward compat\n\n\n this.trigger('timeout', scope, ref, timer);\n return this;\n }\n\n });\n runner.on('move', function () {\n this.trigger(...arguments);\n }).after('destroy', function destroyCleanUp() {\n if (dataHolder) {\n dataHolder.clear();\n }\n\n areaBroker = null;\n proxy = null;\n probeOverseer = null;\n testStore = null;\n });\n return runner;\n } //bind the provider registration capabilities to the testRunnerFactory\n\n\n var runner = providerRegistry(testRunnerFactory, function validateProvider(provider) {\n //mandatory methods\n if (!_.isFunction(provider.loadAreaBroker)) {\n throw new TypeError('The runner provider MUST have a method that returns an areaBroker');\n }\n\n return true;\n });\n\n return runner;\n\n});\n\n","define('taoTests/runner/proxy',['lodash', 'async', 'core/delegator', 'core/eventifier', 'core/providerRegistry', 'core/tokenHandler', 'core/connectivity'], function (_, async, delegator, eventifier, providerRegistry, tokenHandlerFactory, connectivity) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n async = async && Object.prototype.hasOwnProperty.call(async, 'default') ? async['default'] : async;\n delegator = delegator && Object.prototype.hasOwnProperty.call(delegator, 'default') ? delegator['default'] : delegator;\n eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;\n providerRegistry = providerRegistry && Object.prototype.hasOwnProperty.call(providerRegistry, 'default') ? providerRegistry['default'] : providerRegistry;\n tokenHandlerFactory = tokenHandlerFactory && Object.prototype.hasOwnProperty.call(tokenHandlerFactory, 'default') ? tokenHandlerFactory['default'] : tokenHandlerFactory;\n connectivity = connectivity && Object.prototype.hasOwnProperty.call(connectivity, 'default') ? connectivity['default'] : connectivity;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n var _defaults = {};\n var _slice = [].slice;\n /**\n * Defines a proxy bound to a particular adapter\n *\n * @param {String} proxyName - The name of the proxy adapter to use in the returned proxy instance\n * @param {Object} [config] - Some optional config depending of implementation,\n * this object will be forwarded to the proxy adapter\n * @returns {proxy} - The proxy instance, bound to the selected proxy adapter\n */\n\n function proxyFactory(proxyName, config) {\n var proxy, delegateProxy, communicator, communicatorPromise;\n var testDataHolder;\n var extraCallParams = {};\n var proxyAdapter = proxyFactory.getProvider(proxyName);\n\n var initConfig = _.defaults(config || {}, _defaults);\n\n var tokenHandler = tokenHandlerFactory();\n var middlewares = {};\n var initialized = false;\n var onlineStatus = connectivity.isOnline();\n /**\n * Gets parameters merged with extra parameters\n * @param {Object} [params]\n * @returns {Object}\n */\n\n function getParams(params) {\n var mergedParams = _.merge({}, params, extraCallParams);\n\n extraCallParams = {};\n return mergedParams;\n }\n /**\n * Gets the aggregated list of middlewares for a particular queue name\n * @param {String} queue - The name of the queue to get\n * @returns {Array}\n */\n\n\n function getMiddlewares(queue) {\n var list = middlewares[queue] || [];\n\n if (middlewares.all) {\n list = list.concat(middlewares.all);\n }\n\n return list;\n }\n /**\n * Applies the list of registered middlewares onto the received response\n * @param {Object} request - The request descriptor\n * @param {String} request.command - The name of the requested command\n * @param {Object} request.params - The map of provided parameters\n * @param {Object} response The response descriptor\n * @param {String} response.status The status of the response, can be either 'success' or 'error'\n * @param {Object} response.data The full response data\n * @returns {Promise}\n */\n\n\n function applyMiddlewares(request, response) {\n // wrap each middleware to provide parameters\n var list = _.map(getMiddlewares(request.command), function (middleware) {\n return function (next) {\n middleware(request, response, next);\n };\n }); // apply each middleware in series, then resolve or reject the promise\n\n\n return new Promise(function (resolve, reject) {\n async.series(list, function (err) {\n // handle implicit error from response descriptor\n if (!err && 'error' === response.status) {\n err = response.data;\n }\n\n if (err) {\n reject(err);\n } else {\n proxy.trigger('receive', response.data, 'proxy');\n resolve(response.data);\n }\n });\n });\n }\n /**\n * Delegates the call to the proxy implementation and apply the middleware.\n *\n * @param {String} fnName - The name of the delegated method to call\n * @returns {Promise} - The delegated method must return a promise\n * @private\n * @throws Error\n */\n\n\n function delegate(fnName) {\n var request = {\n command: fnName,\n params: _slice.call(arguments, 1)\n };\n\n if (!initialized && !_.contains(['install', 'init'], fnName)) {\n return Promise.reject(new Error('Proxy is not properly initialized or has been destroyed!'));\n }\n\n return delegateProxy.apply(null, arguments).then(function (data) {\n // If the delegate call succeed the proxy is initialized.\n // Place this set here to avoid to wrap the init() into another promise.\n initialized = true; // handle successful request\n\n return applyMiddlewares(request, {\n status: 'success',\n data: data\n });\n }).catch(function (data) {\n // handle failed request\n return applyMiddlewares(request, {\n status: 'error',\n data: data\n });\n });\n }\n /**\n * Defines the test runner proxy\n * @typedef {proxy}\n */\n\n\n proxy = eventifier({\n /**\n * Add a middleware\n * @param {String} [command] The command queue in which add the middleware (default: 'all')\n * @param {Function...} callback - A middleware callback. Must accept 3 parameters: request, response, next.\n * @returns {proxy}\n */\n use: function use(command) {\n var queue = command && _.isString(command) ? command : 'all';\n var list = middlewares[queue] || [];\n middlewares[queue] = list;\n\n _.each(arguments, function (cb) {\n if (_.isFunction(cb)) {\n list.push(cb);\n }\n });\n\n return this;\n },\n\n /**\n * Install the proxy.\n * This step let's attach some features before the proxy reallys starts (before init).\n *\n * @param {Map} dataHolder - the test runner data holder\n * @returns {*}\n */\n install: function install(dataHolder) {\n if (dataHolder) {\n testDataHolder = dataHolder;\n }\n\n return delegate('install', initConfig);\n },\n\n /**\n * Initializes the proxy\n * @param {Object} [params] - An optional list of parameters\n * @returns {Promise} - Returns a promise. The proxy will be fully initialized on resolve.\n * Any error will be provided if rejected.\n * @fires init\n */\n init: function init(params) {\n /**\n * @event proxy#init\n * @param {Promise} promise\n * @param {Object} config\n * @param {Object} params\n */\n return delegate('init', initConfig, getParams(params));\n },\n\n /**\n * Uninstalls the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully uninstalled on resolve.\n * Any error will be provided if rejected.\n * @fires destroy\n */\n destroy: function destroy() {\n /**\n * @event proxy#destroy\n * @param {Promise} promise\n */\n return delegate('destroy').then(function () {\n // The proxy is now destroyed. A call to init() is mandatory to be able to use it again.\n initialized = false; // a communicator has been invoked and...\n\n if (communicatorPromise) {\n return new Promise(function (resolve, reject) {\n function destroyCommunicator() {\n communicator.destroy().then(resolve).catch(reject);\n }\n\n communicatorPromise // ... has been loaded successfully, then destroy it\n .then(function () {\n destroyCommunicator();\n }) // ...has failed to be loaded, maybe no need to destroy it\n .catch(function () {\n if (communicator) {\n destroyCommunicator();\n } else {\n resolve();\n }\n });\n });\n }\n });\n },\n\n /**\n * Get the map that holds the test data\n * @returns {Map|Object} the dataHolder\n */\n getDataHolder: function getDataHolder() {\n return testDataHolder;\n },\n\n /**\n * Set the proxy as online\n * @returns {proxy} chains\n * @fires {proxy#reconnect}\n */\n setOnline: function setOnline() {\n if (this.isOffline()) {\n onlineStatus = true;\n this.trigger('reconnect');\n }\n\n return this;\n },\n\n /**\n * Set the proxy as offline\n * @param {String} [source] - source of the connectivity change\n * @returns {proxy} chains\n * @fires {proxy#disconnect}\n */\n setOffline: function setOffline(source) {\n if (this.isOnline()) {\n onlineStatus = false;\n this.trigger('disconnect', source);\n }\n\n return this;\n },\n\n /**\n * Are we online ?\n * @returns {Boolean}\n */\n isOnline: function isOnline() {\n return onlineStatus;\n },\n\n /**\n * Are we offline\n * @returns {Boolean}\n */\n isOffline: function isOffline() {\n return !onlineStatus;\n },\n\n /**\n * For the proxy a connection error is an error object with\n * source 'network', a 0 code and a false sent attribute.\n *\n * @param {Error|Object} err - the error to verify\n * @returns {Boolean} true if a connection error.\n */\n isConnectivityError: function isConnectivityError(err) {\n return _.isObject(err) && err.source === 'network' && err.code === 0 && err.sent === false;\n },\n\n /**\n * Gets the security token handler\n * @returns {tokenHandler}\n */\n getTokenHandler: function getTokenHandler() {\n return tokenHandler;\n },\n\n /**\n * Checks if a communication channel has been requested.\n * @returns {Boolean}\n */\n hasCommunicator: function hasCommunicator() {\n return !!communicatorPromise;\n },\n\n /**\n * Gets access to the communication channel, load it if not present\n * @returns {Promise} Returns a promise that will resolve the communication channel\n */\n getCommunicator: function getCommunicator() {\n var self = this;\n\n if (!initialized) {\n return Promise.reject(new Error('Proxy is not properly initialized or has been destroyed!'));\n }\n\n if (!communicatorPromise) {\n communicatorPromise = new Promise(function (resolve, reject) {\n if (_.isFunction(proxyAdapter.loadCommunicator)) {\n communicator = proxyAdapter.loadCommunicator.call(self);\n\n if (communicator) {\n communicator.before('error', function (e, err) {\n if (self.isConnectivityError(err)) {\n self.setOffline('communicator');\n }\n }).on('error', function (err) {\n self.trigger('error', err);\n }).on('receive', function (response) {\n self.setOnline();\n self.trigger('receive', response, 'communicator');\n }).init().then(function () {\n return communicator.open().then(function () {\n resolve(communicator);\n }).catch(reject);\n }).catch(reject);\n } else {\n reject(new Error('No communicator has been set up!'));\n }\n } else {\n reject(new Error('The proxy provider does not have a loadCommunicator method'));\n }\n });\n }\n\n return communicatorPromise;\n },\n\n /**\n * Registers a listener on a particular channel\n * @param {String} name - The name of the channel to listen\n * @param {Function} handler - The listener callback\n * @returns {proxy}\n * @throws TypeError if the name is missing or the handler is not a callback\n */\n channel: function channel(name, handler) {\n if (!_.isString(name) || name.length <= 0) {\n throw new TypeError('A channel must have a name');\n }\n\n if (!_.isFunction(handler)) {\n throw new TypeError('A handler must be attached to a channel');\n }\n\n this.getCommunicator().then(function (communicatorInstance) {\n communicatorInstance.channel(name, handler);\n }) // just an empty catch to avoid any error to be displayed in the console when the communicator is not enabled\n .catch(_.noop);\n this.on(`channel-${name}`, handler);\n return this;\n },\n\n /**\n * Sends an messages through the communication implementation.\n * @param {String} channel - The name of the communication channel to use\n * @param {Object} message - The message to send\n * @returns {Promise} The delegated provider's method must return a promise\n */\n send: function send(channel, message) {\n return this.getCommunicator().then(function (communicatorInstance) {\n return communicatorInstance.send(channel, message);\n });\n },\n\n /**\n * Add extra parameters that will be added to the init or the next callTestAction or callItemAction\n * This enables plugins to place parameters for next calls\n * @param {Object} params - the extra parameters\n * @returns {proxy}\n */\n addCallActionParams: function addCallActionParams(params) {\n if (_.isPlainObject(params)) {\n _.merge(extraCallParams, params);\n }\n\n return this;\n },\n\n /**\n * Gets the test definition data\n * @deprecated\n *\n * @returns {Promise} - Returns a promise. The test definition data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getTestData\n */\n getTestData: function getTestData() {\n /**\n * @event proxy#getTestData\n * @param {Promise} promise\n */\n return delegate('getTestData');\n },\n\n /**\n * Gets the test context\n * @returns {Promise} - Returns a promise. The context object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestContext: function getTestContext() {\n /**\n * @event proxy#getTestContext\n * @param {Promise} promise\n */\n return delegate('getTestContext');\n },\n\n /**\n * Gets the test map\n * @returns {Promise} - Returns a promise. The test map object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestMap: function getTestMap() {\n /**\n * @event proxy#getTestMap\n * @param {Promise} promise\n */\n return delegate('getTestMap');\n },\n\n /**\n * Sends the test variables\n * @param {Object} variables\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later (default: false).\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires sendVariables\n */\n sendVariables: function sendVariables(variables, deferred) {\n /**\n * @event proxy#sendVariables\n * @param {Promise} promise\n */\n return delegate('sendVariables', variables, deferred);\n },\n\n /**\n * Calls an action related to the test\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later.\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires callTestAction\n */\n callTestAction: function callTestAction(action, params, deferred) {\n /**\n * @event proxy#callTestAction\n * @param {Promise} promise\n * @param {String} action\n * @param {Object} params\n */\n return delegate('callTestAction', action, getParams(params), deferred);\n },\n\n /**\n * Gets an item definition by its URI, also gets its current state\n * @param {String} uri - The URI of the item to get\n * @param {Object} [params] - addtional params to be appended\n * @returns {Promise} - Returns a promise. The item data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getItem\n */\n getItem: function getItem(uri, params) {\n /**\n * @event proxy#getItem\n * @param {Promise} promise\n * @param {String} uri\n */\n return delegate('getItem', uri, params);\n },\n\n /**\n * Submits the state and the response of a particular item\n * @param {String} uri - The URI of the item to update\n * @param {Object} state - The state to submit\n * @param {Object} response - The response object to submit\n * @param {Object} [params] - addtional params to be appended\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires submitItem\n */\n submitItem: function submitItem(uri, state, response, params) {\n /**\n * @event proxy#submitItem\n * @param {Promise} promise\n * @param {String} uri\n * @param {Object} state\n * @param {Object} response\n */\n return delegate('submitItem', uri, state, response, getParams(params));\n },\n\n /**\n * Calls an action related to a particular item\n * @param {String} uri - The URI of the item for which call the action\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later.\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires callItemAction\n */\n callItemAction: function callItemAction(uri, action, params, deferred) {\n /**\n * @event proxy#callItemAction\n * @param {Promise} promise\n * @param {String} uri\n * @param {String} action\n * @param {Object} params\n */\n return delegate('callItemAction', uri, action, getParams(params), deferred);\n },\n\n /**\n * Sends a telemetry signal\n * @param {String} uri - The URI of the item for which sends the telemetry signal\n * @param {String} signal - The name of the signal to send\n * @param {Object} [params] - Some optional parameters to join to the signal\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires telemetry\n */\n telemetry: function telemetry(uri, signal, params) {\n /**\n * @event proxy#telemetry\n * @param {Promise} promise\n * @param {String} uri\n * @param {String} signal\n * @param {Object} params\n */\n return delegate('telemetry', uri, signal, params);\n }\n }); //listen for connectivty changes\n\n connectivity.on('offline', function () {\n proxy.setOffline('device');\n }).on('online', function () {\n proxy.setOnline();\n }); // catch platform messages that come outside of the communicator component, then each is dispatched to the right channel\n\n proxy.on('message', function (channel, message) {\n this.trigger(`channel-${channel}`, message);\n }).use(function (request, response, next) {\n if (response.data && response.data.messages) {\n // receive server messages\n _.forEach(response.data.messages, function (msg) {\n if (msg.channel) {\n proxy.trigger('message', msg.channel, msg.message);\n } else {\n proxy.trigger('message', 'malformed', msg);\n }\n });\n }\n\n next();\n }) //detect failing request and change the online status\n .use(function (request, response, next) {\n if (proxy.isConnectivityError(response.data)) {\n proxy.setOffline('request');\n } else if (response.data && response.data.sent === true) {\n proxy.setOnline();\n }\n\n next();\n });\n delegateProxy = delegator(proxy, proxyAdapter, {\n name: 'proxy',\n wrapper: function pluginWrapper(response) {\n return Promise.resolve(response);\n }\n });\n return proxy;\n }\n\n var proxy = providerRegistry(proxyFactory);\n\n return proxy;\n\n});\n\n","define('taoTests/runner/providerLoader',['core/logger', 'core/providerLoader', 'core/pluginLoader', 'core/communicator', 'taoTests/runner/runner', 'taoTests/runner/proxy', 'taoItems/runner/api/itemRunner'], function (loggerFactory, providerLoader, pluginLoader, communicator, runner, proxy, itemRunner) { 'use strict';\n\n loggerFactory = loggerFactory && Object.prototype.hasOwnProperty.call(loggerFactory, 'default') ? loggerFactory['default'] : loggerFactory;\n providerLoader = providerLoader && Object.prototype.hasOwnProperty.call(providerLoader, 'default') ? providerLoader['default'] : providerLoader;\n pluginLoader = pluginLoader && Object.prototype.hasOwnProperty.call(pluginLoader, 'default') ? pluginLoader['default'] : pluginLoader;\n communicator = communicator && Object.prototype.hasOwnProperty.call(communicator, 'default') ? communicator['default'] : communicator;\n runner = runner && Object.prototype.hasOwnProperty.call(runner, 'default') ? runner['default'] : runner;\n proxy = proxy && Object.prototype.hasOwnProperty.call(proxy, 'default') ? proxy['default'] : proxy;\n itemRunner = itemRunner && Object.prototype.hasOwnProperty.call(itemRunner, 'default') ? itemRunner['default'] : itemRunner;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2019 Open Assessment Technologies SA ;\n */\n const logger = loggerFactory('taoTests/runner/loader');\n /**\n * @typedef {Object} provider - A provider is an object exposing a list of methods with respect to the API managed by the target.\n * @property {String} name - The name of the provider. It should be unique among all.\n * @property {Function} init - Each provider much expose at least a method `init()`\n * @property {Function} ... - Any other method the target is expecting\n */\n\n /**\n * Load the providers that match the registration\n * @param {Object} providers\n * @param {provider|provider[]} providers.runner\n * @param {provider|provider[]} [providers.proxy]\n * @param {provider|provider[]} [providers.communicator]\n * @param {provider|provider[]} [providers.plugins]\n * @param {Boolean} loadFromBundle - does the loader load the modules from the sources (dev mode) or the bundles\n * @returns {Promise} resolves with the loaded providers per provider type\n */\n\n function loadTestRunnerProviders() {\n let providers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let loadFromBundle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n /**\n * Default way to load the modules and register the providers\n * @param {Object[]} providersToLoad - the list of providers\n * @param {Object} target - a provider target (an object that use the providers), it needs to expose registerProvider\n * @returns {Promise} resolves with the target\n * @throws {TypeError} if the target is not a provider target\n */\n const loadAndRegisterProvider = function () {\n let providersToLoad = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n let target = arguments.length > 1 ? arguments[1] : undefined;\n\n if (!target || typeof target.registerProvider !== 'function') {\n throw new TypeError('Trying to register providers on a target that is not a provider API');\n }\n\n return providerLoader().addList(providersToLoad).load(loadFromBundle).then(loadedProviders => {\n loadedProviders.forEach(provider => target.registerProvider(provider.name, provider));\n return target;\n });\n };\n /**\n * Available provider registration\n */\n\n\n const registration = {\n runner() {\n let runnerProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(runnerProviders, runner);\n },\n\n itemRunner() {\n let itemRunnerProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return providerLoader().addList(itemRunnerProviders).load(loadFromBundle).then(loadedProviders => {\n loadedProviders.forEach(provider => itemRunner.register(provider.name, provider));\n return itemRunner;\n });\n },\n\n communicator() {\n let communicatorProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(communicatorProviders, communicator);\n },\n\n proxy() {\n let proxyProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(proxyProviders, proxy);\n },\n\n plugins() {\n let plugins = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return pluginLoader().addList(plugins).load(loadFromBundle);\n }\n\n };\n\n if (!loadFromBundle) {\n logger.warn('All modules will be loaded from sources');\n }\n\n return Promise.all(Object.keys(providers).map(providerType => {\n if (typeof registration[providerType] === 'function') {\n logger.debug(`Start to load and register the '${providerType}' providers`);\n const providersToLoad = Array.isArray(providers[providerType]) ? providers[providerType] : [providers[providerType]];\n return registration[providerType](providersToLoad).then(loaded => {\n logger.debug(`'${providerType}' providers are loaded and registered`);\n return {\n [providerType]: loaded\n };\n });\n } else {\n logger.warn(`Ignoring the '${providerType}' providers loading, no registration method found`);\n }\n })).then(results => results.reduce((acc, value) => Object.assign(acc, value), {})).catch(err => {\n logger.error(`Error in test runner providers and plugins loading : ${err.message}`);\n throw err;\n });\n }\n\n return loadTestRunnerProviders;\n\n});\n\n","define('taoTests/runner/proxy/sample',[],function () { 'use strict';\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n\n /**\n * @author Jean-Sébastien Conan \n */\n\n /**\n * Sample proxy definition\n * @type {Object}\n */\n var sampleProxy = {\n /**\n * Initializes the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully initialized on resolve.\n * Any error will be provided if rejected.\n */\n init: function init() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // do initialisation\n // once the proxy has been fully initialized notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Uninstalls the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully uninstalled on resolve.\n * Any error will be provided if rejected.\n */\n destroy: function destroy() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // do uninstall actions\n // once the proxy has been fully uninstalled notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets the test definition data\n * @param {Object} config - The config provided to the proxy factory\n * @returns {Promise} - Returns a promise. The test definition data will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestData: function getTestData() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the test definition data\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets the test context\n * @returns {Promise} - Returns a promise. The context object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestContext: function getTestContext() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the test context object\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Calls an action related to the test\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n */\n callTestAction: function callTestAction() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // call the action\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets an item definition by its URI, also gets its current state\n * @param {String} uri - The URI of the item to get\n * @returns {Promise} - Returns a promise. The item data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getItem\n */\n getItem: function getItem() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the definition data and the state of the item\n // once the item data is loaded provide the data by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Submits the state and the response of a particular item\n * @param {String} uri - The URI of the item to update\n * @param {Object} state - The state to submit\n * @param {Object} response - The response object to submit\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires submitItem\n */\n submitItem: function submitItem() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // submit the state and the response of the item\n // once the data has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Calls an action related to a particular item\n * @param {String} uri - The URI of the item for which call the action\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n */\n callItemAction: function callItemAction() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // call the action\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Sends a telemetry signal\n * @param {String} uri - The URI of the item for which sends the telemetry signal\n * @param {String} signal - The name of the signal to send\n * @param {Object} [params] - Some optional parameters to join to the signal\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires telemetry\n */\n telemetry: function telemetry() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // send the signal\n // once the signal has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n }\n };\n\n return sampleProxy;\n\n});\n\n","define('taoTests/runner/runnerComponent',['lodash', 'ui/component', 'taoTests/runner/runner', 'taoTests/runner/providerLoader', 'handlebars'], function (_, component, runnerFactory, providerLoader, Handlebars) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n component = component && Object.prototype.hasOwnProperty.call(component, 'default') ? component['default'] : component;\n runnerFactory = runnerFactory && Object.prototype.hasOwnProperty.call(runnerFactory, 'default') ? runnerFactory['default'] : runnerFactory;\n providerLoader = providerLoader && Object.prototype.hasOwnProperty.call(providerLoader, 'default') ? providerLoader['default'] : providerLoader;\n Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;\n\n var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {\n this.compilerInfo = [4,'>= 1.0.0'];\n helpers = this.merge(helpers, Handlebars.helpers); \n\n\n return \"
\\n\";\n });\n function runnerComponentTpl(data, options, asString) {\n var html = Template(data, options);\n return (asString || true) ? html : $(html);\n }\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technologies SA ;\n */\n /**\n * Validate required options from the configuration\n * @param {Object} config\n * @returns {Boolean} true if valid\n * @throws {TypeError} in case of validation failure\n */\n\n function validateTestRunnerConfiguration() {\n let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const requiredProperties = ['providers', 'options', 'serviceCallId'];\n\n if (typeof config !== 'object') {\n throw new TypeError(`The runner configuration must be an object, '${typeof config}' received`);\n }\n\n if (requiredProperties.some(property => typeof config[property] === 'undefined')) {\n throw new TypeError(`The runner configuration must contains at least the following properties : ${requiredProperties.join(',')}`);\n }\n\n return true;\n }\n /**\n * Get the selected provider if set or infer it from the providers list\n * @param {String} type - the type of provider (runner, communicator, proxy, etc.)\n * @param {Object} config\n * @returns {String} the selected provider for the given type\n */\n\n\n function getSelectedProvider() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'runner';\n let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (config.provider && config.provider[type]) {\n return config.provider[type];\n }\n\n if (config.providers && config.providers[type]) {\n const typeProviders = config.providers[type];\n\n if (typeof typeProviders === 'object' && (typeProviders.id || typeProviders.name)) {\n return typeProviders.id || typeProviders.name;\n }\n\n if (Array.isArray(typeProviders) && typeProviders.length > 0) {\n return typeProviders[0].id || typeProviders[0].name;\n }\n }\n\n return false;\n }\n /**\n * Wraps a test runner into a component\n * @param {jQuery|HTMLElement|String} container - The container in which renders the component\n * @param {Object} config - The component configuration options\n * @param {String} config.serviceCallId - The identifier of the test session\n * @param {Object} config.providers\n * @param {Object} config.options\n * @param {Boolean} [config.loadFromBundle=false] - do we load the modules from the bundles\n * @param {Boolean} [config.replace] - When the component is appended to its container, clears the place before\n * @param {Number|String} [config.width] - The width in pixels, or 'auto' to use the container's width\n * @param {Number|String} [config.height] - The height in pixels, or 'auto' to use the container's height\n * @param {Function} [template] - An optional template for the component\n * @returns {runnerComponent}\n */\n\n\n function runnerComponentFactory() {\n let container = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let template = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : runnerComponentTpl;\n let runner = null;\n let plugins = [];\n\n if (!container) {\n throw new TypeError('A container element must be defined to contain the runnerComponent');\n }\n\n validateTestRunnerConfiguration(config);\n /**\n * @typedef {runner} runnerComponent\n */\n\n const runnerComponent = component({\n /**\n * Gets the option's value\n * @param {String} name - the option key\n * @returns {*}\n */\n getOption(name) {\n return this.config.options[name];\n },\n\n /**\n * Gets the test runner\n * @returns {runner}\n */\n getRunner() {\n return runner;\n }\n\n }).setTemplate(template).on('init', function () {\n //load the defined providers for the runner, the proxy, the communicator, the plugins, etc.\n return providerLoader(config.providers, config.loadFromBundle).then(results => {\n if (results && results.plugins) {\n plugins = results.plugins;\n }\n\n this.render(container);\n this.hide();\n }).catch(err => this.trigger('error', err));\n }).on('render', function () {\n const runnerConfig = Object.assign(_.omit(this.config, ['providers']), {\n renderTo: this.getElement()\n });\n runnerConfig.provider = Object.keys(this.config.providers).reduce((acc, providerType) => {\n if (!acc[providerType] && providerType !== 'plugins') {\n acc[providerType] = getSelectedProvider(providerType, this.config);\n }\n\n return acc;\n }, runnerConfig.provider || {});\n runner = runnerFactory(runnerConfig.provider.runner, plugins, runnerConfig).on('ready', () => {\n _.defer(() => {\n this.setState('ready').trigger('ready', runner).show();\n });\n }).on('destroy', () => runner = null).spread(this, 'error').init();\n }).on('destroy', function () {\n var destroying = runner && runner.destroy();\n runner = null;\n return destroying;\n }).after('destroy', function () {\n this.removeAllListeners();\n });\n return runnerComponent.init(config);\n }\n\n return runnerComponentFactory;\n\n});\n\n","define('taoTests/runner/testStore',['lodash', 'core/store', 'core/logger'], function (_, store, loggerFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n store = store && Object.prototype.hasOwnProperty.call(store, 'default') ? store['default'] : store;\n loggerFactory = loggerFactory && Object.prototype.hasOwnProperty.call(loggerFactory, 'default') ? loggerFactory['default'] : loggerFactory;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technologies SA\n *\n */\n /**\n * The test store logger\n * @type {core/logger}\n */\n\n var logger = loggerFactory('taoQtiTest/runner/provider/testStore');\n /**\n * Database name prefix (suffixed by the test identifier)\n * to check if we use the fragmented mode\n * or the unified mode.\n * @type {String[]}\n */\n\n var legacyPrefixes = ['actions-', 'duration-', 'test-probe', 'timer-'];\n /**\n * List the available modes\n */\n\n var modes = {\n unified: 'unified',\n //one db per test, new mode\n fragmented: 'fragmented' //mutliple dbs per test, legacy mode\n\n };\n /**\n * Check and select the store mode.\n * If any of the \"legacyPrefixes\" store is found, we used the fragmented mode\n * otherwise we'll use the unified mode.\n * @param {String} testId\n * @param {Object} [preselectedBackend] - the storage backend\n * @returns {Promise} resolves with the mode of the current test\n */\n\n var selectStoreMode = function selectStoreMode(testId, preselectedBackend) {\n return store.getAll(function validate(storeName) {\n return _.some(legacyPrefixes, function (prefix) {\n return !_.isEmpty(storeName) && prefix + testId === storeName;\n });\n }, preselectedBackend).then(function (foundStores) {\n if (_.isArray(foundStores) && foundStores.length > 0) {\n return modes.fragmented;\n }\n\n return modes.unified;\n });\n };\n /**\n * Get the store for the given test\n *\n * @param {String} testId - unique test instance id\n * @returns {testStore} a 'wrapped' store instance\n * @param {Object} [preselectedBackend] - the storage backend (automatically selected by default)\n * @throws {TypeError} without a testId\n */\n\n\n function testStoreLoader(testId, preselectedBackend) {\n var storeNames = [];\n var volatiles = [];\n var changeTracking = {};\n var testMode;\n /**\n * Is the test using a unified store mode ?\n * @returns {Promise} true if unified\n */\n\n var isStoreModeUnified = function isStoreModeUnified() {\n if (_.isUndefined(testMode)) {\n return selectStoreMode(testId, preselectedBackend).then(function (result) {\n if (result && typeof modes[result] !== 'undefined') {\n testMode = result;\n } else {\n //use the unified mode by default\n testMode = modes.unified;\n }\n\n logger.debug(`Test store mode ${result} for ${testId}`);\n return result === modes.unified;\n });\n }\n\n return Promise.resolve(testMode === modes.unified);\n };\n\n if (_.isEmpty(testId)) {\n throw new TypeError('The store must be identified with a unique test identifier');\n }\n /**\n * Wraps a store and add the support of \"volatile\" storages\n * @typedef {Object} testStore\n */\n\n\n return {\n /**\n * Get a wrapped store instance, that let's you use multiple stores inside one store...\n * (or in multiple stores if the test is in legacy mode)\n * @param {String} storeName - the name of the sub store\n * @returns {Promise}\n */\n getStore: function getStore(storeName) {\n //call when the current storge has been changed\n //only if the store is set to track changes\n var trackChange = function trackChange() {\n if (_.isBoolean(changeTracking[storeName])) {\n changeTracking[storeName] = true;\n }\n };\n\n if (_.isEmpty(storeName)) {\n throw new TypeError('A store name must be provided to get the store');\n }\n\n if (!_.contains(storeNames, storeName)) {\n storeNames.push(storeName);\n }\n\n return isStoreModeUnified().then(function (isUnified) {\n var loadStore;\n\n if (isUnified) {\n loadStore = store(testId, preselectedBackend);\n } else {\n loadStore = store(`${storeName}-${testId}`, preselectedBackend);\n }\n\n return loadStore.then(function (loadedStore) {\n var keyPattern = new RegExp(`^${storeName}__`);\n\n var storeKey = function storeKey(key) {\n return isUnified ? `${storeName}__${key}` : key;\n };\n /**\n * The wrapped storage\n * @type {Object}\n */\n\n\n return {\n /**\n * Get an item with the given key\n * @param {String} key\n * @returns {Promise<*>} with the result in resolve, undefined if nothing\n */\n getItem: function getItem(key) {\n return loadedStore.getItem(storeKey(key));\n },\n\n /**\n * Get all store items\n * @returns {Promise} with a collection of items\n */\n getItems: function getItems() {\n if (isUnified) {\n return loadedStore.getItems().then(function (entries) {\n return _.transform(entries, function (acc, entry, key) {\n if (keyPattern.test(key)) {\n acc[key.replace(keyPattern, '')] = entry;\n }\n\n return acc;\n }, {});\n });\n } else {\n return loadedStore.getItems();\n }\n },\n\n /**\n * Set an item with the given key\n * @param {String} key - the item key\n * @param {*} value - the item value\n * @returns {Promise} with true in resolve if added/updated\n */\n setItem: function setItem(key, value) {\n trackChange();\n return loadedStore.setItem(storeKey(key), value);\n },\n\n /**\n * Remove an item with the given key\n * @param {String} key - the item key\n * @returns {Promise} with true in resolve if removed\n */\n removeItem: function removeItem(key) {\n trackChange();\n return loadedStore.removeItem(storeKey(key));\n },\n\n /**\n * Clear the current store\n * @returns {Promise} with true in resolve once cleared\n */\n clear: function clear() {\n trackChange();\n\n if (isUnified) {\n return loadedStore.getItems().then(function (entries) {\n _.forEach(entries, function (entry, key) {\n if (keyPattern.test(key)) {\n loadedStore.removeItem(key);\n }\n });\n });\n } else {\n return loadedStore.clear();\n }\n }\n };\n });\n });\n },\n\n /**\n * Define the given store as \"volatile\".\n * It means the store data can be revoked\n * if the user change browser for example\n * @param {String} storeName - the name of the store to set as volatile\n * @returns {testStore} chains\n */\n setVolatile: function setVolatile(storeName) {\n if (!_.contains(volatiles, storeName)) {\n volatiles.push(storeName);\n }\n\n return this;\n },\n\n /**\n * Check the given storeId. If different from the current stored identifier\n * we initiate the invalidation of the volatile data.\n * @param {String} storeId - the id to check\n * @returns {Promise} true if cleared\n */\n clearVolatileIfStoreChange: function clearVolatileIfStoreChange(storeId) {\n var self = this;\n var shouldClear = false;\n return store.getIdentifier(preselectedBackend).then(function (savedStoreId) {\n if (!_.isEmpty(storeId) && !_.isEmpty(savedStoreId) && savedStoreId !== storeId) {\n logger.info(`Storage change detected (${savedStoreId} != ${storeId}) => volatiles data wipe out !`);\n shouldClear = true;\n }\n\n return shouldClear;\n }).then(function (clear) {\n if (clear) {\n return self.clearVolatileStores();\n }\n\n return false;\n });\n },\n\n /**\n * Clear the storages marked as volatile\n * @returns {Promise} true if cleared\n */\n clearVolatileStores: function clearVolatileStores() {\n var self = this;\n var clearing = volatiles.map(function (storeName) {\n return self.getStore(storeName).then(function (storeInstance) {\n return storeInstance.clear();\n });\n });\n return Promise.all(clearing).then(function (results) {\n return results && results.length === volatiles.length;\n });\n },\n\n /**\n * Observe changes on the given store\n *\n * @param {String} storeName - the name of the store to observe\n * @returns {testStore} chains\n */\n startChangeTracking: function startChangeTracking(storeName) {\n changeTracking[storeName] = false;\n return this;\n },\n\n /**\n * Has the store some changes\n *\n * @param {String} storeName - the name of the store to set as volatile\n * @returns {Boolean} true if the given store has some changes\n */\n hasChanges: function hasChanges(storeName) {\n return changeTracking[storeName] === true;\n },\n\n /**\n * Reset the change listening\n *\n * @param {String} storeName - the name of the store\n * @returns {testStore} chains\n */\n resetChanges: function resetChanges(storeName) {\n if (_.isBoolean(changeTracking[storeName])) {\n changeTracking[storeName] = false;\n }\n\n return this;\n },\n\n /**\n * Remove the whole store\n * @returns {Promise} true if done\n */\n remove: function remove() {\n var legacyStoreExp = new RegExp(`-${testId}$`);\n return isStoreModeUnified().then(function (isUnified) {\n if (isUnified) {\n return store(testId, preselectedBackend).then(function (storeInstance) {\n return storeInstance.removeStore();\n });\n }\n\n return store.removeAll(function (storeName) {\n return legacyStoreExp.test(storeName);\n }, preselectedBackend);\n });\n },\n\n /**\n * Wraps the identifier retrieval\n * @returns {Promise} the current store id\n */\n getStorageIdentifier: function getStorageIdentifier() {\n return store.getIdentifier(preselectedBackend);\n }\n };\n }\n\n return testStoreLoader;\n\n});\n\n","\ndefine(\"taoTests/loader/taoTestsRunner.bundle\", function(){});\n","define(\"taoTests/loader/taoTestsRunner.min\", [\"taoItems/loader/taoItems.min\"], function(){});\n"]} \ No newline at end of file +{"version":3,"mappings":"AACAA,MCDA,+FAEAC,sEACAC,gIAoBAC,yBACA,UACA,aACA,UACA,SACA,QACA,CAYAC,gDAEA,iBAEA,GAEAJ,MC/CA,yDA0CA,6BACA,gBAIA,MAHAK,wCACAC,iBACA,GACAA,GACA,CAdA,+CAgBA,wBAEA,GAEAN,MCtDA,0FAEAC,sEACAM,kIAwBA,yCAEAC,qBACA,GAEA,aAEA,GAEAR,MCpCA,kJAiCA,sCAkDA,gCACAS,gCAEAC,wCACAC,cACAC,MACAC,eACAC,gBACAC,8BACAC,qCACA,EAEA,mCACAJ,gFAGAK,mBACA,QAGAC,eACAC,+BAGAlB,4CACA,gEACAmB,mDACA,EACA,CAEA,uCACAX,gCAEAY,wCACAV,cACAC,MACAC,eACAS,eACAR,gBACAC,8BACAC,qCACA,EAEA,mCACAJ,gFAGAK,mBACA,EAGAM,sCAEAC,MADAb,aAEAC,MACAE,gBACAC,8BACAC,qCACA,EACAS,2BACAD,gCACAV,gBACAQ,cACA,GAEAE,kCACAV,gBACAQ,aACAT,UACA,KACAD,gBACAA,kBAEA,mCACAA,+DAGAK,oBAEA,QAGAC,oBAIAjB,gDACA,gEACAmB,mDACA,GAEAnB,+CACA,gEACAmB,kDACA,IAXAM,mBAYA,IA/IAT,UAWAU,aATAC,UAEAC,SAEAC,kBAUAC,0BAEAC,WAMAC,uCACAN,cACAO,8BAGAd,uEAEA,MADAO,yBACAO,6BACA,EACA,EAMAC,qCACAR,iBACA,EAyGA,kFACA,gDA4KA,MArKAV,WAaAmB,wBAEA,2BACA,iDAGA,kDACA,gDAGA,GAEA,EAFAnC,gBACAoC,eACA,UACA,oEAGA,kBASA,GARApC,+DACAiB,uCAGAjB,6DACAiB,qCAGA,oDACA,yFAIAc,SACAb,0BAEA,MAKA,GAJAlB,qDACAiB,6BAGA,kDACA,kDAIAc,SACAN,mBAEA,CAGA,MADAE,oBACA,IACA,EAMAU,6BACA,2CACA,+BACA,EACA,EAMAC,+BACA,aACA,EAMAC,0BACAP,oCAEAF,gCAGA,MAFAF,mBACAC,2BACAW,8BACA,EACA,EACA,EAMAC,uBACA,qCACAT,oCACAF,gCACA,uDAEA,MADAF,UACAY,+CACAE,gBACA,EACA,EACA,EACA,EACA,EACA,EAMAC,uBACA,2CACA,0DACA3C,wBACA4B,iBACAC,2BAGA7B,+BAEA+B,UACA,EACA,EACA,EAOAa,qBAmBA,MAlBAb,YAEA/B,oCACAQ,gCAEAqC,gDACA1B,6BACA,EAEAnB,2CAEAA,0CAEAA,qCACA,GAEA4B,SACAC,kBACAG,oCACA,qDACA,EACA,CACA,EACAhB,QACA,CAjWAhB,sEACA8C,+FACAC,wFAoBAC,4BACAC,4BA4UA,2BAEA,GAEAlD,MCzWA,mLAuCA,yCAuEA,6BACA,kFACAyB,6BAGA,4BACAxB,+BAIA0C,6CAHAA,SAIA,CACA,CASA,2BACA,iBAQA,MANA1C,wCACAA,8BACAkD,gCAEA,GAEAjB,sBACA,CAQA,0BACAd,2BACA,IAzGAA,QAKAgC,WAXAC,0EACAC,sEAeAC,YAKAC,QACAC,QACAC,SACAC,UACAC,UACAC,UACA,EAKA,kBAKA,8DAMAzD,YAMA0D,MAMAC,cAMAC,UAmtBA,MAzpBA5C,oBAUAqC,OAcA,MAbAL,cACAA,iCAIAnD,0CACA,wDACAsD,gCACA,GAEAU,gMACA,sGACA,sBACA,IACA,EAUAN,SAIA,MAHAM,+DACA,4DACA,sBACA,IACA,EAWAC,kBAIA,MAHAD,iDACA,qKACA,sBACA,IACA,EAWAE,6BAIA,MAHAF,sDACA,4EACA,sBACA,IACA,EAUAG,oBAKA,MAJAH,6CACAI,sCACA,kCACA,sBACA,IACA,EASAC,qBAOA,MANA,wCACAL,6CACA,uEACA,sBAGA,IACA,EASAM,oBAOA,MANA,wCACAN,4CACA,sEACA,sBAGA,IACA,EASAL,SAIA,MAHAK,+DACA,4CACA,sBACA,IACA,EASAvB,QAIA,MAHAuB,6DACA,0CACA,sBACA,IACA,EASAJ,UAQA,MAPAI,iEACA,SACA,sBAEA,aACA,gFACA,sBACA,IACA,EAMAO,YACA,iBACA,EAWAC,aACA,mCACA,EAMAC,aACA,cACA,EAOAC,gBACA,oBACA,EAWAC,mBACA,oCACA,EAUAC,4BACA,oCACA,4CAEA,6BACA,gCAEA,CAEA,QACA,EAOAC,gBAKA,MAJA1E,cACAA,+CAGAA,UACA,EAOA2E,WACA,WACA,qCACA,iEAGAjB,oCACAA,qDACAA,mCACA,CAEA,YACA,EAOAkB,mBAKA,MAJA,2DACAjB,qDAGAA,aACA,EAOAkB,eAKA,MAJA,mDACAjB,6CAGAA,SACA,EASAkB,qBACA,4CAEAC,iDAIA,mCAHAjD,4GAIA,EAQAkD,eACA,oBACA,EAUAC,sBACA,sCACA,kDAIA,MADA7B,uBACA,IACA,EASA8B,yBACA,UAMA,MAJArF,6CACAsF,qDAGA,OACA,EAYAC,gCACA,WASA,MANAC,QADA,mCACAvD,4DAEA+B,gDAGAwB,0BACAA,MACA,EAWAC,2BACA,uCACA,wEAGA,wDACA,EAYAC,kCACA,uCACA,wEASA,MANAtB,2CACAuB,UACAlC,SACAmC,WACA,EACAxB,mCACA,IACA,EAOAyB,cACA,6CACA,EAQAC,sBAKA,MAJA3C,wCACAA,oCAGA,IACA,EAMA4C,iBACA,gDACA,EAOAC,4BAKA,MAJA7C,2CACAA,0CAGA,IACA,EAMA8C,aACA,4CACA,EAOAC,oBAKA,MAJA/C,uCACAA,kCAGA,IACA,EAMAgD,gBASA,MARAhD,cACAnD,sCACAmD,8CAEAA,gCAIAA,UACA,EAQAiD,kBACApG,6BACAgE,2BAIA,kCACA,KACA,EAQAqC,sBACArG,iCACAgE,+BAIA,sCACA,KACA,EASAsC,2BACAtG,6BACAgE,oCAIA,2CACA,KACA,EAUAuC,gCACAvG,6BACAgE,yCAIA,yCACA,KACA,EAQAwC,gBACAxG,6BACAgE,yBAIA,yBACA,KACA,EAOAyC,cACAzG,8BACA,uBAKAiC,mBAJA,0BACA+B,uBAOA,wBACA,2CAGA,KACA,EAOA0C,eACA1G,+BACA,wBACA,0BACAgE,uBAGA/B,mBAIA,6BACA,4CAGA,KACA,EAUA0E,+BACA3G,gCACAgE,wCAIA,wCACA,KACA,CAEA,GACA7C,4BACA,0BACA,6CACAgC,YACAA,mBAGAhD,gBACA0D,WACAC,mBACAC,cACA,GACA5C,MACA,CAvzBAnB,sEACA4G,mHACAC,iJACAC,sJAuzBA,kFAEA,0CACA,yFAGA,QACA,GAEA,aAEA,GAEA/G,MCz0BA,qPAsCA,wCAkBA,2BACA,oDAGA,MADAgH,oBACAC,YACA,CAQA,+BACA,gCAMA,MAJAC,mBACAC,mCAGAA,IACA,CAaA,4CAEA,oEACA,sBACAC,iCACA,CACA,GAGA,4CACAC,gCAEAC,iCACAA,mBAGAA,IACAC,aAEAzD,+CACAnB,uBAEA,EACA,EACA,CAWA,0BACA,aACA6E,eACAC,+BACA,QAEAC,oDAIAC,wDAKA,MAFAD,gBAEAE,0BACAC,iBACAjH,SACA,EACA,wBAEA,iCACAiH,eACAjH,SACA,EACA,GAlBAsB,qFAmBA,IAhHA4B,sDACAgE,eACAd,mBACAe,iDAEAC,4CAEAC,mCACAf,eACAQ,eACAQ,qCAsjBA,MAzcApE,mBAOAqE,6BACAtG,kDACAsF,4BASA,MARAD,yBAEAjH,8BACAA,kBACAkH,aAEA,GAEA,IACA,EASAiB,qCAKA,MAJAhF,cACA0E,2BAGAO,8BACA,EASA5E,2BAOA,oDACA,EAQAI,2BAKA,2CAIA,GAFA6D,eAEAY,oBACA,4CACA,+BACAC,kDACA,CAEAD,oBACAE,gBACAC,qBACA,GACAC,iBACAH,aACAE,sBAEA9F,SAEA,EACA,EAEA,EACA,EAMAyD,uCACA,qBACA,EAOAuC,+BAMA,MALA,oBACAT,gBACA,2BAGA,IACA,EAQAU,uCAMA,MALA,mBACAV,gBACA,mCAGA,IACA,EAMAW,6BACA,mBACA,EAMAC,+BACA,mBACA,EASAC,sDACA,2EACA,EAMAC,2CACA,mBACA,EAMAC,2CACA,2BACA,EAMAC,2CACA,oBAEAxB,cAIAY,sBACAA,yDACArI,6CACAsI,sDAEAA,aACAA,4CACAY,+BACAA,+BAEA,4BACAA,yBACA,mCACAA,iBACAA,+CACA,0BACA,2CACAxG,qBACA,gBACA,iBAEA4E,uDAGAA,+EAEA,IAGAe,qBAhCApG,qFAiCA,EASAkH,uCACA,qCACA,kDAGA,0BACA,+DAQA,MALA,4DACAC,0CACA,GACAX,cACA,mCACA,IACA,EAQAY,oCACA,kEACA,iDACA,EACA,EAQAC,yDAKA,MAJAtJ,0BACAA,gCAGA,IACA,EAUA6F,mCAKA,8BACA,EAOAE,yCAKA,iCACA,EAOAE,iCAKA,6BACA,EAUAsD,yDAKA,mDACA,EAWAC,+DAOA,mEACA,EAUAC,qCAMA,qCACA,EAYAC,0DAQA,kEACA,EAYAC,mEAQA,uEACA,EAWAC,gDAQA,8CACA,CACA,GAEAC,qCACAhG,0BACA,0BACAA,iBACA,GAEAA,6CACA,0CACA,uCACAiG,uCAEA9J,+CACA+J,YACAlG,iDAEAA,wCAEA,GAGAuC,MACA,GACA8B,oCACArE,yCACAA,4BACAiG,wCACAjG,kBAGAuC,MACA,GACAsB,4CACAtF,aACA4H,yCACA,gCACA,CACA,GACAnG,KACA,CAtmBA7D,sEACAoH,0FACA6C,8GACArD,mHACAC,iJACAqD,gKACAL,gIAmBAM,cACAC,gBA8kBAvG,qCAEA,YAEA,GAEA9D,MChnBA,wSA8CA,sCACAsK,qEACAC,gFASAC,uCACAC,2EACAC,8CAEA,uDACA,2FAGA,6FACAC,mFACAD,OACA,CACA,EAMAE,cACAxJ,SACA,8EACA,sDACA,EAEAyJ,aACA,kFACA,iGACAF,+EACAE,WACA,CACA,EAEAtC,eACA,oFACA,kEACA,EAEAzE,QACA,6EACA,oDACA,EAEAP,UACA,sEACA,2DACA,CAEA,EAMA,MAJAgH,iBACAO,uDAGA5I,sDACA,kDACA4I,2EACA,+GACA,iEACAA,sEACA,CACA,qBACA,EACA,CACA,CACAA,6FAEA,wFAEA,KADAA,qFACAxD,GACA,EACA,CA7HAyD,kIACAC,uIACAC,6HACA1C,6HACAnH,+FACA0C,0FACA+G,mHAmBA,qDAsGA,8BAEA,GAEA7K,MCrIA,2DA4BA,iBAMAyD,qBAEA,qCAGAd,SAEA,EACA,EAOAkB,2BAEA,qCAGAlB,SAEA,EACA,EAQAmD,mCAEA,qCAGAnD,SAEA,EACA,EAOAqD,yCAEA,qCAGArD,SAEA,EACA,EASA8G,yCAEA,qCAGA9G,SAEA,EACA,EASA+G,2BAEA,qCAGA/G,SAEA,EACA,EAWAgH,iCAEA,qCAGAhH,SAEA,EACA,EAUAiH,yCAEA,qCAGAjH,SAEA,EACA,EAWAkH,+BAEA,qCAGAlH,SAEA,EACA,CACA,EAEA,kBAEA,GAEA3C,MCzLA,+MAeA,mDACA,gCACA,gCACA,CA0BA,2CACA,qEACA,iEAEA,2BACA,+FAGA,2EACA,kIAGA,QACA,CASA,kCACAc,sEACAwC,iEAEA,0CACA,6BAGA,6CACA,2CAEA,0EACA,4CAGA,wDACA,iDAEA,CAEA,QACA,CAiBA,qCACA4H,uEACA5H,iEACA6H,mFACA/J,YACAmC,WAEA,cACA,0FAGA6H,wCAKA,iCAMAC,gBACA,gCACA,EAMAC,YACA,aACA,CAEA,8CAEA,6EACAC,2BACAhI,yBAGA,uBACA,WACA,wCACA,0BACA,oEACAiI,0BACA,GACAC,qFACAC,8CACAA,iEAGAA,IACA,4BACAtK,wFACAnB,aACA,qDACA,EACA,4DACA,2BACA,wCAEA,MADAmB,aACAuK,UACA,8BACA,yBACA,GACA,mCACA,CA1KA1L,sEACA2L,8GACAC,kIACAb,uIACAc,mHAEA,mFAKA,MAJA,kCACAC,+CAGA,0CACA,GAgKA,6BAEA,GAEA/L,MClLA,gHAgFA,uDAIAgM,UAHAC,cACAC,aACAC,kBAOAC,uDACAnM,yBACAoM,iEASA,MAPAL,UADAM,0CACAA,OAGAC,cAGAzB,wDACAwB,sBACA,GAGApK,yCACA,EAEA,qBACA,kFAQA,OAOAsK,sCAGA,uCACAvM,yCACAkM,6BAEA,EAEA,wBACA,sEAOA,MAJAlM,mCACAgM,2BAGAG,8CACA,cAQA,MALAK,WADAC,UACAC,iCAEAA,mDAGAF,wCACAG,0CAEAC,gCACA,2CACA,EAOA,OAMAnD,8BACA,yCACA,EAMAoD,mCACAJ,WACAvH,8CACA,mDAKA,MAJAyH,wBACAlB,uCAGAA,GACA,KACA,GAEAvG,sBAEA,EAQA4H,oCAEA,MADAC,eACA7H,wCACA,EAOA8H,oCAEA,MADAD,eACA7H,qCACA,EAMA+H,6BACAF,eAEAN,UACAvH,8CACAlF,sCACA2M,sBACAzH,2BAEA,EACA,GAEAA,mBAEA,CACA,CACA,EACA,EACA,EASAgI,4CAKA,MAJAlN,kCACAiM,0BAGA,IACA,EAQAkB,2EACAjE,WACAkE,eACA,2EAMA,MALApN,uEACA6K,oGACAuC,gBAGAA,WACA,gCACAH,OACA/D,0BAIA,EACA,EAMAmE,sDACAnE,WACAoE,2CACA,6DACA,4BACA,EACA,GACA,oDACA,iDACA,EACA,EAQAC,4DAEA,MADArB,8BACA,IACA,EAQAsB,0CACA,oCACA,EAQAC,8CAKA,MAJAzN,0CACAkM,8BAGA,IACA,EAMAwB,yBACA,6CACA,2DACAjB,WACAC,8DACA,kCACA,GAGAA,oCACA,qCACA,qBACA,EACA,EAMAiB,qDACA,8CACA,CACA,CACA,CAjWA3N,sEACA0M,0FACA5B,qIAyBAD,8DAQA+C,8DAKAtB,OACAuB,kBAEAC,uBAEA,EAUA1B,oEACA,iDACA,8CACA,sDACA,EACA,uDACApM,8CACAsM,iBAGAA,aACA,EACA,EAgSA,sBAEA,GCtWAvM,6DACAA,MCFA","names":["define","_","areaBroker$1","requireAreas","areaBroker","defaultObjects","map","pluginFactory","hostName","eventNs","probeHandler","now","data","id","type","timestamp","timezone","overseer","probe","collectLatencyEvent","runner","startHandler","marker","stopHandler","last","args","collectEvent","queueStorage","probes","queue","immutableQueue","writing","started","getStorage","Promise","resetStorage","add","name","getQueue","getProbes","push","storage","flush","resolve","start","stop","removeHandler","moment","uuid","timeZone","slice","execStack","dataHolder","pluginFactories","config","plugins","states","init","ready","render","finish","destroy","proxy","probeOverseer","testStore","providerRun","loadItem","renderItem","unloadItem","itemStates","disableItem","enableItem","getConfig","getOptions","getPlugins","getPlugin","getPluginsConfig","getPluginConfig","getAreaBroker","getProxy","getProbeOverseer","getTestStore","getPluginStore","loadedStore","getState","setState","getPersistentState","state","setPersistentState","stored","getItemState","setItemState","loaded","disabled","getTestData","setTestData","getTestContext","setTestContext","getTestMap","setTestMap","getDataHolder","next","previous","jump","skip","exit","pause","resume","timeout","eventifier","providerRegistry","dataHolderFactory","extraCallParams","mergedParams","middlewares","list","middleware","async","err","reject","command","params","initialized","delegateProxy","applyMiddlewares","status","testDataHolder","proxyAdapter","initConfig","tokenHandler","onlineStatus","use","install","delegate","communicatorPromise","communicator","then","destroyCommunicator","catch","setOnline","setOffline","isOnline","isOffline","isConnectivityError","getTokenHandler","hasCommunicator","getCommunicator","self","channel","communicatorInstance","send","addCallActionParams","sendVariables","callTestAction","getItem","submitItem","callItemAction","telemetry","connectivity","response","msg","wrapper","delegator","tokenHandlerFactory","_defaults","_slice","providers","loadFromBundle","loadAndRegisterProvider","providersToLoad","target","loadedProviders","registration","itemRunner","logger","loggerFactory","providerLoader","pluginLoader","container","template","validateTestRunnerConfiguration","getOption","getRunner","results","renderTo","runnerConfig","acc","destroying","component","runnerFactory","Handlebars","helpers","testMode","storeNames","volatiles","changeTracking","isStoreModeUnified","selectStoreMode","result","modes","getStore","loadStore","isUnified","store","keyPattern","storeKey","getItems","setItem","trackChange","removeItem","clear","setVolatile","clearVolatileIfStoreChange","shouldClear","clearVolatileStores","clearing","startChangeTracking","hasChanges","resetChanges","remove","getStorageIdentifier","legacyPrefixes","unified","fragmented"],"sources":["/home/alberto/workspace/oat/taocloud-ami-luoss/tao/views/build/config-wrap-start-default.js","../runner/areaBroker.js","../runner/dataHolder.js","../runner/plugin.js","../runner/probeOverseer.js","../runner/runner.js","../runner/proxy.js","../runner/providerLoader.js","../runner/proxy/sample.js","../runner/runnerComponent.js","../runner/testStore.js","module-create.js","/home/alberto/workspace/oat/taocloud-ami-luoss/tao/views/build/config-wrap-end-default.js"],"sourcesContent":["\n","define('taoTests/runner/areaBroker',['lodash', 'ui/areaBroker'], function (_, areaBroker$1) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n areaBroker$1 = areaBroker$1 && Object.prototype.hasOwnProperty.call(areaBroker$1, 'default') ? areaBroker$1['default'] : areaBroker$1;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technlogies SA\n *\n */\n var requireAreas = ['content', //where the content is renderer, for example an item\n 'toolbox', //the place to add arbitrary tools, like a zoom, a comment box, etc.\n 'navigation', //the navigation controls like next, previous, skip\n 'control', //the control center of the test, progress, timers, etc.\n 'header', //the area that could contains the test titles\n 'panel' //a panel to add more advanced GUI (item review, navigation pane, etc.)\n ];\n /**\n * Creates an area broker with the required areas for the test runner.\n *\n * @see ui/areaBroker\n *\n * @param {jQueryElement|HTMLElement|String} $container - the main container\n * @param {Object} mapping - keys are the area names, values are jQueryElement\n * @returns {broker} the broker\n * @throws {TypeError} without a valid container\n */\n\n var areaBroker = _.partial(areaBroker$1, requireAreas);\n\n return areaBroker;\n\n});\n\n","define('taoTests/runner/dataHolder',[],function () { 'use strict';\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technlogies SA\n *\n */\n\n /**\n * Holds the test runner data.\n *\n * @example\n * var holder = holder();\n * holder.get('testMap');\n *\n * @author Bertrand Chevrier \n */\n\n /**\n * @type {String[]} the list of default objects to create\n */\n const defaultObjects = ['testContext', 'testMap'];\n /**\n * Creates a new data holder,\n * with default entries.\n *\n * @returns {Map} the holder\n */\n\n function dataHolderFactory() {\n var map = new Map();\n defaultObjects.forEach(function (entry) {\n map.set(entry, {});\n });\n return map;\n }\n\n return dataHolderFactory;\n\n});\n\n","define('taoTests/runner/plugin',['lodash', 'core/plugin'], function (_, pluginFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n pluginFactory = pluginFactory && Object.prototype.hasOwnProperty.call(pluginFactory, 'default') ? pluginFactory['default'] : pluginFactory;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n /**\n * A pluginFactory configured for the test runner\n * @returns {Function} the preconfigured plugin factory\n */\n\n var plugin = _.partialRight(pluginFactory, {\n //alias getHost to getTestRunner\n hostName: 'testRunner'\n });\n\n return plugin;\n\n});\n\n","define('taoTests/runner/probeOverseer',['lodash', 'moment', 'lib/uuid', 'lib/moment-timezone.min'], function (_, moment, uuid, momentTimezone_min) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n moment = moment && Object.prototype.hasOwnProperty.call(moment, 'default') ? moment['default'] : moment;\n uuid = uuid && Object.prototype.hasOwnProperty.call(uuid, 'default') ? uuid['default'] : uuid;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technlogies SA\n *\n */\n var timeZone = moment.tz.guess();\n var slice = Array.prototype.slice;\n /**\n * Create the overseer intance\n * @param {runner} runner - a instance of a test runner\n * @returns {probeOverseer} the new probe overseer\n * @throws TypeError if something goes wrong\n */\n\n function probeOverseerFactory(runner) {\n // the created instance\n var overseer; // the list of registered probes\n\n var probes = []; //temp queue\n\n var queue = []; //immutable queue which will not be flushed\n\n var immutableQueue = [];\n /**\n * @type {Storage} to store the collected events\n */\n\n var queueStorage;\n /**\n * @type {Promise} Promises chain to avoid write collisions\n */\n\n var writing = Promise.resolve(); //is the overseer started\n\n var started = false;\n /**\n * Get the storage instance\n * @returns {Promise} that resolves with the storage\n */\n\n var getStorage = function getStorage() {\n if (queueStorage) {\n return Promise.resolve(queueStorage);\n }\n\n return runner.getTestStore().getStore('test-probe').then(function (newStorage) {\n queueStorage = newStorage;\n return Promise.resolve(queueStorage);\n });\n };\n /**\n * Unset the storage instance\n */\n\n\n var resetStorage = function resetStorage() {\n queueStorage = null;\n };\n /**\n * Register the collection event of a probe against a runner\n * @param {Object} probe - a valid probe\n */\n\n\n function collectEvent(probe) {\n var eventNs = `.probe-${probe.name}`; //event handler registered to collect data\n\n var probeHandler = function probeHandler() {\n var now = moment();\n var data = {\n id: uuid(12, 16),\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(slice.call(arguments)));\n }\n\n overseer.push(data);\n }; //fallback\n\n\n if (probe.latency) {\n return collectLatencyEvent(probe);\n }\n\n _.forEach(probe.events, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(probeHandler, eventName));\n });\n }\n\n function collectLatencyEvent(probe) {\n var eventNs = `.probe-${probe.name}`; //start event handler registered to collect data\n\n var startHandler = function startHandler() {\n var now = moment();\n var data = {\n id: uuid(12, 16),\n marker: 'start',\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(slice.call(arguments)));\n }\n\n overseer.push(data);\n }; //stop event handler registered to collect data\n\n\n var stopHandler = function stopHandler() {\n var now = moment();\n var last;\n var data = {\n type: probe.name,\n timestamp: now.format('x') / 1000,\n timezone: now.tz(timeZone).format('Z')\n };\n var args = slice.call(arguments);\n last = _.findLast(immutableQueue, {\n type: probe.name,\n marker: 'start'\n });\n\n if (last && !_.findLast(immutableQueue, {\n type: probe.name,\n marker: 'end',\n id: last.id\n })) {\n data.id = last.id;\n data.marker = 'end';\n\n if (typeof probe.capture === 'function') {\n data.context = probe.capture.apply(probe, [runner].concat(args));\n }\n\n overseer.push(data);\n }\n }; //fallback\n\n\n if (!probe.latency) {\n return collectEvent(probe);\n }\n\n _.forEach(probe.startEvents, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(startHandler, eventName));\n });\n\n _.forEach(probe.stopEvents, function (eventName) {\n var listen = eventName.indexOf('.') > 0 ? eventName : eventName + eventNs;\n runner.on(listen, _.partial(stopHandler, eventName));\n });\n } //argument validation\n\n\n if (!_.isPlainObject(runner) || !_.isFunction(runner.init) || !_.isFunction(runner.on)) {\n throw new TypeError('Please set a test runner');\n }\n /**\n * @typedef {probeOverseer}\n */\n\n\n overseer = {\n /**\n * Add a new probe\n * @param {Object} probe\n * @param {String} probe.name - the probe name\n * @param {Boolean} [probe.latency = false] - simple or latency mode\n * @param {String[]} [probe.events] - the list of events to listen (simple mode)\n * @param {String[]} [probe.startEvents] - the list of events to mark the start (lantency mode)\n * @param {String[]} [probe.stopEvents] - the list of events to mark the end (latency mode)\n * @param {Function} [probe.capture] - lambda fn to define the data context, it receive the test runner and the event parameters\n * @returns {probeOverseer} chains\n * @throws TypeError if the probe is not well formatted\n */\n add: function add(probe) {\n // probe structure strict validation\n if (!_.isPlainObject(probe)) {\n throw new TypeError('A probe is a plain object');\n }\n\n if (!_.isString(probe.name) || _.isEmpty(probe.name)) {\n throw new TypeError('A probe must have a name');\n }\n\n if (_.where(probes, {\n name: probe.name\n }).length > 0) {\n throw new TypeError('A probe with this name is already regsitered');\n }\n\n if (probe.latency) {\n if (_.isString(probe.startEvents) && !_.isEmpty(probe.startEvents)) {\n probe.startEvents = [probe.startEvents];\n }\n\n if (_.isString(probe.stopEvents) && !_.isEmpty(probe.stopEvents)) {\n probe.stopEvents = [probe.stopEvents];\n }\n\n if (!probe.startEvents.length || !probe.stopEvents.length) {\n throw new TypeError('Latency based probes must have startEvents and stopEvents defined');\n } //if already started we register the events on addition\n\n\n if (started) {\n collectLatencyEvent(probe);\n }\n } else {\n if (_.isString(probe.events) && !_.isEmpty(probe.events)) {\n probe.events = [probe.events];\n }\n\n if (!_.isArray(probe.events) || probe.events.length === 0) {\n throw new TypeError('A probe must define events');\n } //if already started we register the events on addition\n\n\n if (started) {\n collectEvent(probe);\n }\n }\n\n probes.push(probe);\n return this;\n },\n\n /**\n * Get the time entries queue\n * @returns {Promise} with the data in parameterj\n */\n getQueue: function getQueue() {\n return getStorage().then(function (storage) {\n return storage.getItem('queue');\n });\n },\n\n /**\n * Get the list of defined probes\n * @returns {Object[]} the probes collection\n */\n getProbes: function getProbes() {\n return probes;\n },\n\n /**\n * Push a time entry to the queue\n * @param {Object} entry - the time entry\n */\n push: function push(entry) {\n getStorage().then(function (storage) {\n //ensure the queue is pushed to the store consistently and atomically\n writing = writing.then(function () {\n queue.push(entry);\n immutableQueue.push(entry);\n return storage.setItem('queue', queue);\n });\n });\n },\n\n /**\n * Flush the queue and get the entries\n * @returns {Promise} with the data in parameter\n */\n flush: function flush() {\n return new Promise(function (resolve) {\n getStorage().then(function (storage) {\n writing = writing.then(function () {\n return storage.getItem('queue').then(function (flushed) {\n queue = [];\n return storage.setItem('queue', queue).then(function () {\n resolve(flushed);\n });\n });\n });\n });\n });\n },\n\n /**\n * Start the probes\n * @returns {Promise} once started\n */\n start: function start() {\n return getStorage().then(function (storage) {\n return storage.getItem('queue').then(function (savedQueue) {\n if (_.isArray(savedQueue)) {\n queue = savedQueue;\n immutableQueue = savedQueue;\n }\n\n _.forEach(probes, collectEvent);\n\n started = true;\n });\n });\n },\n\n /**\n * Stop the probes\n * Be carefull, stop will also clear the store and the queue\n * @returns {Promise} once stopped\n */\n stop: function stop() {\n started = false;\n\n _.forEach(probes, function (probe) {\n var eventNs = `.probe-${probe.name}`;\n\n var removeHandler = function removeHandler(eventName) {\n runner.off(eventName + eventNs);\n };\n\n _.forEach(probe.startEvents, removeHandler);\n\n _.forEach(probe.stopEvents, removeHandler);\n\n _.forEach(probe.events, removeHandler);\n });\n\n queue = [];\n immutableQueue = [];\n return getStorage().then(function (storage) {\n return storage.removeItem('queue').then(resetStorage);\n });\n }\n };\n return overseer;\n }\n\n return probeOverseerFactory;\n\n});\n\n","define('taoTests/runner/runner',['lodash', 'core/eventifier', 'core/providerRegistry', 'taoTests/runner/dataHolder'], function (_, eventifier, providerRegistry, dataHolderFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;\n providerRegistry = providerRegistry && Object.prototype.hasOwnProperty.call(providerRegistry, 'default') ? providerRegistry['default'] : providerRegistry;\n dataHolderFactory = dataHolderFactory && Object.prototype.hasOwnProperty.call(dataHolderFactory, 'default') ? dataHolderFactory['default'] : dataHolderFactory;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2015-2020 (original work) Open Assessment Technologies SA ;\n */\n /**\n * Builds an instance of the QTI test runner\n *\n * @param {String} providerName\n * @param {Function[]} pluginFactories\n * @param {Object} config\n * @param {String} config.serviceCallId - the identifier of the test session\n * @param {String} [config.testDefinition] - the identifier of the test definition\n * @param {String} [config.testCompilation] - the identifier of the compiled test\n * @param {Object} config.options - the test runner configuration options\n * @param {Object} config.options.plugins - the plugins configuration\n * @param {jQueryElement} [config.renderTo] - the dom element that is going to holds the test content (item, rubick, etc)\n * @returns {runner}\n */\n\n function testRunnerFactory(providerName) {\n let pluginFactories = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n /**\n * @type {Object} The test runner instance\n */\n let runner;\n /**\n * @type {Map} Contains the test runner data\n */\n\n let dataHolder;\n /**\n * @type {Object} the registered plugins\n */\n\n const plugins = {};\n /**\n * @type {Object} the test of the runner\n */\n\n const states = {\n init: false,\n ready: false,\n render: false,\n finish: false,\n destroy: false\n };\n /**\n * @type {Object} keeps the states of the items\n */\n\n let itemStates = {};\n /**\n * The selected test runner provider\n */\n\n const provider = testRunnerFactory.getProvider(providerName);\n /**\n * Keep the area broker instance\n * @see taoTests/runner/areaBroker\n */\n\n let areaBroker;\n /**\n * Keep the proxy instance\n * @see taoTests/runner/proxy\n */\n\n let proxy;\n /**\n * Keep the instance of the probes overseer\n * @see taoTests/runner/probeOverseer\n */\n\n let probeOverseer;\n /**\n * Keep the instance of a testStore\n * @see taoTests/runner/testStore\n */\n\n let testStore;\n /**\n * Run a method of the provider (by delegation)\n *\n * @param {String} method - the method to run\n * @param {...} args - rest parameters given to the provider method\n * @returns {Promise} so provider can do async stuffs\n */\n\n function providerRun(method) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n return new Promise(resolve => {\n if (!_.isFunction(provider[method])) {\n return resolve();\n }\n\n return resolve(provider[method].apply(runner, args));\n });\n }\n /**\n * Run a method in all plugins\n *\n * @param {String} method - the method to run\n * @returns {Promise} once that resolve when all plugins are done\n */\n\n\n function pluginRun(method) {\n var execStack = [];\n\n _.forEach(runner.getPlugins(), plugin => {\n if (_.isFunction(plugin[method])) {\n execStack.push(plugin[method]());\n }\n });\n\n return Promise.all(execStack);\n }\n /**\n * Trigger error event\n * @param {Error|String} err - the error\n * @fires runner#error\n */\n\n\n function reportError(err) {\n runner.trigger('error', err);\n }\n /**\n * Defines the test runner\n *\n * @type {runner}\n */\n\n\n runner = eventifier({\n /**\n * Initialize the runner\n * - instantiate the plugins\n * - provider init\n * - plugins init\n * - call render\n * @fires runner#init\n * @returns {runner} chains\n */\n init() {\n if (!dataHolder) {\n dataHolder = this.getDataHolder();\n } //instantiate the plugins first\n\n\n _.forEach(pluginFactories, pluginFactory => {\n const plugin = pluginFactory(runner, this.getAreaBroker());\n plugins[plugin.getName()] = plugin;\n });\n\n providerRun('install').then(_.partial(providerRun, 'loadPersistentStates')).then(_.partial(pluginRun, 'install')).then(_.partial(providerRun, 'init')).then(_.partial(pluginRun, 'init')).then(() => {\n this.setState('init', true).off('init.internal').after('init.internal', () => this.render()).trigger('init');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Render the runner\n * - provider render\n * - plugins render\n * @fires runner#render\n * @fires runner#ready\n * @returns {runner} chains\n */\n render() {\n providerRun('render').then(() => pluginRun('render')).then(() => {\n this.setState('ready', true).trigger('render').trigger('ready');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Load an item\n * - provider loadItem, resolve or return the itemData\n * - plugins loadItem\n * - call renderItem\n * @param {*} itemRef - something that let you identify the item to load\n * @fires runner#loaditem\n * @returns {runner} chains\n */\n loadItem(itemRef) {\n providerRun('loadItem', itemRef).then(itemData => {\n this.setItemState(itemRef, 'loaded', true).off('loaditem.internal').after('loaditem.internal', () => this.renderItem(itemRef, itemData)).trigger('loaditem', itemRef, itemData);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Render an item\n * - provider renderItem\n * - plugins renderItem\n * @param {Object} itemRef\n * @param {Object} itemData - the loaded item data\n * @fires runner#renderitem\n * @returns {runner} chains\n */\n renderItem(itemRef, itemData) {\n providerRun('renderItem', itemRef, itemData).then(() => {\n this.setItemState(itemRef, 'ready', true).trigger('renderitem', itemRef, itemData);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Unload an item (for example to destroy the item)\n * - provider unloadItem\n * - plugins unloadItem\n * @param {*} itemRef - something that let you identify the item to unload\n * @fires runner#unloaditem\n * @returns {runner} chains\n */\n unloadItem(itemRef) {\n providerRun('unloadItem', itemRef).then(() => {\n itemStates = _.omit(itemStates, itemRef);\n this.trigger('unloaditem', itemRef);\n }).catch(reportError);\n return this;\n },\n\n /**\n * Disable an item\n * - provider disableItem\n * @param {*} itemRef - something that let you identify the item\n * @fires runner#disableitem\n * @returns {runner} chains\n */\n disableItem(itemRef) {\n if (!this.getItemState(itemRef, 'disabled')) {\n providerRun('disableItem', itemRef).then(() => {\n this.setItemState(itemRef, 'disabled', true).trigger('disableitem', itemRef);\n }).catch(reportError);\n }\n\n return this;\n },\n\n /**\n * Enable an item\n * - provider enableItem\n * @param {*} itemRef - something that let you identify the item\n * @fires runner#disableitem\n * @returns {runner} chains\n */\n enableItem(itemRef) {\n if (this.getItemState(itemRef, 'disabled')) {\n providerRun('enableItem', itemRef).then(() => {\n this.setItemState(itemRef, 'disabled', false).trigger('enableitem', itemRef);\n }).catch(reportError);\n }\n\n return this;\n },\n\n /**\n * When the test is terminated\n * - provider finish\n * - plugins finsh\n * @fires runner#finish\n * @returns {runner} chains\n */\n finish() {\n providerRun('finish').then(() => pluginRun('finish')).then(() => {\n this.setState('finish', true).trigger('finish');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Flushes the runner\n * - provider flush\n * - plugins flush\n * @fires runner#flush\n * @returns {runner} chains\n */\n flush() {\n providerRun('flush').then(() => pluginRun('flush')).then(() => {\n this.setState('flush', true).trigger('flush');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Destroy\n * - provider destroy\n * - plugins destroy\n * @fires runner#destroy\n * @returns {runner} chains\n */\n destroy() {\n providerRun('destroy').then(() => pluginRun('destroy')).then(() => {\n if (proxy) {\n return proxy.destroy();\n }\n }).then(() => {\n this.setTestContext({}).setTestMap({}).setState('destroy', true).trigger('destroy');\n }).catch(reportError);\n return this;\n },\n\n /**\n * Get the whole test runner configuration\n * @returns {Object} the config\n */\n getConfig() {\n return config || {};\n },\n\n /**\n * Get the options from the configuration parameters, (feature flags, parameter values, etc.)\n *\n * Alias to getConfig().options\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @returns {Object} the configuration options\n */\n getOptions() {\n return this.getConfig().options || {};\n },\n\n /**\n * Get the runner pugins\n * @returns {plugin[]} the plugins\n */\n getPlugins() {\n return plugins;\n },\n\n /**\n * Get a plugin\n * @param {String} name - the plugin name\n * @returns {plugin} the plugin\n */\n getPlugin(name) {\n return plugins[name];\n },\n\n /**\n * Get the configuration of the plugins\n *\n * Alias to getConfig().options.plugins\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @returns {Object} the configuration options\n */\n getPluginsConfig() {\n return this.getOptions().plugins || {};\n },\n\n /**\n * Get the configuration of a given plugin\n *\n * In deprecated mode, this is initialized through getTestData (after /init)\n *\n * @param {String} pluginName - the name of the plugin\n * @returns {Object} the configuration options of the plugin\n */\n getPluginConfig(pluginName) {\n if (pluginName && plugins[pluginName]) {\n const pluginsConfig = this.getPluginsConfig();\n\n if (pluginsConfig[pluginName]) {\n return pluginsConfig[pluginName];\n }\n }\n\n return {};\n },\n\n /**\n * Get the area broker, load it if not present\n *\n * @returns {areaBroker} the areaBroker\n */\n getAreaBroker() {\n if (!areaBroker) {\n areaBroker = provider.loadAreaBroker.call(this);\n }\n\n return areaBroker;\n },\n\n /**\n * Get the proxy, load it if not present\n *\n * @returns {proxy} the proxy\n */\n getProxy() {\n if (!proxy) {\n if (!_.isFunction(provider.loadProxy)) {\n throw new Error('The provider does not have a loadProxy method');\n }\n\n proxy = provider.loadProxy.call(this);\n proxy.on('error', error => this.trigger('error', error));\n proxy.install(this.getDataHolder());\n }\n\n return proxy;\n },\n\n /**\n * Get the probeOverseer, and load it if not present\n *\n * @returns {probeOverseer} the probe overseer\n */\n getProbeOverseer() {\n if (!probeOverseer && _.isFunction(provider.loadProbeOverseer)) {\n probeOverseer = provider.loadProbeOverseer.call(this);\n }\n\n return probeOverseer;\n },\n\n /**\n * Get the testStore, and load it if not present\n *\n * @returns {testStore} the testStore instance\n */\n getTestStore() {\n if (!testStore && _.isFunction(provider.loadTestStore)) {\n testStore = provider.loadTestStore.call(this);\n }\n\n return testStore;\n },\n\n /**\n * Get a plugin store.\n * It's a convenience method that calls testStore.getStore\n * @param {String} name - the name of store, usually the plugin name.\n *\n * @returns {Promise} the plugin store\n */\n getPluginStore(name) {\n const loadedStore = this.getTestStore();\n\n if (!loadedStore || !_.isFunction(loadedStore.getStore)) {\n return Promise.reject(new Error('Please configure a testStore via loadTestStore to be able to get a plugin store'));\n }\n\n return this.getTestStore().getStore(name);\n },\n\n /**\n * Check a runner state\n *\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n */\n getState(name) {\n return !!states[name];\n },\n\n /**\n * Define a runner state\n *\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {runner} chains\n * @throws {TypeError} if the state name is not a valid string\n */\n setState(name, active) {\n if (!_.isString(name) || _.isEmpty(name)) {\n throw new TypeError('The state must have a name');\n }\n\n states[name] = !!active;\n return this;\n },\n\n /**\n * Checks a runner persistent state\n * - provider getPersistentState\n *\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n */\n getPersistentState(name) {\n let state;\n\n if (_.isFunction(provider.getPersistentState)) {\n state = provider.getPersistentState.call(runner, name);\n }\n\n return !!state;\n },\n\n /**\n * Defines a runner persistent state\n * - provider setPersistentState\n *\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {Promise} Returns a promise that:\n * - will be resolved once the state is fully stored\n * - will be rejected if any error occurs or if the state name is not a valid string\n */\n setPersistentState(name, active) {\n let stored;\n\n if (!_.isString(name) || _.isEmpty(name)) {\n stored = Promise.reject(new TypeError('The state must have a name'));\n } else {\n stored = providerRun('setPersistentState', name, !!active);\n }\n\n stored.catch(reportError);\n return stored;\n },\n\n /**\n * Check an item state\n *\n * @param {*} itemRef - something that let you identify the item\n * @param {String} name - the state name\n * @returns {Boolean} if active, false if not set\n *\n * @throws {TypeError} if there is no itemRef nor name\n */\n getItemState(itemRef, name) {\n if (_.isEmpty(itemRef) || _.isEmpty(name)) {\n throw new TypeError('The state is identified by an itemRef and a name');\n }\n\n return !!(itemStates[itemRef] && itemStates[itemRef][name]);\n },\n\n /**\n * Check an item state\n *\n * @param {*} itemRef - something that let you identify the item\n * @param {String} name - the state name\n * @param {Boolean} active - is the state active\n * @returns {runner} chains\n *\n * @throws {TypeError} if there is no itemRef nor name\n */\n setItemState(itemRef, name, active) {\n if (_.isEmpty(itemRef) || _.isEmpty(name)) {\n throw new TypeError('The state is identified by an itemRef and a name');\n }\n\n itemStates[itemRef] = itemStates[itemRef] || {\n loaded: false,\n ready: false,\n disabled: false\n };\n itemStates[itemRef][name] = !!active;\n return this;\n },\n\n /**\n * Get the test data/definition\n * @deprecated\n * @returns {Object} the test data\n */\n getTestData() {\n return dataHolder && dataHolder.get('testData');\n },\n\n /**\n * Set the test data/definition\n * @deprecated\n * @param {Object} testData - the test data\n * @returns {runner} chains\n */\n setTestData(testData) {\n if (dataHolder && _.isPlainObject(testData)) {\n dataHolder.set('testData', testData);\n }\n\n return this;\n },\n\n /**\n * Get the test context/state\n * @returns {Object} the test context\n */\n getTestContext() {\n return dataHolder && dataHolder.get('testContext');\n },\n\n /**\n * Set the test context/state\n * @param {Object} testContext - the context to set\n * @returns {runner} chains\n */\n setTestContext(testContext) {\n if (dataHolder && _.isPlainObject(testContext)) {\n dataHolder.set('testContext', testContext);\n }\n\n return this;\n },\n\n /**\n * Get the test items map\n * @returns {Object} the test map\n */\n getTestMap() {\n return dataHolder && dataHolder.get('testMap');\n },\n\n /**\n * Set the test items map\n * @param {Object} testMap - the map to set\n * @returns {runner} chains\n */\n setTestMap(testMap) {\n if (dataHolder && _.isPlainObject(testMap)) {\n dataHolder.set('testMap', testMap);\n }\n\n return this;\n },\n\n /**\n * Get the data holder\n * @returns {dataHolder}\n */\n getDataHolder() {\n if (!dataHolder) {\n if (_.isFunction(provider.loadDataHolder)) {\n dataHolder = provider.loadDataHolder.call(this);\n } else {\n dataHolder = dataHolderFactory();\n }\n }\n\n return dataHolder;\n },\n\n /**\n * Move next alias\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n next(scope) {\n if (_.isFunction(provider.next)) {\n return providerRun('next', scope);\n } //backward compat\n\n\n this.trigger('move', 'next', scope);\n return this;\n },\n\n /**\n * Move previous alias\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n previous(scope) {\n if (_.isFunction(provider.previous)) {\n return providerRun('previous', scope);\n } //backward compat\n\n\n this.trigger('move', 'previous', scope);\n return this;\n },\n\n /**\n * Move to alias\n * @param {String|Number} position - where to jump\n * @param {String|*} [scope] - the movement scope\n * @fires runner#move\n * @returns {runner} chains\n */\n jump(position, scope) {\n if (_.isFunction(provider.jump)) {\n return providerRun('jump', position, scope);\n } //backward compat\n\n\n this.trigger('move', 'jump', scope, position);\n return this;\n },\n\n /**\n * Skip alias\n * @param {String|*} [scope] - the movement scope\n * @param {String|*} [direction] - next/previous/jump\n * @param {Number|*} [ref] - the item ref\n * @fires runner#skip\n * @returns {runner} chains\n */\n skip(scope, direction, ref) {\n if (_.isFunction(provider.skip)) {\n return providerRun('skip', scope, direction, ref);\n } //backward compat\n\n\n this.trigger('skip', scope, direction, ref);\n return this;\n },\n\n /**\n * Exit the test\n * @param {String|*} [why] - reason the test is exited\n * @fires runner#exit\n * @returns {runner} chains\n */\n exit(why) {\n if (_.isFunction(provider.exit)) {\n return providerRun('exit', why);\n } //backward compat\n\n\n this.trigger('exit', why);\n return this;\n },\n\n /**\n * Pause the current execution\n * @fires runner#pause\n * @returns {runner} chains\n */\n pause() {\n if (_.isFunction(provider.pause)) {\n if (!this.getState('pause')) {\n this.setState('pause', true);\n return providerRun('pause');\n }\n\n return Promise.resolve();\n } //backward compat\n\n\n if (!this.getState('pause')) {\n this.setState('pause', true).trigger('pause');\n }\n\n return this;\n },\n\n /**\n * Resume a paused test\n * @fires runner#pause\n * @returns {runner} chains\n */\n resume() {\n if (_.isFunction(provider.resume)) {\n if (this.getState('pause')) {\n this.setState('pause', false);\n return providerRun('resume');\n }\n\n return Promise.resolve();\n } //backward compat\n\n\n if (this.getState('pause') === true) {\n this.setState('pause', false).trigger('resume');\n }\n\n return this;\n },\n\n /**\n * Notify a test timeout\n * @param {String} scope - The scope where the timeout occurred\n * @param {String} ref - The reference to the place where the timeout occurred\n * @param {Object} [timer] - The timer's descriptor, if any\n * @fires runner#timeout\n * @returns {runner} chains\n */\n timeout(scope, ref, timer) {\n if (_.isFunction(provider.timeout)) {\n return providerRun('timeout', scope, ref, timer);\n } //backward compat\n\n\n this.trigger('timeout', scope, ref, timer);\n return this;\n }\n\n });\n runner.on('move', function () {\n this.trigger(...arguments);\n }).after('destroy', function destroyCleanUp() {\n if (dataHolder) {\n dataHolder.clear();\n }\n\n areaBroker = null;\n proxy = null;\n probeOverseer = null;\n testStore = null;\n });\n return runner;\n } //bind the provider registration capabilities to the testRunnerFactory\n\n\n var runner = providerRegistry(testRunnerFactory, function validateProvider(provider) {\n //mandatory methods\n if (!_.isFunction(provider.loadAreaBroker)) {\n throw new TypeError('The runner provider MUST have a method that returns an areaBroker');\n }\n\n return true;\n });\n\n return runner;\n\n});\n\n","define('taoTests/runner/proxy',['lodash', 'async', 'core/delegator', 'core/eventifier', 'core/providerRegistry', 'core/tokenHandler', 'core/connectivity'], function (_, async, delegator, eventifier, providerRegistry, tokenHandlerFactory, connectivity) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n async = async && Object.prototype.hasOwnProperty.call(async, 'default') ? async['default'] : async;\n delegator = delegator && Object.prototype.hasOwnProperty.call(delegator, 'default') ? delegator['default'] : delegator;\n eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;\n providerRegistry = providerRegistry && Object.prototype.hasOwnProperty.call(providerRegistry, 'default') ? providerRegistry['default'] : providerRegistry;\n tokenHandlerFactory = tokenHandlerFactory && Object.prototype.hasOwnProperty.call(tokenHandlerFactory, 'default') ? tokenHandlerFactory['default'] : tokenHandlerFactory;\n connectivity = connectivity && Object.prototype.hasOwnProperty.call(connectivity, 'default') ? connectivity['default'] : connectivity;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n var _defaults = {};\n var _slice = [].slice;\n /**\n * Defines a proxy bound to a particular adapter\n *\n * @param {String} proxyName - The name of the proxy adapter to use in the returned proxy instance\n * @param {Object} [config] - Some optional config depending of implementation,\n * this object will be forwarded to the proxy adapter\n * @returns {proxy} - The proxy instance, bound to the selected proxy adapter\n */\n\n function proxyFactory(proxyName, config) {\n var proxy, delegateProxy, communicator, communicatorPromise;\n var testDataHolder;\n var extraCallParams = {};\n var proxyAdapter = proxyFactory.getProvider(proxyName);\n\n var initConfig = _.defaults(config || {}, _defaults);\n\n var tokenHandler = tokenHandlerFactory();\n var middlewares = {};\n var initialized = false;\n var onlineStatus = connectivity.isOnline();\n /**\n * Gets parameters merged with extra parameters\n * @param {Object} [params]\n * @returns {Object}\n */\n\n function getParams(params) {\n var mergedParams = _.merge({}, params, extraCallParams);\n\n extraCallParams = {};\n return mergedParams;\n }\n /**\n * Gets the aggregated list of middlewares for a particular queue name\n * @param {String} queue - The name of the queue to get\n * @returns {Array}\n */\n\n\n function getMiddlewares(queue) {\n var list = middlewares[queue] || [];\n\n if (middlewares.all) {\n list = list.concat(middlewares.all);\n }\n\n return list;\n }\n /**\n * Applies the list of registered middlewares onto the received response\n * @param {Object} request - The request descriptor\n * @param {String} request.command - The name of the requested command\n * @param {Object} request.params - The map of provided parameters\n * @param {Object} response The response descriptor\n * @param {String} response.status The status of the response, can be either 'success' or 'error'\n * @param {Object} response.data The full response data\n * @returns {Promise}\n */\n\n\n function applyMiddlewares(request, response) {\n // wrap each middleware to provide parameters\n var list = _.map(getMiddlewares(request.command), function (middleware) {\n return function (next) {\n middleware(request, response, next);\n };\n }); // apply each middleware in series, then resolve or reject the promise\n\n\n return new Promise(function (resolve, reject) {\n async.series(list, function (err) {\n // handle implicit error from response descriptor\n if (!err && 'error' === response.status) {\n err = response.data;\n }\n\n if (err) {\n reject(err);\n } else {\n proxy.trigger('receive', response.data, 'proxy');\n resolve(response.data);\n }\n });\n });\n }\n /**\n * Delegates the call to the proxy implementation and apply the middleware.\n *\n * @param {String} fnName - The name of the delegated method to call\n * @returns {Promise} - The delegated method must return a promise\n * @private\n * @throws Error\n */\n\n\n function delegate(fnName) {\n var request = {\n command: fnName,\n params: _slice.call(arguments, 1)\n };\n\n if (!initialized && !_.contains(['install', 'init'], fnName)) {\n return Promise.reject(new Error('Proxy is not properly initialized or has been destroyed!'));\n }\n\n return delegateProxy.apply(null, arguments).then(function (data) {\n // If the delegate call succeed the proxy is initialized.\n // Place this set here to avoid to wrap the init() into another promise.\n initialized = true; // handle successful request\n\n return applyMiddlewares(request, {\n status: 'success',\n data: data\n });\n }).catch(function (data) {\n // handle failed request\n return applyMiddlewares(request, {\n status: 'error',\n data: data\n });\n });\n }\n /**\n * Defines the test runner proxy\n * @typedef {proxy}\n */\n\n\n proxy = eventifier({\n /**\n * Add a middleware\n * @param {String} [command] The command queue in which add the middleware (default: 'all')\n * @param {Function...} callback - A middleware callback. Must accept 3 parameters: request, response, next.\n * @returns {proxy}\n */\n use: function use(command) {\n var queue = command && _.isString(command) ? command : 'all';\n var list = middlewares[queue] || [];\n middlewares[queue] = list;\n\n _.each(arguments, function (cb) {\n if (_.isFunction(cb)) {\n list.push(cb);\n }\n });\n\n return this;\n },\n\n /**\n * Install the proxy.\n * This step let's attach some features before the proxy reallys starts (before init).\n *\n * @param {Map} dataHolder - the test runner data holder\n * @returns {*}\n */\n install: function install(dataHolder) {\n if (dataHolder) {\n testDataHolder = dataHolder;\n }\n\n return delegate('install', initConfig);\n },\n\n /**\n * Initializes the proxy\n * @param {Object} [params] - An optional list of parameters\n * @returns {Promise} - Returns a promise. The proxy will be fully initialized on resolve.\n * Any error will be provided if rejected.\n * @fires init\n */\n init: function init(params) {\n /**\n * @event proxy#init\n * @param {Promise} promise\n * @param {Object} config\n * @param {Object} params\n */\n return delegate('init', initConfig, getParams(params));\n },\n\n /**\n * Uninstalls the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully uninstalled on resolve.\n * Any error will be provided if rejected.\n * @fires destroy\n */\n destroy: function destroy() {\n /**\n * @event proxy#destroy\n * @param {Promise} promise\n */\n return delegate('destroy').then(function () {\n // The proxy is now destroyed. A call to init() is mandatory to be able to use it again.\n initialized = false; // a communicator has been invoked and...\n\n if (communicatorPromise) {\n return new Promise(function (resolve, reject) {\n function destroyCommunicator() {\n communicator.destroy().then(resolve).catch(reject);\n }\n\n communicatorPromise // ... has been loaded successfully, then destroy it\n .then(function () {\n destroyCommunicator();\n }) // ...has failed to be loaded, maybe no need to destroy it\n .catch(function () {\n if (communicator) {\n destroyCommunicator();\n } else {\n resolve();\n }\n });\n });\n }\n });\n },\n\n /**\n * Get the map that holds the test data\n * @returns {Map|Object} the dataHolder\n */\n getDataHolder: function getDataHolder() {\n return testDataHolder;\n },\n\n /**\n * Set the proxy as online\n * @returns {proxy} chains\n * @fires {proxy#reconnect}\n */\n setOnline: function setOnline() {\n if (this.isOffline()) {\n onlineStatus = true;\n this.trigger('reconnect');\n }\n\n return this;\n },\n\n /**\n * Set the proxy as offline\n * @param {String} [source] - source of the connectivity change\n * @returns {proxy} chains\n * @fires {proxy#disconnect}\n */\n setOffline: function setOffline(source) {\n if (this.isOnline()) {\n onlineStatus = false;\n this.trigger('disconnect', source);\n }\n\n return this;\n },\n\n /**\n * Are we online ?\n * @returns {Boolean}\n */\n isOnline: function isOnline() {\n return onlineStatus;\n },\n\n /**\n * Are we offline\n * @returns {Boolean}\n */\n isOffline: function isOffline() {\n return !onlineStatus;\n },\n\n /**\n * For the proxy a connection error is an error object with\n * source 'network', a 0 code and a false sent attribute.\n *\n * @param {Error|Object} err - the error to verify\n * @returns {Boolean} true if a connection error.\n */\n isConnectivityError: function isConnectivityError(err) {\n return _.isObject(err) && err.source === 'network' && err.code === 0 && err.sent === false;\n },\n\n /**\n * Gets the security token handler\n * @returns {tokenHandler}\n */\n getTokenHandler: function getTokenHandler() {\n return tokenHandler;\n },\n\n /**\n * Checks if a communication channel has been requested.\n * @returns {Boolean}\n */\n hasCommunicator: function hasCommunicator() {\n return !!communicatorPromise;\n },\n\n /**\n * Gets access to the communication channel, load it if not present\n * @returns {Promise} Returns a promise that will resolve the communication channel\n */\n getCommunicator: function getCommunicator() {\n var self = this;\n\n if (!initialized) {\n return Promise.reject(new Error('Proxy is not properly initialized or has been destroyed!'));\n }\n\n if (!communicatorPromise) {\n communicatorPromise = new Promise(function (resolve, reject) {\n if (_.isFunction(proxyAdapter.loadCommunicator)) {\n communicator = proxyAdapter.loadCommunicator.call(self);\n\n if (communicator) {\n communicator.before('error', function (e, err) {\n if (self.isConnectivityError(err)) {\n self.setOffline('communicator');\n }\n }).on('error', function (err) {\n self.trigger('error', err);\n }).on('receive', function (response) {\n self.setOnline();\n self.trigger('receive', response, 'communicator');\n }).init().then(function () {\n return communicator.open().then(function () {\n resolve(communicator);\n }).catch(reject);\n }).catch(reject);\n } else {\n reject(new Error('No communicator has been set up!'));\n }\n } else {\n reject(new Error('The proxy provider does not have a loadCommunicator method'));\n }\n });\n }\n\n return communicatorPromise;\n },\n\n /**\n * Registers a listener on a particular channel\n * @param {String} name - The name of the channel to listen\n * @param {Function} handler - The listener callback\n * @returns {proxy}\n * @throws TypeError if the name is missing or the handler is not a callback\n */\n channel: function channel(name, handler) {\n if (!_.isString(name) || name.length <= 0) {\n throw new TypeError('A channel must have a name');\n }\n\n if (!_.isFunction(handler)) {\n throw new TypeError('A handler must be attached to a channel');\n }\n\n this.getCommunicator().then(function (communicatorInstance) {\n communicatorInstance.channel(name, handler);\n }) // just an empty catch to avoid any error to be displayed in the console when the communicator is not enabled\n .catch(_.noop);\n this.on(`channel-${name}`, handler);\n return this;\n },\n\n /**\n * Sends an messages through the communication implementation.\n * @param {String} channel - The name of the communication channel to use\n * @param {Object} message - The message to send\n * @returns {Promise} The delegated provider's method must return a promise\n */\n send: function send(channel, message) {\n return this.getCommunicator().then(function (communicatorInstance) {\n return communicatorInstance.send(channel, message);\n });\n },\n\n /**\n * Add extra parameters that will be added to the init or the next callTestAction or callItemAction\n * This enables plugins to place parameters for next calls\n * @param {Object} params - the extra parameters\n * @returns {proxy}\n */\n addCallActionParams: function addCallActionParams(params) {\n if (_.isPlainObject(params)) {\n _.merge(extraCallParams, params);\n }\n\n return this;\n },\n\n /**\n * Gets the test definition data\n * @deprecated\n *\n * @returns {Promise} - Returns a promise. The test definition data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getTestData\n */\n getTestData: function getTestData() {\n /**\n * @event proxy#getTestData\n * @param {Promise} promise\n */\n return delegate('getTestData');\n },\n\n /**\n * Gets the test context\n * @returns {Promise} - Returns a promise. The context object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestContext: function getTestContext() {\n /**\n * @event proxy#getTestContext\n * @param {Promise} promise\n */\n return delegate('getTestContext');\n },\n\n /**\n * Gets the test map\n * @returns {Promise} - Returns a promise. The test map object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestMap: function getTestMap() {\n /**\n * @event proxy#getTestMap\n * @param {Promise} promise\n */\n return delegate('getTestMap');\n },\n\n /**\n * Sends the test variables\n * @param {Object} variables\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later (default: false).\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires sendVariables\n */\n sendVariables: function sendVariables(variables, deferred) {\n /**\n * @event proxy#sendVariables\n * @param {Promise} promise\n */\n return delegate('sendVariables', variables, deferred);\n },\n\n /**\n * Calls an action related to the test\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later.\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires callTestAction\n */\n callTestAction: function callTestAction(action, params, deferred) {\n /**\n * @event proxy#callTestAction\n * @param {Promise} promise\n * @param {String} action\n * @param {Object} params\n */\n return delegate('callTestAction', action, getParams(params), deferred);\n },\n\n /**\n * Gets an item definition by its URI, also gets its current state\n * @param {String} uri - The URI of the item to get\n * @param {Object} [params] - addtional params to be appended\n * @returns {Promise} - Returns a promise. The item data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getItem\n */\n getItem: function getItem(uri, params) {\n /**\n * @event proxy#getItem\n * @param {Promise} promise\n * @param {String} uri\n */\n return delegate('getItem', uri, params);\n },\n\n /**\n * Submits the state and the response of a particular item\n * @param {String} uri - The URI of the item to update\n * @param {Object} state - The state to submit\n * @param {Object} response - The response object to submit\n * @param {Object} [params] - addtional params to be appended\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires submitItem\n */\n submitItem: function submitItem(uri, state, response, params) {\n /**\n * @event proxy#submitItem\n * @param {Promise} promise\n * @param {String} uri\n * @param {Object} state\n * @param {Object} response\n */\n return delegate('submitItem', uri, state, response, getParams(params));\n },\n\n /**\n * Calls an action related to a particular item\n * @param {String} uri - The URI of the item for which call the action\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @param {Boolean} deferred whether action can be scheduled (put into queue) to be sent in a bunch of actions later.\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires callItemAction\n */\n callItemAction: function callItemAction(uri, action, params, deferred) {\n /**\n * @event proxy#callItemAction\n * @param {Promise} promise\n * @param {String} uri\n * @param {String} action\n * @param {Object} params\n */\n return delegate('callItemAction', uri, action, getParams(params), deferred);\n },\n\n /**\n * Sends a telemetry signal\n * @param {String} uri - The URI of the item for which sends the telemetry signal\n * @param {String} signal - The name of the signal to send\n * @param {Object} [params] - Some optional parameters to join to the signal\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires telemetry\n */\n telemetry: function telemetry(uri, signal, params) {\n /**\n * @event proxy#telemetry\n * @param {Promise} promise\n * @param {String} uri\n * @param {String} signal\n * @param {Object} params\n */\n return delegate('telemetry', uri, signal, params);\n }\n }); //listen for connectivty changes\n\n connectivity.on('offline', function () {\n proxy.setOffline('device');\n }).on('online', function () {\n proxy.setOnline();\n }); // catch platform messages that come outside of the communicator component, then each is dispatched to the right channel\n\n proxy.on('message', function (channel, message) {\n this.trigger(`channel-${channel}`, message);\n }).use(function (request, response, next) {\n if (response.data && response.data.messages) {\n // receive server messages\n _.forEach(response.data.messages, function (msg) {\n if (msg.channel) {\n proxy.trigger('message', msg.channel, msg.message);\n } else {\n proxy.trigger('message', 'malformed', msg);\n }\n });\n }\n\n next();\n }) //detect failing request and change the online status\n .use(function (request, response, next) {\n if (proxy.isConnectivityError(response.data)) {\n proxy.setOffline('request');\n } else if (response.data && response.data.sent === true) {\n proxy.setOnline();\n }\n\n next();\n });\n delegateProxy = delegator(proxy, proxyAdapter, {\n name: 'proxy',\n wrapper: function pluginWrapper(response) {\n return Promise.resolve(response);\n }\n });\n return proxy;\n }\n\n var proxy = providerRegistry(proxyFactory);\n\n return proxy;\n\n});\n\n","define('taoTests/runner/providerLoader',['core/logger', 'core/providerLoader', 'core/pluginLoader', 'core/communicator', 'taoTests/runner/runner', 'taoTests/runner/proxy', 'taoItems/runner/api/itemRunner'], function (loggerFactory, providerLoader, pluginLoader, communicator, runner, proxy, itemRunner) { 'use strict';\n\n loggerFactory = loggerFactory && Object.prototype.hasOwnProperty.call(loggerFactory, 'default') ? loggerFactory['default'] : loggerFactory;\n providerLoader = providerLoader && Object.prototype.hasOwnProperty.call(providerLoader, 'default') ? providerLoader['default'] : providerLoader;\n pluginLoader = pluginLoader && Object.prototype.hasOwnProperty.call(pluginLoader, 'default') ? pluginLoader['default'] : pluginLoader;\n communicator = communicator && Object.prototype.hasOwnProperty.call(communicator, 'default') ? communicator['default'] : communicator;\n runner = runner && Object.prototype.hasOwnProperty.call(runner, 'default') ? runner['default'] : runner;\n proxy = proxy && Object.prototype.hasOwnProperty.call(proxy, 'default') ? proxy['default'] : proxy;\n itemRunner = itemRunner && Object.prototype.hasOwnProperty.call(itemRunner, 'default') ? itemRunner['default'] : itemRunner;\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2019 Open Assessment Technologies SA ;\n */\n const logger = loggerFactory('taoTests/runner/loader');\n /**\n * @typedef {Object} provider - A provider is an object exposing a list of methods with respect to the API managed by the target.\n * @property {String} name - The name of the provider. It should be unique among all.\n * @property {Function} init - Each provider much expose at least a method `init()`\n * @property {Function} ... - Any other method the target is expecting\n */\n\n /**\n * Load the providers that match the registration\n * @param {Object} providers\n * @param {provider|provider[]} providers.runner\n * @param {provider|provider[]} [providers.proxy]\n * @param {provider|provider[]} [providers.communicator]\n * @param {provider|provider[]} [providers.plugins]\n * @param {Boolean} loadFromBundle - does the loader load the modules from the sources (dev mode) or the bundles\n * @returns {Promise} resolves with the loaded providers per provider type\n */\n\n function loadTestRunnerProviders() {\n let providers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let loadFromBundle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n /**\n * Default way to load the modules and register the providers\n * @param {Object[]} providersToLoad - the list of providers\n * @param {Object} target - a provider target (an object that use the providers), it needs to expose registerProvider\n * @returns {Promise} resolves with the target\n * @throws {TypeError} if the target is not a provider target\n */\n const loadAndRegisterProvider = function () {\n let providersToLoad = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n let target = arguments.length > 1 ? arguments[1] : undefined;\n\n if (!target || typeof target.registerProvider !== 'function') {\n throw new TypeError('Trying to register providers on a target that is not a provider API');\n }\n\n return providerLoader().addList(providersToLoad).load(loadFromBundle).then(loadedProviders => {\n loadedProviders.forEach(provider => target.registerProvider(provider.name, provider));\n return target;\n });\n };\n /**\n * Available provider registration\n */\n\n\n const registration = {\n runner() {\n let runnerProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(runnerProviders, runner);\n },\n\n itemRunner() {\n let itemRunnerProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return providerLoader().addList(itemRunnerProviders).load(loadFromBundle).then(loadedProviders => {\n loadedProviders.forEach(provider => itemRunner.register(provider.name, provider));\n return itemRunner;\n });\n },\n\n communicator() {\n let communicatorProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(communicatorProviders, communicator);\n },\n\n proxy() {\n let proxyProviders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return loadAndRegisterProvider(proxyProviders, proxy);\n },\n\n plugins() {\n let plugins = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n return pluginLoader().addList(plugins).load(loadFromBundle);\n }\n\n };\n\n if (!loadFromBundle) {\n logger.warn('All modules will be loaded from sources');\n }\n\n return Promise.all(Object.keys(providers).map(providerType => {\n if (typeof registration[providerType] === 'function') {\n logger.debug(`Start to load and register the '${providerType}' providers`);\n const providersToLoad = Array.isArray(providers[providerType]) ? providers[providerType] : [providers[providerType]];\n return registration[providerType](providersToLoad).then(loaded => {\n logger.debug(`'${providerType}' providers are loaded and registered`);\n return {\n [providerType]: loaded\n };\n });\n } else {\n logger.warn(`Ignoring the '${providerType}' providers loading, no registration method found`);\n }\n })).then(results => results.reduce((acc, value) => Object.assign(acc, value), {})).catch(err => {\n logger.error(`Error in test runner providers and plugins loading : ${err.message}`);\n throw err;\n });\n }\n\n return loadTestRunnerProviders;\n\n});\n\n","define('taoTests/runner/proxy/sample',[],function () { 'use strict';\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;\n */\n\n /**\n * @author Jean-Sébastien Conan \n */\n\n /**\n * Sample proxy definition\n * @type {Object}\n */\n var sampleProxy = {\n /**\n * Initializes the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully initialized on resolve.\n * Any error will be provided if rejected.\n */\n init: function init() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // do initialisation\n // once the proxy has been fully initialized notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Uninstalls the proxy\n * @returns {Promise} - Returns a promise. The proxy will be fully uninstalled on resolve.\n * Any error will be provided if rejected.\n */\n destroy: function destroy() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // do uninstall actions\n // once the proxy has been fully uninstalled notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets the test definition data\n * @param {Object} config - The config provided to the proxy factory\n * @returns {Promise} - Returns a promise. The test definition data will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestData: function getTestData() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the test definition data\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets the test context\n * @returns {Promise} - Returns a promise. The context object will be provided on resolve.\n * Any error will be provided if rejected.\n */\n getTestContext: function getTestContext() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the test context object\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Calls an action related to the test\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n */\n callTestAction: function callTestAction() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // call the action\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Gets an item definition by its URI, also gets its current state\n * @param {String} uri - The URI of the item to get\n * @returns {Promise} - Returns a promise. The item data will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires getItem\n */\n getItem: function getItem() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // get the definition data and the state of the item\n // once the item data is loaded provide the data by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Submits the state and the response of a particular item\n * @param {String} uri - The URI of the item to update\n * @param {Object} state - The state to submit\n * @param {Object} response - The response object to submit\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires submitItem\n */\n submitItem: function submitItem() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // submit the state and the response of the item\n // once the data has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Calls an action related to a particular item\n * @param {String} uri - The URI of the item for which call the action\n * @param {String} action - The name of the action to call\n * @param {Object} [params] - Some optional parameters to join to the call\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n */\n callItemAction: function callItemAction() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // call the action\n // once the action has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n },\n\n /**\n * Sends a telemetry signal\n * @param {String} uri - The URI of the item for which sends the telemetry signal\n * @param {String} signal - The name of the signal to send\n * @param {Object} [params] - Some optional parameters to join to the signal\n * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve.\n * Any error will be provided if rejected.\n * @fires telemetry\n */\n telemetry: function telemetry() {\n // the method must return a promise\n return new Promise(function (resolve) {\n // send the signal\n // once the signal has been processed notify the success by resolving the promise\n resolve(); // you can also notify error by rejecting the promise\n // reject(error);\n });\n }\n };\n\n return sampleProxy;\n\n});\n\n","define('taoTests/runner/runnerComponent',['lodash', 'ui/component', 'taoTests/runner/runner', 'taoTests/runner/providerLoader', 'handlebars'], function (_, component, runnerFactory, providerLoader, Handlebars) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n component = component && Object.prototype.hasOwnProperty.call(component, 'default') ? component['default'] : component;\n runnerFactory = runnerFactory && Object.prototype.hasOwnProperty.call(runnerFactory, 'default') ? runnerFactory['default'] : runnerFactory;\n providerLoader = providerLoader && Object.prototype.hasOwnProperty.call(providerLoader, 'default') ? providerLoader['default'] : providerLoader;\n Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;\n\n var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {\n this.compilerInfo = [4,'>= 1.0.0'];\n helpers = this.merge(helpers, Handlebars.helpers); \n\n\n return \"
\\n\";\n });\n function runnerComponentTpl(data, options, asString) {\n var html = Template(data, options);\n return (asString || true) ? html : $(html);\n }\n\n /**\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technologies SA ;\n */\n /**\n * Validate required options from the configuration\n * @param {Object} config\n * @returns {Boolean} true if valid\n * @throws {TypeError} in case of validation failure\n */\n\n function validateTestRunnerConfiguration() {\n let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const requiredProperties = ['providers', 'options', 'serviceCallId'];\n\n if (typeof config !== 'object') {\n throw new TypeError(`The runner configuration must be an object, '${typeof config}' received`);\n }\n\n if (requiredProperties.some(property => typeof config[property] === 'undefined')) {\n throw new TypeError(`The runner configuration must contains at least the following properties : ${requiredProperties.join(',')}`);\n }\n\n return true;\n }\n /**\n * Get the selected provider if set or infer it from the providers list\n * @param {String} type - the type of provider (runner, communicator, proxy, etc.)\n * @param {Object} config\n * @returns {String} the selected provider for the given type\n */\n\n\n function getSelectedProvider() {\n let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'runner';\n let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (config.provider && config.provider[type]) {\n return config.provider[type];\n }\n\n if (config.providers && config.providers[type]) {\n const typeProviders = config.providers[type];\n\n if (typeof typeProviders === 'object' && (typeProviders.id || typeProviders.name)) {\n return typeProviders.id || typeProviders.name;\n }\n\n if (Array.isArray(typeProviders) && typeProviders.length > 0) {\n return typeProviders[0].id || typeProviders[0].name;\n }\n }\n\n return false;\n }\n /**\n * Wraps a test runner into a component\n * @param {jQuery|HTMLElement|String} container - The container in which renders the component\n * @param {Object} config - The component configuration options\n * @param {String} config.serviceCallId - The identifier of the test session\n * @param {Object} config.providers\n * @param {Object} config.options\n * @param {Boolean} [config.loadFromBundle=false] - do we load the modules from the bundles\n * @param {Boolean} [config.replace] - When the component is appended to its container, clears the place before\n * @param {Number|String} [config.width] - The width in pixels, or 'auto' to use the container's width\n * @param {Number|String} [config.height] - The height in pixels, or 'auto' to use the container's height\n * @param {Function} [template] - An optional template for the component\n * @returns {runnerComponent}\n */\n\n\n function runnerComponentFactory() {\n let container = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;\n let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let template = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : runnerComponentTpl;\n let runner = null;\n let plugins = [];\n\n if (!container) {\n throw new TypeError('A container element must be defined to contain the runnerComponent');\n }\n\n validateTestRunnerConfiguration(config);\n /**\n * @typedef {runner} runnerComponent\n */\n\n const runnerComponent = component({\n /**\n * Gets the option's value\n * @param {String} name - the option key\n * @returns {*}\n */\n getOption(name) {\n return this.config.options[name];\n },\n\n /**\n * Gets the test runner\n * @returns {runner}\n */\n getRunner() {\n return runner;\n }\n\n }).setTemplate(template).on('init', function () {\n //load the defined providers for the runner, the proxy, the communicator, the plugins, etc.\n return providerLoader(config.providers, config.loadFromBundle).then(results => {\n if (results && results.plugins) {\n plugins = results.plugins;\n }\n\n this.render(container);\n this.hide();\n }).catch(err => this.trigger('error', err));\n }).on('render', function () {\n const runnerConfig = Object.assign(_.omit(this.config, ['providers']), {\n renderTo: this.getElement()\n });\n runnerConfig.provider = Object.keys(this.config.providers).reduce((acc, providerType) => {\n if (!acc[providerType] && providerType !== 'plugins') {\n acc[providerType] = getSelectedProvider(providerType, this.config);\n }\n\n return acc;\n }, runnerConfig.provider || {});\n runner = runnerFactory(runnerConfig.provider.runner, plugins, runnerConfig).on('ready', () => {\n _.defer(() => {\n this.setState('ready').trigger('ready', runner).show();\n });\n }).on('destroy', () => runner = null).spread(this, 'error').init();\n }).on('destroy', function () {\n var destroying = runner && runner.destroy();\n runner = null;\n return destroying;\n }).after('destroy', function () {\n this.removeAllListeners();\n });\n return runnerComponent.init(config);\n }\n\n return runnerComponentFactory;\n\n});\n\n","define('taoTests/runner/testStore',['lodash', 'core/store', 'core/logger'], function (_, store, loggerFactory) { 'use strict';\n\n _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;\n store = store && Object.prototype.hasOwnProperty.call(store, 'default') ? store['default'] : store;\n loggerFactory = loggerFactory && Object.prototype.hasOwnProperty.call(loggerFactory, 'default') ? loggerFactory['default'] : loggerFactory;\n\n /*\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; under version 2\n * of the License (non-upgradable).\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n *\n * Copyright (c) 2017-2019 (original work) Open Assessment Technologies SA\n *\n */\n /**\n * The test store logger\n * @type {core/logger}\n */\n\n var logger = loggerFactory('taoQtiTest/runner/provider/testStore');\n /**\n * Database name prefix (suffixed by the test identifier)\n * to check if we use the fragmented mode\n * or the unified mode.\n * @type {String[]}\n */\n\n var legacyPrefixes = ['actions-', 'duration-', 'test-probe', 'timer-'];\n /**\n * List the available modes\n */\n\n var modes = {\n unified: 'unified',\n //one db per test, new mode\n fragmented: 'fragmented' //mutliple dbs per test, legacy mode\n\n };\n /**\n * Check and select the store mode.\n * If any of the \"legacyPrefixes\" store is found, we used the fragmented mode\n * otherwise we'll use the unified mode.\n * @param {String} testId\n * @param {Object} [preselectedBackend] - the storage backend\n * @returns {Promise} resolves with the mode of the current test\n */\n\n var selectStoreMode = function selectStoreMode(testId, preselectedBackend) {\n return store.getAll(function validate(storeName) {\n return _.some(legacyPrefixes, function (prefix) {\n return !_.isEmpty(storeName) && prefix + testId === storeName;\n });\n }, preselectedBackend).then(function (foundStores) {\n if (_.isArray(foundStores) && foundStores.length > 0) {\n return modes.fragmented;\n }\n\n return modes.unified;\n });\n };\n /**\n * Get the store for the given test\n *\n * @param {String} testId - unique test instance id\n * @returns {testStore} a 'wrapped' store instance\n * @param {Object} [preselectedBackend] - the storage backend (automatically selected by default)\n * @throws {TypeError} without a testId\n */\n\n\n function testStoreLoader(testId, preselectedBackend) {\n var storeNames = [];\n var volatiles = [];\n var changeTracking = {};\n var testMode;\n /**\n * Is the test using a unified store mode ?\n * @returns {Promise} true if unified\n */\n\n var isStoreModeUnified = function isStoreModeUnified() {\n if (_.isUndefined(testMode)) {\n return selectStoreMode(testId, preselectedBackend).then(function (result) {\n if (result && typeof modes[result] !== 'undefined') {\n testMode = result;\n } else {\n //use the unified mode by default\n testMode = modes.unified;\n }\n\n logger.debug(`Test store mode ${result} for ${testId}`);\n return result === modes.unified;\n });\n }\n\n return Promise.resolve(testMode === modes.unified);\n };\n\n if (_.isEmpty(testId)) {\n throw new TypeError('The store must be identified with a unique test identifier');\n }\n /**\n * Wraps a store and add the support of \"volatile\" storages\n * @typedef {Object} testStore\n */\n\n\n return {\n /**\n * Get a wrapped store instance, that let's you use multiple stores inside one store...\n * (or in multiple stores if the test is in legacy mode)\n * @param {String} storeName - the name of the sub store\n * @returns {Promise}\n */\n getStore: function getStore(storeName) {\n //call when the current storge has been changed\n //only if the store is set to track changes\n var trackChange = function trackChange() {\n if (_.isBoolean(changeTracking[storeName])) {\n changeTracking[storeName] = true;\n }\n };\n\n if (_.isEmpty(storeName)) {\n throw new TypeError('A store name must be provided to get the store');\n }\n\n if (!_.contains(storeNames, storeName)) {\n storeNames.push(storeName);\n }\n\n return isStoreModeUnified().then(function (isUnified) {\n var loadStore;\n\n if (isUnified) {\n loadStore = store(testId, preselectedBackend);\n } else {\n loadStore = store(`${storeName}-${testId}`, preselectedBackend);\n }\n\n return loadStore.then(function (loadedStore) {\n var keyPattern = new RegExp(`^${storeName}__`);\n\n var storeKey = function storeKey(key) {\n return isUnified ? `${storeName}__${key}` : key;\n };\n /**\n * The wrapped storage\n * @type {Object}\n */\n\n\n return {\n /**\n * Get an item with the given key\n * @param {String} key\n * @returns {Promise<*>} with the result in resolve, undefined if nothing\n */\n getItem: function getItem(key) {\n return loadedStore.getItem(storeKey(key));\n },\n\n /**\n * Get all store items\n * @returns {Promise} with a collection of items\n */\n getItems: function getItems() {\n if (isUnified) {\n return loadedStore.getItems().then(function (entries) {\n return _.transform(entries, function (acc, entry, key) {\n if (keyPattern.test(key)) {\n acc[key.replace(keyPattern, '')] = entry;\n }\n\n return acc;\n }, {});\n });\n } else {\n return loadedStore.getItems();\n }\n },\n\n /**\n * Set an item with the given key\n * @param {String} key - the item key\n * @param {*} value - the item value\n * @returns {Promise} with true in resolve if added/updated\n */\n setItem: function setItem(key, value) {\n trackChange();\n return loadedStore.setItem(storeKey(key), value);\n },\n\n /**\n * Remove an item with the given key\n * @param {String} key - the item key\n * @returns {Promise} with true in resolve if removed\n */\n removeItem: function removeItem(key) {\n trackChange();\n return loadedStore.removeItem(storeKey(key));\n },\n\n /**\n * Clear the current store\n * @returns {Promise} with true in resolve once cleared\n */\n clear: function clear() {\n trackChange();\n\n if (isUnified) {\n return loadedStore.getItems().then(function (entries) {\n _.forEach(entries, function (entry, key) {\n if (keyPattern.test(key)) {\n loadedStore.removeItem(key);\n }\n });\n });\n } else {\n return loadedStore.clear();\n }\n }\n };\n });\n });\n },\n\n /**\n * Define the given store as \"volatile\".\n * It means the store data can be revoked\n * if the user change browser for example\n * @param {String} storeName - the name of the store to set as volatile\n * @returns {testStore} chains\n */\n setVolatile: function setVolatile(storeName) {\n if (!_.contains(volatiles, storeName)) {\n volatiles.push(storeName);\n }\n\n return this;\n },\n\n /**\n * Check the given storeId. If different from the current stored identifier\n * we initiate the invalidation of the volatile data.\n * @param {String} storeId - the id to check\n * @returns {Promise} true if cleared\n */\n clearVolatileIfStoreChange: function clearVolatileIfStoreChange(storeId) {\n var self = this;\n var shouldClear = false;\n return store.getIdentifier(preselectedBackend).then(function (savedStoreId) {\n if (!_.isEmpty(storeId) && !_.isEmpty(savedStoreId) && savedStoreId !== storeId) {\n logger.info(`Storage change detected (${savedStoreId} != ${storeId}) => volatiles data wipe out !`);\n shouldClear = true;\n }\n\n return shouldClear;\n }).then(function (clear) {\n if (clear) {\n return self.clearVolatileStores();\n }\n\n return false;\n });\n },\n\n /**\n * Clear the storages marked as volatile\n * @returns {Promise} true if cleared\n */\n clearVolatileStores: function clearVolatileStores() {\n var self = this;\n var clearing = volatiles.map(function (storeName) {\n return self.getStore(storeName).then(function (storeInstance) {\n return storeInstance.clear();\n });\n });\n return Promise.all(clearing).then(function (results) {\n return results && results.length === volatiles.length;\n });\n },\n\n /**\n * Observe changes on the given store\n *\n * @param {String} storeName - the name of the store to observe\n * @returns {testStore} chains\n */\n startChangeTracking: function startChangeTracking(storeName) {\n changeTracking[storeName] = false;\n return this;\n },\n\n /**\n * Has the store some changes\n *\n * @param {String} storeName - the name of the store to set as volatile\n * @returns {Boolean} true if the given store has some changes\n */\n hasChanges: function hasChanges(storeName) {\n return changeTracking[storeName] === true;\n },\n\n /**\n * Reset the change listening\n *\n * @param {String} storeName - the name of the store\n * @returns {testStore} chains\n */\n resetChanges: function resetChanges(storeName) {\n if (_.isBoolean(changeTracking[storeName])) {\n changeTracking[storeName] = false;\n }\n\n return this;\n },\n\n /**\n * Remove the whole store\n * @returns {Promise} true if done\n */\n remove: function remove() {\n var legacyStoreExp = new RegExp(`-${testId}$`);\n return isStoreModeUnified().then(function (isUnified) {\n if (isUnified) {\n return store(testId, preselectedBackend).then(function (storeInstance) {\n return storeInstance.removeStore();\n });\n }\n\n return store.removeAll(function (storeName) {\n return legacyStoreExp.test(storeName);\n }, preselectedBackend);\n });\n },\n\n /**\n * Wraps the identifier retrieval\n * @returns {Promise} the current store id\n */\n getStorageIdentifier: function getStorageIdentifier() {\n return store.getIdentifier(preselectedBackend);\n }\n };\n }\n\n return testStoreLoader;\n\n});\n\n","\ndefine(\"taoTests/loader/taoTestsRunner.bundle\", function(){});\n","define(\"taoTests/loader/taoTestsRunner.min\", [\"taoItems/loader/taoItems.min\"], function(){});\n"]} \ No newline at end of file From abade3b8b659b30dd71117f6211eef432fa9b17e Mon Sep 17 00:00:00 2001 From: Alberto Sanchez Gonzalez Date: Thu, 27 Apr 2023 16:44:09 +0200 Subject: [PATCH 2/5] feat: make use of dev branch on tao extension to add brazilian --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index cb8e901f..2d81ac99 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,7 @@ "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "oat-sa/generis": ">=15.22", "oat-sa/tao-core": ">=50.24.6", - "oat-sa/extension-tao-backoffice": ">=6.0.0", + "oat-sa/extension-tao-backoffice": "dev-feature/AUT-2995", "oat-sa/extension-tao-item": ">=11.0.0" }, "autoload": { From bddb39ecdf264814f2ddde75ec413281f644e97d Mon Sep 17 00:00:00 2001 From: Alberto Sanchez Gonzalez Date: Fri, 28 Apr 2023 16:41:52 +0200 Subject: [PATCH 3/5] feat: make use of dev branch on tao extension to add brazilian --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 2d81ac99..f8f42a19 100644 --- a/composer.json +++ b/composer.json @@ -63,9 +63,9 @@ "require": { "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "oat-sa/generis": ">=15.22", - "oat-sa/tao-core": ">=50.24.6", + "oat-sa/tao-core": "dev-feature/AUT-2995", "oat-sa/extension-tao-backoffice": "dev-feature/AUT-2995", - "oat-sa/extension-tao-item": ">=11.0.0" + "oat-sa/extension-tao-item": "dev-feature/AUT-2995" }, "autoload": { "psr-4": { From 759f63ceafe54243411bb3c8cdf5547611ade16f Mon Sep 17 00:00:00 2001 From: Alberto Sanchez Gonzalez Date: Thu, 4 May 2023 16:18:18 +0200 Subject: [PATCH 4/5] Revert "feat: make use of dev branch on tao extension to add brazilian" This reverts commit bddb39ecdf264814f2ddde75ec413281f644e97d. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f8f42a19..2d81ac99 100644 --- a/composer.json +++ b/composer.json @@ -63,9 +63,9 @@ "require": { "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "oat-sa/generis": ">=15.22", - "oat-sa/tao-core": "dev-feature/AUT-2995", + "oat-sa/tao-core": ">=50.24.6", "oat-sa/extension-tao-backoffice": "dev-feature/AUT-2995", - "oat-sa/extension-tao-item": "dev-feature/AUT-2995" + "oat-sa/extension-tao-item": ">=11.0.0" }, "autoload": { "psr-4": { From bc3dcc294a04399b37edde090455358ecc9c2efa Mon Sep 17 00:00:00 2001 From: Alberto Sanchez Gonzalez Date: Thu, 4 May 2023 16:18:20 +0200 Subject: [PATCH 5/5] Revert "feat: make use of dev branch on tao extension to add brazilian" This reverts commit abade3b8b659b30dd71117f6211eef432fa9b17e. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2d81ac99..cb8e901f 100644 --- a/composer.json +++ b/composer.json @@ -64,7 +64,7 @@ "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "oat-sa/generis": ">=15.22", "oat-sa/tao-core": ">=50.24.6", - "oat-sa/extension-tao-backoffice": "dev-feature/AUT-2995", + "oat-sa/extension-tao-backoffice": ">=6.0.0", "oat-sa/extension-tao-item": ">=11.0.0" }, "autoload": {