diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 4288298334b72dc09bfbf1eb4526480ce5c4aa18..70640034cb465c0214a761775926385e69e6786c 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -39,19 +39,15 @@ jobs: - php: '8.2' moodle-branch: 'MOODLE_404_STABLE' database: 'pgsql' - maxima: 'GCL' + maxima: 'SBCL' - php: '8.1' moodle-branch: 'MOODLE_403_STABLE' database: 'pgsql' - maxima: 'SBCL' + maxima: 'GCL' - php: '8.1' moodle-branch: 'MOODLE_402_STABLE' database: 'pgsql' maxima: 'GCL' - - php: '8.0' - moodle-branch: 'MOODLE_402_STABLE' - database: 'pgsql' - maxima: 'SBCL' # Edinburgh is planning to run the setup below for 2023-24. - php: '7.4' moodle-branch: 'MOODLE_401_STABLE' diff --git a/Readme.md b/Readme.md index 7c0350e3233cf77c8208c85626b4260c3c021460..671ccd8ac7f85d5992683030c0dbdd0210dcf23d 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -# STACK 4.6.0 +# STACK 4.7.0 STACK is an assessment system for mathematics, science and related disciplines. STACK is a question type for the Moodle learning management system, and also the ILIAS learning management system. STACK has an API for stand-alone integration into other 3rd party systems. diff --git a/adminui/caschat.php b/adminui/caschat.php index 4c3eace2d5de2fd9487f9742662d4adee89f0564..021b9b0bc4c977f0bd3696dec3b0d6da1911bf8f 100644 --- a/adminui/caschat.php +++ b/adminui/caschat.php @@ -132,6 +132,9 @@ if ($string) { if ($keyvals->get_valid()) { $kvcode = $keyvals->compile('test'); $statements = []; + if ($kvcode['blockexternal']) { + $statements[] = new stack_secure_loader($kvcode['blockexternal'], 'caschat', 'blockexternal'); + } if ($kvcode['contextvariables']) { $statements[] = new stack_secure_loader($kvcode['contextvariables'], 'caschat'); } diff --git a/amd/build/input.min.js b/amd/build/input.min.js index 09f05bec0b26a936fa50ebd9cd2cacc2e7915495..382b470bc7a4cf9706290dc218f8ffa19c0bb5ce 100644 --- a/amd/build/input.min.js +++ b/amd/build/input.min.js @@ -19,6 +19,6 @@ * @copyright 2018 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("qtype_stack/input",["core/ajax","core_filters/events"],(function(Ajax,CustomEvents){function StackInput(validationDiv,prefix,qaid,name,input,language){var TYPING_DELAY=1e3,delayTimeoutHandle=null,validationResults={},lastValidatedValue=getInputValue();function cancelTypingDelay(){delayTimeoutHandle&&clearTimeout(delayTimeoutHandle),delayTimeoutHandle=null}function valueChanging(){cancelTypingDelay(),showWaiting(),delayTimeoutHandle=setTimeout(valueChanged,TYPING_DELAY),setTimeout((function(){checkNoChange()}),0)}function checkNoChange(){getInputValue()===lastValidatedValue&&(cancelTypingDelay(),validationDiv.classList.remove("waiting"))}function valueChanged(){cancelTypingDelay(),showValidationResults()||validateInput()}function validateInput(){Ajax.call([{methodname:"qtype_stack_validate_input",args:{qaid:qaid,name:name,input:getInputValue(),lang:language},done:function(response){validationReceived(response)},fail:function(response){showValidationFailure(response)}}]),showLoading()}function getInputValue(){return input.getValue()}function validationReceived(response){"invalid"!==response.status?(validationResults[response.input]=response,showValidationResults()):showValidationFailure(response)}function extractScripts(html,scriptCommands){for(var result,scriptregexp=/<script[^>]*>([\s\S]*?)<\/script>/g;null!==(result=scriptregexp.exec(html));)scriptCommands.push(result[1]);return html.replace(scriptregexp,"")}function showValidationResults(){var val=getInputValue();if(!validationResults[val])return showWaiting(),!1;var results=validationResults[val];lastValidatedValue=val;var scriptCommands=[];validationDiv.innerHTML=extractScripts(results.message,scriptCommands);for(var i=0;i<scriptCommands.length;i++)eval(scriptCommands[i]);return removeAllClasses(),results.message||validationDiv.classList.add("empty"),CustomEvents.notifyFilterContentUpdated(validationDiv),!0}function showValidationFailure(response){lastValidatedValue="",validationDiv.innerHTML=response.message,removeAllClasses(),validationDiv.classList.add("error"),CustomEvents.notifyFilterContentUpdated(validationDiv)}function showLoading(){removeAllClasses(),validationDiv.classList.add("loading")}function showWaiting(){removeAllClasses(),validationDiv.classList.add("waiting")}function removeAllClasses(){validationDiv.classList.remove("empty"),validationDiv.classList.remove("error"),validationDiv.classList.remove("loading"),validationDiv.classList.remove("waiting")}input.addEventHandlers(valueChanging)}function StackSimpleInput(input){this.addEventHandlers=function(valueChanging){input.addEventListener("input",valueChanging)},this.getValue=function(){return input.value.replace(/^\s+|\s+$/g,"")}}function StackTextareaInput(textarea){this.addEventHandlers=function(valueChanging){textarea.addEventListener("input",valueChanging)},this.getValue=function(){return textarea.value.replace(/^\s+|\s+$/g,"").split(/\s*[\r\n]\s*/).join("<br>")}}function StackRadioInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){var selected=container.querySelector(":checked");return selected?selected.value:""}}function StackCheckboxInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var selected=container.querySelectorAll(":checked"),result=[],i=0;i<selected.length;i++)result[i]=selected[i].value;return result.length>0?result.join(","):""}}function StackMatrixInput(idPrefix,container){var numcol=0,numrow=0;container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");numrow=Math.max(numrow,parseInt(bits[0],10)+1),numcol=Math.max(numcol,parseInt(bits[1],10)+1)}})),this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var values=new Array(numrow),i=0;i<numrow;i++)values[i]=new Array(numcol);return container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");values[bits[0]][bits[1]]=element.value.replace(/^\s+|\s+$/g,"")}})),JSON.stringify(values)}}function initInputs(questionDivId,prefix,qaid,inputs){var questionDiv=document.getElementById(questionDivId),language=null,langInput=document.getElementsByName(prefix+"step_lang");langInput.length>0&&langInput[0].value&&(language=langInput[0].value);for(var allok=!0,i=0;i<inputs.length;i++)allok=initInput(questionDiv,prefix,qaid,inputs[i],language)&&allok;allok&&(questionDiv.classList.contains("dfexplicitvaildate")||questionDiv.classList.contains("dfcbmexplicitvaildate"))&&(questionDiv.querySelector(".im-controls input.submit, .im-controls button.submit").hidden=!0)}function initInput(questionDiv,prefix,qaid,name,language){var validationDiv=document.getElementById(prefix+name+"_val");if(!validationDiv)return!1;var inputTypeHandler=getInputTypeHandler(questionDiv,prefix,name);return!!inputTypeHandler&&(new StackInput(validationDiv,prefix,qaid,name,inputTypeHandler,language),!0)}function getInputTypeHandler(questionDiv,prefix,name){var input=questionDiv.querySelector('[name="'+prefix+name+'"]');if(input)return"TEXTAREA"===input.nodeName?new StackTextareaInput(input):"radio"===input.type?new StackRadioInput(input.closest(".answer")):new StackSimpleInput(input);if((input=questionDiv.querySelector('[name="'+prefix+name+'_1"]'))&&"checkbox"===input.type)return new StackCheckboxInput(input.closest(".answer"));var matrix=document.getElementById(prefix+name+"_container");return matrix?new StackMatrixInput(prefix+name,matrix):null}return{initInputs:initInputs}})); +define("qtype_stack/input",["core/ajax","core_filters/events"],(function(Ajax,CustomEvents){function StackInput(validationDiv,prefix,qaid,name,input,language,validationsInProgress){var TYPING_DELAY=1e3,delayTimeoutHandle=null,validationResults={},lastValidatedValue=getInputValue(),checkButton=document.getElementById(prefix+"-submit");function cancelTypingDelay(){delayTimeoutHandle&&clearTimeout(delayTimeoutHandle),delayTimeoutHandle=null}function valueChanging(){cancelTypingDelay(),showWaiting(),delayTimeoutHandle=setTimeout(valueChanged,TYPING_DELAY),setTimeout((function(){checkNoChange()}),0)}function checkNoChange(){getInputValue()===lastValidatedValue&&(cancelTypingDelay(),validationDiv.classList.remove("waiting"),checkButton&&(validationsInProgress.delete(name),0===validationsInProgress.size&&(checkButton.disabled=!1)))}function valueChanged(){cancelTypingDelay(),showValidationResults()||validateInput()}function validateInput(){Ajax.call([{methodname:"qtype_stack_validate_input",args:{qaid:qaid,name:name,input:getInputValue(),lang:language},done:function(response){validationReceived(response)},fail:function(response){showValidationFailure(response)}}]),showLoading()}function getInputValue(){return input.getValue()}function validationReceived(response){"invalid"!==response.status?(validationResults[response.input]=response,showValidationResults()):showValidationFailure(response)}function extractScripts(html,scriptCommands){for(var result,scriptregexp=/<script[^>]*>([\s\S]*?)<\/script>/g;null!==(result=scriptregexp.exec(html));)scriptCommands.push(result[1]);return html.replace(scriptregexp,"")}function showValidationResults(){var val=getInputValue();if(!validationResults[val])return showWaiting(),!1;var results=validationResults[val];lastValidatedValue=val;var scriptCommands=[];validationDiv.innerHTML=extractScripts(results.message,scriptCommands);for(var i=0;i<scriptCommands.length;i++)eval(scriptCommands[i]);return removeAllClasses(),results.message||validationDiv.classList.add("empty"),CustomEvents.notifyFilterContentUpdated(validationDiv),!0}function showValidationFailure(response){lastValidatedValue="",validationDiv.innerHTML=response.message,removeAllClasses(),validationDiv.classList.add("error"),CustomEvents.notifyFilterContentUpdated(validationDiv)}function showLoading(){removeAllClasses(),validationDiv.classList.add("loading")}function showWaiting(){removeAllClasses(),validationDiv.classList.add("waiting"),checkButton&&(validationsInProgress.add(name),checkButton.disabled=!0)}function removeAllClasses(){validationDiv.classList.remove("empty"),validationDiv.classList.remove("error"),validationDiv.classList.remove("loading"),validationDiv.classList.remove("waiting"),checkButton&&(validationsInProgress.delete(name),0===validationsInProgress.size&&(checkButton.disabled=!1))}input.addEventHandlers(valueChanging)}function StackSimpleInput(input){this.addEventHandlers=function(valueChanging){input.addEventListener("input",valueChanging)},this.getValue=function(){return input.value.replace(/^\s+|\s+$/g,"")}}function StackTextareaInput(textarea){this.addEventHandlers=function(valueChanging){textarea.addEventListener("input",valueChanging)},this.getValue=function(){return textarea.value.replace(/^\s+|\s+$/g,"").split(/\s*[\r\n]\s*/).join("<br>")}}function StackRadioInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){var selected=container.querySelector(":checked");return selected?selected.value:""}}function StackCheckboxInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var selected=container.querySelectorAll(":checked"),result=[],i=0;i<selected.length;i++)result[i]=selected[i].value;return result.length>0?result.join(","):""}}function StackMatrixInput(idPrefix,container){var numcol=0,numrow=0;container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");numrow=Math.max(numrow,parseInt(bits[0],10)+1),numcol=Math.max(numcol,parseInt(bits[1],10)+1)}})),this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var values=new Array(numrow),i=0;i<numrow;i++)values[i]=new Array(numcol);return container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");values[bits[0]][bits[1]]=element.value.replace(/^\s+|\s+$/g,"")}})),JSON.stringify(values)}}function initInputs(questionDivId,prefix,qaid,inputs){var questionDiv=document.getElementById(questionDivId),validationsInProgress=new Set,language=null,langInput=document.getElementsByName(prefix+"step_lang");langInput.length>0&&langInput[0].value&&(language=langInput[0].value);for(var allok=!0,i=0;i<inputs.length;i++)allok=initInput(questionDiv,prefix,qaid,inputs[i],language,validationsInProgress)&&allok;allok&&(questionDiv.classList.contains("dfexplicitvaildate")||questionDiv.classList.contains("dfcbmexplicitvaildate"))&&(questionDiv.querySelector(".im-controls input.submit, .im-controls button.submit").hidden=!0)}function initInput(questionDiv,prefix,qaid,name,language,validationsInProgress){var validationDiv=document.getElementById(prefix+name+"_val");if(!validationDiv)return!1;var inputTypeHandler=getInputTypeHandler(questionDiv,prefix,name);return!!inputTypeHandler&&(new StackInput(validationDiv,prefix,qaid,name,inputTypeHandler,language,validationsInProgress),!0)}function getInputTypeHandler(questionDiv,prefix,name){var input=questionDiv.querySelector('[name="'+prefix+name+'"]');if(input)return"TEXTAREA"===input.nodeName?new StackTextareaInput(input):"radio"===input.type?new StackRadioInput(input.closest(".answer")):new StackSimpleInput(input);if((input=questionDiv.querySelector('[name="'+prefix+name+'_1"]'))&&"checkbox"===input.type)return new StackCheckboxInput(input.closest(".answer"));var matrix=document.getElementById(prefix+name+"_container");return matrix?new StackMatrixInput(prefix+name,matrix):null}return{initInputs:initInputs}})); //# sourceMappingURL=input.min.js.map \ No newline at end of file diff --git a/amd/build/input.min.js.map b/amd/build/input.min.js.map index b0f6901b6f2bf4306ee5201218e2af7cdb504f30..a73b2a70af7bfc702b87a6a6c6a440b2513e5e28 100644 --- a/amd/build/input.min.js.map +++ b/amd/build/input.min.js.map @@ -1 +1 @@ -{"version":3,"file":"input.min.js","sources":["../src/input.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle the real-time validation of the input the student types\n * into STACK questions.\n *\n * The overall way this works is as follows:\n *\n * - right at the end of this file are the init methods, which set things up.\n * - The work common to all input types is done by StackInput.\n * - Sending the Ajax request.\n * - Updating the validation display.\n * - The work specific to different input types (getting the content of the inputs) is done by\n * the classes like\n * - StackSimpleInput\n * - StackTextareaInput\n * - StackMatrixInput\n * objects of these types need to implement the two methods addEventHandlers and getValue().\n *\n * @module qtype_stack/input\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'core/ajax',\n 'core_filters/events'\n], function(\n Ajax,\n CustomEvents\n) {\n\n \"use strict\";\n\n /**\n * Class constructor representing an input in a Stack question.\n *\n * @constructor\n * @param {HTMLElement} validationDiv The div to display the validation in.\n * @param {String} prefix prefix added to the input name to get HTML ids.\n * @param {String} qaid id of the question_attempt.\n * @param {String} name the name of the input we are validating.\n * @param {Object} input An object representing the input element for this input.\n * @param {String} language display language for this attempt.\n */\n function StackInput(validationDiv, prefix, qaid, name, input, language) {\n /** @type {number} delay between the user stopping typing, and the ajax request being sent. */\n var TYPING_DELAY = 1000;\n\n /** @type {?int} if not null, the id of the timer for the typing delay. */\n var delayTimeoutHandle = null;\n\n /** @type {Object} cache of validation results we have already received. */\n var validationResults = {};\n\n /** @type {String} the last value that we sent to be validated. */\n var lastValidatedValue = getInputValue();\n\n /**\n * Cancel any typing pause timer.\n */\n function cancelTypingDelay() {\n if (delayTimeoutHandle) {\n clearTimeout(delayTimeoutHandle);\n }\n delayTimeoutHandle = null;\n }\n\n input.addEventHandlers(valueChanging);\n\n /**\n * Called when the input contents changes. Will validate after TYPING_DELAY if nothing else happens.\n */\n function valueChanging() {\n cancelTypingDelay();\n showWaiting();\n delayTimeoutHandle = setTimeout(valueChanged, TYPING_DELAY);\n setTimeout(function() {\n checkNoChange();\n }, 0);\n }\n\n /**\n * After a small delay, detect the case where the user has got the input back\n * to where they started, so no validation is necessary.\n */\n function checkNoChange() {\n if (getInputValue() === lastValidatedValue) {\n cancelTypingDelay();\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Called to actually validate the input now.\n */\n function valueChanged() {\n cancelTypingDelay();\n if (!showValidationResults()) {\n validateInput();\n }\n }\n\n /**\n * Make an ajax call to validate the input.\n */\n function validateInput() {\n Ajax.call([{\n methodname: 'qtype_stack_validate_input',\n args: {qaid: qaid, name: name, input: getInputValue(), lang: language},\n done: function(response) {\n validationReceived(response);\n },\n fail: function(response) {\n showValidationFailure(response);\n }\n }]);\n showLoading();\n }\n\n /**\n * Returns the current value of the input.\n *\n * @return {String}.\n */\n function getInputValue() {\n return input.getValue();\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function validationReceived(response) {\n if (response.status === 'invalid') {\n showValidationFailure(response);\n return;\n }\n validationResults[response.input] = response;\n showValidationResults();\n }\n\n /**\n * Some browsers cannot execute JavaScript just by inserting script tags.\n * To avoid that problem, remove all script tags from the given content,\n * and run them later.\n *\n * @param {String} html HTML content\n * @param {Array} scriptCommands An array of script tags for later use.\n * @return {String} HTML with JS removed\n */\n function extractScripts(html, scriptCommands) {\n var scriptregexp = /<script[^>]*>([\\s\\S]*?)<\\/script>/g;\n var result;\n while ((result = scriptregexp.exec(html)) !== null) {\n scriptCommands.push(result[1]);\n }\n return html.replace(scriptregexp, '');\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @return {boolean} true if we could show the validation. false we we are we don't have it.\n */\n function showValidationResults() {\n /* eslint no-eval: \"off\" */\n var val = getInputValue();\n if (!validationResults[val]) {\n showWaiting();\n return false;\n }\n var results = validationResults[val];\n lastValidatedValue = val;\n var scriptCommands = [];\n validationDiv.innerHTML = extractScripts(results.message, scriptCommands);\n // Run script commands.\n for (var i = 0; i < scriptCommands.length; i++) {\n eval(scriptCommands[i]);\n }\n removeAllClasses();\n if (!results.message) {\n validationDiv.classList.add('empty');\n }\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n return true;\n }\n\n /**\n * Update the validation div after an ajax validation call failed.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function showValidationFailure(response) {\n lastValidatedValue = '';\n // Reponse usually contains backtrace, debuginfo, errorcode, link, message and moreinfourl.\n validationDiv.innerHTML = response.message;\n removeAllClasses();\n validationDiv.classList.add('error');\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n }\n\n /**\n * Display the loader icon.\n */\n function showLoading() {\n removeAllClasses();\n validationDiv.classList.add('loading');\n }\n\n /**\n * Update the validation div to show that the input contents have changed,\n * so the validation results are no longer relevant.\n */\n function showWaiting() {\n removeAllClasses();\n validationDiv.classList.add('waiting');\n }\n\n /**\n * Strip all our class names from the validation div.\n */\n function removeAllClasses() {\n validationDiv.classList.remove('empty');\n validationDiv.classList.remove('error');\n validationDiv.classList.remove('loading');\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Input type for inputs that are a single input or select.\n *\n * @constructor\n * @param {HTMLElement} input the HTML input that is this STACK input.\n */\n function StackSimpleInput(input) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n input.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n return input.value.replace(/^\\s+|\\s+$/g, '');\n };\n }\n\n /**\n * Input type for textarea inputs.\n *\n * @constructor\n * @param {Object} textarea The input element wrapped in jquery.\n */\n function StackTextareaInput(textarea) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n textarea.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var raw = textarea.value.replace(/^\\s+|\\s+$/g, '');\n // Using <br> here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('<br>');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackRadioInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelector(':checked');\n if (selected) {\n return selected.value;\n } else {\n return '';\n }\n };\n }\n\n /**\n * Input type for inputs that are a set of checkboxes.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackCheckboxInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelectorAll(':checked');\n var result = [];\n for (var i = 0; i < selected.length; i++) {\n result[i] = selected[i].value;\n }\n if (result.length > 0) {\n return result.join(',');\n } else {\n return '';\n }\n };\n }\n\n /**\n * Class constructor representing matrix inputs (one input).\n *\n * @constructor\n * @param {String} idPrefix input id, which is the start of the id of all the different text boxes.\n * @param {HTMLElement} container <div> of this input.\n */\n function StackMatrixInput(idPrefix, container) {\n var numcol = 0;\n var numrow = 0;\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n numrow = Math.max(numrow, parseInt(bits[0], 10) + 1);\n numcol = Math.max(numcol, parseInt(bits[1], 10) + 1);\n });\n\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var values = new Array(numrow);\n for (var i = 0; i < numrow; i++) {\n values[i] = new Array(numcol);\n }\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n values[bits[0]][bits[1]] = element.value.replace(/^\\s+|\\s+$/g, '');\n });\n return JSON.stringify(values);\n };\n }\n\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer div of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n function initInputs(questionDivId, prefix, qaid, inputs) {\n var questionDiv = document.getElementById(questionDivId);\n var language = null;\n var langInput = document.getElementsByName(prefix + 'step_lang');\n if (langInput.length > 0 && langInput[0].value) {\n language = langInput[0].value;\n }\n\n // Initialise all inputs.\n var allok = true;\n for (var i = 0; i < inputs.length; i++) {\n allok = initInput(questionDiv, prefix, qaid, inputs[i], language) && allok;\n }\n\n // With JS With instant validation, we don't need the Check button, so hide it.\n if (allok && (questionDiv.classList.contains('dfexplicitvaildate') ||\n questionDiv.classList.contains('dfcbmexplicitvaildate'))) {\n questionDiv.querySelector('.im-controls input.submit, .im-controls button.submit').hidden = true;\n }\n }\n\n /**\n * Initialise one input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String} name the input to initialise.\n * @return {boolean} true if this input was successfully initialised, else false.\n * @param {String} language display language for this attempt.\n */\n function initInput(questionDiv, prefix, qaid, name, language) {\n var validationDiv = document.getElementById(prefix + name + '_val');\n if (!validationDiv) {\n return false;\n }\n\n var inputTypeHandler = getInputTypeHandler(questionDiv, prefix, name);\n if (inputTypeHandler) {\n new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler, language);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Get the input type handler for a named input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} name the input to initialise.\n * @return {?Object} the input hander, if we can handle it, else null.\n */\n function getInputTypeHandler(questionDiv, prefix, name) {\n // See if it is an ordinary input.\n var input = questionDiv.querySelector('[name=\"' + prefix + name + '\"]');\n if (input) {\n if (input.nodeName === 'TEXTAREA') {\n return new StackTextareaInput(input);\n } else if (input.type === 'radio') {\n return new StackRadioInput(input.closest('.answer'));\n } else {\n return new StackSimpleInput(input);\n }\n }\n\n // See if it is a checkbox input.\n input = questionDiv.querySelector('[name=\"' + prefix + name + '_1\"]');\n if (input && input.type === 'checkbox') {\n return new StackCheckboxInput(input.closest('.answer'));\n }\n\n // See if it is a matrix input.\n var matrix = document.getElementById(prefix + name + '_container');\n if (matrix) {\n return new StackMatrixInput(prefix + name, matrix);\n }\n\n return null;\n }\n\n /** Export our entry point. */\n return {\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n initInputs: initInputs\n };\n});\n"],"names":["define","Ajax","CustomEvents","StackInput","validationDiv","prefix","qaid","name","input","language","TYPING_DELAY","delayTimeoutHandle","validationResults","lastValidatedValue","getInputValue","cancelTypingDelay","clearTimeout","valueChanging","showWaiting","setTimeout","valueChanged","checkNoChange","classList","remove","showValidationResults","validateInput","call","methodname","args","lang","done","response","validationReceived","fail","showValidationFailure","showLoading","getValue","status","extractScripts","html","scriptCommands","result","scriptregexp","exec","push","replace","val","results","innerHTML","message","i","length","eval","removeAllClasses","add","notifyFilterContentUpdated","addEventHandlers","StackSimpleInput","addEventListener","value","StackTextareaInput","textarea","split","join","StackRadioInput","container","selected","querySelector","StackCheckboxInput","querySelectorAll","StackMatrixInput","idPrefix","numcol","numrow","forEach","element","slice","bits","substring","Math","max","parseInt","values","Array","JSON","stringify","initInputs","questionDivId","inputs","questionDiv","document","getElementById","langInput","getElementsByName","allok","initInput","contains","hidden","inputTypeHandler","getInputTypeHandler","nodeName","type","closest","matrix"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCAA,2BAAO,CACH,YACA,wBACD,SACCC,KACAC,uBAgBSC,WAAWC,cAAeC,OAAQC,KAAMC,KAAMC,MAAOC,cAEtDC,aAAe,IAGfC,mBAAqB,KAGrBC,kBAAoB,GAGpBC,mBAAqBC,yBAKhBC,oBACDJ,oBACAK,aAAaL,oBAEjBA,mBAAqB,cAQhBM,gBACLF,oBACAG,cACAP,mBAAqBQ,WAAWC,aAAcV,cAC9CS,YAAW,WACPE,kBACD,YAOEA,gBACDP,kBAAoBD,qBACpBE,oBACAX,cAAckB,UAAUC,OAAO,qBAO9BH,eACLL,oBACKS,yBACDC,yBAOCA,gBACLxB,KAAKyB,KAAK,CAAC,CACPC,WAAY,6BACZC,KAAM,CAACtB,KAAMA,KAAMC,KAAMA,KAAMC,MAAOM,gBAAiBe,KAAMpB,UAC7DqB,KAAM,SAASC,UACXC,mBAAmBD,WAEvBE,KAAM,SAASF,UACXG,sBAAsBH,cAG9BI,uBAQKrB,uBACEN,MAAM4B,oBAQRJ,mBAAmBD,UACA,YAApBA,SAASM,QAIbzB,kBAAkBmB,SAASvB,OAASuB,SACpCP,yBAJIU,sBAAsBH,mBAgBrBO,eAAeC,KAAMC,wBAEtBC,OADAC,aAAe,qCAE2B,QAAtCD,OAASC,aAAaC,KAAKJ,QAC/BC,eAAeI,KAAKH,OAAO,WAExBF,KAAKM,QAAQH,aAAc,aAQ7BlB,4BAEDsB,IAAMhC,oBACLF,kBAAkBkC,YACnB5B,eACO,MAEP6B,QAAUnC,kBAAkBkC,KAChCjC,mBAAqBiC,QACjBN,eAAiB,GACrBpC,cAAc4C,UAAYV,eAAeS,QAAQE,QAAST,oBAErD,IAAIU,EAAI,EAAGA,EAAIV,eAAeW,OAAQD,IACvCE,KAAKZ,eAAeU,WAExBG,mBACKN,QAAQE,SACT7C,cAAckB,UAAUgC,IAAI,SAGhCpD,aAAaqD,2BAA2BnD,gBACjC,WAQF8B,sBAAsBH,UAC3BlB,mBAAqB,GAErBT,cAAc4C,UAAYjB,SAASkB,QACnCI,mBACAjD,cAAckB,UAAUgC,IAAI,SAE5BpD,aAAaqD,2BAA2BnD,wBAMnC+B,cACLkB,mBACAjD,cAAckB,UAAUgC,IAAI,oBAOvBpC,cACLmC,mBACAjD,cAAckB,UAAUgC,IAAI,oBAMvBD,mBACLjD,cAAckB,UAAUC,OAAO,SAC/BnB,cAAckB,UAAUC,OAAO,SAC/BnB,cAAckB,UAAUC,OAAO,WAC/BnB,cAAckB,UAAUC,OAAO,WAjKnCf,MAAMgD,iBAAiBvC,wBA2KlBwC,iBAAiBjD,YAMjBgD,iBAAmB,SAASvC,eAI7BT,MAAMkD,iBAAiB,QAASzC,qBAQ/BmB,SAAW,kBACL5B,MAAMmD,MAAMd,QAAQ,aAAc,cAUxCe,mBAAmBC,eAMnBL,iBAAmB,SAASvC,eAC7B4C,SAASH,iBAAiB,QAASzC,qBAQlCmB,SAAW,kBACFyB,SAASF,MAAMd,QAAQ,aAAc,IAEpCiB,MAAM,gBAAgBC,KAAK,kBAUrCC,gBAAgBC,gBAMhBT,iBAAmB,SAASvC,eAI7BgD,UAAUP,iBAAiB,QAASzC,qBAQnCmB,SAAW,eACR8B,SAAWD,UAAUE,cAAc,mBACnCD,SACOA,SAASP,MAET,aAWVS,mBAAmBH,gBAMnBT,iBAAmB,SAASvC,eAI7BgD,UAAUP,iBAAiB,QAASzC,qBAQnCmB,SAAW,mBACR8B,SAAWD,UAAUI,iBAAiB,YACtC5B,OAAS,GACJS,EAAI,EAAGA,EAAIgB,SAASf,OAAQD,IACjCT,OAAOS,GAAKgB,SAAShB,GAAGS,aAExBlB,OAAOU,OAAS,EACTV,OAAOsB,KAAK,KAEZ,aAYVO,iBAAiBC,SAAUN,eAC5BO,OAAS,EACTC,OAAS,EACbR,UAAUI,iBAAiB,oBAAoBK,SAAQ,SAASC,YACxDA,QAAQpE,KAAKqE,MAAM,EAAGL,SAASpB,OAAS,KAAOoB,SAAW,aAG1DM,KAAOF,QAAQpE,KAAKuE,UAAUP,SAASpB,OAAS,GAAGW,MAAM,KAC7DW,OAASM,KAAKC,IAAIP,OAAQQ,SAASJ,KAAK,GAAI,IAAM,GAClDL,OAASO,KAAKC,IAAIR,OAAQS,SAASJ,KAAK,GAAI,IAAM,YAQjDrB,iBAAmB,SAASvC,eAC7BgD,UAAUP,iBAAiB,QAASzC,qBAQnCmB,SAAW,mBACR8C,OAAS,IAAIC,MAAMV,QACdvB,EAAI,EAAGA,EAAIuB,OAAQvB,IACxBgC,OAAOhC,GAAK,IAAIiC,MAAMX,eAE1BP,UAAUI,iBAAiB,oBAAoBK,SAAQ,SAASC,YACxDA,QAAQpE,KAAKqE,MAAM,EAAGL,SAASpB,OAAS,KAAOoB,SAAW,aAG1DM,KAAOF,QAAQpE,KAAKuE,UAAUP,SAASpB,OAAS,GAAGW,MAAM,KAC7DoB,OAAOL,KAAK,IAAIA,KAAK,IAAMF,QAAQhB,MAAMd,QAAQ,aAAc,QAE5DuC,KAAKC,UAAUH,kBAYrBI,WAAWC,cAAelF,OAAQC,KAAMkF,YACzCC,YAAcC,SAASC,eAAeJ,eACtC9E,SAAW,KACXmF,UAAYF,SAASG,kBAAkBxF,OAAS,aAChDuF,UAAUzC,OAAS,GAAKyC,UAAU,GAAGjC,QACrClD,SAAWmF,UAAU,GAAGjC,eAIxBmC,OAAQ,EACH5C,EAAI,EAAGA,EAAIsC,OAAOrC,OAAQD,IAC/B4C,MAAQC,UAAUN,YAAapF,OAAQC,KAAMkF,OAAOtC,GAAIzC,WAAaqF,MAIrEA,QAAUL,YAAYnE,UAAU0E,SAAS,uBACrCP,YAAYnE,UAAU0E,SAAS,4BACvBP,YAAYtB,cAAc,yDAAyD8B,QAAS,YAcvGF,UAAUN,YAAapF,OAAQC,KAAMC,KAAME,cAC5CL,cAAgBsF,SAASC,eAAetF,OAASE,KAAO,YACvDH,qBACM,MAGP8F,iBAAmBC,oBAAoBV,YAAapF,OAAQE,cAC5D2F,uBACI/F,WAAWC,cAAeC,OAAQC,KAAMC,KAAM2F,iBAAkBzF,WAC7D,YAcN0F,oBAAoBV,YAAapF,OAAQE,UAE1CC,MAAQiF,YAAYtB,cAAc,UAAY9D,OAASE,KAAO,SAC9DC,YACuB,aAAnBA,MAAM4F,SACC,IAAIxC,mBAAmBpD,OACR,UAAfA,MAAM6F,KACN,IAAIrC,gBAAgBxD,MAAM8F,QAAQ,YAElC,IAAI7C,iBAAiBjD,WAKpCA,MAAQiF,YAAYtB,cAAc,UAAY9D,OAASE,KAAO,UAClC,aAAfC,MAAM6F,YACR,IAAIjC,mBAAmB5D,MAAM8F,QAAQ,gBAI5CC,OAASb,SAASC,eAAetF,OAASE,KAAO,qBACjDgG,OACO,IAAIjC,iBAAiBjE,OAASE,KAAMgG,QAGxC,WAIJ,CASHjB,WAAYA"} \ No newline at end of file +{"version":3,"file":"input.min.js","sources":["../src/input.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle the real-time validation of the input the student types\n * into STACK questions.\n *\n * The overall way this works is as follows:\n *\n * - right at the end of this file are the init methods, which set things up.\n * - The work common to all input types is done by StackInput.\n * - Sending the Ajax request.\n * - Updating the validation display.\n * - The work specific to different input types (getting the content of the inputs) is done by\n * the classes like\n * - StackSimpleInput\n * - StackTextareaInput\n * - StackMatrixInput\n * objects of these types need to implement the two methods addEventHandlers and getValue().\n *\n * @module qtype_stack/input\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'core/ajax',\n 'core_filters/events'\n], function(\n Ajax,\n CustomEvents\n) {\n\n \"use strict\";\n\n /**\n * Class constructor representing an input in a Stack question.\n *\n * @constructor\n * @param {HTMLElement} validationDiv The div to display the validation in.\n * @param {String} prefix prefix added to the input name to get HTML ids.\n * @param {String} qaid id of the question_attempt.\n * @param {String} name the name of the input we are validating.\n * @param {Object} input An object representing the input element for this input.\n * @param {String} language display language for this attempt.\n * @param {Set} validationsInProgress names of inputs being validated for this question.\n */\n function StackInput(validationDiv, prefix, qaid, name, input, language, validationsInProgress) {\n /** @type {number} delay between the user stopping typing, and the ajax request being sent. */\n var TYPING_DELAY = 1000;\n\n /** @type {?int} if not null, the id of the timer for the typing delay. */\n var delayTimeoutHandle = null;\n\n /** @type {Object} cache of validation results we have already received. */\n var validationResults = {};\n\n /** @type {String} the last value that we sent to be validated. */\n var lastValidatedValue = getInputValue();\n /** @type {HTMLElement} the 'Check' button for this question if it exists. */\n var checkButton = document.getElementById(prefix + '-submit');\n\n /**\n * Cancel any typing pause timer.\n */\n function cancelTypingDelay() {\n if (delayTimeoutHandle) {\n clearTimeout(delayTimeoutHandle);\n }\n delayTimeoutHandle = null;\n }\n\n input.addEventHandlers(valueChanging);\n\n /**\n * Called when the input contents changes. Will validate after TYPING_DELAY if nothing else happens.\n */\n function valueChanging() {\n cancelTypingDelay();\n showWaiting();\n delayTimeoutHandle = setTimeout(valueChanged, TYPING_DELAY);\n setTimeout(function() {\n checkNoChange();\n }, 0);\n }\n\n /**\n * After a small delay, detect the case where the user has got the input back\n * to where they started, so no validation is necessary.\n */\n function checkNoChange() {\n if (getInputValue() === lastValidatedValue) {\n cancelTypingDelay();\n validationDiv.classList.remove('waiting');\n if (checkButton) {\n validationsInProgress.delete(name);\n if (validationsInProgress.size === 0) {\n checkButton.disabled = false;\n }\n }\n }\n }\n\n /**\n * Called to actually validate the input now.\n */\n function valueChanged() {\n cancelTypingDelay();\n if (!showValidationResults()) {\n validateInput();\n }\n }\n\n /**\n * Make an ajax call to validate the input.\n */\n function validateInput() {\n Ajax.call([{\n methodname: 'qtype_stack_validate_input',\n args: {qaid: qaid, name: name, input: getInputValue(), lang: language},\n done: function(response) {\n validationReceived(response);\n },\n fail: function(response) {\n showValidationFailure(response);\n }\n }]);\n showLoading();\n }\n\n /**\n * Returns the current value of the input.\n *\n * @return {String}.\n */\n function getInputValue() {\n return input.getValue();\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function validationReceived(response) {\n if (response.status === 'invalid') {\n showValidationFailure(response);\n return;\n }\n validationResults[response.input] = response;\n showValidationResults();\n }\n\n /**\n * Some browsers cannot execute JavaScript just by inserting script tags.\n * To avoid that problem, remove all script tags from the given content,\n * and run them later.\n *\n * @param {String} html HTML content\n * @param {Array} scriptCommands An array of script tags for later use.\n * @return {String} HTML with JS removed\n */\n function extractScripts(html, scriptCommands) {\n var scriptregexp = /<script[^>]*>([\\s\\S]*?)<\\/script>/g;\n var result;\n while ((result = scriptregexp.exec(html)) !== null) {\n scriptCommands.push(result[1]);\n }\n return html.replace(scriptregexp, '');\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @return {boolean} true if we could show the validation. false we we are we don't have it.\n */\n function showValidationResults() {\n /* eslint no-eval: \"off\" */\n var val = getInputValue();\n if (!validationResults[val]) {\n showWaiting();\n return false;\n }\n var results = validationResults[val];\n lastValidatedValue = val;\n var scriptCommands = [];\n validationDiv.innerHTML = extractScripts(results.message, scriptCommands);\n // Run script commands.\n for (var i = 0; i < scriptCommands.length; i++) {\n eval(scriptCommands[i]);\n }\n removeAllClasses();\n if (!results.message) {\n validationDiv.classList.add('empty');\n }\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n return true;\n }\n\n /**\n * Update the validation div after an ajax validation call failed.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function showValidationFailure(response) {\n lastValidatedValue = '';\n // Reponse usually contains backtrace, debuginfo, errorcode, link, message and moreinfourl.\n validationDiv.innerHTML = response.message;\n removeAllClasses();\n validationDiv.classList.add('error');\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n }\n\n /**\n * Display the loader icon.\n */\n function showLoading() {\n removeAllClasses();\n validationDiv.classList.add('loading');\n }\n\n /**\n * Update the validation div to show that the input contents have changed,\n * so the validation results are no longer relevant.\n */\n function showWaiting() {\n removeAllClasses();\n validationDiv.classList.add('waiting');\n if (checkButton) {\n validationsInProgress.add(name);\n checkButton.disabled = true;\n }\n }\n\n /**\n * Strip all our class names from the validation div.\n */\n function removeAllClasses() {\n validationDiv.classList.remove('empty');\n validationDiv.classList.remove('error');\n validationDiv.classList.remove('loading');\n validationDiv.classList.remove('waiting');\n if (checkButton) {\n validationsInProgress.delete(name);\n if (validationsInProgress.size === 0) {\n checkButton.disabled = false;\n }\n }\n }\n }\n\n /**\n * Input type for inputs that are a single input or select.\n *\n * @constructor\n * @param {HTMLElement} input the HTML input that is this STACK input.\n */\n function StackSimpleInput(input) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n input.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n return input.value.replace(/^\\s+|\\s+$/g, '');\n };\n }\n\n /**\n * Input type for textarea inputs.\n *\n * @constructor\n * @param {Object} textarea The input element wrapped in jquery.\n */\n function StackTextareaInput(textarea) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n textarea.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var raw = textarea.value.replace(/^\\s+|\\s+$/g, '');\n // Using <br> here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('<br>');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackRadioInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelector(':checked');\n if (selected) {\n return selected.value;\n } else {\n return '';\n }\n };\n }\n\n /**\n * Input type for inputs that are a set of checkboxes.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackCheckboxInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelectorAll(':checked');\n var result = [];\n for (var i = 0; i < selected.length; i++) {\n result[i] = selected[i].value;\n }\n if (result.length > 0) {\n return result.join(',');\n } else {\n return '';\n }\n };\n }\n\n /**\n * Class constructor representing matrix inputs (one input).\n *\n * @constructor\n * @param {String} idPrefix input id, which is the start of the id of all the different text boxes.\n * @param {HTMLElement} container <div> of this input.\n */\n function StackMatrixInput(idPrefix, container) {\n var numcol = 0;\n var numrow = 0;\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n numrow = Math.max(numrow, parseInt(bits[0], 10) + 1);\n numcol = Math.max(numcol, parseInt(bits[1], 10) + 1);\n });\n\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var values = new Array(numrow);\n for (var i = 0; i < numrow; i++) {\n values[i] = new Array(numcol);\n }\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n values[bits[0]][bits[1]] = element.value.replace(/^\\s+|\\s+$/g, '');\n });\n return JSON.stringify(values);\n };\n }\n\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer div of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n function initInputs(questionDivId, prefix, qaid, inputs) {\n var questionDiv = document.getElementById(questionDivId);\n var validationsInProgress = new Set();\n var language = null;\n var langInput = document.getElementsByName(prefix + 'step_lang');\n if (langInput.length > 0 && langInput[0].value) {\n language = langInput[0].value;\n }\n\n // Initialise all inputs.\n var allok = true;\n for (var i = 0; i < inputs.length; i++) {\n allok = initInput(questionDiv, prefix, qaid, inputs[i], language, validationsInProgress) && allok;\n }\n\n // With JS With instant validation, we don't need the Check button, so hide it.\n if (allok && (questionDiv.classList.contains('dfexplicitvaildate') ||\n questionDiv.classList.contains('dfcbmexplicitvaildate'))) {\n questionDiv.querySelector('.im-controls input.submit, .im-controls button.submit').hidden = true;\n }\n }\n\n /**\n * Initialise one input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String} name the input to initialise.\n * @return {boolean} true if this input was successfully initialised, else false.\n * @param {String} language display language for this attempt.\n * @param {Set} validationsInProgress names of inputs being validated for this question.\n */\n function initInput(questionDiv, prefix, qaid, name, language, validationsInProgress) {\n var validationDiv = document.getElementById(prefix + name + '_val');\n if (!validationDiv) {\n return false;\n }\n var inputTypeHandler = getInputTypeHandler(questionDiv, prefix, name);\n if (inputTypeHandler) {\n new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler, language, validationsInProgress);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Get the input type handler for a named input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} name the input to initialise.\n * @return {?Object} the input hander, if we can handle it, else null.\n */\n function getInputTypeHandler(questionDiv, prefix, name) {\n // See if it is an ordinary input.\n var input = questionDiv.querySelector('[name=\"' + prefix + name + '\"]');\n if (input) {\n if (input.nodeName === 'TEXTAREA') {\n return new StackTextareaInput(input);\n } else if (input.type === 'radio') {\n return new StackRadioInput(input.closest('.answer'));\n } else {\n return new StackSimpleInput(input);\n }\n }\n\n // See if it is a checkbox input.\n input = questionDiv.querySelector('[name=\"' + prefix + name + '_1\"]');\n if (input && input.type === 'checkbox') {\n return new StackCheckboxInput(input.closest('.answer'));\n }\n\n // See if it is a matrix input.\n var matrix = document.getElementById(prefix + name + '_container');\n if (matrix) {\n return new StackMatrixInput(prefix + name, matrix);\n }\n\n return null;\n }\n\n /** Export our entry point. */\n return {\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n initInputs: initInputs\n };\n});\n"],"names":["define","Ajax","CustomEvents","StackInput","validationDiv","prefix","qaid","name","input","language","validationsInProgress","TYPING_DELAY","delayTimeoutHandle","validationResults","lastValidatedValue","getInputValue","checkButton","document","getElementById","cancelTypingDelay","clearTimeout","valueChanging","showWaiting","setTimeout","valueChanged","checkNoChange","classList","remove","delete","size","disabled","showValidationResults","validateInput","call","methodname","args","lang","done","response","validationReceived","fail","showValidationFailure","showLoading","getValue","status","extractScripts","html","scriptCommands","result","scriptregexp","exec","push","replace","val","results","innerHTML","message","i","length","eval","removeAllClasses","add","notifyFilterContentUpdated","addEventHandlers","StackSimpleInput","addEventListener","value","StackTextareaInput","textarea","split","join","StackRadioInput","container","selected","querySelector","StackCheckboxInput","querySelectorAll","StackMatrixInput","idPrefix","numcol","numrow","forEach","element","slice","bits","substring","Math","max","parseInt","values","Array","JSON","stringify","initInputs","questionDivId","inputs","questionDiv","Set","langInput","getElementsByName","allok","initInput","contains","hidden","inputTypeHandler","getInputTypeHandler","nodeName","type","closest","matrix"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCAA,2BAAO,CACH,YACA,wBACD,SACCC,KACAC,uBAiBSC,WAAWC,cAAeC,OAAQC,KAAMC,KAAMC,MAAOC,SAAUC,2BAEhEC,aAAe,IAGfC,mBAAqB,KAGrBC,kBAAoB,GAGpBC,mBAAqBC,gBAErBC,YAAcC,SAASC,eAAeb,OAAS,oBAK1Cc,oBACDP,oBACAQ,aAAaR,oBAEjBA,mBAAqB,cAQhBS,gBACLF,oBACAG,cACAV,mBAAqBW,WAAWC,aAAcb,cAC9CY,YAAW,WACPE,kBACD,YAOEA,gBACDV,kBAAoBD,qBACpBK,oBACAf,cAAcsB,UAAUC,OAAO,WAC3BX,cACAN,sBAAsBkB,OAAOrB,MACM,IAA/BG,sBAAsBmB,OACtBb,YAAYc,UAAW,cAS9BN,eACLL,oBACKY,yBACDC,yBAOCA,gBACL/B,KAAKgC,KAAK,CAAC,CACPC,WAAY,6BACZC,KAAM,CAAC7B,KAAMA,KAAMC,KAAMA,KAAMC,MAAOO,gBAAiBqB,KAAM3B,UAC7D4B,KAAM,SAASC,UACXC,mBAAmBD,WAEvBE,KAAM,SAASF,UACXG,sBAAsBH,cAG9BI,uBAQK3B,uBACEP,MAAMmC,oBAQRJ,mBAAmBD,UACA,YAApBA,SAASM,QAIb/B,kBAAkByB,SAAS9B,OAAS8B,SACpCP,yBAJIU,sBAAsBH,mBAgBrBO,eAAeC,KAAMC,wBAEtBC,OADAC,aAAe,qCAE2B,QAAtCD,OAASC,aAAaC,KAAKJ,QAC/BC,eAAeI,KAAKH,OAAO,WAExBF,KAAKM,QAAQH,aAAc,aAQ7BlB,4BAEDsB,IAAMtC,oBACLF,kBAAkBwC,YACnB/B,eACO,MAEPgC,QAAUzC,kBAAkBwC,KAChCvC,mBAAqBuC,QACjBN,eAAiB,GACrB3C,cAAcmD,UAAYV,eAAeS,QAAQE,QAAST,oBAErD,IAAIU,EAAI,EAAGA,EAAIV,eAAeW,OAAQD,IACvCE,KAAKZ,eAAeU,WAExBG,mBACKN,QAAQE,SACTpD,cAAcsB,UAAUmC,IAAI,SAGhC3D,aAAa4D,2BAA2B1D,gBACjC,WAQFqC,sBAAsBH,UAC3BxB,mBAAqB,GAErBV,cAAcmD,UAAYjB,SAASkB,QACnCI,mBACAxD,cAAcsB,UAAUmC,IAAI,SAE5B3D,aAAa4D,2BAA2B1D,wBAMnCsC,cACLkB,mBACAxD,cAAcsB,UAAUmC,IAAI,oBAOvBvC,cACLsC,mBACAxD,cAAcsB,UAAUmC,IAAI,WACxB7C,cACAN,sBAAsBmD,IAAItD,MAC1BS,YAAYc,UAAW,YAOtB8B,mBACLxD,cAAcsB,UAAUC,OAAO,SAC/BvB,cAAcsB,UAAUC,OAAO,SAC/BvB,cAAcsB,UAAUC,OAAO,WAC/BvB,cAAcsB,UAAUC,OAAO,WAC3BX,cACAN,sBAAsBkB,OAAOrB,MACM,IAA/BG,sBAAsBmB,OACtBb,YAAYc,UAAW,IA/KnCtB,MAAMuD,iBAAiB1C,wBA2LlB2C,iBAAiBxD,YAMjBuD,iBAAmB,SAAS1C,eAI7Bb,MAAMyD,iBAAiB,QAAS5C,qBAQ/BsB,SAAW,kBACLnC,MAAM0D,MAAMd,QAAQ,aAAc,cAUxCe,mBAAmBC,eAMnBL,iBAAmB,SAAS1C,eAC7B+C,SAASH,iBAAiB,QAAS5C,qBAQlCsB,SAAW,kBACFyB,SAASF,MAAMd,QAAQ,aAAc,IAEpCiB,MAAM,gBAAgBC,KAAK,kBAUrCC,gBAAgBC,gBAMhBT,iBAAmB,SAAS1C,eAI7BmD,UAAUP,iBAAiB,QAAS5C,qBAQnCsB,SAAW,eACR8B,SAAWD,UAAUE,cAAc,mBACnCD,SACOA,SAASP,MAET,aAWVS,mBAAmBH,gBAMnBT,iBAAmB,SAAS1C,eAI7BmD,UAAUP,iBAAiB,QAAS5C,qBAQnCsB,SAAW,mBACR8B,SAAWD,UAAUI,iBAAiB,YACtC5B,OAAS,GACJS,EAAI,EAAGA,EAAIgB,SAASf,OAAQD,IACjCT,OAAOS,GAAKgB,SAAShB,GAAGS,aAExBlB,OAAOU,OAAS,EACTV,OAAOsB,KAAK,KAEZ,aAYVO,iBAAiBC,SAAUN,eAC5BO,OAAS,EACTC,OAAS,EACbR,UAAUI,iBAAiB,oBAAoBK,SAAQ,SAASC,YACxDA,QAAQ3E,KAAK4E,MAAM,EAAGL,SAASpB,OAAS,KAAOoB,SAAW,aAG1DM,KAAOF,QAAQ3E,KAAK8E,UAAUP,SAASpB,OAAS,GAAGW,MAAM,KAC7DW,OAASM,KAAKC,IAAIP,OAAQQ,SAASJ,KAAK,GAAI,IAAM,GAClDL,OAASO,KAAKC,IAAIR,OAAQS,SAASJ,KAAK,GAAI,IAAM,YAQjDrB,iBAAmB,SAAS1C,eAC7BmD,UAAUP,iBAAiB,QAAS5C,qBAQnCsB,SAAW,mBACR8C,OAAS,IAAIC,MAAMV,QACdvB,EAAI,EAAGA,EAAIuB,OAAQvB,IACxBgC,OAAOhC,GAAK,IAAIiC,MAAMX,eAE1BP,UAAUI,iBAAiB,oBAAoBK,SAAQ,SAASC,YACxDA,QAAQ3E,KAAK4E,MAAM,EAAGL,SAASpB,OAAS,KAAOoB,SAAW,aAG1DM,KAAOF,QAAQ3E,KAAK8E,UAAUP,SAASpB,OAAS,GAAGW,MAAM,KAC7DoB,OAAOL,KAAK,IAAIA,KAAK,IAAMF,QAAQhB,MAAMd,QAAQ,aAAc,QAE5DuC,KAAKC,UAAUH,kBAYrBI,WAAWC,cAAezF,OAAQC,KAAMyF,YACzCC,YAAc/E,SAASC,eAAe4E,eACtCpF,sBAAwB,IAAIuF,IAC5BxF,SAAW,KACXyF,UAAYjF,SAASkF,kBAAkB9F,OAAS,aAChD6F,UAAUxC,OAAS,GAAKwC,UAAU,GAAGhC,QACrCzD,SAAWyF,UAAU,GAAGhC,eAIxBkC,OAAQ,EACH3C,EAAI,EAAGA,EAAIsC,OAAOrC,OAAQD,IAC/B2C,MAAQC,UAAUL,YAAa3F,OAAQC,KAAMyF,OAAOtC,GAAIhD,SAAUC,wBAA0B0F,MAI5FA,QAAUJ,YAAYtE,UAAU4E,SAAS,uBACrCN,YAAYtE,UAAU4E,SAAS,4BACvBN,YAAYtB,cAAc,yDAAyD6B,QAAS,YAevGF,UAAUL,YAAa3F,OAAQC,KAAMC,KAAME,SAAUC,2BACtDN,cAAgBa,SAASC,eAAeb,OAASE,KAAO,YACvDH,qBACM,MAEPoG,iBAAmBC,oBAAoBT,YAAa3F,OAAQE,cAC5DiG,uBACIrG,WAAWC,cAAeC,OAAQC,KAAMC,KAAMiG,iBAAkB/F,SAAUC,wBACvE,YAcN+F,oBAAoBT,YAAa3F,OAAQE,UAE1CC,MAAQwF,YAAYtB,cAAc,UAAYrE,OAASE,KAAO,SAC9DC,YACuB,aAAnBA,MAAMkG,SACC,IAAIvC,mBAAmB3D,OACR,UAAfA,MAAMmG,KACN,IAAIpC,gBAAgB/D,MAAMoG,QAAQ,YAElC,IAAI5C,iBAAiBxD,WAKpCA,MAAQwF,YAAYtB,cAAc,UAAYrE,OAASE,KAAO,UAClC,aAAfC,MAAMmG,YACR,IAAIhC,mBAAmBnE,MAAMoG,QAAQ,gBAI5CC,OAAS5F,SAASC,eAAeb,OAASE,KAAO,qBACjDsG,OACO,IAAIhC,iBAAiBxE,OAASE,KAAMsG,QAGxC,WAIJ,CASHhB,WAAYA"} \ No newline at end of file diff --git a/amd/src/input.js b/amd/src/input.js index a3273ac408a59cf7d1cb5af01a7851249002661f..4a62dade5f23cae990920d99cf7cbd59eac47cf0 100644 --- a/amd/src/input.js +++ b/amd/src/input.js @@ -54,8 +54,9 @@ define([ * @param {String} name the name of the input we are validating. * @param {Object} input An object representing the input element for this input. * @param {String} language display language for this attempt. + * @param {Set} validationsInProgress names of inputs being validated for this question. */ - function StackInput(validationDiv, prefix, qaid, name, input, language) { + function StackInput(validationDiv, prefix, qaid, name, input, language, validationsInProgress) { /** @type {number} delay between the user stopping typing, and the ajax request being sent. */ var TYPING_DELAY = 1000; @@ -67,6 +68,8 @@ define([ /** @type {String} the last value that we sent to be validated. */ var lastValidatedValue = getInputValue(); + /** @type {HTMLElement} the 'Check' button for this question if it exists. */ + var checkButton = document.getElementById(prefix + '-submit'); /** * Cancel any typing pause timer. @@ -100,6 +103,12 @@ define([ if (getInputValue() === lastValidatedValue) { cancelTypingDelay(); validationDiv.classList.remove('waiting'); + if (checkButton) { + validationsInProgress.delete(name); + if (validationsInProgress.size === 0) { + checkButton.disabled = false; + } + } } } @@ -230,6 +239,10 @@ define([ function showWaiting() { removeAllClasses(); validationDiv.classList.add('waiting'); + if (checkButton) { + validationsInProgress.add(name); + checkButton.disabled = true; + } } /** @@ -240,6 +253,12 @@ define([ validationDiv.classList.remove('error'); validationDiv.classList.remove('loading'); validationDiv.classList.remove('waiting'); + if (checkButton) { + validationsInProgress.delete(name); + if (validationsInProgress.size === 0) { + checkButton.disabled = false; + } + } } } @@ -431,6 +450,7 @@ define([ */ function initInputs(questionDivId, prefix, qaid, inputs) { var questionDiv = document.getElementById(questionDivId); + var validationsInProgress = new Set(); var language = null; var langInput = document.getElementsByName(prefix + 'step_lang'); if (langInput.length > 0 && langInput[0].value) { @@ -440,7 +460,7 @@ define([ // Initialise all inputs. var allok = true; for (var i = 0; i < inputs.length; i++) { - allok = initInput(questionDiv, prefix, qaid, inputs[i], language) && allok; + allok = initInput(questionDiv, prefix, qaid, inputs[i], language, validationsInProgress) && allok; } // With JS With instant validation, we don't need the Check button, so hide it. @@ -459,16 +479,16 @@ define([ * @param {String} name the input to initialise. * @return {boolean} true if this input was successfully initialised, else false. * @param {String} language display language for this attempt. + * @param {Set} validationsInProgress names of inputs being validated for this question. */ - function initInput(questionDiv, prefix, qaid, name, language) { + function initInput(questionDiv, prefix, qaid, name, language, validationsInProgress) { var validationDiv = document.getElementById(prefix + name + '_val'); if (!validationDiv) { return false; } - var inputTypeHandler = getInputTypeHandler(questionDiv, prefix, name); if (inputTypeHandler) { - new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler, language); + new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler, language, validationsInProgress); return true; } else { return false; diff --git a/api/README.md b/api/README.md index d36ee63faa7a98e7f0aa58a95e896857c6f33885..9d7b2aebf4949be54640b4bab240ee54b7b0282a 100644 --- a/api/README.md +++ b/api/README.md @@ -15,7 +15,7 @@ E.g. see `https://hub.docker.com/r/mathinstitut/goemaxima` for images. The image requires maxima to be available via http. The URL can be configured via the environment variable `MAXIMA_URL` and defaults to `http://maxima:8080/maxima`. An example docker-compose file deploying both stack and maxima in the goemaxima variant is provided below: ``` -version: "3.9" +version: "4.0" services: maxima: image: mathinstitut/goemaxima:2023121100-latest @@ -48,11 +48,13 @@ The application can also be installed manually, although this variant has only u ## Usage instructions -The STACK service implemented in this repository provides a stateless REST-API with three distinct routes, which all expect and produce `application/json` requests/responses: +The STACK service implemented in this repository provides a stateless REST-API with five distinct routes, which all expect and produce `application/json` requests/responses: -- POST /render: Render a stack question +- POST /render: Render a STACK question - POST /grade: Grade user input for a question - POST /validate: Validate a user's input +- POST /download: Serves a file for questions that have download links +- POST /test: Run a questions tests against all deployed variants ### Render route @@ -141,6 +143,75 @@ The `POST /download` route is used to download files created by questions. The requested file is returned. +### Test route + +The `POST /test` route is used to run a question's test cases. + +- `questionDefinition`: The Moodle-XML-Export of a single STACK question. + +The grading route returns the following fields: + +- string: `name`: The name of the question. +- string: `messages`: Question level error messages. +- boolean: `isupgradeerror`: Are there any issues related to questions being non-compliant with a STACK upgrade? +- boolean: `isgeneralfeedback`: Does the question have general feedback? +- boolean: `isdeployedseeds`: Does the question have deployed seeds? +- boolean: `israndomvariants`: Does the question use random variants? +- boolean: `istests`: Does the question have tests? +- object: `results`: The test results for each each seed, keyed by seed. If the question does not have random variants, there will be a single entry keyed `noseed`. + +In the `results` object, each seed will key an object: +- int|null: `passes`: Number of tests passed. +- int|null: `fails`: Number of tests failed. +- string: `messages`: Seed level error message. Includes summaries from the test, runtime errors and general feedback errors. +- object: `outcomes`: Gives detailed breakdown of test result. Entries keyed by `<testcase>`. + +In the outcomes object, each test will key an object: +- boolean: `passed`: Did the test pass? +- string: `reason`: Reason for failure. A test empty message or the part of the output (e.g. score) which doesn't match the expected result. +- object: `inputs`: Keyed by input name. Details of the inputs and their values. +- object: `outcomes`: Keyed by PRT name. Details of the outcomes and expected outcomes for each PRT. + +Example result object: +``` +"563119235": { + "passes": 1, + "fails": 0, + "messages": "", + "outcomes": { + "1": { + "passed": true, + "reason": "", + "inputs": { + "ans1": { + "inputexpression": "ans1", + "inputentered": "1.6486", + "inputmodified": "1.6486", + "inputdisplayed": "\\[ 1.6486 \\]", + "inputstatus": "Score", + "errors": "" + } + }, + "outcomes": { + "prt1": { + "outcome": true, + "score": 1, + "penalty": 0, + "answernote": "prt1-1-T", + "expectedscore": 1, + "expectedpenalty": 0, + "expectedanswernote": "prt1-1-T", + "feedback": "", + "reason": "" + } + } + } + } +} + ``` + +If a question has no tests, a default test will be run to check if the model answers return a score of 1. + ### Rendered CASText format The API returns rendered CASText as parts of its responses in multiple places. The CASText is output as a single string in an intermediate format, which cannot be directly fed to browsers for display, and requires further processing. Applications using the API have to handle the following cases: @@ -164,7 +235,6 @@ If an error occurs during processing of a request, a response with a single JSON ### Limitations -- Questions requiring custom javascript are not supported. This includes questions using JSXGraph. - If a question uses randomization, it has to contain deployed variants. - Grading is only done if all inputs are present and valid (which implies non-empty in most cases). @@ -195,7 +265,7 @@ To ease the development process, the Dockerfile contained in the repository cont docker compose -f docker-compose.dev.yml build docker compose -f docker-compose.dev.yml up -The required development image will automatically be build. After the stack started, you will be able to access the service via http://localhost:3080. Any performed changes in the PHP code will be visible live. Note, that Maxima is provided by a geomaxima docker image, and this image will _not_ reflect local changes. The development build also contains the xdebug extension, which is configured to connect to `host.docker.internal` as a debugger, which will resolve to the locale machines ip address when using docker desktop. Please note that the performance of the development setup will be significantly worse than in production. +The required development image will automatically be built. After the stack started, you will be able to access the service via http://localhost:3080. Any performed changes in the PHP code will be visible live. Note, that Maxima is provided by a geomaxima docker image, and this image will _not_ reflect local changes. The development build also contains the xdebug extension, which is configured to connect to `host.docker.internal` as a debugger, which will resolve to the locale machines ip address when using docker desktop. Please note that the performance of the development setup will be significantly worse than in production. ### Docker production setup @@ -238,6 +308,8 @@ To allow the stack-moodle-plugin to work standalone, some classes and functions A basic frontend is provided at `http://localhost:3080/stack.php`. This should allow you to load the STACK sample questions and try them out. This requires API specific versions of `cors.php` and `stackjsvle.js` (to access files and create iframes) which are in the public folder. +`http://localhost:3080/bulktest.php` provides a front end for selecting a folder of STACK question files and running their included tests, similar to the STACK bulk test functionality in Moodle. + ### Modifications of existing STACK code The implementation of the standalone api required some modifications to existing STACK code, which could cause issues with future upstream patches. All performed modifications are documented in this section. @@ -262,7 +334,7 @@ To be accessible directly, the following property/method visibility have been pr #### Minor changes in STACK 4.6.0 - Some new language keys have been added. -- Some imports inside the `question.php` and `mathsoutputfilterbase.class.php` files have been wrapped inside an if statement, to only be performed in non api contexts. +- Some imports inside the `question.php` and `mathsoutputfilterbase.class.php` files have been wrapped inside an if statement, to only be performed in non-API contexts. - A new `get_ta_render_for_input` function has been added to the `qtype_stack_question` class. - A new `pluginfiles` property has been added to the `qtype_stack_question` class. - `iframe.block.php` handles plot URLs and iframe creation conditional on context (i.e API vs not API). diff --git a/api/composer.json b/api/composer.json index ea478cf19ae6e3c44022d134b2863ed802c83500..2b1d936bdefaf6bd90ea3a0b188222bd6ae5f144 100644 --- a/api/composer.json +++ b/api/composer.json @@ -3,7 +3,7 @@ "type": "project", "require": { "slim/slim": "4.*", - "slim/psr7": "^1.6", + "slim/psr7": "^1.6.1", "erusev/parsedown": "^1.7.4" }, "authors": [ diff --git a/api/composer.lock b/api/composer.lock index a6aabb900f45668afecf2b11c1652922f0bfec52..170dc1046f05762ca5740eb276be4a046b6b39b8 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "86ccba856047aba257c6695db856ecde", + "content-hash": "f163e5500e1e8d33e543a427654239e2", "packages": [ { "name": "erusev/parsedown", @@ -217,21 +217,21 @@ }, { "name": "psr/http-factory", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0" + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -251,10 +251,10 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -266,31 +266,31 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2019-04-30T12:38:16+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -319,27 +319,27 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { "name": "psr/http-server-handler", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-server-handler.git", - "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", - "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", "shasum": "" }, "require": { "php": ">=7.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -359,7 +359,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP server-side request handler", @@ -375,28 +375,27 @@ "server" ], "support": { - "issues": "https://github.com/php-fig/http-server-handler/issues", - "source": "https://github.com/php-fig/http-server-handler/tree/master" + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" }, - "time": "2018-10-30T16:46:14+00:00" + "time": "2023-04-10T20:06:20+00:00" }, { "name": "psr/http-server-middleware", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-server-middleware.git", - "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", - "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", "shasum": "" }, "require": { "php": ">=7.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.0 || ^2.0", "psr/http-server-handler": "^1.0" }, "type": "library", @@ -417,7 +416,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP server-side middleware", @@ -433,36 +432,36 @@ ], "support": { "issues": "https://github.com/php-fig/http-server-middleware/issues", - "source": "https://github.com/php-fig/http-server-middleware/tree/master" + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" }, - "time": "2018-10-30T17:12:04+00:00" + "time": "2023-04-11T06:14:47+00:00" }, { "name": "psr/log", - "version": "3.0.0", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { - "php": ">=8.0.0" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "src" + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -483,9 +482,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2021-05-03T11:20:27+00:00" }, { "name": "ralouphie/getallheaders", @@ -533,16 +532,16 @@ }, { "name": "slim/psr7", - "version": "1.6", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/slimphp/Slim-Psr7.git", - "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d" + "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3471c22c1a0d26c51c78f6aeb06489d38cf46a4d", - "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/72d2b2bac94ab4575d369f605dbfafbe168d3163", + "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163", "shasum": "" }, "require": { @@ -561,7 +560,7 @@ "adriansuter/php-autoload-override": "^1.3", "ext-json": "*", "http-interop/http-factory-tests": "^0.9.0", - "php-http/psr7-integration-tests": "dev-master", + "php-http/psr7-integration-tests": "1.1", "phpspec/prophecy": "^1.15", "phpspec/prophecy-phpunit": "^2.0", "phpstan/phpstan": "^1.8", @@ -609,22 +608,22 @@ ], "support": { "issues": "https://github.com/slimphp/Slim-Psr7/issues", - "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6" + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6.1" }, - "time": "2022-11-05T18:50:24+00:00" + "time": "2023-04-17T16:02:20+00:00" }, { "name": "slim/slim", - "version": "4.11.0", + "version": "4.14.0", "source": { "type": "git", "url": "https://github.com/slimphp/Slim.git", - "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7" + "reference": "5943393b88716eb9e82c4161caa956af63423913" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7", - "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913", + "reference": "5943393b88716eb9e82c4161caa956af63423913", "shasum": "" }, "require": { @@ -632,28 +631,29 @@ "nikic/fast-route": "^1.3", "php": "^7.4 || ^8.0", "psr/container": "^1.0 || ^2.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", "psr/http-server-handler": "^1.0", "psr/http-server-middleware": "^1.0", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "require-dev": { - "adriansuter/php-autoload-override": "^1.3", + "adriansuter/php-autoload-override": "^1.4", "ext-simplexml": "*", - "guzzlehttp/psr7": "^2.4", - "httpsoft/http-message": "^1.0", - "httpsoft/http-server-request": "^1.0", - "laminas/laminas-diactoros": "^2.17", - "nyholm/psr7": "^1.5", - "nyholm/psr7-server": "^1.0", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/phpstan": "^1.8", - "phpunit/phpunit": "^9.5", - "slim/http": "^1.2", - "slim/psr7": "^1.5", - "squizlabs/php_codesniffer": "^3.7" + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5.24" }, "suggest": { "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", @@ -726,20 +726,20 @@ "type": "tidelift" } ], - "time": "2022-11-06T16:33:39+00:00" + "time": "2024-06-13T08:54:48+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -747,9 +747,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -793,7 +790,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -809,7 +806,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" } ], "packages-dev": [], diff --git a/api/config_sample.txt b/api/config_sample.txt index 7f82639ae2d22e56d6c7ae6654f71d04e49e11d0..65020a242a25954941fee9b9a9d0e0930fa7ba21 100644 --- a/api/config_sample.txt +++ b/api/config_sample.txt @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -// This script handles the various deploy/undeploy actions from questiontestrun.php. -// // @copyright 2023 RWTH Aachen // @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. @@ -93,10 +91,13 @@ $CFG->inputmustverify = 1; $CFG->inputshowvalidation = 1; // These should match the version of goemaxima in docker-compose. -$CFG->stackmaximaversion = "2024060300"; -$CFG->version = "2024060300"; +$CFG->stackmaximaversion = "2025072400"; +$CFG->version = "2025072400"; // Do not change this setting. $CFG->mathsdisplay = 'api'; $CFG->libdir = $CFG->dirroot . '/emulation/libdir'; + +// MathJax URL. +$CFG->httpsurl = 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; diff --git a/api/controller/DownloadController.php b/api/controller/DownloadController.php index 517b6aa99559c3984a400497532f69e16a742dcf..1b7adaf00392ea0a387d04726569f886842edd81 100644 --- a/api/controller/DownloadController.php +++ b/api/controller/DownloadController.php @@ -41,7 +41,7 @@ class DownloadController { $name = $data['filename']; $tdid = $data['fileid']; - $question = StackQuestionLoader::loadxml($data["questionDefinition"]); + $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question']; StackSeedHelper::initialize_seed($question, $data["seed"]); diff --git a/api/controller/GradingController.php b/api/controller/GradingController.php index a1e9029db01a80f9a0195f0f7a17b470e5c65434..ac92728e00a35bf6a7d40e5d4a1e37de57f28b45 100644 --- a/api/controller/GradingController.php +++ b/api/controller/GradingController.php @@ -44,7 +44,7 @@ class GradingController { // TO-DO: Validate. $data = $request->getParsedBody(); - $question = StackQuestionLoader::loadxml($data["questionDefinition"]); + $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question']; StackSeedHelper::initialize_seed($question, $data["seed"]); diff --git a/api/controller/RenderController.php b/api/controller/RenderController.php index a89da53a5d95bd506504bd4a9985b2bdaac03417..a17bb9b7b9330a0eb58a06de2c64b7841ee0039b 100644 --- a/api/controller/RenderController.php +++ b/api/controller/RenderController.php @@ -45,7 +45,7 @@ class RenderController { // TO-DO: Validate. $data = $request->getParsedBody(); - $question = StackQuestionLoader::loadxml($data["questionDefinition"]); + $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question']; StackSeedHelper::initialize_seed($question, $data["seed"]); diff --git a/api/controller/TestController.php b/api/controller/TestController.php new file mode 100644 index 0000000000000000000000000000000000000000..1f60dada4d8af6cbf1ddcb7a9cdb0dc594ca156b --- /dev/null +++ b/api/controller/TestController.php @@ -0,0 +1,223 @@ +<?php +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +// This script handles the running of question tests for a supplied question +// +// @copyright 2024 University of Edinburgh +// @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + +namespace api\controller; +defined('MOODLE_INTERNAL') || die(); +require_once(__DIR__ . '/../dtos/StackTestResponse.php'); +require_once(__DIR__ . '/../util/StackQuestionLoader.php'); +require_once(__DIR__ . '/../util/StackSeedHelper.php'); +require_once(__DIR__ . '/../../stack/questiontestresult.php'); + +use api\util\StackQuestionLoader; +use api\util\StackSeedHelper; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; +use api\dtos\StackTestResponse; + +/** + * Handles the running of question tests for a supplied question + * + * Based heavily on bulktester.class.php and questiontest.php but they rely on + * Moodle context and create HTML. Here we're just getting test results and + * leaving display for the front end. + */ +class TestController { + /** + * @throws \stack_exception + * @throws \Exception + */ + public function __invoke(Request $request, Response $response, array $args): Response { + // TO-DO: Validate. + $data = $request->getParsedBody(); + + list('question' => $question, 'testcases' => $testcases) = StackQuestionLoader::loadxml($data["questionDefinition"], true); + $question->castextprocessor = new \castext2_qa_processor(new \stack_outofcontext_process()); + + $testresponse = new StackTestResponse(); + $testresponse->name = $question->name; + + // We want to flag if the question is missing general feedback, has deployed seeds, + // has random variants and/or has tests. It's up to the front end to decide what to do with that info. + if (trim($question->generalfeedback) !== '') { + $testresponse->isgeneralfeedback = true; + } + + if (!empty($question->deployedseeds)) { + $testresponse->isdeployedseeds = true; + } + + if ($question->has_random_variants()) { + $testresponse->israndomvariants = true; + } + + if ($testcases) { + $testresponse->istests = true; + } + + // If the question uses random variants but has no deployed seeds we can't even initialise + // the question so return response. + if ($testresponse->israndomvariants && !$testresponse->isdeployedseeds) { + $testresponse->results = []; + $response->getBody()->write(json_encode($testresponse)); + return $response->withHeader('Content-Type', 'application/json'); + } else { + StackSeedHelper::initialize_seed($question, $data["seed"]); + $question->initialise_question_from_seed(); + } + + // Check for upgrade errors and return response immediately if so. + // Errors will be listed in overall response messages. + $dummycontext = new \stdClass(); // Required for unit tests. + $dummycontext->id = 0; + $upgradeerrors = $question->validate_against_stackversion($dummycontext); + if ($upgradeerrors != '') { + $testresponse->isupgradeerror = true; + $testresponse->messages = $upgradeerrors; + $testresponse->results = []; + $response->getBody()->write(json_encode($testresponse)); + return $response->withHeader('Content-Type', 'application/json'); + } + + // Create test results for each deployed seed. If no random variants, then use 'noseed' as + // array index. + if (empty($question->deployedseeds)) { + try { + $testresponse->results = [ + 'noseed' => $this->qtype_stack_test_question($question, $testcases, null), + ]; + } catch (\stack_exception $e) { + $testresponse->results['noseed'] = [ + 'passes' => null, + 'fails' => null, + 'messages' => stack_string('errors') . ' : ' . $e, + 'outcomes' => null, + ]; + } + } else { + foreach ($question->deployedseeds as $seed) { + try { + $testresponse->results[$seed] = $this->qtype_stack_test_question($question, $testcases, $seed); + } catch (\stack_exception $e) { + $testresponse->results[$seed] = [ + 'passes' => null, + 'fails' => null, + 'messages' => stack_string('errors') . ' : ' . $e, + 'outcomes' => null, + ]; + } + } + } + $response->getBody()->write(json_encode($testresponse)); + return $response->withHeader('Content-Type', 'application/json'); + } + + /** + * Run the tests for one variant of one question and display the results. + * + * @param object $question the question to test. + * @param array $testcases the questions tests. + * @param int|null $seed if we want to force a particular version. + * @return array with elements: + * int passes - number of tests passed. + * int fails - number of tests failed. + * string messages - error messages. + * array outcomes - detailed info on the outcomes of the test. + * (See stack_question_test_result->passed_with_reasons. + * TO-DO Is it worth creating a class for this?) + */ + public function qtype_stack_test_question($question, $testcases, $seed = null) { + if (!is_null($seed)) { + $question->seed = (int) $seed; + } + // Execute the tests for each seed. + // Return number of passed tests, number of failed tests, any error messages + // and outcomes - an array of summaries of the test results. + $passes = 0; + $fails = 0; + $message = ''; + $outcomes = []; + $question->options->set_option('decimals', '.'); + foreach ($testcases as $testcase) { + $response = \stack_question_test::compute_response($question, $testcase->inputs); + $results = $testcase->process_results($question, $response); + $summary = $results->passed_with_reasons(); + $outcomes[$testcase->testcase] = $summary; + if ($summary['passed']) { + $passes += 1; + } else { + $fails += 1; + $message .= $summary['reason']; + } + } + + // If we don't have any tests, check to see if the model answers give a score of 1. + if (count($testcases) === 0 && count($question->prts) > 0) { + $inputs = []; + foreach ($question->inputs as $inputname => $input) { + $inputs[$inputname] = $input->get_teacher_answer_testcase(); + } + $qtest = new \stack_question_test(stack_string('autotestcase'), $inputs); + $response = \stack_question_test::compute_response($question, $inputs); + + foreach ($question->prts as $prtname => $prt) { + $result = $question->get_prt_result($prtname, $response, false); + // We could just check if score === 1 at this point but by creating + // a test and running it we get the full outcomes in the same + // format as above. + $answernotes = $result->get_answernotes(); + $answernote = [end($answernotes)]; + $qtest->add_expected_result($prtname, new \stack_potentialresponse_tree_state( + 1, true, 1, 0, '', $answernote)); + } + $results = $qtest->process_results($question, $response); + $summary = $results->passed_with_reasons(); + $outcomes[$qtest->testcase] = $summary; + if ($summary['passed']) { + $passes = 1; + } else { + $fails = 1; + $message = stack_string('defaulttestfail'); + } + } + + $generalfeedback = $question->get_generalfeedback_castext(); + + $generalfeedback->get_rendered($question->castextprocessor); + if ($generalfeedback->get_errors() != '') { + $s = stack_string('stackInstall_testsuite_errors') . ' ' . + stack_string('generalfeedback') . ': ' . $generalfeedback->get_errors(); + $message .= $s; + } + + if (!empty($question->runtimeerrors)) { + $s = stack_string('stackInstall_testsuite_errors') . ' ' . + implode(' ', array_keys($question->runtimeerrors)); + $message .= $s; + } + + return [ + 'passes' => $passes, + 'fails' => $fails, + 'messages' => $message, + 'outcomes' => $outcomes, + ]; + } +} diff --git a/api/controller/ValidationController.php b/api/controller/ValidationController.php index b10545e2eec067c3dbced95321db1a0b1d132765..4eb1c732e22752370f72f9acbb69ee8e9376a087 100644 --- a/api/controller/ValidationController.php +++ b/api/controller/ValidationController.php @@ -42,7 +42,7 @@ class ValidationController { // TO-DO: Validate. $data = $request->getParsedBody(); - $question = StackQuestionLoader::loadxml($data["questionDefinition"]); + $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question']; StackSeedHelper::initialize_seed($question, $data["seed"]); diff --git a/api/docker/docker-compose.dev.yml b/api/docker/docker-compose.dev.yml index 268a66b5103817ad5cfbaea88328252a25f38920..548f6fc22156215be30ecbf762c6786bf593e7be 100644 --- a/api/docker/docker-compose.dev.yml +++ b/api/docker/docker-compose.dev.yml @@ -1,7 +1,7 @@ version: "4.0" services: maxima: - image: mathinstitut/goemaxima:2024060300-latest + image: mathinstitut/goemaxima:2025072400-latest tmpfs: - "/tmp" restart: unless-stopped diff --git a/api/docker/docker-compose.yml b/api/docker/docker-compose.yml index df97a5a405c3a96fae1d1d0c3eac6e5c6ea7ac1b..054c3dee214133e3b8b3551ef2bd9d066d669182 100644 --- a/api/docker/docker-compose.yml +++ b/api/docker/docker-compose.yml @@ -1,7 +1,7 @@ version: "4.0" services: maxima: - image: mathinstitut/goemaxima:2024060300-latest + image: mathinstitut/goemaxima:2025072400-latest tmpfs: - "/tmp" restart: unless-stopped @@ -15,7 +15,7 @@ services: read_only: true stack: # Location of published STACK API image goes here. - image: + image: restart: unless-stopped ports: - '3080:80' diff --git a/api/dtos/StackTestResponse.php b/api/dtos/StackTestResponse.php new file mode 100644 index 0000000000000000000000000000000000000000..e5e86f82b3dc3d542a567f4020a8150a063096a0 --- /dev/null +++ b/api/dtos/StackTestResponse.php @@ -0,0 +1,45 @@ +<?php +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +/** + * Response to a question test request + * + * @copyright 2024 Uuniversity of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ + +namespace api\dtos; + +class StackTestResponse { + /** @var string */ + public $name = ''; + /** @var string */ + public $messages = ''; + /** @var bool */ + public $isupgradeerror = false; + /** @var bool */ + public $isgeneralfeedback = false; + /** @var bool */ + public $isdeployedseeds = false; + /** @var bool */ + public $israndomvariants = false; + /** @var bool */ + public $istests = false; + /** @var array + * Array keyed by seed (or 'noseed'). Subarrays have 'passes' , 'fails', 'messages[]', 'outcomes'. + */ + public $results = []; +} diff --git a/api/emulation/MoodleEmulation.php b/api/emulation/MoodleEmulation.php index 86593cd21eeb943d822c4bf728f79b03635900e0..ae8cbf908de5dd768d7db6518d647e7cfd48bf8a 100644 --- a/api/emulation/MoodleEmulation.php +++ b/api/emulation/MoodleEmulation.php @@ -89,6 +89,15 @@ function require_login() { return; } +function get_file_storage() { + $storage = new class { + public function get_area_files($x, $y, $z, $a) { + return []; + } + }; + return $storage; +} + // Specialized emulations. require_once('Constants.php'); require_once('Localization.php'); diff --git a/api/public/bulktest.php b/api/public/bulktest.php new file mode 100644 index 0000000000000000000000000000000000000000..a50e7f4b48bf7a62d756f09e6bf89844e5b3195e --- /dev/null +++ b/api/public/bulktest.php @@ -0,0 +1,415 @@ +<?php +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +// This script handles the various deploy/undeploy actions from questiontestrun.php. +// +// @copyright 2023 University of Edinburgh +// @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. +require_once('../config.php'); +require_once(__DIR__ . '../../emulation/MoodleEmulation.php'); +// Required to pass Moodle code check. Uses emulation stub. +require_login(); +?> +<html> + <head> + <meta charset="utf-8"/> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" /> + <style> + .feedback { + color: black; + background-color: #fcf2d4; + border-radius: 4px; + border: 1px solid #7d5a2933; + padding: 5px; + margin-left: 10px; + width: fit-content; + } + .passed { + background-color: lightgreen; + } + .failed { + background-color: pink; + } + .seed { + color: darkblue; + } + .question-title { + margin-top: 20px; + } + .path-title { + color: grey; + } + a.nav-link:link, a.nav-link:visited, a.nav-link:hover, a.nav-link:active { + color:black; + text-decoration:none; + } + </style> + </head> + <body> + <script> + // Keep track of all requests sent to the server so we can check they're all complete. + var requests = []; + var filesToProcess = []; + // Keep an array for which questions have failed for each reason for easy display of summary. + var noFeedbackArray = []; + var noTestsArray = []; + var upgradeIssueArray = []; + var noDeployedSeedsArray = []; + var failedTestsArray = []; + var generalErrorArray = []; + + /** + * Send a question to the server for testing. Filepath required + * for ordering the output by folder. + */ + function send(filepath, questionxml) { + const http = new XMLHttpRequest(); + requests.push(http); + document.getElementById('bulktest-button').setAttribute('disabled', true); + document.getElementById('bulktest-spinner').removeAttribute('hidden'); + const url = window.location.origin + '/test'; + http.open("POST", url, true); + http.setRequestHeader('Content-Type', 'application/json'); + + // Create nested <div>s with ids and titles representing the file structure in + // preparation for displaying results. + // Files being sent in sorted order so we don't need to sort again. + const pathArray = filepath.split('/'); + let currentDiv = ''; + for (const part of pathArray) { + let prevDiv = currentDiv; + currentDiv += (currentDiv) ? '/' : ''; + currentDiv += part; + if (!document.getElementById(currentDiv)) { + const newDivEl = document.createElement("div"); + newDivEl.setAttribute('id', currentDiv); + newDivEl.innerHTML = '<h5 class="path-title">' + currentDiv + '</h5>'; + if (prevDiv) { + const prevDivEl = document.getElementById(prevDiv); + newDivEl.setAttribute('style', 'margin-left: 10px;'); + prevDivEl.appendChild(newDivEl); + } else { + document.getElementById('output').appendChild(newDivEl); + } + } + } + http.onreadystatechange = function() { + if(http.readyState == 4) { + // Create div to show results of an individual question. + const resultDiv = document.createElement("div"); + resultDiv.setAttribute('style', 'margin-left: 10px;'); + try { + // If there's a JSON error, display output then this whole question has a problem somewhere. + // Add to general erros and give up. + const json = JSON.parse(http.responseText); + if (json.message) { + resultDiv.innerHTML = '<p class="feedback failed">' + json.error + ' - JSON: ' + http.responseText + '</p>'; + const parentDivEl = document.getElementById(filepath); + parentDivEl.appendChild(resultDiv); + generalErrorArray.push(filepath); + } else { + let resultHtml = '<h3 class="question-title">' + json.name + '</h3>'; + resultDiv.setAttribute('id', json.name); + + // Display issues based on returned flags. + resultHtml += (json.isgeneralfeedback) ? + '' : '<p class="feedback"><?php echo stack_string('bulktestnogeneralfeedback')?></p>'; + resultHtml += (json.istests) ? '' : '<p class="feedback"><?php echo stack_string('bulktestnotests')?></p>'; + resultHtml += (json.israndomvariants && !json.isdeployedseeds) ? + '<p class="feedback"><?php echo stack_string('bulktestnodeployedseeds')?></p>' : ''; + resultHtml += (json.israndomvariants && json.isdeployedseeds) ? + '<div style="margin-left: 20px">' : ''; // Open div for seeds. + for (seed in json.results) { + // If there are no random variants, there should be one result indexed as 'noseed'. + if (seed !== 'noseed') { + resultHtml += '<h5 class="seed"><?php echo stack_string('seedx', '')?>' + seed + '</h5>'; + } + if (json.istests && json.results[seed].passes !== null) { + // If tests have been run, displays number of passes and fails. + resultHtml += '<p class="feedback' + ((json.results[seed].fails === 0) ? ' passed' :' failed') + '">' + + json.results[seed].passes + ' <?php echo stack_string('api_passes')?>, ' + + json.results[seed].fails + ' <?php echo stack_string('api_failures')?>.</p>'; + if ((json.results[seed].fails !== 0) || json.results[seed].messages) { + failedTestsArray.push({'name': json.name, 'seed': seed, 'filepath': filepath, + 'passes': json.results[seed].passes, 'fails': json.results[seed].fails, + 'message': json.results[seed].messages}); + for (const testname in json.results[seed].outcomes) { + const outcome = json.results[seed].outcomes[testname]; + // Display outcomes of failed tests if available. There should be a reason if not. + // Reason will be displayed as part of messages. + if (!outcome.passed) { + if (!outcome.reason) { + resultHtml += '<p>' + testname + ' : ' + JSON.stringify(outcome.inputs) + '</p>'; + resultHtml += '<p>' + testname + ' : ' + JSON.stringify(outcome.outcomes) + '</p>'; + } + } + } + } + } + if (!json.istests && json.results[seed].passes == 1) { + resultHtml += '<p class="feedback passed">' + '<?php echo stack_string('defaulttestpass')?>' + '</p>'; + } + // Display seed level messages - will be exceptions. + if (json.results[seed].messages) { + resultHtml += '<p class="feedback failed">' + json.results[seed].messages + '</p>'; + } + // If we've got no tests but a failed test, then our fallback test of using the teacher's + // answer and expecting a score of 1 has failed. + if (!json.istests && json.results[seed].fails) { + failedTestsArray.push({'name': json.name, 'seed': seed, 'filepath': filepath, + 'message': json.results[seed].messages}); + } + } + resultHtml += (json.israndomvariants && json.isdeployedseeds) ? '</div>' : ''; // Close div for seeds. + // Display question level messages. (Upgrade errors). + resultHtml += (json.messages) ? '<p class="feedback failed">' + json.messages + '</p>' : ''; + resultDiv.innerHTML = resultHtml; + // Append result to correct div then sort questions by name. (Calls are async so we may not + // get the results back in the correct order). + const parentDivEl = document.getElementById(filepath); + parentDivEl.appendChild(resultDiv); + parentDivEl.replaceChildren(...Array.from(parentDivEl.children).sort((a,b) => a.id.localeCompare(b.id))); + + // Update the lists of failed tests in each category. + const overallUpdate = [ + [!json.istests, noTestsArray], + [!json.isgeneralfeedback, noFeedbackArray], + [json.israndomvariants && !json.isdeployedseeds, noDeployedSeedsArray], + [json.isupgradeerror, upgradeIssueArray], + [json.message && !json.isupgradeerror, generalErrorArray], + ] + for (const update of overallUpdate) { + if (update[0] === true) { + update[1].push({'name': json.name, 'filepath': filepath}) + } + } + } + } catch(e) { + // Something has gone very wrong. + resultDiv.innerText = e.message + ' - JSON: ' + http.responseText; + resultDiv.innerHTML += '<br><br>'; + document.getElementById('errors').appendChild(resultDiv); + document.getElementById('errors').removeAttribute('hidden'); + generalErrorArray.push(filepath); + } + + // Remove current request from pending array + requests = requests.filter(req => req !== http); + if (requests.length === 0 && filesToProcess.length === 0) { + displayOverallResults(); + } + } + }; + http.send(JSON.stringify({'questionDefinition': questionxml})); + } + + /** + * Display the overall pass/fail message and the collections of failed + * tests by category of failure. We need to have processed all the files + * and got a response to all the requests before running this. + * + * @return void + */ + function displayOverallResults() { + // All done. Display final lists of failed questions by category. + let overallPass = true; + document.getElementById('bulktest-button').removeAttribute('disabled'); + document.getElementById('bulktest-spinner').setAttribute('hidden', true); + document.getElementById('overall-results').removeAttribute('hidden'); + const displayUpdate = [ + [noTestsArray, 'no-tests'], + [noFeedbackArray, 'no-feedback'], + [upgradeIssueArray, 'upgrade-fail'], + [noDeployedSeedsArray, 'no-deployed-seeds'], + [failedTestsArray, 'failed-tests'], + [generalErrorArray, 'general-error'], + ] + for (const update of displayUpdate) { + const targetTitle = document.getElementById(update[1] + '-title') + if (update[0].length === 0) { + targetTitle.setAttribute('hidden', true); + continue; + } + overallPass = false; + targetTitle.removeAttribute('hidden'); + const targetDiv = document.getElementById(update[1]); + targetDiv.innerHTML = ''; + const listEl = document.createElement('ul'); + for (const issue of update[0]) { + const itemEl = document.createElement('li'); + itemEl.innerHTML = issue.filepath + itemEl.innerHTML += (issue.name !== undefined) ? ' : ' + issue.name : ''; + itemEl.innerHTML += (issue.seed !== undefined && issue.seed !== 'noseed') ? + ' : <?php echo stack_string('seedx', '')?>' + issue.seed : ''; + itemEl.innerHTML += (issue.passes !== undefined) ? + ' - (' + issue.passes + ' <?php echo stack_string('api_passes')?>, ' + + issue.fails + ' <?php echo stack_string('api_failures')?>)' : ''; + itemEl.innerHTML += (issue.message !== undefined) ? '<br>' + issue.message : ''; + listEl.appendChild(itemEl); + } + listEl.replaceChildren(...Array.from(listEl.children).sort((a,b) => a.innerHTML.localeCompare(b.innerHTML))); + targetDiv.appendChild(listEl); + document.getElementById('overall-result').innerHTML = (overallPass) ? + '<div class="feedback passed"><?php echo stack_string('stackInstall_testsuite_pass')?></div><br>' : + '<div class="feedback failed"><?php echo stack_string('stackInstall_testsuite_fail')?></div><br>'; + } + } + + /** + * Initialise output and sort selected files. + * Keeps track of files processed so far to avoid race condition possibility + * between the calls to the server and the reading/parsing of a long file. + * + * @return void + */ + function testFolder() { + let files = document.getElementById('local-folder').files; + if (!files.length) { + return; + } + document.getElementById('bulktest-button').setAttribute('disabled', true); + document.getElementById('bulktest-spinner').removeAttribute('hidden'); + document.getElementById('overall-results').setAttribute('hidden', true); + document.getElementById('errors').setAttribute('hidden', true); + document.getElementById('errors').innerHTML = '<h1><?php echo stack_string('api_errors')?></h1><br>'; + document.getElementById('output').innerHTML = ''; + requests = []; + filesToProcess = []; + noFeedbackArray = []; + noTestsArray = []; + upgradeIssueArray = []; + noDeployedSeedsArray = []; + failedTestsArray = []; + generalErrorArray = []; + readingFile = true; + files = Array.from(files).sort((a,b) => a.webkitRelativePath.localeCompare(b.webkitRelativePath)); + for (const file of files) { + filesToProcess.push(file.webkitRelativePath); + } + for (const file of files) { + if (file.type === 'application/xml' || file.type === 'text/xml') { + getLocalQuestionFile(file); + } else { + filesToProcess = filesToProcess.filter(item => item !== file.webkitRelativePath); + } + } + if (requests.length === 0 && filesToProcess.length === 0) { + document.getElementById('bulktest-button').removeAttribute('disabled'); + document.getElementById('bulktest-spinner').setAttribute('hidden', true); + } + } + + /** + * Read a file + */ + function getLocalQuestionFile(file) { + if (file) { + const reader = new FileReader(); + reader.readAsText(file, "UTF-8"); + reader.onload = function (evt) { + sendQuestionsFromFile(file.webkitRelativePath, evt.target.result); + filesToProcess = filesToProcess.filter(item => item !== file.webkitRelativePath); + // Maybe we're done. Check if so and display the results if appropriate. + // This is unlikely but maybe we finished with a large file with no + // STACK questions and so all the requests are already complete. + if (requests.length === 0 && filesToProcess.length === 0) { + displayOverallResults(); + } + } + } + } + + /** + * Parse an XML file, chop into stack questions and send test requests for each one. + */ + function sendQuestionsFromFile(filepath, fileContents) { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(fileContents, "text/xml"); + const errorNode = xmlDoc.querySelector("parsererror"); + if (errorNode) { + const resultDiv = document.createElement("div"); + resultDiv.innerHTML += '<p class="feedback failed">' + filepath + ': ' + errorNode.innerHTML + '</p><br><br>'; + document.getElementById('errors').appendChild(resultDiv); + document.getElementById('errors').removeAttribute('hidden'); + generalErrorArray.push(filepath); + return; + } + let questions = xmlDoc.getElementsByTagName("question"); + for (const question of questions) { + if (question.getAttribute('type').toLowerCase() === 'stack') { + send(filepath, '<quiz>\n' + question.outerHTML + '\n</quiz>'); + } + } + } + + </script> + + <div class="container-fluid que stack"> + <div class="vstack gap-3 ms-3 col-lg-8"> + <div> + <a href="https://stack-assessment.org/" class="nav-link"> + <span style="display: flex; align-items: center; font-size: 20px"> + <span style="display: flex; align-items: center;"> + <img src="logo_large.png" style="height: 50px;"> + <span style="font-size: 50px;"><b>STACK </b></span> + </span> + | Online assessment + </span> + </a> + </div> + <?php echo stack_string('api_choose_folder')?>: + <input type="file" id="local-folder" accept=".xml" name="local-folder" webkitdirectory directory multiple/> + <div> + <button id="bulktest-button" onclick="testFolder()" class="btn btn-primary" type="button"> + <span id="bulktest-spinner" class="spinner-border spinner-border-sm" role="status" aria-hidden="true" hidden></span> + Test + </button> + </div> + </div> + <br> + <div id='output'> + </div> + <div id='errors' hidden> + </div> + <br><br> + <div id="overall-results" hidden> + <h1>Overall Results</h1> + <div id="overall-result"> + </div> + <h3 id="failed-tests-title"><?php echo stack_string('stackInstall_testsuite_failingtests')?></h3> + <div id="failed-tests"> + </div> + <h3 id="upgrade-fail-title"><?php echo stack_string('stackInstall_testsuite_failingupgrades')?></h3> + <div id="upgrade-fail"> + </div> + <h3 id="no-tests-title"><?php echo stack_string('stackInstall_testsuite_notests')?></h3> + <div id="no-tests"> + </div> + <h3 id="no-feedback-title"><?php echo stack_string('stackInstall_testsuite_nogeneralfeedback')?></h3> + <div id="no-feedback"> + </div> + <h3 id="no-deployed-seeds-title"><?php echo stack_string('stackInstall_testsuite_nodeployedseeds')?></h3> + <div id="no-deployed-seeds"> + </div> + <h3 id="general-error-title"><?php echo stack_string('api_general_errors')?></h3> + <div id="general-error"> + </div> + </div> + <br> + + </body> +</html> + diff --git a/api/public/index.php b/api/public/index.php index 4b010f3b239f153ff607139191b7e486fa28e269..2ba9a78eebe990c137f1253e0b31c28b7fa830cf 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -25,6 +25,7 @@ require_once(__DIR__ . '../../emulation/MoodleEmulation.php'); require_login(); use api\controller\GradingController; use api\controller\RenderController; +use api\controller\TestController; use api\controller\ValidationController; use api\controller\DownloadController; use api\util\ErrorRenderer; @@ -43,6 +44,7 @@ $errorhandler = $errormiddleware->getDefaultErrorHandler(); $errorhandler->forceContentType("application/json"); $errorhandler->registerErrorRenderer('application/json', ErrorRenderer::class); $app->post('/render', RenderController::class); +$app->post('/test', TestController::class); $app->post('/grade', GradingController::class); $app->post('/validate', ValidationController::class); $app->post('/download', DownloadController::class); diff --git a/api/public/stack.php b/api/public/stack.php index 8656b4a67ff57aa5d5bbb7ca059a8c4450311d73..dade32f92f7b956dbdeeec2e97d732e40fa60728 100644 --- a/api/public/stack.php +++ b/api/public/stack.php @@ -137,16 +137,18 @@ require_login(); // Display rendered question and solution. function send() { const http = new XMLHttpRequest(); - const url = "http://localhost:3080/render"; + const url = window.location.origin + '/render'; http.open("POST", url, true); http.setRequestHeader('Content-Type', 'application/json'); http.onreadystatechange = function() { if(http.readyState == 4) { try { const json = JSON.parse(http.responseText); - if (json.error) { - document.getElementById('output').innerText = http.responseText; + if (json.message) { + document.getElementById('errors').innerText = json.message; return; + } else { + document.getElementById('errors').innerText = ''; } renameIframeHolders(); let question = json.questionrender; @@ -158,8 +160,9 @@ require_login(); question = question.replace(`[[validation:${name}]]`, `<span name='${validationPrefix + name}'></span>`); if (input.samplesolutionrender && name !== 'remember') { // Display render of answer and matching user input to produce the answer. - correctAnswers += `<p>A correct answer is: \\[{${input.samplesolutionrender}}\\], - which can be typed as follows: `; + correctAnswers += `<p> + <?php echo stack_string('teacheranswershow_mcq', '')?> \\[{${input.samplesolutionrender}}\\], + <?php echo stack_string('api_which_typed')?>: `; for (const [name, solution] of Object.entries(input.samplesolution)) { if (name.indexOf('_val') === -1) { correctAnswers += `<span class='correct-answer'>${solution}</span>`; @@ -221,7 +224,8 @@ require_login(); MathJax.Hub.Queue(["Typeset", MathJax.Hub]); } catch(e) { - document.getElementById('output').innerText = http.responseText; + document.getElementById('errors').innerText = http.responseText; + return; } } }; @@ -231,7 +235,7 @@ require_login(); // Validate an input. Called a set amount of time after an input is last updated. function validate(element) { const http = new XMLHttpRequest(); - const url = "http://localhost:3080/validate"; + const url = window.location.origin + '/validate'; http.open("POST", url, true); // Remove API prefix and subanswer id. const answerName = element.name.slice(15).split('_', 1)[0]; @@ -240,9 +244,11 @@ require_login(); if(http.readyState == 4) { try { const json = JSON.parse(http.responseText); - if (json.error) { - document.getElementById('output').innerText = http.responseText; + if (json.message) { + document.getElementById('errors').innerText = json.message; return; + } else { + document.getElementById('errors').innerText = ''; } renameIframeHolders(); const validationHTML = json.validation; @@ -257,7 +263,8 @@ require_login(); MathJax.Hub.Queue(["Typeset", MathJax.Hub]); } catch(e) { - document.getElementById('output').innerText = http.responseText; + document.getElementById('errors').innerText = http.responseText; + return; } } }; @@ -270,7 +277,7 @@ require_login(); // Submit answers. function answer() { const http = new XMLHttpRequest(); - const url = "http://localhost:3080/grade"; + const url = window.location.origin + '/grade'; http.open("POST", url, true); if (!document.getElementById('output').innerText) { @@ -282,18 +289,21 @@ require_login(); if(http.readyState == 4) { try { const json = JSON.parse(http.responseText); - if (json.error) { - document.getElementById('output').innerText = http.responseText; + if (json.message) { + document.getElementById('errors').innerText = json.message; return; + } else { + document.getElementById('errors').innerText = ''; } if (!json.isgradable) { document.getElementById('stackapi_validity').innerText - = ' Please enter valid answers for all parts of the question.'; + = ' <?php echo stack_string('api_valid_all_parts')?>'; return; } renameIframeHolders(); document.getElementById('score').innerText - = (json.score * json.scoreweights.total).toFixed(2) + ' out of ' + json.scoreweights.total; + = (json.score * json.scoreweights.total).toFixed(2) + + ' <?php echo stack_string('api_out_of')?> ' + json.scoreweights.total; document.getElementById('stackapi_score').style.display = 'block'; document.getElementById('response_summary').innerText = json.responsesummary; document.getElementById('stackapi_summary').style.display = 'block'; @@ -319,7 +329,7 @@ require_login(); if (elements.length > 0) { const element = elements[0]; if (json.scores[name] !== undefined) { - fb = fb + `<div>Marks for this submission: + fb = fb + `<div><?php echo stack_string('api_marks_sub')?>: ${(json.scores[name] * json.scoreweights[name] * json.scoreweights.total).toFixed(2)} / ${(json.scoreweights[name] * json.scoreweights.total).toFixed(2)}.</div>`; } @@ -335,7 +345,8 @@ require_login(); MathJax.Hub.Queue(["Typeset", MathJax.Hub]); } catch(e) { - document.getElementById('output').innerText = http.responseText; + document.getElementById('errors').innerText = http.responseText; + return; } } }; @@ -357,7 +368,7 @@ require_login(); function download(filename, fileid) { const http = new XMLHttpRequest(); - const url = "http://localhost:3080/download"; + const url = window.location.origin + '/download'; http.open("POST", url, true); http.setRequestHeader('Content-Type', 'application/json'); // Something funky going on with closures and callbacks. This seems @@ -379,7 +390,8 @@ require_login(); link.click(); } catch(e) { - document.getElementById('output').innerText = http.responseText; + document.getElementById('errors').innerText = http.responseText; + return; } } }; @@ -458,7 +470,7 @@ require_login(); selectQuestion.setAttribute("onchange", "setQuestion(this.value)"); selectQuestion.id = "stackapi_question_select"; const holder = document.getElementById("stackapi_question_select_holder"); - holder.innerHTML = "Select a question: "; + holder.innerHTML = "<?php echo stack_string('api_q_select')?>: "; holder.appendChild(selectQuestion); let firstquestion = null for (const question of xmlDoc.getElementsByTagName("question")) { @@ -493,9 +505,9 @@ require_login(); </span> </a> </div> - Choose a STACK sample file: + <?php echo stack_string('api_choose_q')?>: <select id="file_selector" placeholder="Select question" autocomplete="off" onchange="getQuestionFile(this.value)"> - <option value="" selected>Please select a question file</option> + <option value="" selected><?php echo stack_string('api_choose_file')?></option> <?php $filenames = scandir('../../samplequestions'); foreach ($filenames as $filename) { @@ -505,35 +517,36 @@ require_login(); } ?> </select> - Or select a file of your own: + <?php echo stack_string('api_local_file')?>: <input type="file" id="local-file" name="local-file" accept=".xml" onchange="getLocalQuestionFile(this.files[0])"/> <div id="stackapi_question_select_holder"></div> - <h2>Question XML</h2> + <h2><?php echo stack_string('api_q_xml')?></h2> <textarea id="xml" cols="100" rows="10"></textarea> - <h2>Seed: <input id="seed" type="number"></h2> + <h2><?php echo stack_string('seedx', '')?> <input id="seed" type="number"></h2> <div> - <input type="button" onclick="send()" class="btn btn-primary" value="Display Question"/> - <input type="checkbox" id="readOnly" style="margin-left: 10px"/> Read Only + <input type="button" onclick="send()" class="btn btn-primary" value="<?php echo stack_string('api_display')?>"/> + <input type="checkbox" id="readOnly" style="margin-left: 10px"/> <?php echo stack_string('api_read_only')?> </div> + <div id='errors'></div> <div id="stackapi_qtext" class="col-lg-8" style="display: none"> - <h2>Question text:</h2> + <h2><?php echo stack_string('questiontext')?>:</h2> <div id="output" class="formulation"></div> <div id="specificfeedback"></div> <br> - <input type="button" onclick="answer()" class="btn btn-primary" value="Submit Answers"/> + <input type="button" onclick="answer()" class="btn btn-primary" value="<?php echo stack_string('api_submit')?>"/> <span id="stackapi_validity" style="color:darkred"></span> </div> <div id="stackapi_generalfeedback" class="col-lg-8" style="display: none"> - <h2>General feedback:</h2> + <h2><?php echo stack_string('generalfeedback')?>:</h2> <div id="generalfeedback" class="feedback"></div> </div> - <h2 id="stackapi_score" style="display: none">Score: <span id="score"></span></h2> + <h2 id="stackapi_score" style="display: none"><?php echo stack_string('score')?>: <span id="score"></span></h2> <div id="stackapi_summary" class="col-lg-10" style="display: none"> - <h2>Response summary:</h2> + <h2><?php echo stack_string('api_response')?>:</h2> <div id="response_summary" class="feedback"></div> </div> <div id="stackapi_correct" class="col-lg-10" style="display: none"> - <h2>Correct answers:</h2> + <h2><?php echo stack_string('api_correct')?>:</h2> <div id="formatcorrectresponse" class="feedback"></div> </div> </div> diff --git a/api/util/StackQuestionLoader.php b/api/util/StackQuestionLoader.php index 719ab1c729c2514589085422ef0da64a3ef67b4d..ac3c0565fed4eac7f01dd2efc5eeecd6781f94fe 100644 --- a/api/util/StackQuestionLoader.php +++ b/api/util/StackQuestionLoader.php @@ -23,13 +23,15 @@ namespace api\util; use SimpleXMLElement; defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../../question.php'); +require_once(__DIR__ . '/../../stack/questiontest.php'); +require_once(__DIR__ . '/../../stack/potentialresponsetreestate.class.php'); /** * TO-DO: Rework, dont use legacy classes * Converts question xml into usable format */ class StackQuestionLoader { - public static function loadxml($xml) { + public static function loadxml($xml, $includetests=false) { // TO-DO: Consider defaults. try { $xmldata = new SimpleXMLElement($xml); @@ -66,8 +68,8 @@ class StackQuestionLoader { $question->questiontextformat = (string) $xmldata->question->questiontext['format']; $question->generalfeedback = (string) $xmldata->question->generalfeedback->text; $question->generalfeedbackformat = (string) $xmldata->question->generalfeedback['format']; - $question->defaultmark = isset($xmldata->question->defaultgrade) ? (float) $xmldata->question->defaultgrade : 1.0; - $question->penalty = isset($xmldata->question->penalty) ? (float) $xmldata->question->penalty : 0.1; + $question->defaultmark = (array) $xmldata->question->defaultgrade ? (float) $xmldata->question->defaultgrade : 1.0; + $question->penalty = (array) $xmldata->question->penalty ? (float) $xmldata->question->penalty : 0.1; // Based on initialise_question_instance from questiontype.php. $question->stackversion = (string) $xmldata->question->stackversion->text; @@ -75,6 +77,8 @@ class StackQuestionLoader { $question->questionnote = (string) $xmldata->question->questionnote->text; $question->specificfeedback = (string) $xmldata->question->specificfeedback->text; $question->specificfeedbackformat = (string) $xmldata->question->specificfeedback['format']; + $question->questiondescription = (string) $xmldata->question->questiondescription; + $question->questiondescriptionformat = (string) $xmldata->question->questiondescription['format']; if (isset($xmldata->question->prtcorrect->text)) { $question->prtcorrect = (string) $xmldata->question->prtcorrect->text; $question->prtcorrectformat = (string) $xmldata->question->prtcorrect['format']; @@ -102,56 +106,57 @@ class StackQuestionLoader { $question->options = new \stack_options(); $question->options->set_option( 'multiplicationsign', - isset($xmldata->question->multiplicationsign) ? + (array) $xmldata->question->multiplicationsign ? (string) $xmldata->question->multiplicationsign : get_config('qtype_stack', 'multiplicationsign') ); $question->options->set_option( 'complexno', - isset($xmldata->question->complexno) ? + (array) $xmldata->question->complexno ? (string) $xmldata->question->complexno : get_config('qtype_stack', 'complexno') ); $question->options->set_option( 'inversetrig', - isset($xmldata->question->inversetrig) ? + (array) $xmldata->question->inversetrig ? (string) $xmldata->question->inversetrig : get_config('qtype_stack', 'inversetrig') ); $question->options->set_option( 'logicsymbol', - isset($xmldata->question->logicsymbol) ? + (array) $xmldata->question->logicsymbol ? (string) $xmldata->question->logicsymbol : get_config('qtype_stack', 'logicsymbol') ); $question->options->set_option( 'matrixparens', - isset($xmldata->question->matrixparens) ? + (array) $xmldata->question->matrixparens ? (string) $xmldata->question->matrixparens : get_config('qtype_stack', 'matrixparens') ); $question->options->set_option( 'sqrtsign', - isset($xmldata->question->sqrtsign) ? + (array) $xmldata->question->sqrtsign ? self::parseboolean($xmldata->question->sqrtsign) : (bool) get_config('qtype_stack', 'sqrtsign') ); $question->options->set_option( 'simplify', - isset($xmldata->question->questionsimplify) ? + (array) $xmldata->question->questionsimplify ? self::parseboolean($xmldata->question->questionsimplify) : (bool) get_config('qtype_stack', 'questionsimplify') ); $question->options->set_option( 'assumepos', - isset($xmldata->question->assumepositive) ? + (array) $xmldata->question->assumepositive ? self::parseboolean($xmldata->question->assumepositive) : (bool) get_config('qtype_stack', 'assumepositive') ); $question->options->set_option( 'assumereal', - isset($xmldata->question->assumereal) ? + (array) $xmldata->question->assumereal ? self::parseboolean($xmldata->question->assumereal) : (bool) get_config('qtype_stack', 'assumereal') ); $question->options->set_option( 'decimals', - isset($xmldata->question->decimals) ? (string) $xmldata->question->decimals : get_config('qtype_stack', 'decimals') + (array) $xmldata->question->decimals ? + (string) $xmldata->question->decimals : get_config('qtype_stack', 'decimals') ); $question->options->set_option( 'scientificnotation', - isset($xmldata->question->scientificnotation) ? + (array) $xmldata->question->scientificnotation ? (string) $xmldata->question->scientificnotation : get_config('qtype_stack', 'scientificnotation') ); @@ -163,25 +168,25 @@ class StackQuestionLoader { $requiredparams = \stack_input_factory::get_parameters_used(); foreach ($inputmap as $name => $inputdata) { $allparameters = [ - 'boxWidth' => isset($inputdata->boxsize) ? + 'boxWidth' => (array) $inputdata->boxsize ? (int) $inputdata->boxsize : get_config('qtype_stack', 'inputboxsize'), - 'insertStars' => isset($inputdata->insertstars) ? + 'insertStars' => (array) $inputdata->insertstars ? (int) $inputdata->insertstars : get_config('qtype_stack', 'inputinsertstars'), 'syntaxHint' => isset($inputdata->syntaxhint) ? (string) $inputdata->syntaxhint : '', - 'syntaxAttribute' => isset($inputdata->syntaxattribute) ? (int) $inputdata->syntaxattribute : 0, + 'syntaxAttribute' => (array) $inputdata->syntaxattribute ? (int) $inputdata->syntaxattribute : 0, 'forbidWords' => isset($inputdata->forbidwords) ? (string) $inputdata->forbidwords : get_config('qtype_stack', 'inputforbidwords'), 'allowWords' => isset($inputdata->allowwords) ? (string) $inputdata->allowwords : '', - 'forbidFloats' => isset($inputdata->forbidfloat) ? + 'forbidFloats' => (array) $inputdata->forbidfloat ? self::parseboolean($inputdata->forbidfloat) : (bool) get_config('qtype_stack', 'inputforbidfloat'), - 'lowestTerms' => isset($inputdata->requirelowestterms) ? + 'lowestTerms' => (array) $inputdata->requirelowestterms ? self::parseboolean($inputdata->requirelowestterms) : (bool) get_config('qtype_stack', 'inputrequirelowestterms'), - 'sameType' => isset($inputdata->checkanswertype) ? + 'sameType' => (array) $inputdata->checkanswertype ? self::parseboolean($inputdata->checkanswertype) : (bool) get_config('qtype_stack', 'inputcheckanswertype'), - 'mustVerify' => isset($inputdata->mustverify) ? + 'mustVerify' => (array) $inputdata->mustverify ? self::parseboolean($inputdata->mustverify) : (bool) get_config('qtype_stack', 'inputmustverify'), - 'showValidation' => isset($inputdata->showvalidation) ? + 'showValidation' => (array) $inputdata->showvalidation ? (int) $inputdata->showvalidation : get_config('qtype_stack', 'inputshowvalidation'), 'options' => isset($inputdata->options) ? (string) $inputdata->options : '', ]; @@ -219,9 +224,9 @@ class StackQuestionLoader { $data = new \stdClass(); $data->name = (string) $prtdata->name; - $data->autosimplify = isset($prtdata->autosimplify) ? self::parseboolean($prtdata->autosimplify) : true; - $data->feedbackstyle = isset($prtdata->feedbackstyle) ? (int) $prtdata->feedbackstyle : 1; - $data->value = isset($prtdata->value) ? (float) $prtdata->value : 1.0; + $data->autosimplify = (array) $prtdata->autosimplify ? self::parseboolean($prtdata->autosimplify) : true; + $data->feedbackstyle = (array) $prtdata->feedbackstyle ? (int) $prtdata->feedbackstyle : 1; + $data->value = (array) $prtdata->value ? (float) $prtdata->value : 1.0; $data->firstnodename = null; $data->feedbackvariables = (string) $prtdata->feedbackvariables->text; @@ -238,18 +243,18 @@ class StackQuestionLoader { $newnode->testoptions = (string) $node->testoptions; $newnode->quiet = self::parseboolean($node->quiet); - $newnode->truescoremode = isset($node->truescoremode) ? (string) $node->truescoremode : 'add'; - $newnode->truescore = isset($node->truescore) ? (float) $node->truescore : 1.0; - $newnode->truepenalty = isset($node->truepenalty) ? (float) $node->truepenalty : 0.0; - $newnode->truenextnode = isset($node->truenextnode) ? (string) $node->truenextnode : '-1'; + $newnode->truescoremode = (array) $node->truescoremode ? (string) $node->truescoremode : '+'; + $newnode->truescore = (array) $node->truescore ? (string) $node->truescore : 1.0; + $newnode->truepenalty = (array) $node->truepenalty ? (string) $node->truepenalty : null; + $newnode->truenextnode = (array) $node->truenextnode ? (string) $node->truenextnode : '-1'; $newnode->trueanswernote = (string) $node->trueanswernote; $newnode->truefeedback = (string) $node->truefeedback->text; $newnode->truefeedbackformat = (string) $node->truefeedback['format']; - $newnode->falsescoremode = isset($node->falsescoremode) ? (string) $node->falsescoremode : 'equals'; - $newnode->falsescore = isset($node->falsescore) ? (float) $node->falsescore : 0.0; - $newnode->falsepenalty = isset($node->falsepenalty) ? (float) $node->falsepenalty : 0.0; - $newnode->falsenextnode = isset($node->falsenextnode) ? (string) $node->falsenextnode : '-1'; + $newnode->falsescoremode = (array) $node->falsescoremode ? (string) $node->falsescoremode : '='; + $newnode->falsescore = (array) $node->falsescore ? (string) $node->falsescore : 0.0; + $newnode->falsepenalty = (array) $node->falsepenalty ? (string) $node->falsepenalty : null; + $newnode->falsenextnode = (array) $node->falsenextnode ? (string) $node->falsenextnode : '-1'; $newnode->falseanswernote = (string) $node->falseanswernote; $newnode->falsefeedback = (string) $node->falsefeedback->text; $newnode->falsefeedbackformat = (string) $node->falsefeedback['format']; @@ -267,8 +272,28 @@ class StackQuestionLoader { } $question->deployedseeds = $deployedseeds; + $testcases = []; + if ($includetests) { + foreach ($xmldata->question->qtest as $test) { + $testinputs = []; + foreach ($test->testinput as $testinput) { + $testinputs[(string) $testinput->name] = (string) $testinput->value; + } + $testcase = new \stack_question_test((string) $test->description, $testinputs, (string) $test->testcase); + foreach ($test->expected as $expected) { + $testcase->add_expected_result((string) $expected->name, + new \stack_potentialresponse_tree_state(1, true, + (array) $expected->expectedscore ? + (string) $expected->expectedscore : null, + (array) $expected->expectedpenalty ? + (string) $expected->expectedpenalty : null, + '', [(string) $expected->expectedanswernote])); + } + $testcases[] = $testcase; + } + } - return $question; + return ['question' => $question, 'testcases' => $testcases]; } private static function handlefiles(\SimpleXMLElement $files) { diff --git a/backup/moodle2/backup_qtype_stack_plugin.class.php b/backup/moodle2/backup_qtype_stack_plugin.class.php index 37dc9a4ecde6a66beffce23fd8239db8b356b2c6..383c8ed159aaf7cd52c7b5fb775add9597bd3d75 100644 --- a/backup/moodle2/backup_qtype_stack_plugin.class.php +++ b/backup/moodle2/backup_qtype_stack_plugin.class.php @@ -47,6 +47,7 @@ class backup_qtype_stack_plugin extends backup_qtype_plugin { $stackoptions = new backup_nested_element('stackoptions', ['id'], [ 'stackversion', 'questionvariables', 'specificfeedback', 'specificfeedbackformat', + 'questiondescription', 'questiondescriptionformat', 'questionnote', 'questionnoteformat', 'questionsimplify', 'assumepositive', 'assumereal', 'prtcorrect', 'prtcorrectformat', 'prtpartiallycorrect', 'prtpartiallycorrectformat', 'prtincorrect', 'prtincorrectformat', diff --git a/deploy.php b/deploy.php index 071c25bb6a0cf98ed2586031294398fc82c092c9..4849a9757be671fe7e4b5f1bc5200cb906b61ad7 100644 --- a/deploy.php +++ b/deploy.php @@ -61,9 +61,7 @@ if (!is_null($deploy)) { $undeploy = optional_param('undeploy', null, PARAM_INT); if (!is_null($undeploy)) { $question->undeploy_variant($undeploy); - - // As we redirect, switch to the undeployed variant, so it easy to re-deploy - // if you just made a mistake. + // As we redirect, switch to the undeployed variant, so it easy to re-deploy if you just made a mistake. $nexturl->param('seed', $undeploy); redirect($nexturl); } @@ -81,7 +79,11 @@ if (!is_null($undeploy) && $question->deployedseeds) { // Process undeployall if applicable. $deployfromlist = optional_param('deployfromlist', null, PARAM_INT); $deploysystematic = optional_param('deploysystematic', null, PARAM_INT); -if (!is_null($deployfromlist) || !is_null($deploysystematic)) { +$deploysystematicfrom = optional_param('deploysystematicfrom', null, PARAM_INT); +$deploysystematicto = optional_param('deploysystematicto', null, PARAM_INT); +$usefromtofeature = false; +if (!is_null($deployfromlist) || !is_null($deploysystematic) || (!is_null($deploysystematicfrom) && + !is_null($deploysystematicto))) { // Check data integrity. $dataproblem = false; @@ -89,6 +91,9 @@ if (!is_null($deployfromlist) || !is_null($deploysystematic)) { if (!is_null($deployfromlist)) { $deploytxt = optional_param('deployfromlist', null, PARAM_TEXT); $baseseeds = explode("\n", trim($deploytxt)); + } else if (!is_null($deploysystematicfrom) && !is_null($deploysystematicto)) { + $baseseeds = range($deploysystematicfrom, $deploysystematicto); + $usefromtofeature = true; } else { $baseseeds = range(1, $deploysystematic); } @@ -132,9 +137,18 @@ if (!is_null($deployfromlist) || !is_null($deploysystematic)) { } // Undeploy all existing variants. + // If the deploy-from-to feature is used, only undeploy variants that already exist. if ($question->deployedseeds) { - foreach ($question->deployedseeds as $seed) { - $question->undeploy_variant($seed); + if ($usefromtofeature) { + foreach ($question->deployedseeds as $seed) { + if (in_array($seed, $newseeds)) { + $question->undeploy_variant($seed); + } + } + } else { + foreach ($question->deployedseeds as $seed) { + $question->undeploy_variant($seed); + } } } // Deploy all new variants. diff --git a/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md b/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md index 908be6522f8d0ae4ba5d2df047e8af0ab8420af2..c3c39dc8f39ec3474dc6feffce896efa7c924dc2 100644 --- a/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md +++ b/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md @@ -487,6 +487,33 @@ i/15))</pre></td> <td class="cell c5">0</td> <td class="cell c6"></td> </tr> +<tr class="pass"> + <td class="cell c0">AlgEquiv</td> + <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td> + <td class="cell c2"><pre>'root(x)</pre></td> + <td class="cell c3"><pre>x^(1/2)</pre></td> + <td class="cell c4"></td> + <td class="cell c5">1</td> + <td class="cell c6"></td> +</tr> +<tr class="pass"> + <td class="cell c0">AlgEquiv</td> + <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td> + <td class="cell c2"><pre>'root(x,m)</pre></td> + <td class="cell c3"><pre>x^(1/m)</pre></td> + <td class="cell c4"></td> + <td class="cell c5">1</td> + <td class="cell c6"></td> +</tr> +<tr class="pass"> + <td class="cell c0">AlgEquiv</td> + <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td> + <td class="cell c2"><pre>x</pre></td> + <td class="cell c3"><pre>'root(x^2)</pre></td> + <td class="cell c4"></td> + <td class="cell c5">0</td> + <td class="cell c6"></td> +</tr> <tr class="pass"> <td class="cell c0">AlgEquiv</td> <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td> diff --git a/doc/en/Authoring/Options.md b/doc/en/Authoring/Options.md index e7a89777946aec940cd49c099f707c5bc84f38da..c04f24e1d58448dc82c5373fadd572a9212b10cc 100644 --- a/doc/en/Authoring/Options.md +++ b/doc/en/Authoring/Options.md @@ -75,9 +75,9 @@ The expression `(make_multsgn("cross"), a*b)` uses parentheses as an abbreviatio The value of this option `onum` will only put a multiplication sign between numbers. This means you will see \(3\times 5\, x\) and not \(3\, 5\, x\) as you would if you have "none". -There is a special atom which controls the multiplication symbol. If you would like a dot then define +There is a special atom which controls the multiplication symbol used with option `onum`. If you would like a dot then define - texput(multsgnonlyfornumberssym, "\\times"); + texput(multsgnonlyfornumberssym, "\\cdot"); in the question variables. @@ -113,6 +113,8 @@ Do you really want to continue using \(\sqrt{}\) in your teaching? In his *Elem A lot of elementary mathematics involves converting from one form to another and back again. Sometimes these forms have important differences of use, e.g. factored form or completed square form for a quadratic. However, sometimes these equivalent forms are more customary than because it *"manifestly corresponds with the nature of the thing"* in question. I digress... +STACK defines an \(n\)th root function `root(x,n)` which is a noun form for \(\sqrt[n]{x}\). This can be used by students, but if teachers wish to use this in question variables etc. then they must prefix this with the apostophie to create the nounform `'root(x,n)` to prevent immediate evaluation to `x^(1/n)`. + ### sqrt(-1) {#sqrt_minus_one} ### In Maxima `%i` is the complex unit satisfying `%i^2=-1`. However, students would diff --git a/doc/en/Authoring/Variables.md b/doc/en/Authoring/Variables.md index d00d786f59cdcdc2ecc52aef0a412f2586c045b9..0228b096d407703d76d2a991298983abecc77aa0 100644 --- a/doc/en/Authoring/Variables.md +++ b/doc/en/Authoring/Variables.md @@ -46,9 +46,9 @@ The question variables are evaluated when a variant of a question is created. * General feedback (also known as the worked solution). * All fields in each of the [potential response tree](Potential_response_trees.md). * Each input when testing the item. -* Question variables are not available to inputs when a student is validating their answer, unless special ``context variables'' are defined. +* Question variables are not available to inputs when a student is validating their answer, unless special ``context variables'' are defined in a preamble. -### Context variables +### Question variables preamble and context variables If the following commands appear within the question variables they will be available in every part of the question, in particular these commands will affect how students' input is validated. This enables teachers to affect the display of the student's answer validation, and add assumptions to PRTs. @@ -58,16 +58,29 @@ If the following commands appear within the question variables they will be avai This collection of special variables are called "context variables". -Only single texput commands are gathered into the context variables. You cannot use other variables or other functions defined in the question variables. So, `texput(blob, "\\diamond")` is fine, but passing a function to texput to display more complex output is not currently supported. +STACK has a special constant `%_stack_preamble_end`. Any variables _before_ this constant will be included within the context variables. This enables you to define functions, e.g. to use with `textput`. -For example, to redefine how the logarithm is displayed, use `texput(log, "\\log ", prefix);`. +Note, that students are not permitted to use any variable name defined by the teacher in the question variables. This includes both the context variables, and the regular remaining question variables. It is not possible to define variables which a student can then use. Students _can_ use function names defined in the preamble. e.g. you can put `vec(ex):=stackvector(ex);` into the preamble. -It is possible to use an unnamed `lambda` function. E.g. if you have a function `tup` then +For example, `texput(blob, "\\diamond")` is simple. You can also define a function and use this function in texput. + +``` +tuptex(z):= block([a,b], [a,b]:args(z), sconcat("\\left[",tex1(a),",",tex1(b),"\\right)")); +texput(tup, tuptex); +%_stack_preamble_end; +``` + +It is also possible to use an unnamed `lambda` function. E.g. if you have a function `tup` then texput(tup, lambda([z], block([a,b], [a,b]:args(z), sconcat("\\left[",tex1(a),",",tex1(b),"\\right)")))); will display `tup(a,b)` as \( \left[a,b\right) \). +To create a function `hat` so that input `hat(x)` is displayed as \(\hat{x}\) you can use: + + /* In question variables. */ + texput(hat, lambda([ex], sconcat("\\hat{", tex1(first(ex)), "}"))); + As a more complicated example, to typeset `u(A_k,k,1,inf)` as \({\bigcup_{k = 1}^{\infty } {A}_{k}}\) you can use the following: texput(u,lambda([ex],if length(ex)<4 then return("\\bigcup_{?=?}^{?} ? ") else diff --git a/doc/en/CAS/Maxima.md b/doc/en/CAS/Maxima.md index 9da591f0bc7699e775db14d65dad1de79d7bda7a..8cdadef312b633dbb41a993829fe15bac74fc2e2 100644 --- a/doc/en/CAS/Maxima.md +++ b/doc/en/CAS/Maxima.md @@ -79,7 +79,7 @@ STACK creates a range of additional functions and restricts those available, man | Command | Description | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -| `factorlist(ex)` | Returns a list of factors of ex without multiplicities. +| `factorlist(ex)` | Returns a list of factors of `ex` without multiplicities. Note, the product of these factors may not be the original expression, and may differ by a factor of \(\pm 1\) due to unary minus extraction and ordering of variables. For this reason, if you want to decide if `f1` is a factor of `ex` then it's better to check `remainder(ex,f1)` is zero, than membership of the factor list. E.g. both `remainder(a^2-b^2,b-a)` and `remainder(a^2-b^2,a-b)` are zero, but `factorlist(a^2-b^2)` gives `[b-a,b+a]` which does not contain `a-b` as a factor. | `zip_with(f,a,b)` | This function applies the binary function \(f\) to two lists \(a\) and \(b\) returning a list. An example is given in adding matrices to [show working](Matrix.md#Showing_working). | `coeff_list(ex,v)` | This function takes an expression `ex` and returns a list of coefficients of `v`. | `coeff_list_nz(ex,v)` | This function takes an expression `ex` and returns a list of nonzero coefficients of `v`. diff --git a/doc/en/CAS/Systematic_deployment.md b/doc/en/CAS/Systematic_deployment.md index 90e6fd9f62f5180ff794f905ca25c8679ee07607..f98864acd61dc92a013a19c6844512e81c2f83a2 100644 --- a/doc/en/CAS/Systematic_deployment.md +++ b/doc/en/CAS/Systematic_deployment.md @@ -32,7 +32,7 @@ It is your responsibility to make sure the index remains within range! You can It is sensible to always ensure your `stack_seed` does not create run-time errors. Notice that although the `mod` function does return `0` we have avoided possible zero indexes when defining `n1`. -Of course, there are many other ways to map deployed seeds onto systematic deployment of variants. Using consecutive integers from \(1, \ldots, n\) as the starting point is probably simplest and easiest to maintain. For this reason there is a special option to do this on the deploy variants page. +Of course, there are many other ways to map deployed seeds onto systematic deployment of variants. Using consecutive integers from \(1, \ldots, n\) as the starting point is probably simplest and easiest to maintain. For this reason there is a special option to do this on the deploy variants page. There is also an option to use consecutive integers from \(n, \ldots, m\). Notes diff --git a/doc/en/Developer/Development_history.md b/doc/en/Developer/Development_history.md index c4fd6ac945160cbfb45d75dfa56640df9d66755f..dcc451aa644fc92c2bbce189d6a42d2ad28baf54 100644 --- a/doc/en/Developer/Development_history.md +++ b/doc/en/Developer/Development_history.md @@ -2,6 +2,17 @@ For current and future plans, see [Development track](Development_track.md) and [Future plans](Future_plans.md). +## Version 4.6.0 + +Released July 2024. + +1. Fix [issue #1160](https://github.com/maths/moodle-qtype_stack/issues/879) Allow configuring the MathJax URL +2. Add in stack preamble via `%_stack_preamble_end;` in the question variables to allow some variables to be available in inputs. This fixes [issue #1207](https://github.com/maths/moodle-qtype_stack/issues/1207]) and [issue #1133](https://github.com/maths/moodle-qtype_stack/issues/1133). +3. Allow Maxima code in keyvals to terminate expressions with a `$` (as in Maxima) [issue #1019](https://github.com/maths/moodle-qtype_stack/issues/1019]). This will allow better copy/paste to and from desktop maxima. +4. Add in an option to fine-tune the multiplication sign used for scientific units: `multsgnstackunits`. See discussion in [issue #1080](https://github.com/maths/moodle-qtype_stack/issues/1080]). +5. Add in the "Deploy from n to m" deature to systematically deploy seeds. + + ## Version 4.6.0 Released June 2024. diff --git a/doc/en/Developer/Development_track.md b/doc/en/Developer/Development_track.md index 7c4550bc4c22c470bf0d3e55b9403d9f283e7db1..7d1a597bc5ad55b71567adf7222ef0b09c8b0b56 100644 --- a/doc/en/Developer/Development_track.md +++ b/doc/en/Developer/Development_track.md @@ -5,20 +5,19 @@ past development history is documented on [Development history](Development_hist We use the [github issue tracker](https://github.com/maths/moodle-qtype_stack/issues) to track "milestones". -## Version 4.7.0 +## Version 4.8.0 -Issues with [github milestone 4.7.0](https://github.com/maths/moodle-qtype_stack/issues?q=is%3Aissue+milestone%3A4.7.0) include +Issues with [github milestone 4.8.0](https://github.com/maths/moodle-qtype_stack/issues?q=is%3Aissue+milestone%3A4.8.0) include -1. Fix [issue #1160](https://github.com/maths/moodle-qtype_stack/issues/879) Allow configuring the MathJax URL -2. Release "Adapt" block. [issue #975](https://github.com/maths/moodle-qtype_stack/issues/975) -3. Fix [issue #406](https://github.com/maths/moodle-qtype_stack/issues/406) -4. Error messages: use caserror.class more fully to use user information to target error messages. -5. Remove all "cte" code from Maxima - mostly install. -6. Review and fix [issue #1063](https://github.com/maths/moodle-qtype_stack/issues/1063): "Extra options" set to "simp" and number of decimals shown in validation field +1. Release "Adapt" block. [issue #975](https://github.com/maths/moodle-qtype_stack/issues/975) +2. Fix [issue #406](https://github.com/maths/moodle-qtype_stack/issues/406) +3. Error messages: use caserror.class more fully to use user information to target error messages. +4. Remove all "cte" code from Maxima - mostly install. +5. Review and fix [issue #1063](https://github.com/maths/moodle-qtype_stack/issues/1063): "Extra options" set to "simp" and number of decimals shown in validation field ## Parson's block development track -For v4.7.0: +For v4.8.0: 1. Nested lists (flat list vs. nested/tree) and different proof types -- iff, induction, etc. how do we indicate the different scaffolding for this? 2. Use syntax hint to set up a non-empty starting point. diff --git a/doc/en/Developer/Parser.md b/doc/en/Developer/Parser.md index a994ccac92efc16313ba9920465f7b66db53485b..af4404c5d996ee0e07a2e15345b707b94d9ca9d4 100644 --- a/doc/en/Developer/Parser.md +++ b/doc/en/Developer/Parser.md @@ -5,7 +5,7 @@ We need to use node: - apt-get install node npm + apt-get install nodejs npm Inside `stack/stack/maximaparser` (or anywhere else), and not as root diff --git a/doc/en/Developer/Releasing.md b/doc/en/Developer/Releasing.md index bb7b8918a711c2288489e0705659a37b58ddf0da..454a986b66792407794cc68f0fd1bd0cad123331 100644 --- a/doc/en/Developer/Releasing.md +++ b/doc/en/Developer/Releasing.md @@ -42,16 +42,16 @@ Unless you want to discuss something confidential with the developers, please do * Spin up the STACK API in Docker and check it still works with a selection of questions, including download and JSXGraph. * Chances are it won't work because even the latest version of goemaxima is out of date. * You will need to create a local up-to-date image of goemaxima: - * Clone the goemaxima repo and create a folder stack/STACKVERSION e.g. `stack/2024050600` matching the latest STACK version. + * Clone the goemaxima repo and create a folder stack/STACKVERSION e.g. `stack/2025072400` matching the latest STACK version. * Copy the stack/maxima folder from STACK into this new folder. * Create `maximalocal.mac.template` as described in `Adding_new_version.md` in goemaxima docs (or just copy from previous goemaxima version). * In `buildimage.sh` set `maximaver` and `sbclver` e.g. `maximaver="5.45.1" sbclver="2.2.6"`. (`maximaver` should match `maximalocal.mac.template`) * `./buildweb.sh` (You may need to install `go` first: `sudo snap install go --classic`). - * `.buildimage.s 2024050600` (If Docker struggles to fetch metadata `sudo vi ~/.docker/config.json` and change `credsStore` to `credStore`). - * You should have now created a `goemaxima:2024050600-dev` image locally. + * `.buildimage.s 2025072400` (If Docker struggles to fetch metadata `sudo vi ~/.docker/config.json` and change `credsStore` to `credStore`). + * You should have now created a `goemaxima:2025072400-dev` image locally. * Temporarily update STACK API locally: - * Update maxima image in STACK API to `goemaxima:2024050600-dev` in `docker-compose.dev.yml`. - * Update `stackmaximaversion` and `version` in `config.php` for the API to e.g. 2024050600. + * Update maxima image in STACK API to `goemaxima:2025072400-dev` in `docker-compose.dev.yml`. + * Update `stackmaximaversion` and `version` in `config.php` for the API to e.g. 2025072400. * `docker compose -f docker-compose.dev.yml up` ### Version numbers diff --git a/doc/en/Developer/Unit_tests.md b/doc/en/Developer/Unit_tests.md index 7b18a471fc2fbfad65a6f1666c5d39df894158d8..31acd903333b07c9d4f4019c293baf8de0922a72 100644 --- a/doc/en/Developer/Unit_tests.md +++ b/doc/en/Developer/Unit_tests.md @@ -109,6 +109,18 @@ Note you need to make sure the `QTYPE_STACK_TEST_CONFIG_CASRESULTSCACHE` variabl To make sure the CAS cache is cleared after each unit test, revert back to the `db` settings for `QTYPE_STACK_TEST_CONFIG_CASRESULTSCACHE` as described above. This will be slow... +## Running Moodle unit tests on other plugins without maxima. + +It is possible that you want to install the `qtype_stack` PHP code, but not complete the installation of Maxima, and then run the PHP unit tests on a different plugin. Trying to run unit tests on an incomplete install _should_ fail badly. By default it does, and by design we have set it up to fail when you execute + + php admin/tool/phpunit/cli/init.php + +on the whole moodle. If you need to avoid this failure then + + define('QTYPE_STACK_TEST_CONFIG_PLATFORM', 'none'); + +within the config.php. See [issue #1104](https://github.com/maths/moodle-qtype_stack/issues/1104) for discussion of this feature. + # Other configuration issues Moodle overrides the PHP debug message settings. To see errors and warnings, go to diff --git a/doc/en/Installation/STACK_versions.md b/doc/en/Installation/STACK_versions.md index c355cb8dd8774d31d3d9f067228d1da39023d5fe..91073a89fa256f992d48ce298ab68b903a599980 100644 --- a/doc/en/Installation/STACK_versions.md +++ b/doc/en/Installation/STACK_versions.md @@ -9,6 +9,7 @@ when releasing. Release | Version number | Supported Maxima versions --------|----------------|-------------------------- +4.7.0 | 2025072400 | 5.40.0, 5.41.0, 5.42.0, 5.42.1, 5.42.2, 5.43.0, 5.43.1, 5.43.2, 5.44.0, 5.46.0, 5.47.0 4.6.0 | 2024060300 | 5.40.0, 5.41.0, 5.42.0, 5.42.1, 5.42.2, 5.43.0, 5.43.1, 5.43.2, 5.44.0, 5.46.0, 5.47.0 4.5.0 | 2023121100 | 5.40.0, 5.41.0, 5.42.0, 5.42.1, 5.42.2, 5.43.0, 5.43.1, 5.43.2, 5.44.0, 5.46.0, 5.47.0 4.4.5 | 2023072101 | 5.40.0, 5.41.0, 5.42.0, 5.42.1, 5.42.2, 5.43.0, 5.43.1, 5.43.2, 5.44.0, 5.46.0, 5.47.0 diff --git a/doc/en/Plots/Plots.md b/doc/en/Plots/Plots.md index b4361fa17dae32bdfc98a542ee5eb8599a6beadf..fcd4fa2963d878268e0de2bcc04e449f4445751d 100644 --- a/doc/en/Plots/Plots.md +++ b/doc/en/Plots/Plots.md @@ -222,3 +222,6 @@ The following CASText gives representative examples of the plot2d features suppo {@plot([parametric, (exp(cos(t))-2*cos(4*t)-sin(t/12)^5)*sin(t), (exp(cos(t))-2*cos(4*t)-sin(t/12)^5)*cos(t), [t, -8*%pi, 8*%pi]], [nticks, 100], [box,false])@} <h3>Putting the axes in the middle</h3> {@plot([x^2/(1+x^2),2*x/(1+x^2)^2], [x, -2, 2], [y,-2.1,2.1], [box, false], [yx_ratio, 1], [axes, solid], [xtics, -2, 0.5, 2],[ytics, -2, 0.5, 2])@} + <h3>Example with ticks, colour and alt-text</h3> + {@plot([6*x,6^x,x^6,x^(1/6)], [x, -2.2, 2.2], [y, -5.2, 5.2], [box, false], [yx_ratio, 1], [axes, solid], [xtics, -5, 1, 5],[ytics, -5, 1, 5], cons(legend, ["f", "F", "g", "G"]), [alt, "Graph Of Multiple Functions"], [style, [linespoints, 1, 1.5]], [nticks, 5], [color, "#785EF0", "#DC267F", "#FE6100", "#648FFF"], [adapt_depth, 0]);@} + diff --git a/doc/en/Topics/Units.md b/doc/en/Topics/Units.md index 20d775e7a5770afb7e5d8399c46f5ae268d82b04..451eef9aa544a99251e627e86b9e7ecbf59d9ebd 100644 --- a/doc/en/Topics/Units.md +++ b/doc/en/Topics/Units.md @@ -159,6 +159,14 @@ try to split the expression into units and numbers, and the return the units and The function `stack_units_split` is deprecated. DO NOT USE. +## Fine-tuning the display ## + +By default STACK's TeX function prints out `stackunits(10,m/s)` as \( 10\, m/s\). That is, without any multiplication sign between the numerical part and the units. In some edge cases you might want to add this multiplication sign in. To do this, use + + texput(multsgnstackunits, "\\cdot"); + +in the question variables. In castext you can use, e.g. `{@(texput(multsgnstackunits, "\\cdot "), stackunits(1, s^-1))@}` to create output \({1\cdot s^ {- 1 }}\). + ## Custom units ## The teacher may want to use their own units. For example, the core `unit` package in Maxima does not include `mm` (millimetre), it is defined there as a word `millimetre`. This is one reason for creating our own custom units package. diff --git a/lang/de/qtype_stack.php b/lang/de/qtype_stack.php index 4d1f3ea493b1509d03a71f0f6ac3c1535cb115d2..6e6f33d467835ece99954bedbb922ef126831e03 100644 --- a/lang/de/qtype_stack.php +++ b/lang/de/qtype_stack.php @@ -546,7 +546,7 @@ $string['hyp_inverse_functions_fact'] = '\\[\\cosh^{-1}(x)=\\ln\\left(x+\\sqrt{x \\[\\sinh^{-1}(x)=\\ln\\left(x+\\sqrt{x^2+1}\\right)\\] \\[\\tanh^{-1}(x) = \\frac{1}{2}\\ln\\left({1+x\\over 1-x}\\right) \\quad \\mbox{ for } -1< x < 1\\]'; $string['hyp_inverse_functions_name'] = 'Inverse hyperbolische Funktionen'; -$string['illegalcaschars'] = 'Die Zeichen @, $ und \\ sind in der CAS-Eingabe nicht erlaubt.'; +$string['illegalcaschars'] = 'Die Zeichen @ und \\ sind in der CAS-Eingabe nicht erlaubt.'; $string['inputdisplayed'] = 'Angezeigt als'; $string['inputentered'] = 'Eingegebener Wert'; $string['inputexpression'] = 'Test-Eingabe'; diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php index 0ef0872ec48b2c0716184692bebd17286afe57c8..602848289923fa197f42979b57ff363a3b312389 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -161,7 +161,7 @@ $string['showvalidationcompact'] = 'Yes, compact'; $string['inputinvalidparamater'] = 'Invalid parameter'; $string['mustverifyshowvalidation'] = 'You cannot choose to require two step validation but not show the results of validation to the student after the first step. This puts the student in an impossible position.'; $string['htmlfragment'] = 'You appear to have some HTML elements in your expression.'; -$string['illegalcaschars'] = 'The characters @, $ and \\ are not allowed in CAS input.'; +$string['illegalcaschars'] = 'The characters @ and \\ are not allowed in CAS input.'; $string['inputextraoptions'] = 'Extra options'; $string['inputextraoptions_help'] = 'Some input types require extra options in order to work. You can enter them here. This value is a CAS expression.'; $string['inputextraoptions_link'] = '%%WWWROOT%%/question/type/stack/doc/doc.php/Authoring/Inputs.md#Extra options'; @@ -512,7 +512,8 @@ $string['testallincategory'] = 'Test all questions in this category'; $string['overallresult'] = 'Overall result'; $string['seedx'] = 'Seed {$a}'; $string['testpassesandfails'] = '{$a->passes} passes and {$a->fails} failures.'; - +$string['defaulttestpass'] = 'Default test using model answers returns a score of 1.'; +$string['defaulttestfail'] = 'Default test using model answers does not return a score of 1.'; // Strings used by the question test script. $string['addanothertestcase'] = 'Add another test case...'; $string['addatestcase'] = 'Add a test case...'; @@ -532,6 +533,8 @@ $string['deployedvariantsn'] = 'Deployed variants ({$a})'; $string['deploymanybtn'] = 'Deploy # of variants:'; $string['deploymanyerror'] = 'Error in user input: cannot deploy "{$a->err}" variants.'; $string['deploysystematicbtn'] = 'Deploy seeds from 1 to: '; +$string['deploysystematicfrombtn'] = 'Deploy seeds from: '; +$string['deploysystematicto'] = 'to: '; $string['deployduplicateerror'] = 'Duplicate question notes detected in the deployed variants. We strongly recommend each question note is only deployed once, otherwise you will have difficulty collecting meaningful stats when grouping by variant. Please consider deleting some variants with duplicate notes.'; $string['deploytoomanyerror'] = 'STACK will try to deploy up to at most 100 new variants in any one request. No new variants deployed.'; $string['deploymanynonew'] = 'Too many repeated existing question notes were generated.'; @@ -576,6 +579,8 @@ $string['runquestiontests_help'] = 'The dashboard runs question tests which unit $string['runquestiontests_alert'] = 'Question is missing tests or variants.'; $string['runquestiontests_auto'] = 'Automatically adding one test case assuming the teacher\'s input gets full marks. Please check the answer note carefully.'; $string['runquestiontests_autoprompt'] = 'Add test case assuming the teacher\'s input gets full marks.'; +$string['runquestiontests_explanation'] = 'If you add the test, its output will look like this:'; +$string['runquestiontests_example'] = 'example'; $string['autotestcase'] = 'Test case assuming the teacher\'s input gets full marks.'; $string['showingundeployedvariant'] = 'Showing undeployed variant: {$a}'; $string['switchtovariant'] = 'Switch to variant: '; @@ -913,6 +918,7 @@ $string['Illegal_sets'] = 'Your answer contains sets "{a,b,c}" these are not all $string['Illegal_groups'] = 'Your answer contains evaluation groups "(a,b,c)" these are not allowed here.'; $string['Illegal_groupping'] = 'Your answer contains parenthesis used to group operations, these are forbidden here. You should probably manipulate the expression to eliminate them.'; $string['Illegal_control_flow'] = 'Your answer contains control-flow statements like the <code>if</code>-conditional or the <code>do</code>-loop, these are forbidden here, you should probably provide the result of these statements as the answer.'; +$string['Illegal_extraevaluation'] = "Maxima's extra evaluation operator <code>''</code> is not supported by STACK."; $string['qm_error'] = 'Your answer contains question mark characters, ?, which are not permitted in answers. You should replace these with a specific value.'; $string['Equiv_Illegal_set'] = 'Sets are not allowed when reasoning by equivalence.'; $string['Equiv_Illegal_list'] = 'Lists are not allowed when reasoning by equivalence.'; @@ -949,20 +955,20 @@ $string['stackBlock_parsons_unknown_named_version'] = 'The Parson\'s block only $string['stackBlock_parsons_unknown_mathjax_version'] = 'The Parson\'s block only supports MathJax versions {$a->mjversion} for the mathjax parameter.'; $string['stackBlock_parsons_ref'] = 'The Parson\'s block only supports referencing inputs present in the same CASText section \'{$a->var}\' does not exist here.'; $string['stackBlock_parsons_param'] = 'The Parson\'s block supports only these parameters in this context: \'{$a->param}\'.'; -$string['stackBlock_parsons_contents'] = 'The contents of a Parson\'s block must be a either a JSON of the form {#stackjson_stringify(steps)#}, where `steps` is the two-dimensional Maxima array containing key, value pairs of items, or of the form {\'steps\' : {#stackjson_stringify(steps)#}, \'options\' : {JSON containing Sortable options}, \'header\' : [List of headers], \'available_header\' : \'string containing header for the available list\', \'index\' : [List containing the index]}, where the \'options\', \'header\', \'available_header\', and \'index\' keys are optional. Alternatively, the contents of the Parsons block may contain raw JSON equivalents. Make sure that the `steps` Maxima variable is of the correct format. Note that all steps must be strings. See https://docs.stack-assessment.org/en/Authoring/Parsons/ for details.'; +$string['stackBlock_parsons_contents'] = 'The contents of a Parson\'s block must be a either a JSON of the form {#stackjson_stringify(steps)#}, where \'steps\' is the two-dimensional Maxima array containing key, value pairs of items, or of the form {\'steps\' : {#stackjson_stringify(steps)#}, \'options\' : {JSON containing Sortable options}, \'header\' : [List of headers], \'available_header\' : \'string containing header for the available list\', \'index\' : [List containing the index]}, where the \'options\', \'header\', \'available_header\', and \'index\' keys are optional. Alternatively, the contents of the Parsons block may contain raw JSON equivalents. Make sure that the \'steps\' Maxima variable is of the correct format. Note that all steps must be strings. See https://docs.stack-assessment.org/en/Authoring/Parsons/ for details.'; $string['stackBlock_incorrect_header_length'] = 'The list of headers should have the same length as the number of columns passed to the block header.'; $string['stackBlock_incorrect_available_header_type'] = 'The header for the available list should be passed as a string or a list of length one.'; $string['stackBlock_incorrect_index_length'] = 'The length of the index should be one more than the number of rows passed to the block header. An item in the top-left corner should always go in the index'; $string['stackBlock_incorrect_index_type'] = 'Index should be an array containing strings.'; $string['stackBlock_incorrect_header_type'] = 'Headers should be an array containing strings.'; -$string['stackBlock_parsons_invalid_columns_value'] = 'The value of `columns` in the Parson\'s block header should be a string containing a positive integer.'; -$string['stackBlock_parsons_invalid_rows_value'] = 'The value of `rows` in the Parson\'s block header should be a string containing a positive integer.'; -$string['stackBlock_parsons_invalid_item-height_value'] = 'The value of `item-height` in the Parson\'s block header should be a string containing a positive integer.'; -$string['stackBlock_parsons_invalid_item-width_value'] = 'The value of `item-width` in the Parson\'s block header should be a string containing a positive integer.'; +$string['stackBlock_parsons_invalid_columns_value'] = 'The value of \'columns\' in the Parson\'s block header should be a string containing a positive integer.'; +$string['stackBlock_parsons_invalid_rows_value'] = 'The value of \'rows\' in the Parson\'s block header should be a string containing a positive integer.'; +$string['stackBlock_parsons_invalid_item-height_value'] = 'The value of \'item-height\' in the Parson\'s block header should be a string containing a positive integer.'; +$string['stackBlock_parsons_invalid_item-width_value'] = 'The value of \'item-width\' in the Parson\'s block header should be a string containing a positive integer.'; $string['stackBlock_unknown_sortable_option'] = 'Unknown Sortable options found, the following are being ignored: '; $string['stackBlock_overwritten_sortable_option'] = 'Unchangeable Sortable options found, the following are being ignored: '; $string['stackBlock_parsons_unknown_transpose_value'] = 'Transpose must be one of \'true\' or \'false\'.'; -$string['stackBlock_parsons_underdefined_grid'] = 'When defining `rows` for a Parson\'s block one must also define `columns`.'; +$string['stackBlock_parsons_underdefined_grid'] = 'When defining \'rows\' for a Parson\'s block one must also define \'columns\'.'; $string['stackBlock_proof_mode_index'] = 'The use of \'index\' is not supported when using the Parson\'s block for proof assessment.'; $string['stackBlock_proof_incorrect_header_length'] = 'Headers should be an array containing a single header; use \'available_header\' to update the header for the available list.'; @@ -1525,7 +1531,25 @@ $string['castext_error_unevaluated'] = 'This text content was never evaluated.'; - // API strings. +$string['api_choose_file'] = 'Please select a question file'; +$string['api_choose_folder'] = 'Choose a STACK folder'; +$string['api_choose_q'] = 'Choose a STACK sample file'; +$string['api_correct'] = 'Correct answers'; +$string['api_display'] = 'Display Question'; +$string['api_errors'] = 'Errors'; +$string['api_failures'] = 'failures'; +$string['api_general_errors'] = 'General errors e.g. broken XML'; +$string['api_local_file'] = 'Or select a file of your own'; +$string['api_marks_sub'] = 'Marks for this submission'; $string['api_no_deployed_variants'] = 'The question XML does not contain deployed variants'; +$string['api_out_of'] = 'out of'; +$string['api_passes'] = 'passes'; +$string['api_q_select'] = 'Select a question'; +$string['api_q_xml'] = 'Question XML'; +$string['api_read_only'] = 'Read Only'; +$string['api_response'] = 'Response summary'; $string['api_seed_not_in_variants'] = 'The specified seed belongs to no deployed variant'; +$string['api_submit'] = 'Submit Answers'; +$string['api_valid_all_parts'] = 'Please enter valid answers for all parts of the question.'; +$string['api_which_typed'] = 'which can be typed as follows'; diff --git a/question.php b/question.php index 8fc7081bfeb77ff6ca55bde0c67f1de3beb4f251..5a7868f71d1eb22b4989eafa8005aa64d4bf39c3 100644 --- a/question.php +++ b/question.php @@ -378,7 +378,8 @@ class qtype_stack_question extends question_graded_automatically_with_countback } if ($this->get_cached('preamble-qv') !== null) { - $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble')); + $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', + 'blockexternal')); } // Context variables should be first. if ($this->get_cached('contextvariables-qv') !== null) { @@ -550,6 +551,10 @@ class qtype_stack_question extends question_graded_automatically_with_countback if ($this->tas[$name]->is_correctly_evaluated()) { $teacheranswer = $this->tas[$name]->get_value(); } + if ($this->get_cached('preamble-qv') !== null) { + $input->add_contextsession(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', + 'blockexternal')); + } if ($this->get_cached('contextvariables-qv') !== null) { $input->add_contextsession(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv')); } @@ -622,7 +627,7 @@ class qtype_stack_question extends question_graded_automatically_with_countback stack_utils::php_string_to_maxima_string($selected), 'language setting'), false); } if ($this->get_cached('preamble-qv') !== null) { - $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble')); + $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', 'blockexternal')); } if ($this->get_cached('contextvariables-qv') !== null) { $session->add_statement(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv')); @@ -675,7 +680,8 @@ class qtype_stack_question extends question_graded_automatically_with_countback stack_utils::php_string_to_maxima_string($selected), 'language setting'), false); } if ($this->get_cached('preamble-qv') !== null) { - $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble')); + $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', + 'blockexternal')); } if ($this->get_cached('contextvariables-qv') !== null) { $session->add_statement(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv')); @@ -1200,12 +1206,12 @@ class qtype_stack_question extends question_graded_automatically_with_countback } if ($this->get_cached('preamble-qv') !== null) { - $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble')); + $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', 'blockexternal')); } // Add preamble from PRTs as well. foreach ($this->get_cached('prt-preamble') as $name => $stmt) { if (isset($prts[$name])) { - $session->add_statement(new stack_secure_loader($stmt, 'preamble PRT: ' . $name)); + $session->add_statement(new stack_secure_loader($stmt, 'preamble PRT: ' . $name, 'blockexternal')); } } diff --git a/questiontestrun.php b/questiontestrun.php index a4ff85d8f3a9f891ee13f55db87c793f4296c216..1ceec928f098cc94e85282290366d415d4e38f68 100644 --- a/questiontestrun.php +++ b/questiontestrun.php @@ -176,27 +176,12 @@ $questionvariablevalues = $question->get_question_session_keyval_representation( // Load the list of test cases. $testscases = question_bank::get_qtype('stack')->load_question_tests($question->id); // Create the default test case. +$defaulttest = null; +$defaulttestresult = null; + if (optional_param('defaulttestcase', null, PARAM_INT) && $canedit) { - $inputs = []; - foreach ($question->inputs as $inputname => $input) { - $inputs[$inputname] = $input->get_teacher_answer_testcase(); - } - $qtest = new stack_question_test(stack_string('autotestcase'), $inputs); - $response = stack_question_test::compute_response($question, $inputs); - - foreach ($question->prts as $prtname => $prt) { - $result = $question->get_prt_result($prtname, $response, false); - // For testing purposes we just take the last note. - $answernotes = $result->get_answernotes(); - $answernote = [end($answernotes)]; - // Here we hard-wire 1 mark and 0 penalty. This is what we normally want for the - // teacher's answer. If the question does not give full marks to the teacher's answer then - // the test case will fail, and the user can confirm the failing behaviour if they really intended this. - // Normally we'd want a failing test case with the teacher's answer not getting full marks! - $qtest->add_expected_result($prtname, new stack_potentialresponse_tree_state( - 1, true, 1, 0, '', $answernote)); - } - question_bank::get_qtype('stack')->save_question_test($questionid, $qtest); + $defaulttest = stack_bulk_tester::create_default_test($question); + question_bank::get_qtype('stack')->save_question_test($questionid, $defaulttest); $testscases = question_bank::get_qtype('stack')->load_question_tests($question->id); echo html_writer::tag('p', stack_string_error('runquestiontests_auto')); @@ -217,6 +202,15 @@ if (empty($testscases) && $canedit) { echo html_writer::end_tag('form'); } +if (empty($testscases)) { + echo "\n<hr/>\n"; + $defaulttest = stack_bulk_tester::create_default_test($question); + $defaulttestresult = $defaulttest->test_question($questionid, $seed, $context); + echo stack_string('runquestiontests_explanation'); + echo $defaulttestresult->html_output($question, stack_string('runquestiontests_example')); + echo "\n<hr/>\n"; +} + $deployfeedback = optional_param('deployfeedback', null, PARAM_TEXT); if (!is_null($deployfeedback)) { echo html_writer::tag('p', $deployfeedback, ['class' => 'overallresult pass']); @@ -429,7 +423,7 @@ if ($question->has_random_variants()) { echo ' ' . stack_string('deploymanynotes'); echo html_writer::end_tag('form'); - // Systematic deployment of variants. + // Systematic deployment of variants (from 1 to ...). echo html_writer::start_tag('form', [ 'method' => 'get', 'class' => 'deploysystematic', 'action' => new moodle_url('/question/type/stack/deploy.php', $urlparams), @@ -445,6 +439,27 @@ if ($question->has_random_variants()) { ]); echo html_writer::end_tag('form'); + // Systematic deployment of variants (from ... to ...). + echo html_writer::start_tag('form', [ + 'method' => 'get', 'class' => 'deploysystematicfromto', + 'action' => new moodle_url('/question/type/stack/deploy.php', $urlparams), + ]); + echo html_writer::input_hidden_params(new moodle_url($PAGE->url, ['sesskey' => sesskey()]), ['seed']); + echo ' ' . html_writer::empty_tag('input', [ + 'type' => 'submit', 'class' => 'btn btn-secondary', + 'value' => stack_string('deploysystematicfrombtn'), + ]); + echo ' ' . html_writer::empty_tag('input', [ + 'type' => 'text', 'size' => 3, + 'id' => 'deploysystematicfromfield', 'name' => 'deploysystematicfrom', 'value' => '', + ]); + echo ' ' . stack_string('deploysystematicto'); + echo ' ' . html_writer::empty_tag('input', [ + 'type' => 'text', 'size' => 3, + 'id' => 'deploysystematictofield', 'name' => 'deploysystematicto', 'value' => '', + ]); + echo html_writer::end_tag('form'); + // Deploy many from a CS list of integer seeds. echo "\n" . html_writer::start_tag('form', [ 'method' => 'get', 'class' => 'deployfromlist', diff --git a/stack/bulktester.class.php b/stack/bulktester.class.php index 8dae8fd8313b63a108aec839387bb210a5da48c6..83c91487d886f0ee50deba680f0efe4508554413 100644 --- a/stack/bulktester.class.php +++ b/stack/bulktester.class.php @@ -450,6 +450,18 @@ class stack_bulk_tester { return [false, "Attempting to start the question threw an exception!"]; } + if (!$tests) { + $defaulttest = self::create_default_test($question); + $defaulttestresult = $defaulttest->test_question($qid, $seed, $context); + if ($defaulttestresult->passed()) { + $ok = true; + $message = stack_string('defaulttestpass'); + } else { + $ok = false; + $message = stack_string('defaulttestfail'); + } + } + // Prepare the display options. $options = new question_display_options(); $options->readonly = true; @@ -582,4 +594,41 @@ class stack_bulk_tester { echo html_writer::tag('p', html_writer::link(new moodle_url('/question/type/stack/adminui/bulktestindex.php'), get_string('back'))); } + + /** + * Create a default test for a question. + * + * Expected score of 1 and penalty of 0 using the model answers. + * The answer note will be set to whatever answer note the model + * answer returns. + * + * Question usage by attempt needs to have already been set up + * and the question started. + * + * @param object $question + * @return stack_question_test + */ + public static function create_default_test($question) { + $inputs = []; + foreach ($question->inputs as $inputname => $input) { + $inputs[$inputname] = $input->get_teacher_answer_testcase(); + } + $qtest = new stack_question_test(stack_string('autotestcase'), $inputs); + $response = stack_question_test::compute_response($question, $inputs); + + foreach ($question->prts as $prtname => $prt) { + $result = $question->get_prt_result($prtname, $response, false); + // For testing purposes we just take the last note. + $answernotes = $result->get_answernotes(); + $answernote = [end($answernotes)]; + // Here we hard-wire 1 mark and 0 penalty. This is what we normally want for the + // teacher's answer. If the question does not give full marks to the teacher's answer then + // the test case will fail, and the user can confirm the failing behaviour if they really intended this. + // Normally we'd want a failing test case with the teacher's answer not getting full marks! + $qtest->add_expected_result($prtname, new stack_potentialresponse_tree_state( + 1, true, 1, 0, '', $answernote)); + } + + return $qtest; + } } diff --git a/stack/cas/cassession2.class.php b/stack/cas/cassession2.class.php index a7d280acb073f4f1d3fd59f0cf20f526fa8a946f..9bdec031deb2390e282b7b3e5a4f79f154c5a6d6 100644 --- a/stack/cas/cassession2.class.php +++ b/stack/cas/cassession2.class.php @@ -332,8 +332,9 @@ class stack_cas_session2 { $line .= stack_utils::php_string_to_maxima_string($statement->get_source_context()); $line .= ')'; - if (method_exists($statement, 'is_toplevel_property') && $statement->is_toplevel_property('blockexternal')) { - $preblock .= $line . "$\n"; + if (($statement instanceof stack_secure_loader && $statement->get_blockexternal()) || + (method_exists($statement, 'is_toplevel_property') && $statement->is_toplevel_property('blockexternal'))) { + $preblock .= 'errcatch(' . $ef . ")$\n"; } else { $command .= self::SEP . $line; } diff --git a/stack/cas/castext2/blocks/parsons.block.php b/stack/cas/castext2/blocks/parsons.block.php index 747589d28d63b6efc46aa9776ec2ccfa9e65788f..a8df15152f326cb62a16bb471df3e9c99c3e2364 100644 --- a/stack/cas/castext2/blocks/parsons.block.php +++ b/stack/cas/castext2/blocks/parsons.block.php @@ -234,14 +234,14 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { // If the author's JSON has invalid structure throw an error. $code .= 'if (valid === false) {stack_js.display_error("' . stack_string('stackBlock_parsons_contents') . '");}' . "\n"; - + // More specific pieces of validation // Check typing of headers, it should be an array containing strings. - $code .= 'if (!(Array.isArray(headers))) + $code .= 'if (!(Array.isArray(headers))) {stack_js.display_error("' . stack_string('stackBlock_incorrect_header_type') . '");}' . "\n"; // If the length of headers does not match the number of columns expected throw an error. - // Error is different for proof vs. matching + // Error is different for proof vs. matching. $code .= 'if (headers.length !== ' . $ogcolumns . ') {stack_js.display_error("'; if ($proofmode) { $code .= stack_string('stackBlock_proof_incorrect_header_length') . '");}' . "\n"; @@ -249,27 +249,26 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { $code .= stack_string('stackBlock_incorrect_header_length') . '");}' . "\n"; } - // Validate available headers. It - // is either a string or an array containing a single string. + // Validate available headers. It is either a string or an array containing a single string. $code .= 'if (!(typeof(available_header) === "string" || (Array.isArray(available_header) && available_header.length === 1 && typeof(available_header[0]) === "string"))) {stack_js.display_error("' . stack_string('stackBlock_incorrect_available_header_type') . '");}' . "\n"; - // Extract available header if it is an array containing a single string + // Extract available header if it is an array containing a single string. $code .= 'if (Array.isArray(available_header)) {available_header = available_header[0]};' . "\n"; // If index is passed then it should be an array containing strings. $code .= 'if (index !== undefined && !(Array.isArray(index) && index.every((idx) => typeof(idx) === "string"))) {stack_js.display_error("' . stack_string('stackBlock_incorrect_index_type') . '");}' . "\n"; - // If rows and index are passed then the length of index should match the value of rows + 1 + // If rows and index are passed then the length of index should match the value of rows + 1. if ($ogrows !== null) { $code .= 'if (index !== undefined && index.length !== ' . ($ogrows + 1) . ') {stack_js.display_error("' . stack_string('stackBlock_incorrect_index_length') . '");}' . "\n"; } - // Index cannot be used in proof mode due to styling issues + // Index cannot be used in proof mode due to styling issues. if ($proofmode) { - $code .= 'if (index !== undefined) + $code .= 'if (index !== undefined) {stack_js.display_error("' . stack_string('stackBlock_proof_mode_index') . '");}' . "\n"; } @@ -304,8 +303,8 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { $code .= 'var possibleOptionKeys = Object.keys(sortableUsed[0][0].options).concat(SUPPORTED_CALLBACK_FUNCTIONS);' . "\n"; // Now set appropriate options. - $code .= 'sortableUsed.forEach((sortableList) => - sortableList.forEach((sortable) => + $code .= 'sortableUsed.forEach((sortableList) => + sortableList.forEach((sortable) => Object.entries(stackSortable.options.used).forEach( ([key, val]) => sortable.option(key, val))));' . "\n"; $code .= 'var sortableAvailable = Sortable.create(availableList, stackSortable.options.available);' . "\n"; @@ -318,7 +317,7 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { ) );' . "\n"; - $code .= 'sortableAvailable.option("onSort", + $code .= 'sortableAvailable.option("onSort", () => { stackSortable.update_state(sortableUsed, sortableAvailable); stackSortable.update_grid_empty_css();});' . "\n"; @@ -353,10 +352,10 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { if (!$existsuserheight) { $code .= ($mathjaxversion === "2") ? 'MathJax.Hub.Queue(() => { - stackSortable.resize_grid_items(); + stackSortable.resize_grid_items(); stack_js.resize_containing_frame("' . $width . '", get_iframe_height() + "px");})' : 'mathJaxPromise.then(() => { - stackSortable.resize_grid_items(); + stackSortable.resize_grid_items(); stack_js.resize_containing_frame("' . $width . '", get_iframe_height() + "px");});'; $code .= "\n"; } @@ -395,7 +394,7 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { $height = array_key_exists('height', $this->params) ? $this->params['height'] : '400px'; // NOTE! List ordered by length. For the trimming logic. - $validunits = [ + $validunits = [ 'vmin', 'vmax', 'rem', 'em', 'ex', 'px', 'cm', 'mm', 'in', 'pt', 'pc', 'ch', 'vh', 'vw', '%', ]; @@ -473,7 +472,7 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { } } - // Check value of transpose is only "true" or "false" + // Check value of transpose is only "true" or "false". if (array_key_exists('transpose', $this->params)) { if (!in_array($this->params['transpose'], ['true', 'false'])) { $valid = false; @@ -481,15 +480,15 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { } } - // Check value of columns is a string containing a numeric positive integer + // Check value of columns is a string containing a numeric positive integer. if (array_key_exists("columns", $this->params)) { if (!(preg_match('/^\d+$/', $this->params["columns"]) && intval($this->params["columns"]) > 0)) { $valid = false; $err[] = stack_string("stackBlock_parsons_invalid_columns_value"); } } - - // Check value of rows is a string containing a numeric positive integer + + // Check value of rows is a string containing a numeric positive integer. if (array_key_exists("rows", $this->params)) { if (!(preg_match('/^\d+$/', $this->params["rows"]) && intval($this->params["rows"]) > 0)) { $valid = false; @@ -497,13 +496,13 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { } } - // Check we cannot have rows specified without columns + // Check we cannot have rows specified without columns. if (array_key_exists("rows", $this->params) && !array_key_exists("columns", $this->params)) { $valid = false; $err[] = stack_string("stackBlock_parsons_underdefined_grid"); } - // Check value of `item-height` is a string containing a positive integer + // Check value of `item-height` is a string containing a positive integer. if (array_key_exists("item-height", $this->params)) { if (!(preg_match('/^\d+$/', $this->params["item-height"]) && intval($this->params["item-height"]) > 0)) { $valid = false; @@ -511,7 +510,7 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block { } } - // Check value of `item-width` is a string containing a positive integer + // Check value of `item-width` is a string containing a positive integer. if (array_key_exists("item-width", $this->params)) { if (!(preg_match('/^\d+$/', $this->params["item-width"]) && intval($this->params["item-width"]) > 0)) { $valid = false; diff --git a/stack/cas/keyval.class.php b/stack/cas/keyval.class.php index d34bbf9b2043824db75d495c8c4caf6093847e3d..8552b254a65d70d23d5992d37edec14fb552db4a 100644 --- a/stack/cas/keyval.class.php +++ b/stack/cas/keyval.class.php @@ -104,9 +104,8 @@ class stack_cas_keyval { $str = str_replace('?', 'QMCHAR', $str); - // CAS keyval may not contain @ or $ outside strings. - // We should certainly prevent the $ to make sure statements are separated by ;, although Maxima does allow $. - if (strpos($str, '@') !== false || strpos($str, '$') !== false) { + // CAS keyval may not contain @ outside strings. + if (strpos($str, '@') !== false) { $this->errors[] = new $this->errclass(stack_string('illegalcaschars'), $this->context); $this->valid = false; return false; @@ -387,12 +386,22 @@ class stack_cas_keyval { if ($item->statement instanceof MP_FunctionCall) { $op = $item->statement->name->value; } - if (stack_cas_security::get_feature($op, 'blockexternal') !== null) { - $bestatements[] = $statement; - } - // Note that stack_reet_vars needs to be both blockexternal and a contextvariable. + // Notes on ordergreat and stack_reset_vars. + // We must have ordergreat/orderless outside the main block, so we need blockexternals. + // If we use stack_reset_vars after an ordergreat it "kills" the effects of the order change. + // Hence, we can't have stack_reset_vars in both the context variables and the blockexternals. + // This is the edge case where we re-order i,j,k to be i+j+k, not the Maxima default k+j+i. if (stack_cas_security::get_feature($op, 'contextvariable') !== null) { $contextvariables[] = $statement; + } + // Test for end of context variables. + if ($item->statement instanceof MP_Identifier) { + if ($item->statement->value == '%_stack_preamble_end') { + $contextvariables = array_merge($contextvariables, $statements); + $statements = []; + } + } else if (stack_cas_security::get_feature($op, 'blockexternal') !== null) { + $bestatements[] = $statement; } else { $statements[] = $statement; } @@ -412,7 +421,6 @@ class stack_cas_keyval { if (count($bestatements) == 0) { $bestatements = null; } else { - // These statement groups always end with a 'true' to ensure minimal output. $bestatements = '(' . implode(',', $bestatements) . ',true)'; } if (count($statements) == 0) { diff --git a/stack/cas/parsingrules/033_no_extra_evaluation.filter.php b/stack/cas/parsingrules/033_no_extra_evaluation.filter.php new file mode 100644 index 0000000000000000000000000000000000000000..6bbd683bf9a318a453b3e3937c53f29aeb0d3594 --- /dev/null +++ b/stack/cas/parsingrules/033_no_extra_evaluation.filter.php @@ -0,0 +1,41 @@ +<?php +// This file is part of Stack - https://stack.maths.ed.ac.uk +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +defined('MOODLE_INTERNAL') || die(); +require_once(__DIR__ . '/filter.interface.php'); + +/** + * AST filter that looks for the Maxima '' operator for extra evaluation, which is not supported. + */ +class stack_ast_filter_033_no_extra_evaluation implements stack_cas_astfilter { + + public function filter(MP_Node $ast, array &$errors, array &$answernotes, stack_cas_security $identifierrules): MP_Node { + + $process = function($node) use (&$errors, &$answernotes) { + if ($node instanceof MP_PrefixOp && $node->op === "''") { + $node->position['invalid'] = true; + if (array_search('Illegal_extraevaluation', $answernotes) === false) { + $answernotes[] = 'Illegal_extraevaluation'; + $errors[] = stack_string('Illegal_extraevaluation'); + } + $answernotes[] = 'Illegal_extraevaluation'; + } + return true; + }; + $ast->callbackRecurse($process); + return $ast; + } +} diff --git a/stack/cas/parsingrules/996_call_modification.filter.php b/stack/cas/parsingrules/996_call_modification.filter.php index 59717b122ca3b3d01c9a13e5cf22e6ac5d905f94..83c5d6fc3e80d4c5e2b561cbfe3f2d625a4fd8c7 100644 --- a/stack/cas/parsingrules/996_call_modification.filter.php +++ b/stack/cas/parsingrules/996_call_modification.filter.php @@ -87,7 +87,7 @@ class stack_ast_filter_996_call_modification implements stack_cas_astfilter { // The order of these ifs is critical, we build up the checks // so that no basic check gets lost due to more advanced ones - // doing more conplex things. The advanced cases assume that + // doing more complex things. The advanced cases assume that // the simpler ones have been done already. if (!($node->parentnode instanceof MP_Group) || $node->parentnode->items[0]->toString() !== $namecheck->toString()) { diff --git a/stack/cas/parsingrules/parsingrule.factory.php b/stack/cas/parsingrules/parsingrule.factory.php index a6943fd9aafef0fd29aa56e99d260f294a6cf72c..1aacd11149b3fcb034c67e06017d42a46345417f 100644 --- a/stack/cas/parsingrules/parsingrule.factory.php +++ b/stack/cas/parsingrules/parsingrule.factory.php @@ -27,6 +27,7 @@ require_once(__DIR__ . '/022_trig_replace_synonyms.filter.php'); require_once(__DIR__ . '/025_no_trig_power.filter.php'); require_once(__DIR__ . '/030_no_trig_space.filter.php'); require_once(__DIR__ . '/031_no_trig_brackets.filter.php'); +require_once(__DIR__ . '/033_no_extra_evaluation.filter.php'); require_once(__DIR__ . '/050_no_chained_inequalities.filter.php'); require_once(__DIR__ . '/090_special_forbidden_characters.filter.php'); require_once(__DIR__ . '/101_no_floats.filter.php'); @@ -102,6 +103,8 @@ class stack_parsing_rule_factory { return new stack_ast_filter_030_no_trig_space(); case '031_no_trig_brackets': return new stack_ast_filter_031_no_trig_brackets(); + case '033_no_extra_evaluation': + return new stack_ast_filter_033_no_extra_evaluation(); case '050_no_chained_inequalities': return new stack_ast_filter_050_no_chained_inequalities(); case '090_special_forbidden_characters': @@ -204,6 +207,7 @@ class stack_parsing_rule_factory { '022_trig_replace_synonyms', '025_no_trig_power', '030_no_trig_space', '031_no_trig_brackets', + '033_no_extra_evaluation', '050_no_chained_inequalities', '090_special_forbidden_characters', '101_no_floats', '102_no_strings', diff --git a/stack/cas/secure_loader.class.php b/stack/cas/secure_loader.class.php index 281a45c49238816313ade7e5705bd139ce0bfc10..4e2c4274b09185ad7eb3dbb72fec37f7953f4c9d 100644 --- a/stack/cas/secure_loader.class.php +++ b/stack/cas/secure_loader.class.php @@ -31,8 +31,9 @@ class stack_secure_loader implements cas_evaluatable { private $code; private $errors; private $context; + private $blockexternal; - public function __construct(string $securedcode, string $fromwhere='') { + public function __construct(string $securedcode, string $fromwhere = '', string $blockexternal = '') { if ($securedcode === null) { throw new stack_exception('secure_loader: the code must not be null.'); } @@ -42,6 +43,10 @@ class stack_secure_loader implements cas_evaluatable { $this->context = $fromwhere; $this->code = $securedcode; $this->errors = []; + $this->blockexternal = false; + if ($blockexternal === 'blockexternal') { + $this->blockexternal = true; + } } public function get_valid(): bool { @@ -80,6 +85,10 @@ class stack_secure_loader implements cas_evaluatable { public function get_key(): string { return ''; } + + public function get_blockexternal(): bool { + return $this->blockexternal; + } } class stack_secure_loader_value extends stack_secure_loader implements cas_value_extractor { diff --git a/stack/cas/security-map.json b/stack/cas/security-map.json index bac110da349a23c451913dfc9a58a1dbfffc33d4..37a3a62fcf320efbcbf57f29fb715d9f8f0bfdee 100644 --- a/stack/cas/security-map.json +++ b/stack/cas/security-map.json @@ -128,6 +128,9 @@ "%s": { "function": "?" }, + "%_stack_preamble_end": { + "constant": "t" + }, "%stmt": { "variable": "f" }, @@ -254,6 +257,9 @@ "function": "s", "variable": "s" }, + "EMPTYANSWER": { + "variable": "s" + }, "EMPTYCHAR": { "variable": "s" }, @@ -5192,16 +5198,14 @@ }, "ordergreat": { "function": "s", - "blockexternal": "true", - "contextvariable": "true" + "blockexternal": "true" }, "ordergreatp": { "function": "s" }, "orderless": { "function": "s", - "blockexternal": "true", - "contextvariable": "true" + "blockexternal": "true" }, "orderlessp": { "function": "s" @@ -6708,7 +6712,12 @@ "globalyforbiddenfunction": true }, "root": { - "function": "s" + "function": "s", + "nounfunction": "'root" + }, + "'root": { + "function": "t", + "nounfunctionfor": "root" }, "rootsconmode": { "variable": "s" @@ -7303,8 +7312,7 @@ }, "stack_reset_vars": { "function": "?", - "blockexternal": "true", - "contextvariable": "true" + "blockexternal": "true" }, "stack_validate": { "function": "s" diff --git a/stack/input/inputbase.class.php b/stack/input/inputbase.class.php index 07f945f8d9b7d534161da04eb8690de3ccff7e5d..3225e270bd3f87b0835fc0b313cbfa5e35ddbcaa 100644 --- a/stack/input/inputbase.class.php +++ b/stack/input/inputbase.class.php @@ -458,7 +458,7 @@ abstract class stack_input { public function add_contextsession($contextsession) { if ($contextsession != null) { // Always make this the start of an array. - $this->contextsession = [$contextsession]; + $this->contextsession = array_merge($this->contextsession, [$contextsession]); } } @@ -1091,6 +1091,13 @@ abstract class stack_input { $additionalvars = []; + if ($questionvariables) { + if ($questionvariables['preamble-qv'] !== null) { + $additionalvars['preamble-qv'] = new stack_secure_loader($questionvariables['preamble-qv'], + 'preamble', 'blockexternal'); + } + } + if (array_key_exists('floatnum', $this->extraoptions) && $this->extraoptions['floatnum']) { $additionalvars['floatnum'] = stack_ast_container::make_from_teacher_source('simp_floatnump('.$this->name.')', '', new stack_cas_security(), []); @@ -1136,9 +1143,6 @@ abstract class stack_input { if ((array_key_exists('validator', $this->extraoptions) && $this->extraoptions['validator']) || (array_key_exists('feedback', $this->extraoptions) && $this->extraoptions['feedback'])) { if ($questionvariables) { - if ($questionvariables['preamble-qv'] !== null) { - $additionalvars['preamble-qv'] = new stack_secure_loader($questionvariables['preamble-qv'], 'preamble'); - } if ($questionvariables['contextvariables-qv'] !== null) { $additionalvars['contextvariables-qv'] = new stack_secure_loader($questionvariables['contextvariables-qv'], 'contextvariables'); diff --git a/stack/mathsoutput/mathsoutputapi.class.php b/stack/mathsoutput/mathsoutputapi.class.php index c78d10c416998d6a13d33b23d69f118617230dcb..965c1a16df53db75ed58470997ef57f4b099f401 100644 --- a/stack/mathsoutput/mathsoutputapi.class.php +++ b/stack/mathsoutput/mathsoutputapi.class.php @@ -47,7 +47,7 @@ class stack_maths_output_api extends stack_maths_output_filter_base { $text = $this->replace_dollars($text); } - $text = stack_fact_sheets::display($text, new \qtype_stack_renderer()); + $text = stack_fact_sheets::display($text ?? '', new \qtype_stack_renderer()); return $text; } diff --git a/stack/maxima/assessment.mac b/stack/maxima/assessment.mac index 560fc2ef99e48a187bc7cd846a5a832174772cc9..fe7b2bdf3f831c76fa8b6f5fbe876dc0b59339e1 100644 --- a/stack/maxima/assessment.mac +++ b/stack/maxima/assessment.mac @@ -365,6 +365,10 @@ root([ex]) := block( if length(ex) = 1 then return(sqrt(first(ex))), if length(ex) = 2 then return(first(ex)^(1/second(ex))) )$ +texroot(ex) := if is(length(args(ex))=1) then concat("\\sqrt{", tex1(first(args(ex))), "}") else concat("\\sqrt[", tex1(second(args(ex))), "]{", tex1(first(args(ex))), "}")$ +texput(nounify(root), texroot)$ +texput(verbify(root), texroot)$ + /* Denominators of fractions should not contain sqrt, root, %i or fractional powers. */ rational_fail(ex) := block( @@ -553,7 +557,11 @@ commonfaclist(l) := block([i, a, ret], else ret:"fail", return(ret) )$ -/* Returns a list of factors of ex without multiplicities. */ +/* + * Returns a list of factors of ex without multiplicities. + * @param[scalar expression] ex, expression to be factored. + * @return[list] the list of factors, without multiplicities. + */ factorlist(ex) := block([simp:false, ret:"", ex2], ex:ev(factor(ex), simp), if mapatom(ex) then return([ex]), diff --git a/stack/maxima/contrib/prooflib_test.mac b/stack/maxima/contrib/prooflib_test.mac index cc5c1e7061589df044fff095ba1675794cc203d7..0b91af3b2032ee8823d13866828d0ea7b8370616 100644 --- a/stack/maxima/contrib/prooflib_test.mac +++ b/stack/maxima/contrib/prooflib_test.mac @@ -59,7 +59,7 @@ s_test_case(proof_alternatives(proof_cases(A,B,C)), [proof_cases(A,B,C),proof_ca s_test_case(proof_alternatives(proof_goal(A,B,C)), [proof_goal(A,B,C),proof_goal(B,A,C)]); s_test_case(proof_alternatives(proof_iff(proof(proof_opt(A), B),C)), [proof_iff(proof(A,B),C),proof_iff(proof(B),C),proof_iff(C,proof(A,B)),proof_iff(C,proof(B))]); -s_test_case(proof_parsons_interpret("{\"used\":[\"0\",\"3\",\"5\"],\"available\":[\"1\",\"2\",\"4\",\"6\",\"7\"]}"), proof("0","3","5")); +s_test_case(proof_parsons_interpret("{\"used\":[[[\"0\",\"3\",\"5\"]]],\"available\":[\"1\",\"2\",\"4\",\"6\",\"7\"]}"), proof("0","3","5")); s_test_case(proof_inline_maths("\\[ 3 = 2^{\\frac{p}{q}}\\]"), "\\( 3 = 2^{\\frac{p}{q}}\\)"); diff --git a/stack/maxima/rtest_assessment_simpboth.mac b/stack/maxima/rtest_assessment_simpboth.mac index 3406ce251a31e8c750d66c47a4bc82fef3d674c6..ce0fa764113e65dc47892b1f1ba901cb0b3f9c42 100644 --- a/stack/maxima/rtest_assessment_simpboth.mac +++ b/stack/maxima/rtest_assessment_simpboth.mac @@ -387,6 +387,8 @@ factorlist(-x^2-5*x+6); [x-1,x+6]$ factorlist(x^3-1); [x-1,x^2+x+1]$ +factorlist(a^2-b^2); +[b-a,b+a]$ cartesian_product({1, 2}, {3, 4}); {[1, 3], [1, 4], [2, 3], [2, 4]}$ diff --git a/stack/maxima/stackmaxima.mac b/stack/maxima/stackmaxima.mac index c508ece7487b52362773062fc30cf22053e18443..7d5d8e56f6a66f4356a163bd9dccd80c331d26d6 100644 --- a/stack/maxima/stackmaxima.mac +++ b/stack/maxima/stackmaxima.mac @@ -47,6 +47,7 @@ stack_reset(not_used) := block( Pi: %pi, PI: %pi, pi() := %pi, /* Why does Excel do this?! */ + i:%i, /* Display of matrixes */ lmxchar: "[", /* Sets up randomization, using Maxima's internal random command. */ @@ -199,16 +200,15 @@ declare ("#", commutative); simplify(ex) := ev(fullratsimp(ex), simp); /* Allows simplify to be something. */ degree(ex, v) := ev(hipow(expand(ex), v), simp); /* See notes on hipow. */ - make_complexJ(OPT_COMPLEXJ) := block( if OPT_COMPLEXJ = "i" then - (i:%i,texput(%i,"\\mathrm{i}")) + (texput(%i,"\\mathrm{i}")) else if OPT_COMPLEXJ = "j" then - (%j:%i,j:%i,texput(%i,"\\mathrm{j}")) + (kill(i),%j:%i,j:%i,texput(%i,"\\mathrm{j}")) else if OPT_COMPLEXJ = "symi" then - (texput(%i,"\\mathrm{i}")) + (kill(i),texput(%i,"\\mathrm{i}")) else if OPT_COMPLEXJ = "symj" then - (texput(%i,"\\mathrm{j}")) + (kill(i),texput(%i,"\\mathrm{j}")) else true )$ @@ -784,9 +784,6 @@ stack_disp_sub_script(ex) := block([s], if taylorp(ex) then return(ex), if safe_setp(ex) then return(apply(set, maplist(stack_disp_sub_script, args(ex)))), if arrayp(ex) then return(arraymake(op(ex), maplist(stack_disp_sub_script, args(ex)))), - /* The following are not, strictly speaking, a subscript issue, but we don't want another recursive call. */ - /* Strip out empty plus operators, which cause problems in display with simp:false. */ - if is(safe_op(ex)="+") and is(length(args(ex))=1) then return(stack_disp_sub_script(first(args(ex)))), /* Now deal with supscripts. */ if not(atom(ex)) then return(apply(op(ex), maplist(stack_disp_sub_script, args(ex)))), if simp_numberp(ex) or stringp(ex) or ex or not(ex) then return(ex), @@ -898,12 +895,12 @@ texput(matrix, stack_matrix_disp)$ unary_minus_traverse(ex) := block( /* We want atom here, not mapatom to catch a[4]. */ if atom(ex) then return(ex), + if op(ex) = "-" and (is(first(args(ex))=0) or is(first(args(ex))=0.0)) then return(ex), if op(ex) = "-" and numberp(first(args(ex))) then return(ev(ex,simp)), if arrayp(ex) then return(arraymake(op(ex), maplist(unary_minus_traverse, args(ex)))), apply(op(ex), map(unary_minus_traverse, args(ex)) ) )$ - /* Pulls out "-" to the front of any expression in a sum of products which needs it. */ /* For example, -(2*y^2) is ok */ /* But (-3)*7 is not. */ @@ -3334,4 +3331,4 @@ is_lang(code):=ev(is(%_STACK_LANG=code),simp=true)$ /* Stack expects some output with the version number the output happens at */ /* maximalocal.mac after additional library loading */ -stackmaximaversion:2024060300$ +stackmaximaversion:2025072400$ diff --git a/stack/maxima/stackstrings.mac b/stack/maxima/stackstrings.mac index 585ac1fed67da82ed8a42c35bbaf28ea09fa875b..065ec93b5001fd15de3920b6c824d593be46253f 100644 --- a/stack/maxima/stackstrings.mac +++ b/stack/maxima/stackstrings.mac @@ -228,7 +228,7 @@ stackjson_stringify(obj) := block([tmp,r,l], /* Prior code: `r : sconcat("\"",simplode(map(stackjson_protect_escapes, charlist(obj))),"\"")` */ /* However, there is evidence showing that this code is quadratic and that the batch optimisation helps to alleviate this. */ /* See here: https://docs.stack-assessment.org/en/Developer/Optimising_STACK_for_large_Maxima_variables/ for more details. */ - else if stringp(obj) then block([char_list], + else if stringp(obj) then block([char_list, batch_size, i, j], /* Create character list with escapes protected */ char_list: map(stackjson_protect_escapes, charlist(obj)), /* Set batch size to 64, which is inferred from the maximum function argument limit in GCL-compiled Lisp. Other compilations (e.g., SBCL) are less limited in this respect. */ diff --git a/stack/maxima/stacktex.lisp b/stack/maxima/stacktex.lisp index 505c730213c2da53c177ac93d7be61865fcd4015..d9b7bfeeb44c561dfa2cd1b8f7003453dc415221 100644 --- a/stack/maxima/stacktex.lisp +++ b/stack/maxima/stacktex.lisp @@ -241,7 +241,7 @@ ;; This list is an exception, e.g. conjugate(x)^2. ;; We use this list because tex-mexpt is also defined in stacktex40.lisp for earlier versions of Maxima. (defvar tex-mexpt-fnlist '(%sum %product %derivative %integrate %at $conjugate $texsub $lg $logbase %sqrt - %lsum %limit $pderivop $#pm#)) + %lsum %limit $pderivop $#pm# $disp_select $displaydp $displaysci)) ;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks. (defun tex-mexpt (x l r) diff --git a/stack/maxima/stackunits.mac b/stack/maxima/stackunits.mac index 3ddb9cd4accee1f482454796e5e9511cd9c3cc39..f24075b6e4ba63015804d6dd5dcd2f9c2499f847 100644 --- a/stack/maxima/stackunits.mac +++ b/stack/maxima/stackunits.mac @@ -392,8 +392,10 @@ stack_validate_units(expr, LowestTerms, TAns, fracdisp) := block( [simp:false, e return(expr) )$ +texput(multsgnstackunits, "\\, "); + /* Finer control over display of units, separating out the number from the units. */ -stackunitstex(ex) := block ([a, b, c, astr, bstr], +stackunitstex(ex) := block([a, b, c, astr, bstr], a:first(args(ex)), b:second(args(ex)), if scientific_notationp(a) then make_multsgn("cross"), @@ -410,8 +412,9 @@ stackunitstex(ex) := block ([a, b, c, astr, bstr], bstr:tex1(b), if is(strim(" ", astr)="") then return(bstr), if is(strim(" ", bstr)="") then return(astr), - sconcat(astr,"\\, ", bstr) + sconcat(astr, tex1(multsgnstackunits), bstr) )$ + texput(stackunits, stackunitstex); texput(NULLUNITS, ""); texput(NULLNUM, ""); diff --git a/stack/maximaparser/autogen/gen.js b/stack/maximaparser/autogen/gen.js index bd425e264f4a3b66777b72b7832c2568344f2689..444af8f7dfa18bf9a37ce5a71356241a6ca27771 100644 --- a/stack/maximaparser/autogen/gen.js +++ b/stack/maximaparser/autogen/gen.js @@ -5,7 +5,7 @@ let fs = require('fs'); let pegjs = require('pegjs'); let phpegjs = require('phpegjs'); -let tspegjs = require('ts-pegjs'); +// let tspegjs = require('ts-pegjs'); var parserCode = fs.readFile('./parser-grammar.pegjs','utf8',function @@ -23,7 +23,7 @@ var parserCode = fs.readFile('./parser-grammar.pegjs','utf8',function let TSparser = pegjs.generate(data, { output: 'source', cache: true, - plugins: [tspegjs], +// plugins: [tspegjs], allowedStartRules: ["Root", "Equivline"], tspegjs: { customHeader: 'import {MPNode, MPOperation, MPAtom, MPInteger, MPFloat, MPString, MPBoolean, MPIdentifier, MPComment, MPFunctionCall, MPGroup, MPSet, MPList, MPPrefixOp, MPPostfixOp, MPIndexing, MPIf, MPLoop, MPLoopBit, MPEvaluationFlag, MPStatement, MPRoot, MPAnnotation} from \'./MP_classes\';' diff --git a/stack/maximaparser/autogen/parser-grammar.pegjs b/stack/maximaparser/autogen/parser-grammar.pegjs index 206d7cdea7f366da70eceff84447b1652068f4a8..557bedf7d223861f55db8e52af66a330677dfb4b 100644 --- a/stack/maximaparser/autogen/parser-grammar.pegjs +++ b/stack/maximaparser/autogen/parser-grammar.pegjs @@ -2,7 +2,6 @@ * Grammar for parsing STACK-Maxima commands/statements coming from keyval or casstring fields. * Not a complete Maxima syntax parser, but probably not that far from such. * Known missing parts, i.e., stuff that I did not bother to add (yet): - * - '$' silent line terminator * - end condition for "for ... in ... do" * * Also includes the STACK specific |x| => abs(x) syntax trick. But at the cost of the infix operator |. @@ -242,7 +241,7 @@ Equivline } Line - = __? s:Statement _? ';' {/** <?php return $s; ?> **/ return s;} + = __? s:Statement _? [;$] {/** <?php return $s; ?> **/ return s;} / Comment Integer "integer" diff --git a/stack/maximaparser/autogen/parser.mbstring.php b/stack/maximaparser/autogen/parser.mbstring.php index ec5bb49fd18c803f80680a6ddf039a6125ad7464..46541e64a5ca4bbfcd06e52b89147ea44ed978f0 100644 --- a/stack/maximaparser/autogen/parser.mbstring.php +++ b/stack/maximaparser/autogen/parser.mbstring.php @@ -439,6 +439,8 @@ class MP_Parser { private $peg_c208; private $peg_c209; private $peg_c210; + private $peg_c211; + private $peg_c212; private function peg_f0($lines, $final) { $items = array(); @@ -1081,8 +1083,8 @@ class MP_Parser { $s3 = null; } if ($s3 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) { - $s4 = $this->peg_c6; + if (peg_regex_test($this->peg_c6, $this->input_substr($this->peg_currPos, 1))) { + $s4 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s4 = $this->peg_FAILED; @@ -2050,13 +2052,13 @@ class MP_Parser { $s3 = null; } if ($s3 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) { - $s4 = $this->peg_c6; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) { + $s4 = $this->peg_c52; $this->peg_currPos++; } else { $s4 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c7); + $this->peg_fail($this->peg_c53); } } if ($s4 !== $this->peg_FAILED) { @@ -2081,13 +2083,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c52) { - $s1 = $this->peg_c52; + if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c54) { + $s1 = $this->peg_c54; $this->peg_currPos += 8; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c53); + $this->peg_fail($this->peg_c55); } } if ($s1 !== $this->peg_FAILED) { @@ -2100,13 +2102,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c54) { - $s5 = $this->peg_c54; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c56) { + $s5 = $this->peg_c56; $this->peg_currPos += 2; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c55); + $this->peg_fail($this->peg_c57); } } if ($s5 !== $this->peg_FAILED) { @@ -2122,13 +2124,13 @@ class MP_Parser { $s8 = null; } if ($s8 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) { - $s9 = $this->peg_c6; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) { + $s9 = $this->peg_c52; $this->peg_currPos++; } else { $s9 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c7); + $this->peg_fail($this->peg_c53); } } if ($s9 !== $this->peg_FAILED) { @@ -2173,13 +2175,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c56) { - $s1 = $this->peg_c56; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c58) { + $s1 = $this->peg_c58; $this->peg_currPos += 6; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c57); + $this->peg_fail($this->peg_c59); } } if ($s1 !== $this->peg_FAILED) { @@ -2214,13 +2216,13 @@ class MP_Parser { $s8 = null; } if ($s8 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) { - $s9 = $this->peg_c6; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) { + $s9 = $this->peg_c52; $this->peg_currPos++; } else { $s9 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c7); + $this->peg_fail($this->peg_c53); } } if ($s9 !== $this->peg_FAILED) { @@ -2307,7 +2309,7 @@ class MP_Parser { if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c58); + $this->peg_fail($this->peg_c60); } } @@ -2326,33 +2328,33 @@ class MP_Parser { return $cached["result"]; } - if (peg_regex_test($this->peg_c59, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c61, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c60); + $this->peg_fail($this->peg_c62); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c61) { - $s0 = $this->peg_c61; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c63) { + $s0 = $this->peg_c63; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c62); + $this->peg_fail($this->peg_c64); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c63) { - $s0 = $this->peg_c63; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { + $s0 = $this->peg_c65; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c64); + $this->peg_fail($this->peg_c66); } } if ($s0 === $this->peg_FAILED) { @@ -2416,13 +2418,13 @@ class MP_Parser { $s1 = null; } if ($s1 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s2 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s2 = $this->peg_c67; $this->peg_currPos++; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s2 !== $this->peg_FAILED) { @@ -2444,13 +2446,13 @@ class MP_Parser { } } if ($s6 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { - $s6 = $this->peg_c67; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c69) { + $s6 = $this->peg_c69; $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c68); + $this->peg_fail($this->peg_c70); } } } @@ -2638,13 +2640,13 @@ class MP_Parser { } $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) { - $s1 = $this->peg_c69; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) { + $s1 = $this->peg_c71; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c70); + $this->peg_fail($this->peg_c72); } } if ($s1 !== $this->peg_FAILED) { @@ -2660,13 +2662,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s5 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s5 = $this->peg_c73; $this->peg_currPos += 4; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s5 !== $this->peg_FAILED) { @@ -2684,13 +2686,13 @@ class MP_Parser { $s10 = null; } if ($s10 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) { - $s11 = $this->peg_c73; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) { + $s11 = $this->peg_c75; $this->peg_currPos += 6; } else { $s11 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c74); + $this->peg_fail($this->peg_c76); } } if ($s11 !== $this->peg_FAILED) { @@ -2706,13 +2708,13 @@ class MP_Parser { $s14 = null; } if ($s14 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s15 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s15 = $this->peg_c73; $this->peg_currPos += 4; } else { $s15 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s15 !== $this->peg_FAILED) { @@ -2766,13 +2768,13 @@ class MP_Parser { $s10 = null; } if ($s10 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) { - $s11 = $this->peg_c73; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) { + $s11 = $this->peg_c75; $this->peg_currPos += 6; } else { $s11 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c74); + $this->peg_fail($this->peg_c76); } } if ($s11 !== $this->peg_FAILED) { @@ -2788,13 +2790,13 @@ class MP_Parser { $s14 = null; } if ($s14 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s15 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s15 = $this->peg_c73; $this->peg_currPos += 4; } else { $s15 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s15 !== $this->peg_FAILED) { @@ -2849,13 +2851,13 @@ class MP_Parser { $s9 = null; } if ($s9 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c75) { - $s10 = $this->peg_c75; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c77) { + $s10 = $this->peg_c77; $this->peg_currPos += 4; } else { $s10 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c76); + $this->peg_fail($this->peg_c78); } } if ($s10 !== $this->peg_FAILED) { @@ -2919,13 +2921,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) { - $s1 = $this->peg_c69; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) { + $s1 = $this->peg_c71; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c70); + $this->peg_fail($this->peg_c72); } } if ($s1 !== $this->peg_FAILED) { @@ -2941,13 +2943,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s5 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s5 = $this->peg_c73; $this->peg_currPos += 4; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s5 !== $this->peg_FAILED) { @@ -2965,13 +2967,13 @@ class MP_Parser { $s10 = null; } if ($s10 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) { - $s11 = $this->peg_c73; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) { + $s11 = $this->peg_c75; $this->peg_currPos += 6; } else { $s11 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c74); + $this->peg_fail($this->peg_c76); } } if ($s11 !== $this->peg_FAILED) { @@ -2987,13 +2989,13 @@ class MP_Parser { $s14 = null; } if ($s14 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s15 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s15 = $this->peg_c73; $this->peg_currPos += 4; } else { $s15 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s15 !== $this->peg_FAILED) { @@ -3047,13 +3049,13 @@ class MP_Parser { $s10 = null; } if ($s10 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) { - $s11 = $this->peg_c73; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) { + $s11 = $this->peg_c75; $this->peg_currPos += 6; } else { $s11 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c74); + $this->peg_fail($this->peg_c76); } } if ($s11 !== $this->peg_FAILED) { @@ -3069,13 +3071,13 @@ class MP_Parser { $s14 = null; } if ($s14 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s15 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s15 = $this->peg_c73; $this->peg_currPos += 4; } else { $s15 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s15 !== $this->peg_FAILED) { @@ -3162,13 +3164,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) { - $s1 = $this->peg_c69; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) { + $s1 = $this->peg_c71; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c70); + $this->peg_fail($this->peg_c72); } } if ($s1 !== $this->peg_FAILED) { @@ -3184,13 +3186,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s5 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s5 = $this->peg_c73; $this->peg_currPos += 4; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s5 !== $this->peg_FAILED) { @@ -3206,13 +3208,13 @@ class MP_Parser { $s8 = null; } if ($s8 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c75) { - $s9 = $this->peg_c75; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c77) { + $s9 = $this->peg_c77; $this->peg_currPos += 4; } else { $s9 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c76); + $this->peg_fail($this->peg_c78); } } if ($s9 !== $this->peg_FAILED) { @@ -3272,13 +3274,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) { - $s1 = $this->peg_c69; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) { + $s1 = $this->peg_c71; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c70); + $this->peg_fail($this->peg_c72); } } if ($s1 !== $this->peg_FAILED) { @@ -3294,13 +3296,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) { - $s5 = $this->peg_c71; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) { + $s5 = $this->peg_c73; $this->peg_currPos += 4; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c72); + $this->peg_fail($this->peg_c74); } } if ($s5 !== $this->peg_FAILED) { @@ -3369,13 +3371,13 @@ class MP_Parser { $s2 = $this->peg_parseLoopBit(); } if ($s1 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c77) { - $s2 = $this->peg_c77; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c79) { + $s2 = $this->peg_c79; $this->peg_currPos += 2; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c78); + $this->peg_fail($this->peg_c80); } } if ($s2 !== $this->peg_FAILED) { @@ -3411,13 +3413,13 @@ class MP_Parser { $s2 = $this->peg_parseLoopBit(); } if ($s1 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c77) { - $s2 = $this->peg_c77; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c79) { + $s2 = $this->peg_c79; $this->peg_currPos += 2; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c78); + $this->peg_fail($this->peg_c80); } } if ($s2 !== $this->peg_FAILED) { @@ -3456,83 +3458,83 @@ class MP_Parser { } $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c79) { - $s1 = $this->peg_c79; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c81) { + $s1 = $this->peg_c81; $this->peg_currPos += 3; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c80); + $this->peg_fail($this->peg_c82); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c81) { - $s1 = $this->peg_c81; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) { + $s1 = $this->peg_c83; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c82); + $this->peg_fail($this->peg_c84); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) { - $s1 = $this->peg_c83; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) { + $s1 = $this->peg_c85; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c84); + $this->peg_fail($this->peg_c86); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) { - $s1 = $this->peg_c85; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c87) { + $s1 = $this->peg_c87; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c86); + $this->peg_fail($this->peg_c88); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c87) { - $s1 = $this->peg_c87; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c89) { + $s1 = $this->peg_c89; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c88); + $this->peg_fail($this->peg_c90); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c89) { - $s1 = $this->peg_c89; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c91) { + $s1 = $this->peg_c91; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c90); + $this->peg_fail($this->peg_c92); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c91) { - $s1 = $this->peg_c91; + if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c93) { + $s1 = $this->peg_c93; $this->peg_currPos += 5; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c92); + $this->peg_fail($this->peg_c94); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c93) { - $s1 = $this->peg_c93; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c95) { + $s1 = $this->peg_c95; $this->peg_currPos += 6; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c94); + $this->peg_fail($this->peg_c96); } } } @@ -3573,83 +3575,83 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c79) { - $s1 = $this->peg_c79; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c81) { + $s1 = $this->peg_c81; $this->peg_currPos += 3; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c80); + $this->peg_fail($this->peg_c82); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c81) { - $s1 = $this->peg_c81; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) { + $s1 = $this->peg_c83; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c82); + $this->peg_fail($this->peg_c84); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) { - $s1 = $this->peg_c83; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) { + $s1 = $this->peg_c85; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c84); + $this->peg_fail($this->peg_c86); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) { - $s1 = $this->peg_c85; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c87) { + $s1 = $this->peg_c87; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c86); + $this->peg_fail($this->peg_c88); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c87) { - $s1 = $this->peg_c87; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c89) { + $s1 = $this->peg_c89; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c88); + $this->peg_fail($this->peg_c90); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c89) { - $s1 = $this->peg_c89; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c91) { + $s1 = $this->peg_c91; $this->peg_currPos += 4; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c90); + $this->peg_fail($this->peg_c92); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c91) { - $s1 = $this->peg_c91; + if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c93) { + $s1 = $this->peg_c93; $this->peg_currPos += 5; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c92); + $this->peg_fail($this->peg_c94); } } if ($s1 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c93) { - $s1 = $this->peg_c93; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c95) { + $s1 = $this->peg_c95; $this->peg_currPos += 6; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c94); + $this->peg_fail($this->peg_c96); } } } @@ -3660,13 +3662,13 @@ class MP_Parser { } } if ($s1 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) { - $s2 = $this->peg_c95; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { + $s2 = $this->peg_c97; $this->peg_currPos++; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c96); + $this->peg_fail($this->peg_c98); } } if ($s2 !== $this->peg_FAILED) { @@ -3682,13 +3684,13 @@ class MP_Parser { $s5 = null; } if ($s5 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { - $s6 = $this->peg_c97; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) { + $s6 = $this->peg_c99; $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c98); + $this->peg_fail($this->peg_c100); } } if ($s6 !== $this->peg_FAILED) { @@ -3745,24 +3747,24 @@ class MP_Parser { return $cached["result"]; } - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c99) { - $s0 = $this->peg_c99; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c101) { + $s0 = $this->peg_c101; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c100); + $this->peg_fail($this->peg_c102); } } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c101) { - $s1 = $this->peg_c101; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c103) { + $s1 = $this->peg_c103; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c102); + $this->peg_fail($this->peg_c104); } } if ($s1 !== $this->peg_FAILED) { @@ -3786,103 +3788,103 @@ class MP_Parser { $s0 = $this->peg_FAILED; } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c103) { - $s0 = $this->peg_c103; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) { + $s0 = $this->peg_c105; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c104); + $this->peg_fail($this->peg_c106); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) { - $s0 = $this->peg_c105; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c107) { + $s0 = $this->peg_c107; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c106); + $this->peg_fail($this->peg_c108); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c107) { - $s0 = $this->peg_c107; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c109) { + $s0 = $this->peg_c109; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c108); + $this->peg_fail($this->peg_c110); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c109) { - $s0 = $this->peg_c109; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c111) { + $s0 = $this->peg_c111; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c110); + $this->peg_fail($this->peg_c112); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c111) { - $s0 = $this->peg_c111; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c113) { + $s0 = $this->peg_c113; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c112); + $this->peg_fail($this->peg_c114); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c113) { - $s0 = $this->peg_c113; + if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c115) { + $s0 = $this->peg_c115; $this->peg_currPos += 8; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c114); + $this->peg_fail($this->peg_c116); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c115) { - $s0 = $this->peg_c115; + if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c117) { + $s0 = $this->peg_c117; $this->peg_currPos += 5; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c116); + $this->peg_fail($this->peg_c118); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c117) { - $s0 = $this->peg_c117; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c119) { + $s0 = $this->peg_c119; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c118); + $this->peg_fail($this->peg_c120); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c119) { - $s0 = $this->peg_c119; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c121) { + $s0 = $this->peg_c121; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c120); + $this->peg_fail($this->peg_c122); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c121) { - $s0 = $this->peg_c121; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c123) { + $s0 = $this->peg_c123; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c122); + $this->peg_fail($this->peg_c124); } } } @@ -3912,23 +3914,23 @@ class MP_Parser { return $cached["result"]; } - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c123) { - $s0 = $this->peg_c123; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c125) { + $s0 = $this->peg_c125; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c124); + $this->peg_fail($this->peg_c126); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c125) { - $s0 = $this->peg_c125; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c127) { + $s0 = $this->peg_c127; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c126); + $this->peg_fail($this->peg_c128); } } } @@ -3948,33 +3950,33 @@ class MP_Parser { return $cached["result"]; } - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c127) { - $s0 = $this->peg_c127; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c129) { + $s0 = $this->peg_c129; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c128); + $this->peg_fail($this->peg_c130); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c129) { - $s0 = $this->peg_c129; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c131) { + $s0 = $this->peg_c131; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c130); + $this->peg_fail($this->peg_c132); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c131) { - $s0 = $this->peg_c131; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c133) { + $s0 = $this->peg_c133; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c132); + $this->peg_fail($this->peg_c134); } } if ($s0 === $this->peg_FAILED) { @@ -3998,24 +4000,24 @@ class MP_Parser { } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c99) { - $s0 = $this->peg_c99; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c101) { + $s0 = $this->peg_c101; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c100); + $this->peg_fail($this->peg_c102); } } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c101) { - $s1 = $this->peg_c101; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c103) { + $s1 = $this->peg_c103; $this->peg_currPos += 2; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c102); + $this->peg_fail($this->peg_c104); } } if ($s1 !== $this->peg_FAILED) { @@ -4039,223 +4041,223 @@ class MP_Parser { $s0 = $this->peg_FAILED; } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c103) { - $s0 = $this->peg_c103; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) { + $s0 = $this->peg_c105; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c104); + $this->peg_fail($this->peg_c106); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) { - $s0 = $this->peg_c105; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c107) { + $s0 = $this->peg_c107; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c106); + $this->peg_fail($this->peg_c108); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c133) { - $s0 = $this->peg_c133; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c135) { + $s0 = $this->peg_c135; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c134); + $this->peg_fail($this->peg_c136); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c135) { - $s0 = $this->peg_c135; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c137) { + $s0 = $this->peg_c137; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c136); + $this->peg_fail($this->peg_c138); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c137) { - $s0 = $this->peg_c137; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c139) { + $s0 = $this->peg_c139; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c138); + $this->peg_fail($this->peg_c140); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c139) { - $s0 = $this->peg_c139; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c141) { + $s0 = $this->peg_c141; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c140); + $this->peg_fail($this->peg_c142); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c141) { - $s0 = $this->peg_c141; + if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c143) { + $s0 = $this->peg_c143; $this->peg_currPos += 7; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c142); + $this->peg_fail($this->peg_c144); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c143) { - $s0 = $this->peg_c143; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c145) { + $s0 = $this->peg_c145; $this->peg_currPos += 6; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c144); + $this->peg_fail($this->peg_c146); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c145) { - $s0 = $this->peg_c145; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c147) { + $s0 = $this->peg_c147; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c146); + $this->peg_fail($this->peg_c148); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c147) { - $s0 = $this->peg_c147; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c149) { + $s0 = $this->peg_c149; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c148); + $this->peg_fail($this->peg_c150); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c149) { - $s0 = $this->peg_c149; + if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c151) { + $s0 = $this->peg_c151; $this->peg_currPos += 7; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c150); + $this->peg_fail($this->peg_c152); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c151) { - $s0 = $this->peg_c151; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c153) { + $s0 = $this->peg_c153; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c152); + $this->peg_fail($this->peg_c154); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c153) { - $s0 = $this->peg_c153; + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c155) { + $s0 = $this->peg_c155; $this->peg_currPos += 4; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c154); + $this->peg_fail($this->peg_c156); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c155) { - $s0 = $this->peg_c155; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c157) { + $s0 = $this->peg_c157; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c156); + $this->peg_fail($this->peg_c158); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c157) { - $s0 = $this->peg_c157; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c159) { + $s0 = $this->peg_c159; $this->peg_currPos += 3; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c158); + $this->peg_fail($this->peg_c160); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c159) { - $s0 = $this->peg_c159; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c161) { + $s0 = $this->peg_c161; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c160); + $this->peg_fail($this->peg_c162); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c161) { - $s0 = $this->peg_c161; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c163) { + $s0 = $this->peg_c163; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c162); + $this->peg_fail($this->peg_c164); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { - $s0 = $this->peg_c67; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c69) { + $s0 = $this->peg_c69; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c68); + $this->peg_fail($this->peg_c70); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c163) { - $s0 = $this->peg_c163; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c165) { + $s0 = $this->peg_c165; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c164); + $this->peg_fail($this->peg_c166); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c165) { - $s0 = $this->peg_c165; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c167) { + $s0 = $this->peg_c167; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c166); + $this->peg_fail($this->peg_c168); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c167) { - $s0 = $this->peg_c167; + if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c169) { + $s0 = $this->peg_c169; $this->peg_currPos += 2; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c168); + $this->peg_fail($this->peg_c170); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c169) { - $s0 = $this->peg_c169; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c171) { + $s0 = $this->peg_c171; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c170); + $this->peg_fail($this->peg_c172); } } if ($s0 === $this->peg_FAILED) { @@ -4269,33 +4271,33 @@ class MP_Parser { } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c171) { - $s0 = $this->peg_c171; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c173) { + $s0 = $this->peg_c173; $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c172); + $this->peg_fail($this->peg_c174); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c173) { - $s0 = $this->peg_c173; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c175) { + $s0 = $this->peg_c175; $this->peg_currPos += 6; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c174); + $this->peg_fail($this->peg_c176); } } if ($s0 === $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c175) { - $s0 = $this->peg_c175; + if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c177) { + $s0 = $this->peg_c177; $this->peg_currPos += 6; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c176); + $this->peg_fail($this->peg_c178); } } } @@ -4450,13 +4452,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c177) { - $s1 = $this->peg_c177; + if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c179) { + $s1 = $this->peg_c179; $this->peg_currPos += 7; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c178); + $this->peg_fail($this->peg_c180); } } if ($s1 !== $this->peg_FAILED) { @@ -4475,13 +4477,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c179) { - $s1 = $this->peg_c179; + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c181) { + $s1 = $this->peg_c181; $this->peg_currPos += 3; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c180); + $this->peg_fail($this->peg_c182); } } if ($s1 !== $this->peg_FAILED) { @@ -4689,13 +4691,13 @@ class MP_Parser { } $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) { - $s1 = $this->peg_c95; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { + $s1 = $this->peg_c97; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c96); + $this->peg_fail($this->peg_c98); } } if ($s1 !== $this->peg_FAILED) { @@ -4713,13 +4715,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -4756,13 +4758,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -4798,13 +4800,13 @@ class MP_Parser { $s5 = null; } if ($s5 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { - $s6 = $this->peg_c97; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) { + $s6 = $this->peg_c99; $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c98); + $this->peg_fail($this->peg_c100); } } if ($s6 !== $this->peg_FAILED) { @@ -4837,13 +4839,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) { - $s1 = $this->peg_c95; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { + $s1 = $this->peg_c97; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c96); + $this->peg_fail($this->peg_c98); } } if ($s1 !== $this->peg_FAILED) { @@ -4852,13 +4854,13 @@ class MP_Parser { $s2 = null; } if ($s2 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) { - $s3 = $this->peg_c97; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) { + $s3 = $this->peg_c99; $this->peg_currPos++; } else { $s3 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c98); + $this->peg_fail($this->peg_c100); } } if ($s3 !== $this->peg_FAILED) { @@ -5082,13 +5084,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c181) { - $s1 = $this->peg_c181; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) { + $s1 = $this->peg_c183; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c182); + $this->peg_fail($this->peg_c184); } } if ($s1 !== $this->peg_FAILED) { @@ -5104,13 +5106,13 @@ class MP_Parser { $s4 = null; } if ($s4 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c181) { - $s5 = $this->peg_c181; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) { + $s5 = $this->peg_c183; $this->peg_currPos++; } else { $s5 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c182); + $this->peg_fail($this->peg_c184); } } if ($s5 !== $this->peg_FAILED) { @@ -5240,13 +5242,13 @@ class MP_Parser { } $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) { - $s1 = $this->peg_c183; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) { + $s1 = $this->peg_c185; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c184); + $this->peg_fail($this->peg_c186); } } if ($s1 !== $this->peg_FAILED) { @@ -5264,13 +5266,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -5307,13 +5309,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -5349,13 +5351,13 @@ class MP_Parser { $s5 = null; } if ($s5 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) { - $s6 = $this->peg_c185; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) { + $s6 = $this->peg_c187; $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c186); + $this->peg_fail($this->peg_c188); } } if ($s6 !== $this->peg_FAILED) { @@ -5388,13 +5390,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) { - $s1 = $this->peg_c183; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) { + $s1 = $this->peg_c185; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c184); + $this->peg_fail($this->peg_c186); } } if ($s1 !== $this->peg_FAILED) { @@ -5403,13 +5405,13 @@ class MP_Parser { $s2 = null; } if ($s2 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) { - $s3 = $this->peg_c185; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) { + $s3 = $this->peg_c187; $this->peg_currPos++; } else { $s3 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c186); + $this->peg_fail($this->peg_c188); } } if ($s3 !== $this->peg_FAILED) { @@ -5446,13 +5448,13 @@ class MP_Parser { } $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) { - $s1 = $this->peg_c187; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) { + $s1 = $this->peg_c189; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c188); + $this->peg_fail($this->peg_c190); } } if ($s1 !== $this->peg_FAILED) { @@ -5470,13 +5472,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -5513,13 +5515,13 @@ class MP_Parser { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) { - $s7 = $this->peg_c65; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) { + $s7 = $this->peg_c67; $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c66); + $this->peg_fail($this->peg_c68); } } if ($s7 !== $this->peg_FAILED) { @@ -5555,13 +5557,13 @@ class MP_Parser { $s5 = null; } if ($s5 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) { - $s6 = $this->peg_c189; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c191) { + $s6 = $this->peg_c191; $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c190); + $this->peg_fail($this->peg_c192); } } if ($s6 !== $this->peg_FAILED) { @@ -5594,13 +5596,13 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = $this->peg_currPos; - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) { - $s1 = $this->peg_c187; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) { + $s1 = $this->peg_c189; $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c188); + $this->peg_fail($this->peg_c190); } } if ($s1 !== $this->peg_FAILED) { @@ -5609,13 +5611,13 @@ class MP_Parser { $s2 = null; } if ($s2 !== $this->peg_FAILED) { - if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) { - $s3 = $this->peg_c189; + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c191) { + $s3 = $this->peg_c191; $this->peg_currPos++; } else { $s3 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c190); + $this->peg_fail($this->peg_c192); } } if ($s3 !== $this->peg_FAILED) { @@ -5680,24 +5682,24 @@ class MP_Parser { $this->peg_silentFails++; $s0 = $this->peg_currPos; $s1 = array(); - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s2 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } while ($s2 !== $this->peg_FAILED) { $s1[] = $s2; - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s2 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s2 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } } @@ -5707,24 +5709,24 @@ class MP_Parser { $s4 = $this->peg_parseComment(); if ($s4 !== $this->peg_FAILED) { $s5 = array(); - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s6 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } while ($s6 !== $this->peg_FAILED) { $s5[] = $s6; - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s6 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } } @@ -5746,24 +5748,24 @@ class MP_Parser { $s4 = $this->peg_parseComment(); if ($s4 !== $this->peg_FAILED) { $s5 = array(); - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s6 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } while ($s6 !== $this->peg_FAILED) { $s5[] = $s6; - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s6 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s6 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } } @@ -5795,25 +5797,25 @@ class MP_Parser { } if ($s0 === $this->peg_FAILED) { $s0 = array(); - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s1 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } if ($s1 !== $this->peg_FAILED) { while ($s1 !== $this->peg_FAILED) { $s0[] = $s1; - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s1 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } } @@ -5825,7 +5827,7 @@ class MP_Parser { if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c191); + $this->peg_fail($this->peg_c193); } } @@ -5846,25 +5848,25 @@ class MP_Parser { $this->peg_silentFails++; $s0 = array(); - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s1 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } if ($s1 !== $this->peg_FAILED) { while ($s1 !== $this->peg_FAILED) { $s0[] = $s1; - if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) { $s1 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c193); + $this->peg_fail($this->peg_c195); } } } @@ -5875,7 +5877,7 @@ class MP_Parser { if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c191); + $this->peg_fail($this->peg_c193); } } @@ -5895,53 +5897,53 @@ class MP_Parser { } $this->peg_silentFails++; - if (peg_regex_test($this->peg_c195, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c197, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c196); + $this->peg_fail($this->peg_c198); } } if ($s0 === $this->peg_FAILED) { - if (peg_regex_test($this->peg_c197, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c199, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c198); + $this->peg_fail($this->peg_c200); } } if ($s0 === $this->peg_FAILED) { - if (peg_regex_test($this->peg_c199, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c201, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c200); + $this->peg_fail($this->peg_c202); } } if ($s0 === $this->peg_FAILED) { - if (peg_regex_test($this->peg_c201, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c203, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c202); + $this->peg_fail($this->peg_c204); } } if ($s0 === $this->peg_FAILED) { - if (peg_regex_test($this->peg_c203, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c205, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c204); + $this->peg_fail($this->peg_c206); } } } @@ -5952,7 +5954,7 @@ class MP_Parser { if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c194); + $this->peg_fail($this->peg_c196); } } @@ -5972,20 +5974,20 @@ class MP_Parser { } $this->peg_silentFails++; - if (peg_regex_test($this->peg_c206, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c208, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c207); + $this->peg_fail($this->peg_c209); } } $this->peg_silentFails--; if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c205); + $this->peg_fail($this->peg_c207); } } @@ -6005,20 +6007,20 @@ class MP_Parser { } $this->peg_silentFails++; - if (peg_regex_test($this->peg_c209, $this->input_substr($this->peg_currPos, 1))) { + if (peg_regex_test($this->peg_c211, $this->input_substr($this->peg_currPos, 1))) { $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c210); + $this->peg_fail($this->peg_c212); } } $this->peg_silentFails--; if ($s0 === $this->peg_FAILED) { $s1 = $this->peg_FAILED; if ($this->peg_silentFails === 0) { - $this->peg_fail($this->peg_c208); + $this->peg_fail($this->peg_c210); } } @@ -6050,8 +6052,8 @@ class MP_Parser { $this->peg_c3 = array( "type" => "literal", "value" => "let ", "description" => "\"let \"" ); $this->peg_c4 = " "; $this->peg_c5 = array( "type" => "literal", "value" => " ", "description" => "\" \"" ); - $this->peg_c6 = ";"; - $this->peg_c7 = array( "type" => "literal", "value" => ";", "description" => "\";\"" ); + $this->peg_c6 = "/^[;\\\$]/"; + $this->peg_c7 = array( "type" => "class", "value" => "[;\$]", "description" => "[;\$]" ); $this->peg_c8 = array("type" => "other", "description" => "integer" ); $this->peg_c9 = "/^[0-9]/"; $this->peg_c10 = array( "type" => "class", "value" => "[0-9]", "description" => "[0-9]" ); @@ -6096,165 +6098,167 @@ class MP_Parser { $this->peg_c49 = array("type" => "other", "description" => "annotation" ); $this->peg_c50 = "ignore"; $this->peg_c51 = array( "type" => "literal", "value" => "ignore", "description" => "\"ignore\"" ); - $this->peg_c52 = "function"; - $this->peg_c53 = array( "type" => "literal", "value" => "function", "description" => "\"function\"" ); - $this->peg_c54 = "=>"; - $this->peg_c55 = array( "type" => "literal", "value" => "=>", "description" => "\"=>\"" ); - $this->peg_c56 = "assume"; - $this->peg_c57 = array( "type" => "literal", "value" => "assume", "description" => "\"assume\"" ); - $this->peg_c58 = array("type" => "other", "description" => "identifier" ); - $this->peg_c59 = "/^[a-zA-Z]/"; - $this->peg_c60 = array( "type" => "class", "value" => "[a-zA-Z]", "description" => "[a-zA-Z]" ); - $this->peg_c61 = "_"; - $this->peg_c62 = array( "type" => "literal", "value" => "_", "description" => "\"_\"" ); - $this->peg_c63 = "%"; - $this->peg_c64 = array( "type" => "literal", "value" => "%", "description" => "\"%\"" ); - $this->peg_c65 = ","; - $this->peg_c66 = array( "type" => "literal", "value" => ",", "description" => "\",\"" ); - $this->peg_c67 = ":"; - $this->peg_c68 = array( "type" => "literal", "value" => ":", "description" => "\":\"" ); - $this->peg_c69 = "if"; - $this->peg_c70 = array( "type" => "literal", "value" => "if", "description" => "\"if\"" ); - $this->peg_c71 = "then"; - $this->peg_c72 = array( "type" => "literal", "value" => "then", "description" => "\"then\"" ); - $this->peg_c73 = "elseif"; - $this->peg_c74 = array( "type" => "literal", "value" => "elseif", "description" => "\"elseif\"" ); - $this->peg_c75 = "else"; - $this->peg_c76 = array( "type" => "literal", "value" => "else", "description" => "\"else\"" ); - $this->peg_c77 = "do"; - $this->peg_c78 = array( "type" => "literal", "value" => "do", "description" => "\"do\"" ); - $this->peg_c79 = "for"; - $this->peg_c80 = array( "type" => "literal", "value" => "for", "description" => "\"for\"" ); - $this->peg_c81 = "from"; - $this->peg_c82 = array( "type" => "literal", "value" => "from", "description" => "\"from\"" ); - $this->peg_c83 = "step"; - $this->peg_c84 = array( "type" => "literal", "value" => "step", "description" => "\"step\"" ); - $this->peg_c85 = "next"; - $this->peg_c86 = array( "type" => "literal", "value" => "next", "description" => "\"next\"" ); - $this->peg_c87 = "in"; - $this->peg_c88 = array( "type" => "literal", "value" => "in", "description" => "\"in\"" ); - $this->peg_c89 = "thru"; - $this->peg_c90 = array( "type" => "literal", "value" => "thru", "description" => "\"thru\"" ); - $this->peg_c91 = "while"; - $this->peg_c92 = array( "type" => "literal", "value" => "while", "description" => "\"while\"" ); - $this->peg_c93 = "unless"; - $this->peg_c94 = array( "type" => "literal", "value" => "unless", "description" => "\"unless\"" ); - $this->peg_c95 = "("; - $this->peg_c96 = array( "type" => "literal", "value" => "(", "description" => "\"(\"" ); - $this->peg_c97 = ")"; - $this->peg_c98 = array( "type" => "literal", "value" => ")", "description" => "\")\"" ); - $this->peg_c99 = "#pm#"; - $this->peg_c100 = array( "type" => "literal", "value" => "#pm#", "description" => "\"#pm#\"" ); - $this->peg_c101 = "+-"; - $this->peg_c102 = array( "type" => "literal", "value" => "+-", "description" => "\"+-\"" ); - $this->peg_c103 = "-"; - $this->peg_c104 = array( "type" => "literal", "value" => "-", "description" => "\"-\"" ); - $this->peg_c105 = "+"; - $this->peg_c106 = array( "type" => "literal", "value" => "+", "description" => "\"+\"" ); - $this->peg_c107 = "''"; - $this->peg_c108 = array( "type" => "literal", "value" => "''", "description" => "\"''\"" ); - $this->peg_c109 = "'"; - $this->peg_c110 = array( "type" => "literal", "value" => "'", "description" => "\"'\"" ); - $this->peg_c111 = "not "; - $this->peg_c112 = array( "type" => "literal", "value" => "not ", "description" => "\"not \"" ); - $this->peg_c113 = "nounnot "; - $this->peg_c114 = array( "type" => "literal", "value" => "nounnot ", "description" => "\"nounnot \"" ); - $this->peg_c115 = "%not "; - $this->peg_c116 = array( "type" => "literal", "value" => "%not ", "description" => "\"%not \"" ); - $this->peg_c117 = "?? "; - $this->peg_c118 = array( "type" => "literal", "value" => "?? ", "description" => "\"?? \"" ); - $this->peg_c119 = "? "; - $this->peg_c120 = array( "type" => "literal", "value" => "? ", "description" => "\"? \"" ); - $this->peg_c121 = "?"; - $this->peg_c122 = array( "type" => "literal", "value" => "?", "description" => "\"?\"" ); - $this->peg_c123 = "!!"; - $this->peg_c124 = array( "type" => "literal", "value" => "!!", "description" => "\"!!\"" ); - $this->peg_c125 = "!"; - $this->peg_c126 = array( "type" => "literal", "value" => "!", "description" => "\"!\"" ); - $this->peg_c127 = "**"; - $this->peg_c128 = array( "type" => "literal", "value" => "**", "description" => "\"**\"" ); - $this->peg_c129 = "^^"; - $this->peg_c130 = array( "type" => "literal", "value" => "^^", "description" => "\"^^\"" ); - $this->peg_c131 = "^"; - $this->peg_c132 = array( "type" => "literal", "value" => "^", "description" => "\"^\"" ); - $this->peg_c133 = "%and"; - $this->peg_c134 = array( "type" => "literal", "value" => "%and", "description" => "\"%and\"" ); - $this->peg_c135 = "%or"; - $this->peg_c136 = array( "type" => "literal", "value" => "%or", "description" => "\"%or\"" ); - $this->peg_c137 = "and"; - $this->peg_c138 = array( "type" => "literal", "value" => "and", "description" => "\"and\"" ); - $this->peg_c139 = "or"; - $this->peg_c140 = array( "type" => "literal", "value" => "or", "description" => "\"or\"" ); - $this->peg_c141 = "nounand"; - $this->peg_c142 = array( "type" => "literal", "value" => "nounand", "description" => "\"nounand\"" ); - $this->peg_c143 = "nounor"; - $this->peg_c144 = array( "type" => "literal", "value" => "nounor", "description" => "\"nounor\"" ); - $this->peg_c145 = "nand"; - $this->peg_c146 = array( "type" => "literal", "value" => "nand", "description" => "\"nand\"" ); - $this->peg_c147 = "nor"; - $this->peg_c148 = array( "type" => "literal", "value" => "nor", "description" => "\"nor\"" ); - $this->peg_c149 = "implies"; - $this->peg_c150 = array( "type" => "literal", "value" => "implies", "description" => "\"implies\"" ); - $this->peg_c151 = "xor"; - $this->peg_c152 = array( "type" => "literal", "value" => "xor", "description" => "\"xor\"" ); - $this->peg_c153 = "xnor"; - $this->peg_c154 = array( "type" => "literal", "value" => "xnor", "description" => "\"xnor\"" ); - $this->peg_c155 = "#"; - $this->peg_c156 = array( "type" => "literal", "value" => "#", "description" => "\"#\"" ); - $this->peg_c157 = "::="; - $this->peg_c158 = array( "type" => "literal", "value" => "::=", "description" => "\"::=\"" ); - $this->peg_c159 = ":="; - $this->peg_c160 = array( "type" => "literal", "value" => ":=", "description" => "\":=\"" ); - $this->peg_c161 = "::"; - $this->peg_c162 = array( "type" => "literal", "value" => "::", "description" => "\"::\"" ); - $this->peg_c163 = "<="; - $this->peg_c164 = array( "type" => "literal", "value" => "<=", "description" => "\"<=\"" ); - $this->peg_c165 = "<"; - $this->peg_c166 = array( "type" => "literal", "value" => "<", "description" => "\"<\"" ); - $this->peg_c167 = ">="; - $this->peg_c168 = array( "type" => "literal", "value" => ">=", "description" => "\">=\"" ); - $this->peg_c169 = ">"; - $this->peg_c170 = array( "type" => "literal", "value" => ">", "description" => "\">\"" ); - $this->peg_c171 = "~"; - $this->peg_c172 = array( "type" => "literal", "value" => "~", "description" => "\"~\"" ); - $this->peg_c173 = "@@IS@@"; - $this->peg_c174 = array( "type" => "literal", "value" => "@@IS@@", "description" => "\"@@IS@@\"" ); - $this->peg_c175 = "@@Is@@"; - $this->peg_c176 = array( "type" => "literal", "value" => "@@Is@@", "description" => "\"@@Is@@\"" ); - $this->peg_c177 = "nounnot"; - $this->peg_c178 = array( "type" => "literal", "value" => "nounnot", "description" => "\"nounnot\"" ); - $this->peg_c179 = "not"; - $this->peg_c180 = array( "type" => "literal", "value" => "not", "description" => "\"not\"" ); - $this->peg_c181 = "|"; - $this->peg_c182 = array( "type" => "literal", "value" => "|", "description" => "\"|\"" ); - $this->peg_c183 = "["; - $this->peg_c184 = array( "type" => "literal", "value" => "[", "description" => "\"[\"" ); - $this->peg_c185 = "]"; - $this->peg_c186 = array( "type" => "literal", "value" => "]", "description" => "\"]\"" ); - $this->peg_c187 = "{"; - $this->peg_c188 = array( "type" => "literal", "value" => "{", "description" => "\"{\"" ); - $this->peg_c189 = "}"; - $this->peg_c190 = array( "type" => "literal", "value" => "}", "description" => "\"}\"" ); - $this->peg_c191 = array("type" => "other", "description" => "whitespace" ); - $this->peg_c192 = "/^[ \\t\\n\\r\\x0B\\f \\x{FEFF} \\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}\\n-\\r]/"; - $this->peg_c193 = array( "type" => "class", "value" => "[ \t\n\r\x0B\f \x{FEFF} \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]", "description" => "[ \t\n\r\x0B\f \x{FEFF} \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]" ); - $this->peg_c194 = array("type" => "other", "description" => "unicode letter character" ); - $this->peg_c195 = "/^[a-zµß-öø-\\x{00FF}\\x{0101}\\x{0103}\\x{0105}\\x{0107}\\x{0109}\\x{010B}\\x{010D}\\x{010F}\\x{0111}\\x{0113}\\x{0115}\\x{0117}\\x{0119}\\x{011B}\\x{011D}\\x{011F}\\x{0121}\\x{0123}\\x{0125}\\x{0127}\\x{0129}\\x{012B}\\x{012D}\\x{012F}\\x{0131}\\x{0133}\\x{0135}\\x{0137}-\\x{0138}\\x{013A}\\x{013C}\\x{013E}\\x{0140}\\x{0142}\\x{0144}\\x{0146}\\x{0148}-\\x{0149}\\x{014B}\\x{014D}\\x{014F}\\x{0151}\\x{0153}\\x{0155}\\x{0157}\\x{0159}\\x{015B}\\x{015D}\\x{015F}\\x{0161}\\x{0163}\\x{0165}\\x{0167}\\x{0169}\\x{016B}\\x{016D}\\x{016F}\\x{0171}\\x{0173}\\x{0175}\\x{0177}\\x{017A}\\x{017C}\\x{017E}-\\x{0180}\\x{0183}\\x{0185}\\x{0188}\\x{018C}-\\x{018D}\\x{0192}\\x{0195}\\x{0199}-\\x{019B}\\x{019E}\\x{01A1}\\x{01A3}\\x{01A5}\\x{01A8}\\x{01AA}-\\x{01AB}\\x{01AD}\\x{01B0}\\x{01B4}\\x{01B6}\\x{01B9}-\\x{01BA}\\x{01BD}-\\x{01BF}\\x{01C6}\\x{01C9}\\x{01CC}\\x{01CE}\\x{01D0}\\x{01D2}\\x{01D4}\\x{01D6}\\x{01D8}\\x{01DA}\\x{01DC}-\\x{01DD}\\x{01DF}\\x{01E1}\\x{01E3}\\x{01E5}\\x{01E7}\\x{01E9}\\x{01EB}\\x{01ED}\\x{01EF}-\\x{01F0}\\x{01F3}\\x{01F5}\\x{01F9}\\x{01FB}\\x{01FD}\\x{01FF}\\x{0201}\\x{0203}\\x{0205}\\x{0207}\\x{0209}\\x{020B}\\x{020D}\\x{020F}\\x{0211}\\x{0213}\\x{0215}\\x{0217}\\x{0219}\\x{021B}\\x{021D}\\x{021F}\\x{0221}\\x{0223}\\x{0225}\\x{0227}\\x{0229}\\x{022B}\\x{022D}\\x{022F}\\x{0231}\\x{0233}-\\x{0239}\\x{023C}\\x{023F}-\\x{0240}\\x{0242}\\x{0247}\\x{0249}\\x{024B}\\x{024D}\\x{024F}-\\x{0293}\\x{0295}-\\x{02AF}\\x{0371}\\x{0373}\\x{0377}\\x{037B}-\\x{037D}\\x{0390}\\x{03AC}-\\x{03CE}\\x{03D0}-\\x{03D1}\\x{03D5}-\\x{03D7}\\x{03D9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03E3}\\x{03E5}\\x{03E7}\\x{03E9}\\x{03EB}\\x{03ED}\\x{03EF}-\\x{03F3}\\x{03F5}\\x{03F8}\\x{03FB}-\\x{03FC}\\x{0430}-\\x{045F}\\x{0461}\\x{0463}\\x{0465}\\x{0467}\\x{0469}\\x{046B}\\x{046D}\\x{046F}\\x{0471}\\x{0473}\\x{0475}\\x{0477}\\x{0479}\\x{047B}\\x{047D}\\x{047F}\\x{0481}\\x{048B}\\x{048D}\\x{048F}\\x{0491}\\x{0493}\\x{0495}\\x{0497}\\x{0499}\\x{049B}\\x{049D}\\x{049F}\\x{04A1}\\x{04A3}\\x{04A5}\\x{04A7}\\x{04A9}\\x{04AB}\\x{04AD}\\x{04AF}\\x{04B1}\\x{04B3}\\x{04B5}\\x{04B7}\\x{04B9}\\x{04BB}\\x{04BD}\\x{04BF}\\x{04C2}\\x{04C4}\\x{04C6}\\x{04C8}\\x{04CA}\\x{04CC}\\x{04CE}-\\x{04CF}\\x{04D1}\\x{04D3}\\x{04D5}\\x{04D7}\\x{04D9}\\x{04DB}\\x{04DD}\\x{04DF}\\x{04E1}\\x{04E3}\\x{04E5}\\x{04E7}\\x{04E9}\\x{04EB}\\x{04ED}\\x{04EF}\\x{04F1}\\x{04F3}\\x{04F5}\\x{04F7}\\x{04F9}\\x{04FB}\\x{04FD}\\x{04FF}\\x{0501}\\x{0503}\\x{0505}\\x{0507}\\x{0509}\\x{050B}\\x{050D}\\x{050F}\\x{0511}\\x{0513}\\x{0515}\\x{0517}\\x{0519}\\x{051B}\\x{051D}\\x{051F}\\x{0521}\\x{0523}\\x{0525}\\x{0527}\\x{0529}\\x{052B}\\x{052D}\\x{052F}\\x{0561}-\\x{0587}\\x{13F8}-\\x{13FD}\\x{1D00}-\\x{1D2B}\\x{1D6B}-\\x{1D77}\\x{1D79}-\\x{1D9A}\\x{1E01}\\x{1E03}\\x{1E05}\\x{1E07}\\x{1E09}\\x{1E0B}\\x{1E0D}\\x{1E0F}\\x{1E11}\\x{1E13}\\x{1E15}\\x{1E17}\\x{1E19}\\x{1E1B}\\x{1E1D}\\x{1E1F}\\x{1E21}\\x{1E23}\\x{1E25}\\x{1E27}\\x{1E29}\\x{1E2B}\\x{1E2D}\\x{1E2F}\\x{1E31}\\x{1E33}\\x{1E35}\\x{1E37}\\x{1E39}\\x{1E3B}\\x{1E3D}\\x{1E3F}\\x{1E41}\\x{1E43}\\x{1E45}\\x{1E47}\\x{1E49}\\x{1E4B}\\x{1E4D}\\x{1E4F}\\x{1E51}\\x{1E53}\\x{1E55}\\x{1E57}\\x{1E59}\\x{1E5B}\\x{1E5D}\\x{1E5F}\\x{1E61}\\x{1E63}\\x{1E65}\\x{1E67}\\x{1E69}\\x{1E6B}\\x{1E6D}\\x{1E6F}\\x{1E71}\\x{1E73}\\x{1E75}\\x{1E77}\\x{1E79}\\x{1E7B}\\x{1E7D}\\x{1E7F}\\x{1E81}\\x{1E83}\\x{1E85}\\x{1E87}\\x{1E89}\\x{1E8B}\\x{1E8D}\\x{1E8F}\\x{1E91}\\x{1E93}\\x{1E95}-\\x{1E9D}\\x{1E9F}\\x{1EA1}\\x{1EA3}\\x{1EA5}\\x{1EA7}\\x{1EA9}\\x{1EAB}\\x{1EAD}\\x{1EAF}\\x{1EB1}\\x{1EB3}\\x{1EB5}\\x{1EB7}\\x{1EB9}\\x{1EBB}\\x{1EBD}\\x{1EBF}\\x{1EC1}\\x{1EC3}\\x{1EC5}\\x{1EC7}\\x{1EC9}\\x{1ECB}\\x{1ECD}\\x{1ECF}\\x{1ED1}\\x{1ED3}\\x{1ED5}\\x{1ED7}\\x{1ED9}\\x{1EDB}\\x{1EDD}\\x{1EDF}\\x{1EE1}\\x{1EE3}\\x{1EE5}\\x{1EE7}\\x{1EE9}\\x{1EEB}\\x{1EED}\\x{1EEF}\\x{1EF1}\\x{1EF3}\\x{1EF5}\\x{1EF7}\\x{1EF9}\\x{1EFB}\\x{1EFD}\\x{1EFF}-\\x{1F07}\\x{1F10}-\\x{1F15}\\x{1F20}-\\x{1F27}\\x{1F30}-\\x{1F37}\\x{1F40}-\\x{1F45}\\x{1F50}-\\x{1F57}\\x{1F60}-\\x{1F67}\\x{1F70}-\\x{1F7D}\\x{1F80}-\\x{1F87}\\x{1F90}-\\x{1F97}\\x{1FA0}-\\x{1FA7}\\x{1FB0}-\\x{1FB4}\\x{1FB6}-\\x{1FB7}\\x{1FBE}\\x{1FC2}-\\x{1FC4}\\x{1FC6}-\\x{1FC7}\\x{1FD0}-\\x{1FD3}\\x{1FD6}-\\x{1FD7}\\x{1FE0}-\\x{1FE7}\\x{1FF2}-\\x{1FF4}\\x{1FF6}-\\x{1FF7}\\x{210A}\\x{210E}-\\x{210F}\\x{2113}\\x{212F}\\x{2134}\\x{2139}\\x{213C}-\\x{213D}\\x{2146}-\\x{2149}\\x{214E}\\x{2184}\\x{2C30}-\\x{2C5E}\\x{2C61}\\x{2C65}-\\x{2C66}\\x{2C68}\\x{2C6A}\\x{2C6C}\\x{2C71}\\x{2C73}-\\x{2C74}\\x{2C76}-\\x{2C7B}\\x{2C81}\\x{2C83}\\x{2C85}\\x{2C87}\\x{2C89}\\x{2C8B}\\x{2C8D}\\x{2C8F}\\x{2C91}\\x{2C93}\\x{2C95}\\x{2C97}\\x{2C99}\\x{2C9B}\\x{2C9D}\\x{2C9F}\\x{2CA1}\\x{2CA3}\\x{2CA5}\\x{2CA7}\\x{2CA9}\\x{2CAB}\\x{2CAD}\\x{2CAF}\\x{2CB1}\\x{2CB3}\\x{2CB5}\\x{2CB7}\\x{2CB9}\\x{2CBB}\\x{2CBD}\\x{2CBF}\\x{2CC1}\\x{2CC3}\\x{2CC5}\\x{2CC7}\\x{2CC9}\\x{2CCB}\\x{2CCD}\\x{2CCF}\\x{2CD1}\\x{2CD3}\\x{2CD5}\\x{2CD7}\\x{2CD9}\\x{2CDB}\\x{2CDD}\\x{2CDF}\\x{2CE1}\\x{2CE3}-\\x{2CE4}\\x{2CEC}\\x{2CEE}\\x{2CF3}\\x{2D00}-\\x{2D25}\\x{2D27}\\x{2D2D}\\x{A641}\\x{A643}\\x{A645}\\x{A647}\\x{A649}\\x{A64B}\\x{A64D}\\x{A64F}\\x{A651}\\x{A653}\\x{A655}\\x{A657}\\x{A659}\\x{A65B}\\x{A65D}\\x{A65F}\\x{A661}\\x{A663}\\x{A665}\\x{A667}\\x{A669}\\x{A66B}\\x{A66D}\\x{A681}\\x{A683}\\x{A685}\\x{A687}\\x{A689}\\x{A68B}\\x{A68D}\\x{A68F}\\x{A691}\\x{A693}\\x{A695}\\x{A697}\\x{A699}\\x{A69B}\\x{A723}\\x{A725}\\x{A727}\\x{A729}\\x{A72B}\\x{A72D}\\x{A72F}-\\x{A731}\\x{A733}\\x{A735}\\x{A737}\\x{A739}\\x{A73B}\\x{A73D}\\x{A73F}\\x{A741}\\x{A743}\\x{A745}\\x{A747}\\x{A749}\\x{A74B}\\x{A74D}\\x{A74F}\\x{A751}\\x{A753}\\x{A755}\\x{A757}\\x{A759}\\x{A75B}\\x{A75D}\\x{A75F}\\x{A761}\\x{A763}\\x{A765}\\x{A767}\\x{A769}\\x{A76B}\\x{A76D}\\x{A76F}\\x{A771}-\\x{A778}\\x{A77A}\\x{A77C}\\x{A77F}\\x{A781}\\x{A783}\\x{A785}\\x{A787}\\x{A78C}\\x{A78E}\\x{A791}\\x{A793}-\\x{A795}\\x{A797}\\x{A799}\\x{A79B}\\x{A79D}\\x{A79F}\\x{A7A1}\\x{A7A3}\\x{A7A5}\\x{A7A7}\\x{A7A9}\\x{A7B5}\\x{A7B7}\\x{A7FA}\\x{AB30}-\\x{AB5A}\\x{AB60}-\\x{AB65}\\x{AB70}-\\x{ABBF}\\x{FB00}-\\x{FB06}\\x{FB13}-\\x{FB17}\\x{FF41}-\\x{FF5A}]/"; - $this->peg_c196 = array( "type" => "class", "value" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]", "description" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]" ); - $this->peg_c197 = "/^[\\x{02B0}-\\x{02C1}\\x{02C6}-\\x{02D1}\\x{02E0}-\\x{02E4}\\x{02EC}\\x{02EE}\\x{0374}\\x{037A}\\x{0559}\\x{0640}\\x{06E5}-\\x{06E6}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{081A}\\x{0824}\\x{0828}\\x{0971}\\x{0E46}\\x{0EC6}\\x{10FC}\\x{17D7}\\x{1843}\\x{1AA7}\\x{1C78}-\\x{1C7D}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{2C7C}-\\x{2C7D}\\x{2D6F}\\x{2E2F}\\x{3005}\\x{3031}-\\x{3035}\\x{303B}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A717}-\\x{A71F}\\x{A770}\\x{A788}\\x{A7F8}-\\x{A7F9}\\x{A9CF}\\x{A9E6}\\x{AA70}\\x{AADD}\\x{AAF3}-\\x{AAF4}\\x{AB5C}-\\x{AB5F}\\x{FF70}\\x{FF9E}-\\x{FF9F}]/"; - $this->peg_c198 = array( "type" => "class", "value" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]", "description" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]" ); - $this->peg_c199 = "/^[ªº\\x{01BB}\\x{01C0}-\\x{01C3}\\x{0294}\\x{05D0}-\\x{05EA}\\x{05F0}-\\x{05F2}\\x{0620}-\\x{063F}\\x{0641}-\\x{064A}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D5}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0710}\\x{0712}-\\x{072F}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07CA}-\\x{07EA}\\x{0800}-\\x{0815}\\x{0840}-\\x{0858}\\x{08A0}-\\x{08B4}\\x{0904}-\\x{0939}\\x{093D}\\x{0950}\\x{0958}-\\x{0961}\\x{0972}-\\x{0980}\\x{0985}-\\x{098C}\\x{098F}-\\x{0990}\\x{0993}-\\x{09A8}\\x{09AA}-\\x{09B0}\\x{09B2}\\x{09B6}-\\x{09B9}\\x{09BD}\\x{09CE}\\x{09DC}-\\x{09DD}\\x{09DF}-\\x{09E1}\\x{09F0}-\\x{09F1}\\x{0A05}-\\x{0A0A}\\x{0A0F}-\\x{0A10}\\x{0A13}-\\x{0A28}\\x{0A2A}-\\x{0A30}\\x{0A32}-\\x{0A33}\\x{0A35}-\\x{0A36}\\x{0A38}-\\x{0A39}\\x{0A59}-\\x{0A5C}\\x{0A5E}\\x{0A72}-\\x{0A74}\\x{0A85}-\\x{0A8D}\\x{0A8F}-\\x{0A91}\\x{0A93}-\\x{0AA8}\\x{0AAA}-\\x{0AB0}\\x{0AB2}-\\x{0AB3}\\x{0AB5}-\\x{0AB9}\\x{0ABD}\\x{0AD0}\\x{0AE0}-\\x{0AE1}\\x{0AF9}\\x{0B05}-\\x{0B0C}\\x{0B0F}-\\x{0B10}\\x{0B13}-\\x{0B28}\\x{0B2A}-\\x{0B30}\\x{0B32}-\\x{0B33}\\x{0B35}-\\x{0B39}\\x{0B3D}\\x{0B5C}-\\x{0B5D}\\x{0B5F}-\\x{0B61}\\x{0B71}\\x{0B83}\\x{0B85}-\\x{0B8A}\\x{0B8E}-\\x{0B90}\\x{0B92}-\\x{0B95}\\x{0B99}-\\x{0B9A}\\x{0B9C}\\x{0B9E}-\\x{0B9F}\\x{0BA3}-\\x{0BA4}\\x{0BA8}-\\x{0BAA}\\x{0BAE}-\\x{0BB9}\\x{0BD0}\\x{0C05}-\\x{0C0C}\\x{0C0E}-\\x{0C10}\\x{0C12}-\\x{0C28}\\x{0C2A}-\\x{0C39}\\x{0C3D}\\x{0C58}-\\x{0C5A}\\x{0C60}-\\x{0C61}\\x{0C85}-\\x{0C8C}\\x{0C8E}-\\x{0C90}\\x{0C92}-\\x{0CA8}\\x{0CAA}-\\x{0CB3}\\x{0CB5}-\\x{0CB9}\\x{0CBD}\\x{0CDE}\\x{0CE0}-\\x{0CE1}\\x{0CF1}-\\x{0CF2}\\x{0D05}-\\x{0D0C}\\x{0D0E}-\\x{0D10}\\x{0D12}-\\x{0D3A}\\x{0D3D}\\x{0D4E}\\x{0D5F}-\\x{0D61}\\x{0D7A}-\\x{0D7F}\\x{0D85}-\\x{0D96}\\x{0D9A}-\\x{0DB1}\\x{0DB3}-\\x{0DBB}\\x{0DBD}\\x{0DC0}-\\x{0DC6}\\x{0E01}-\\x{0E30}\\x{0E32}-\\x{0E33}\\x{0E40}-\\x{0E45}\\x{0E81}-\\x{0E82}\\x{0E84}\\x{0E87}-\\x{0E88}\\x{0E8A}\\x{0E8D}\\x{0E94}-\\x{0E97}\\x{0E99}-\\x{0E9F}\\x{0EA1}-\\x{0EA3}\\x{0EA5}\\x{0EA7}\\x{0EAA}-\\x{0EAB}\\x{0EAD}-\\x{0EB0}\\x{0EB2}-\\x{0EB3}\\x{0EBD}\\x{0EC0}-\\x{0EC4}\\x{0EDC}-\\x{0EDF}\\x{0F00}\\x{0F40}-\\x{0F47}\\x{0F49}-\\x{0F6C}\\x{0F88}-\\x{0F8C}\\x{1000}-\\x{102A}\\x{103F}\\x{1050}-\\x{1055}\\x{105A}-\\x{105D}\\x{1061}\\x{1065}-\\x{1066}\\x{106E}-\\x{1070}\\x{1075}-\\x{1081}\\x{108E}\\x{10D0}-\\x{10FA}\\x{10FD}-\\x{1248}\\x{124A}-\\x{124D}\\x{1250}-\\x{1256}\\x{1258}\\x{125A}-\\x{125D}\\x{1260}-\\x{1288}\\x{128A}-\\x{128D}\\x{1290}-\\x{12B0}\\x{12B2}-\\x{12B5}\\x{12B8}-\\x{12BE}\\x{12C0}\\x{12C2}-\\x{12C5}\\x{12C8}-\\x{12D6}\\x{12D8}-\\x{1310}\\x{1312}-\\x{1315}\\x{1318}-\\x{135A}\\x{1380}-\\x{138F}\\x{1401}-\\x{166C}\\x{166F}-\\x{167F}\\x{1681}-\\x{169A}\\x{16A0}-\\x{16EA}\\x{16F1}-\\x{16F8}\\x{1700}-\\x{170C}\\x{170E}-\\x{1711}\\x{1720}-\\x{1731}\\x{1740}-\\x{1751}\\x{1760}-\\x{176C}\\x{176E}-\\x{1770}\\x{1780}-\\x{17B3}\\x{17DC}\\x{1820}-\\x{1842}\\x{1844}-\\x{1877}\\x{1880}-\\x{18A8}\\x{18AA}\\x{18B0}-\\x{18F5}\\x{1900}-\\x{191E}\\x{1950}-\\x{196D}\\x{1970}-\\x{1974}\\x{1980}-\\x{19AB}\\x{19B0}-\\x{19C9}\\x{1A00}-\\x{1A16}\\x{1A20}-\\x{1A54}\\x{1B05}-\\x{1B33}\\x{1B45}-\\x{1B4B}\\x{1B83}-\\x{1BA0}\\x{1BAE}-\\x{1BAF}\\x{1BBA}-\\x{1BE5}\\x{1C00}-\\x{1C23}\\x{1C4D}-\\x{1C4F}\\x{1C5A}-\\x{1C77}\\x{1CE9}-\\x{1CEC}\\x{1CEE}-\\x{1CF1}\\x{1CF5}-\\x{1CF6}\\x{2135}-\\x{2138}\\x{2D30}-\\x{2D67}\\x{2D80}-\\x{2D96}\\x{2DA0}-\\x{2DA6}\\x{2DA8}-\\x{2DAE}\\x{2DB0}-\\x{2DB6}\\x{2DB8}-\\x{2DBE}\\x{2DC0}-\\x{2DC6}\\x{2DC8}-\\x{2DCE}\\x{2DD0}-\\x{2DD6}\\x{2DD8}-\\x{2DDE}\\x{3006}\\x{303C}\\x{3041}-\\x{3096}\\x{309F}\\x{30A1}-\\x{30FA}\\x{30FF}\\x{3105}-\\x{312D}\\x{3131}-\\x{318E}\\x{31A0}-\\x{31BA}\\x{31F0}-\\x{31FF}\\x{3400}-\\x{4DB5}\\x{4E00}-\\x{9FD5}\\x{A000}-\\x{A014}\\x{A016}-\\x{A48C}\\x{A4D0}-\\x{A4F7}\\x{A500}-\\x{A60B}\\x{A610}-\\x{A61F}\\x{A62A}-\\x{A62B}\\x{A66E}\\x{A6A0}-\\x{A6E5}\\x{A78F}\\x{A7F7}\\x{A7FB}-\\x{A801}\\x{A803}-\\x{A805}\\x{A807}-\\x{A80A}\\x{A80C}-\\x{A822}\\x{A840}-\\x{A873}\\x{A882}-\\x{A8B3}\\x{A8F2}-\\x{A8F7}\\x{A8FB}\\x{A8FD}\\x{A90A}-\\x{A925}\\x{A930}-\\x{A946}\\x{A960}-\\x{A97C}\\x{A984}-\\x{A9B2}\\x{A9E0}-\\x{A9E4}\\x{A9E7}-\\x{A9EF}\\x{A9FA}-\\x{A9FE}\\x{AA00}-\\x{AA28}\\x{AA40}-\\x{AA42}\\x{AA44}-\\x{AA4B}\\x{AA60}-\\x{AA6F}\\x{AA71}-\\x{AA76}\\x{AA7A}\\x{AA7E}-\\x{AAAF}\\x{AAB1}\\x{AAB5}-\\x{AAB6}\\x{AAB9}-\\x{AABD}\\x{AAC0}\\x{AAC2}\\x{AADB}-\\x{AADC}\\x{AAE0}-\\x{AAEA}\\x{AAF2}\\x{AB01}-\\x{AB06}\\x{AB09}-\\x{AB0E}\\x{AB11}-\\x{AB16}\\x{AB20}-\\x{AB26}\\x{AB28}-\\x{AB2E}\\x{ABC0}-\\x{ABE2}\\x{AC00}-\\x{D7A3}\\x{D7B0}-\\x{D7C6}\\x{D7CB}-\\x{D7FB}\\x{F900}-\\x{FA6D}\\x{FA70}-\\x{FAD9}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB38}-\\x{FB3C}\\x{FB3E}\\x{FB40}-\\x{FB41}\\x{FB43}-\\x{FB44}\\x{FB46}-\\x{FBB1}\\x{FBD3}-\\x{FD3D}\\x{FD50}-\\x{FD8F}\\x{FD92}-\\x{FDC7}\\x{FDF0}-\\x{FDFB}\\x{FE70}-\\x{FE74}\\x{FE76}-\\x{FEFC}\\x{FF66}-\\x{FF6F}\\x{FF71}-\\x{FF9D}\\x{FFA0}-\\x{FFBE}\\x{FFC2}-\\x{FFC7}\\x{FFCA}-\\x{FFCF}\\x{FFD2}-\\x{FFD7}\\x{FFDA}-\\x{FFDC}]/"; - $this->peg_c200 = array( "type" => "class", "value" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]", "description" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]" ); - $this->peg_c201 = "/^[\\x{01C5}\\x{01C8}\\x{01CB}\\x{01F2}\\x{1F88}-\\x{1F8F}\\x{1F98}-\\x{1F9F}\\x{1FA8}-\\x{1FAF}\\x{1FBC}\\x{1FCC}\\x{1FFC}]/"; - $this->peg_c202 = array( "type" => "class", "value" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]", "description" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]" ); - $this->peg_c203 = "/^[A-ZÀ-ÖØ-Þ\\x{0100}\\x{0102}\\x{0104}\\x{0106}\\x{0108}\\x{010A}\\x{010C}\\x{010E}\\x{0110}\\x{0112}\\x{0114}\\x{0116}\\x{0118}\\x{011A}\\x{011C}\\x{011E}\\x{0120}\\x{0122}\\x{0124}\\x{0126}\\x{0128}\\x{012A}\\x{012C}\\x{012E}\\x{0130}\\x{0132}\\x{0134}\\x{0136}\\x{0139}\\x{013B}\\x{013D}\\x{013F}\\x{0141}\\x{0143}\\x{0145}\\x{0147}\\x{014A}\\x{014C}\\x{014E}\\x{0150}\\x{0152}\\x{0154}\\x{0156}\\x{0158}\\x{015A}\\x{015C}\\x{015E}\\x{0160}\\x{0162}\\x{0164}\\x{0166}\\x{0168}\\x{016A}\\x{016C}\\x{016E}\\x{0170}\\x{0172}\\x{0174}\\x{0176}\\x{0178}-\\x{0179}\\x{017B}\\x{017D}\\x{0181}-\\x{0182}\\x{0184}\\x{0186}-\\x{0187}\\x{0189}-\\x{018B}\\x{018E}-\\x{0191}\\x{0193}-\\x{0194}\\x{0196}-\\x{0198}\\x{019C}-\\x{019D}\\x{019F}-\\x{01A0}\\x{01A2}\\x{01A4}\\x{01A6}-\\x{01A7}\\x{01A9}\\x{01AC}\\x{01AE}-\\x{01AF}\\x{01B1}-\\x{01B3}\\x{01B5}\\x{01B7}-\\x{01B8}\\x{01BC}\\x{01C4}\\x{01C7}\\x{01CA}\\x{01CD}\\x{01CF}\\x{01D1}\\x{01D3}\\x{01D5}\\x{01D7}\\x{01D9}\\x{01DB}\\x{01DE}\\x{01E0}\\x{01E2}\\x{01E4}\\x{01E6}\\x{01E8}\\x{01EA}\\x{01EC}\\x{01EE}\\x{01F1}\\x{01F4}\\x{01F6}-\\x{01F8}\\x{01FA}\\x{01FC}\\x{01FE}\\x{0200}\\x{0202}\\x{0204}\\x{0206}\\x{0208}\\x{020A}\\x{020C}\\x{020E}\\x{0210}\\x{0212}\\x{0214}\\x{0216}\\x{0218}\\x{021A}\\x{021C}\\x{021E}\\x{0220}\\x{0222}\\x{0224}\\x{0226}\\x{0228}\\x{022A}\\x{022C}\\x{022E}\\x{0230}\\x{0232}\\x{023A}-\\x{023B}\\x{023D}-\\x{023E}\\x{0241}\\x{0243}-\\x{0246}\\x{0248}\\x{024A}\\x{024C}\\x{024E}\\x{0370}\\x{0372}\\x{0376}\\x{037F}\\x{0386}\\x{0388}-\\x{038A}\\x{038C}\\x{038E}-\\x{038F}\\x{0391}-\\x{03A1}\\x{03A3}-\\x{03AB}\\x{03CF}\\x{03D2}-\\x{03D4}\\x{03D8}\\x{03DA}\\x{03DC}\\x{03DE}\\x{03E0}\\x{03E2}\\x{03E4}\\x{03E6}\\x{03E8}\\x{03EA}\\x{03EC}\\x{03EE}\\x{03F4}\\x{03F7}\\x{03F9}-\\x{03FA}\\x{03FD}-\\x{042F}\\x{0460}\\x{0462}\\x{0464}\\x{0466}\\x{0468}\\x{046A}\\x{046C}\\x{046E}\\x{0470}\\x{0472}\\x{0474}\\x{0476}\\x{0478}\\x{047A}\\x{047C}\\x{047E}\\x{0480}\\x{048A}\\x{048C}\\x{048E}\\x{0490}\\x{0492}\\x{0494}\\x{0496}\\x{0498}\\x{049A}\\x{049C}\\x{049E}\\x{04A0}\\x{04A2}\\x{04A4}\\x{04A6}\\x{04A8}\\x{04AA}\\x{04AC}\\x{04AE}\\x{04B0}\\x{04B2}\\x{04B4}\\x{04B6}\\x{04B8}\\x{04BA}\\x{04BC}\\x{04BE}\\x{04C0}-\\x{04C1}\\x{04C3}\\x{04C5}\\x{04C7}\\x{04C9}\\x{04CB}\\x{04CD}\\x{04D0}\\x{04D2}\\x{04D4}\\x{04D6}\\x{04D8}\\x{04DA}\\x{04DC}\\x{04DE}\\x{04E0}\\x{04E2}\\x{04E4}\\x{04E6}\\x{04E8}\\x{04EA}\\x{04EC}\\x{04EE}\\x{04F0}\\x{04F2}\\x{04F4}\\x{04F6}\\x{04F8}\\x{04FA}\\x{04FC}\\x{04FE}\\x{0500}\\x{0502}\\x{0504}\\x{0506}\\x{0508}\\x{050A}\\x{050C}\\x{050E}\\x{0510}\\x{0512}\\x{0514}\\x{0516}\\x{0518}\\x{051A}\\x{051C}\\x{051E}\\x{0520}\\x{0522}\\x{0524}\\x{0526}\\x{0528}\\x{052A}\\x{052C}\\x{052E}\\x{0531}-\\x{0556}\\x{10A0}-\\x{10C5}\\x{10C7}\\x{10CD}\\x{13A0}-\\x{13F5}\\x{1E00}\\x{1E02}\\x{1E04}\\x{1E06}\\x{1E08}\\x{1E0A}\\x{1E0C}\\x{1E0E}\\x{1E10}\\x{1E12}\\x{1E14}\\x{1E16}\\x{1E18}\\x{1E1A}\\x{1E1C}\\x{1E1E}\\x{1E20}\\x{1E22}\\x{1E24}\\x{1E26}\\x{1E28}\\x{1E2A}\\x{1E2C}\\x{1E2E}\\x{1E30}\\x{1E32}\\x{1E34}\\x{1E36}\\x{1E38}\\x{1E3A}\\x{1E3C}\\x{1E3E}\\x{1E40}\\x{1E42}\\x{1E44}\\x{1E46}\\x{1E48}\\x{1E4A}\\x{1E4C}\\x{1E4E}\\x{1E50}\\x{1E52}\\x{1E54}\\x{1E56}\\x{1E58}\\x{1E5A}\\x{1E5C}\\x{1E5E}\\x{1E60}\\x{1E62}\\x{1E64}\\x{1E66}\\x{1E68}\\x{1E6A}\\x{1E6C}\\x{1E6E}\\x{1E70}\\x{1E72}\\x{1E74}\\x{1E76}\\x{1E78}\\x{1E7A}\\x{1E7C}\\x{1E7E}\\x{1E80}\\x{1E82}\\x{1E84}\\x{1E86}\\x{1E88}\\x{1E8A}\\x{1E8C}\\x{1E8E}\\x{1E90}\\x{1E92}\\x{1E94}\\x{1E9E}\\x{1EA0}\\x{1EA2}\\x{1EA4}\\x{1EA6}\\x{1EA8}\\x{1EAA}\\x{1EAC}\\x{1EAE}\\x{1EB0}\\x{1EB2}\\x{1EB4}\\x{1EB6}\\x{1EB8}\\x{1EBA}\\x{1EBC}\\x{1EBE}\\x{1EC0}\\x{1EC2}\\x{1EC4}\\x{1EC6}\\x{1EC8}\\x{1ECA}\\x{1ECC}\\x{1ECE}\\x{1ED0}\\x{1ED2}\\x{1ED4}\\x{1ED6}\\x{1ED8}\\x{1EDA}\\x{1EDC}\\x{1EDE}\\x{1EE0}\\x{1EE2}\\x{1EE4}\\x{1EE6}\\x{1EE8}\\x{1EEA}\\x{1EEC}\\x{1EEE}\\x{1EF0}\\x{1EF2}\\x{1EF4}\\x{1EF6}\\x{1EF8}\\x{1EFA}\\x{1EFC}\\x{1EFE}\\x{1F08}-\\x{1F0F}\\x{1F18}-\\x{1F1D}\\x{1F28}-\\x{1F2F}\\x{1F38}-\\x{1F3F}\\x{1F48}-\\x{1F4D}\\x{1F59}\\x{1F5B}\\x{1F5D}\\x{1F5F}\\x{1F68}-\\x{1F6F}\\x{1FB8}-\\x{1FBB}\\x{1FC8}-\\x{1FCB}\\x{1FD8}-\\x{1FDB}\\x{1FE8}-\\x{1FEC}\\x{1FF8}-\\x{1FFB}\\x{2102}\\x{2107}\\x{210B}-\\x{210D}\\x{2110}-\\x{2112}\\x{2115}\\x{2119}-\\x{211D}\\x{2124}\\x{2126}\\x{2128}\\x{212A}-\\x{212D}\\x{2130}-\\x{2133}\\x{213E}-\\x{213F}\\x{2145}\\x{2183}\\x{2C00}-\\x{2C2E}\\x{2C60}\\x{2C62}-\\x{2C64}\\x{2C67}\\x{2C69}\\x{2C6B}\\x{2C6D}-\\x{2C70}\\x{2C72}\\x{2C75}\\x{2C7E}-\\x{2C80}\\x{2C82}\\x{2C84}\\x{2C86}\\x{2C88}\\x{2C8A}\\x{2C8C}\\x{2C8E}\\x{2C90}\\x{2C92}\\x{2C94}\\x{2C96}\\x{2C98}\\x{2C9A}\\x{2C9C}\\x{2C9E}\\x{2CA0}\\x{2CA2}\\x{2CA4}\\x{2CA6}\\x{2CA8}\\x{2CAA}\\x{2CAC}\\x{2CAE}\\x{2CB0}\\x{2CB2}\\x{2CB4}\\x{2CB6}\\x{2CB8}\\x{2CBA}\\x{2CBC}\\x{2CBE}\\x{2CC0}\\x{2CC2}\\x{2CC4}\\x{2CC6}\\x{2CC8}\\x{2CCA}\\x{2CCC}\\x{2CCE}\\x{2CD0}\\x{2CD2}\\x{2CD4}\\x{2CD6}\\x{2CD8}\\x{2CDA}\\x{2CDC}\\x{2CDE}\\x{2CE0}\\x{2CE2}\\x{2CEB}\\x{2CED}\\x{2CF2}\\x{A640}\\x{A642}\\x{A644}\\x{A646}\\x{A648}\\x{A64A}\\x{A64C}\\x{A64E}\\x{A650}\\x{A652}\\x{A654}\\x{A656}\\x{A658}\\x{A65A}\\x{A65C}\\x{A65E}\\x{A660}\\x{A662}\\x{A664}\\x{A666}\\x{A668}\\x{A66A}\\x{A66C}\\x{A680}\\x{A682}\\x{A684}\\x{A686}\\x{A688}\\x{A68A}\\x{A68C}\\x{A68E}\\x{A690}\\x{A692}\\x{A694}\\x{A696}\\x{A698}\\x{A69A}\\x{A722}\\x{A724}\\x{A726}\\x{A728}\\x{A72A}\\x{A72C}\\x{A72E}\\x{A732}\\x{A734}\\x{A736}\\x{A738}\\x{A73A}\\x{A73C}\\x{A73E}\\x{A740}\\x{A742}\\x{A744}\\x{A746}\\x{A748}\\x{A74A}\\x{A74C}\\x{A74E}\\x{A750}\\x{A752}\\x{A754}\\x{A756}\\x{A758}\\x{A75A}\\x{A75C}\\x{A75E}\\x{A760}\\x{A762}\\x{A764}\\x{A766}\\x{A768}\\x{A76A}\\x{A76C}\\x{A76E}\\x{A779}\\x{A77B}\\x{A77D}-\\x{A77E}\\x{A780}\\x{A782}\\x{A784}\\x{A786}\\x{A78B}\\x{A78D}\\x{A790}\\x{A792}\\x{A796}\\x{A798}\\x{A79A}\\x{A79C}\\x{A79E}\\x{A7A0}\\x{A7A2}\\x{A7A4}\\x{A7A6}\\x{A7A8}\\x{A7AA}-\\x{A7AD}\\x{A7B0}-\\x{A7B4}\\x{A7B6}\\x{FF21}-\\x{FF3A}]/"; - $this->peg_c204 = array( "type" => "class", "value" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]", "description" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]" ); - $this->peg_c205 = array("type" => "other", "description" => "unicode superscript/subscript character" ); - $this->peg_c206 = "/^[²³¹\\x{2070}-\\x{209C}\\x{2C7C}\\x{1D62}-\\x{1D6A}]/"; - $this->peg_c207 = array( "type" => "class", "value" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]", "description" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]" ); - $this->peg_c208 = array("type" => "other", "description" => "special unicode chars" ); - $this->peg_c209 = "/^[µ\\x{0370}-\\x{0371}\\x{037F}\\x{0391}-\\x{0392}\\x{0393}-\\x{0394}\\x{0395}-\\x{0396}\\x{0397}-\\x{0398}\\x{0399}-\\x{039A}\\x{039B}-\\x{039C}\\x{039D}-\\x{039E}\\x{039F}-\\x{03A0}\\x{03A1}\\x{03A3}-\\x{03A4}\\x{03A5}-\\x{03A6}\\x{03A7}-\\x{03A8}\\x{03A9}\\x{03B1}-\\x{03B2}\\x{03B3}-\\x{03B4}\\x{03B5}-\\x{03B6}\\x{03B7}-\\x{03B8}\\x{03B9}-\\x{03BA}\\x{03BB}-\\x{03BC}\\x{03BD}-\\x{03BE}\\x{03BF}-\\x{03C0}\\x{03C1}-\\x{03C2}\\x{03C3}-\\x{03C4}\\x{03C5}-\\x{03C6}\\x{03C7}-\\x{03C8}\\x{03C9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03F7}-\\x{03F8}\\x{03FA}-\\x{03FB}\\x{1D26}-\\x{1D27}\\x{1D28}-\\x{1D29}\\x{1D2A}\\x{2102}\\x{2107}\\x{210A}-\\x{210B}\\x{210C}-\\x{210D}\\x{210E}-\\x{210F}\\x{2110}-\\x{2111}\\x{2112}-\\x{2113}\\x{2115}\\x{2119}-\\x{211A}\\x{211B}-\\x{211C}\\x{211D}\\x{2124}\\x{2126}-\\x{2127}\\x{2128}\\x{212B}-\\x{212C}\\x{212D}\\x{212F}-\\x{2130}\\x{2131}\\x{2133}-\\x{2134}\\x{2135}-\\x{2136}\\x{2137}-\\x{2138}\\x{213C}-\\x{213D}\\x{213E}-\\x{213F}\\x{2145}-\\x{2146}\\x{2147}-\\x{2148}\\x{2149}\\x{2205}\\x{221E}\\x{29B0}\\x{AB65}]/"; - $this->peg_c210 = array( "type" => "class", "value" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]", "description" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]" ); + $this->peg_c52 = ";"; + $this->peg_c53 = array( "type" => "literal", "value" => ";", "description" => "\";\"" ); + $this->peg_c54 = "function"; + $this->peg_c55 = array( "type" => "literal", "value" => "function", "description" => "\"function\"" ); + $this->peg_c56 = "=>"; + $this->peg_c57 = array( "type" => "literal", "value" => "=>", "description" => "\"=>\"" ); + $this->peg_c58 = "assume"; + $this->peg_c59 = array( "type" => "literal", "value" => "assume", "description" => "\"assume\"" ); + $this->peg_c60 = array("type" => "other", "description" => "identifier" ); + $this->peg_c61 = "/^[a-zA-Z]/"; + $this->peg_c62 = array( "type" => "class", "value" => "[a-zA-Z]", "description" => "[a-zA-Z]" ); + $this->peg_c63 = "_"; + $this->peg_c64 = array( "type" => "literal", "value" => "_", "description" => "\"_\"" ); + $this->peg_c65 = "%"; + $this->peg_c66 = array( "type" => "literal", "value" => "%", "description" => "\"%\"" ); + $this->peg_c67 = ","; + $this->peg_c68 = array( "type" => "literal", "value" => ",", "description" => "\",\"" ); + $this->peg_c69 = ":"; + $this->peg_c70 = array( "type" => "literal", "value" => ":", "description" => "\":\"" ); + $this->peg_c71 = "if"; + $this->peg_c72 = array( "type" => "literal", "value" => "if", "description" => "\"if\"" ); + $this->peg_c73 = "then"; + $this->peg_c74 = array( "type" => "literal", "value" => "then", "description" => "\"then\"" ); + $this->peg_c75 = "elseif"; + $this->peg_c76 = array( "type" => "literal", "value" => "elseif", "description" => "\"elseif\"" ); + $this->peg_c77 = "else"; + $this->peg_c78 = array( "type" => "literal", "value" => "else", "description" => "\"else\"" ); + $this->peg_c79 = "do"; + $this->peg_c80 = array( "type" => "literal", "value" => "do", "description" => "\"do\"" ); + $this->peg_c81 = "for"; + $this->peg_c82 = array( "type" => "literal", "value" => "for", "description" => "\"for\"" ); + $this->peg_c83 = "from"; + $this->peg_c84 = array( "type" => "literal", "value" => "from", "description" => "\"from\"" ); + $this->peg_c85 = "step"; + $this->peg_c86 = array( "type" => "literal", "value" => "step", "description" => "\"step\"" ); + $this->peg_c87 = "next"; + $this->peg_c88 = array( "type" => "literal", "value" => "next", "description" => "\"next\"" ); + $this->peg_c89 = "in"; + $this->peg_c90 = array( "type" => "literal", "value" => "in", "description" => "\"in\"" ); + $this->peg_c91 = "thru"; + $this->peg_c92 = array( "type" => "literal", "value" => "thru", "description" => "\"thru\"" ); + $this->peg_c93 = "while"; + $this->peg_c94 = array( "type" => "literal", "value" => "while", "description" => "\"while\"" ); + $this->peg_c95 = "unless"; + $this->peg_c96 = array( "type" => "literal", "value" => "unless", "description" => "\"unless\"" ); + $this->peg_c97 = "("; + $this->peg_c98 = array( "type" => "literal", "value" => "(", "description" => "\"(\"" ); + $this->peg_c99 = ")"; + $this->peg_c100 = array( "type" => "literal", "value" => ")", "description" => "\")\"" ); + $this->peg_c101 = "#pm#"; + $this->peg_c102 = array( "type" => "literal", "value" => "#pm#", "description" => "\"#pm#\"" ); + $this->peg_c103 = "+-"; + $this->peg_c104 = array( "type" => "literal", "value" => "+-", "description" => "\"+-\"" ); + $this->peg_c105 = "-"; + $this->peg_c106 = array( "type" => "literal", "value" => "-", "description" => "\"-\"" ); + $this->peg_c107 = "+"; + $this->peg_c108 = array( "type" => "literal", "value" => "+", "description" => "\"+\"" ); + $this->peg_c109 = "''"; + $this->peg_c110 = array( "type" => "literal", "value" => "''", "description" => "\"''\"" ); + $this->peg_c111 = "'"; + $this->peg_c112 = array( "type" => "literal", "value" => "'", "description" => "\"'\"" ); + $this->peg_c113 = "not "; + $this->peg_c114 = array( "type" => "literal", "value" => "not ", "description" => "\"not \"" ); + $this->peg_c115 = "nounnot "; + $this->peg_c116 = array( "type" => "literal", "value" => "nounnot ", "description" => "\"nounnot \"" ); + $this->peg_c117 = "%not "; + $this->peg_c118 = array( "type" => "literal", "value" => "%not ", "description" => "\"%not \"" ); + $this->peg_c119 = "?? "; + $this->peg_c120 = array( "type" => "literal", "value" => "?? ", "description" => "\"?? \"" ); + $this->peg_c121 = "? "; + $this->peg_c122 = array( "type" => "literal", "value" => "? ", "description" => "\"? \"" ); + $this->peg_c123 = "?"; + $this->peg_c124 = array( "type" => "literal", "value" => "?", "description" => "\"?\"" ); + $this->peg_c125 = "!!"; + $this->peg_c126 = array( "type" => "literal", "value" => "!!", "description" => "\"!!\"" ); + $this->peg_c127 = "!"; + $this->peg_c128 = array( "type" => "literal", "value" => "!", "description" => "\"!\"" ); + $this->peg_c129 = "**"; + $this->peg_c130 = array( "type" => "literal", "value" => "**", "description" => "\"**\"" ); + $this->peg_c131 = "^^"; + $this->peg_c132 = array( "type" => "literal", "value" => "^^", "description" => "\"^^\"" ); + $this->peg_c133 = "^"; + $this->peg_c134 = array( "type" => "literal", "value" => "^", "description" => "\"^\"" ); + $this->peg_c135 = "%and"; + $this->peg_c136 = array( "type" => "literal", "value" => "%and", "description" => "\"%and\"" ); + $this->peg_c137 = "%or"; + $this->peg_c138 = array( "type" => "literal", "value" => "%or", "description" => "\"%or\"" ); + $this->peg_c139 = "and"; + $this->peg_c140 = array( "type" => "literal", "value" => "and", "description" => "\"and\"" ); + $this->peg_c141 = "or"; + $this->peg_c142 = array( "type" => "literal", "value" => "or", "description" => "\"or\"" ); + $this->peg_c143 = "nounand"; + $this->peg_c144 = array( "type" => "literal", "value" => "nounand", "description" => "\"nounand\"" ); + $this->peg_c145 = "nounor"; + $this->peg_c146 = array( "type" => "literal", "value" => "nounor", "description" => "\"nounor\"" ); + $this->peg_c147 = "nand"; + $this->peg_c148 = array( "type" => "literal", "value" => "nand", "description" => "\"nand\"" ); + $this->peg_c149 = "nor"; + $this->peg_c150 = array( "type" => "literal", "value" => "nor", "description" => "\"nor\"" ); + $this->peg_c151 = "implies"; + $this->peg_c152 = array( "type" => "literal", "value" => "implies", "description" => "\"implies\"" ); + $this->peg_c153 = "xor"; + $this->peg_c154 = array( "type" => "literal", "value" => "xor", "description" => "\"xor\"" ); + $this->peg_c155 = "xnor"; + $this->peg_c156 = array( "type" => "literal", "value" => "xnor", "description" => "\"xnor\"" ); + $this->peg_c157 = "#"; + $this->peg_c158 = array( "type" => "literal", "value" => "#", "description" => "\"#\"" ); + $this->peg_c159 = "::="; + $this->peg_c160 = array( "type" => "literal", "value" => "::=", "description" => "\"::=\"" ); + $this->peg_c161 = ":="; + $this->peg_c162 = array( "type" => "literal", "value" => ":=", "description" => "\":=\"" ); + $this->peg_c163 = "::"; + $this->peg_c164 = array( "type" => "literal", "value" => "::", "description" => "\"::\"" ); + $this->peg_c165 = "<="; + $this->peg_c166 = array( "type" => "literal", "value" => "<=", "description" => "\"<=\"" ); + $this->peg_c167 = "<"; + $this->peg_c168 = array( "type" => "literal", "value" => "<", "description" => "\"<\"" ); + $this->peg_c169 = ">="; + $this->peg_c170 = array( "type" => "literal", "value" => ">=", "description" => "\">=\"" ); + $this->peg_c171 = ">"; + $this->peg_c172 = array( "type" => "literal", "value" => ">", "description" => "\">\"" ); + $this->peg_c173 = "~"; + $this->peg_c174 = array( "type" => "literal", "value" => "~", "description" => "\"~\"" ); + $this->peg_c175 = "@@IS@@"; + $this->peg_c176 = array( "type" => "literal", "value" => "@@IS@@", "description" => "\"@@IS@@\"" ); + $this->peg_c177 = "@@Is@@"; + $this->peg_c178 = array( "type" => "literal", "value" => "@@Is@@", "description" => "\"@@Is@@\"" ); + $this->peg_c179 = "nounnot"; + $this->peg_c180 = array( "type" => "literal", "value" => "nounnot", "description" => "\"nounnot\"" ); + $this->peg_c181 = "not"; + $this->peg_c182 = array( "type" => "literal", "value" => "not", "description" => "\"not\"" ); + $this->peg_c183 = "|"; + $this->peg_c184 = array( "type" => "literal", "value" => "|", "description" => "\"|\"" ); + $this->peg_c185 = "["; + $this->peg_c186 = array( "type" => "literal", "value" => "[", "description" => "\"[\"" ); + $this->peg_c187 = "]"; + $this->peg_c188 = array( "type" => "literal", "value" => "]", "description" => "\"]\"" ); + $this->peg_c189 = "{"; + $this->peg_c190 = array( "type" => "literal", "value" => "{", "description" => "\"{\"" ); + $this->peg_c191 = "}"; + $this->peg_c192 = array( "type" => "literal", "value" => "}", "description" => "\"}\"" ); + $this->peg_c193 = array("type" => "other", "description" => "whitespace" ); + $this->peg_c194 = "/^[ \\t\\n\\r\\x0B\\f \\x{FEFF} \\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}\\n-\\r]/"; + $this->peg_c195 = array( "type" => "class", "value" => "[ \t\n\r\x0B\f \x{FEFF} \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]", "description" => "[ \t\n\r\x0B\f \x{FEFF} \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]" ); + $this->peg_c196 = array("type" => "other", "description" => "unicode letter character" ); + $this->peg_c197 = "/^[a-zµß-öø-\\x{00FF}\\x{0101}\\x{0103}\\x{0105}\\x{0107}\\x{0109}\\x{010B}\\x{010D}\\x{010F}\\x{0111}\\x{0113}\\x{0115}\\x{0117}\\x{0119}\\x{011B}\\x{011D}\\x{011F}\\x{0121}\\x{0123}\\x{0125}\\x{0127}\\x{0129}\\x{012B}\\x{012D}\\x{012F}\\x{0131}\\x{0133}\\x{0135}\\x{0137}-\\x{0138}\\x{013A}\\x{013C}\\x{013E}\\x{0140}\\x{0142}\\x{0144}\\x{0146}\\x{0148}-\\x{0149}\\x{014B}\\x{014D}\\x{014F}\\x{0151}\\x{0153}\\x{0155}\\x{0157}\\x{0159}\\x{015B}\\x{015D}\\x{015F}\\x{0161}\\x{0163}\\x{0165}\\x{0167}\\x{0169}\\x{016B}\\x{016D}\\x{016F}\\x{0171}\\x{0173}\\x{0175}\\x{0177}\\x{017A}\\x{017C}\\x{017E}-\\x{0180}\\x{0183}\\x{0185}\\x{0188}\\x{018C}-\\x{018D}\\x{0192}\\x{0195}\\x{0199}-\\x{019B}\\x{019E}\\x{01A1}\\x{01A3}\\x{01A5}\\x{01A8}\\x{01AA}-\\x{01AB}\\x{01AD}\\x{01B0}\\x{01B4}\\x{01B6}\\x{01B9}-\\x{01BA}\\x{01BD}-\\x{01BF}\\x{01C6}\\x{01C9}\\x{01CC}\\x{01CE}\\x{01D0}\\x{01D2}\\x{01D4}\\x{01D6}\\x{01D8}\\x{01DA}\\x{01DC}-\\x{01DD}\\x{01DF}\\x{01E1}\\x{01E3}\\x{01E5}\\x{01E7}\\x{01E9}\\x{01EB}\\x{01ED}\\x{01EF}-\\x{01F0}\\x{01F3}\\x{01F5}\\x{01F9}\\x{01FB}\\x{01FD}\\x{01FF}\\x{0201}\\x{0203}\\x{0205}\\x{0207}\\x{0209}\\x{020B}\\x{020D}\\x{020F}\\x{0211}\\x{0213}\\x{0215}\\x{0217}\\x{0219}\\x{021B}\\x{021D}\\x{021F}\\x{0221}\\x{0223}\\x{0225}\\x{0227}\\x{0229}\\x{022B}\\x{022D}\\x{022F}\\x{0231}\\x{0233}-\\x{0239}\\x{023C}\\x{023F}-\\x{0240}\\x{0242}\\x{0247}\\x{0249}\\x{024B}\\x{024D}\\x{024F}-\\x{0293}\\x{0295}-\\x{02AF}\\x{0371}\\x{0373}\\x{0377}\\x{037B}-\\x{037D}\\x{0390}\\x{03AC}-\\x{03CE}\\x{03D0}-\\x{03D1}\\x{03D5}-\\x{03D7}\\x{03D9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03E3}\\x{03E5}\\x{03E7}\\x{03E9}\\x{03EB}\\x{03ED}\\x{03EF}-\\x{03F3}\\x{03F5}\\x{03F8}\\x{03FB}-\\x{03FC}\\x{0430}-\\x{045F}\\x{0461}\\x{0463}\\x{0465}\\x{0467}\\x{0469}\\x{046B}\\x{046D}\\x{046F}\\x{0471}\\x{0473}\\x{0475}\\x{0477}\\x{0479}\\x{047B}\\x{047D}\\x{047F}\\x{0481}\\x{048B}\\x{048D}\\x{048F}\\x{0491}\\x{0493}\\x{0495}\\x{0497}\\x{0499}\\x{049B}\\x{049D}\\x{049F}\\x{04A1}\\x{04A3}\\x{04A5}\\x{04A7}\\x{04A9}\\x{04AB}\\x{04AD}\\x{04AF}\\x{04B1}\\x{04B3}\\x{04B5}\\x{04B7}\\x{04B9}\\x{04BB}\\x{04BD}\\x{04BF}\\x{04C2}\\x{04C4}\\x{04C6}\\x{04C8}\\x{04CA}\\x{04CC}\\x{04CE}-\\x{04CF}\\x{04D1}\\x{04D3}\\x{04D5}\\x{04D7}\\x{04D9}\\x{04DB}\\x{04DD}\\x{04DF}\\x{04E1}\\x{04E3}\\x{04E5}\\x{04E7}\\x{04E9}\\x{04EB}\\x{04ED}\\x{04EF}\\x{04F1}\\x{04F3}\\x{04F5}\\x{04F7}\\x{04F9}\\x{04FB}\\x{04FD}\\x{04FF}\\x{0501}\\x{0503}\\x{0505}\\x{0507}\\x{0509}\\x{050B}\\x{050D}\\x{050F}\\x{0511}\\x{0513}\\x{0515}\\x{0517}\\x{0519}\\x{051B}\\x{051D}\\x{051F}\\x{0521}\\x{0523}\\x{0525}\\x{0527}\\x{0529}\\x{052B}\\x{052D}\\x{052F}\\x{0561}-\\x{0587}\\x{13F8}-\\x{13FD}\\x{1D00}-\\x{1D2B}\\x{1D6B}-\\x{1D77}\\x{1D79}-\\x{1D9A}\\x{1E01}\\x{1E03}\\x{1E05}\\x{1E07}\\x{1E09}\\x{1E0B}\\x{1E0D}\\x{1E0F}\\x{1E11}\\x{1E13}\\x{1E15}\\x{1E17}\\x{1E19}\\x{1E1B}\\x{1E1D}\\x{1E1F}\\x{1E21}\\x{1E23}\\x{1E25}\\x{1E27}\\x{1E29}\\x{1E2B}\\x{1E2D}\\x{1E2F}\\x{1E31}\\x{1E33}\\x{1E35}\\x{1E37}\\x{1E39}\\x{1E3B}\\x{1E3D}\\x{1E3F}\\x{1E41}\\x{1E43}\\x{1E45}\\x{1E47}\\x{1E49}\\x{1E4B}\\x{1E4D}\\x{1E4F}\\x{1E51}\\x{1E53}\\x{1E55}\\x{1E57}\\x{1E59}\\x{1E5B}\\x{1E5D}\\x{1E5F}\\x{1E61}\\x{1E63}\\x{1E65}\\x{1E67}\\x{1E69}\\x{1E6B}\\x{1E6D}\\x{1E6F}\\x{1E71}\\x{1E73}\\x{1E75}\\x{1E77}\\x{1E79}\\x{1E7B}\\x{1E7D}\\x{1E7F}\\x{1E81}\\x{1E83}\\x{1E85}\\x{1E87}\\x{1E89}\\x{1E8B}\\x{1E8D}\\x{1E8F}\\x{1E91}\\x{1E93}\\x{1E95}-\\x{1E9D}\\x{1E9F}\\x{1EA1}\\x{1EA3}\\x{1EA5}\\x{1EA7}\\x{1EA9}\\x{1EAB}\\x{1EAD}\\x{1EAF}\\x{1EB1}\\x{1EB3}\\x{1EB5}\\x{1EB7}\\x{1EB9}\\x{1EBB}\\x{1EBD}\\x{1EBF}\\x{1EC1}\\x{1EC3}\\x{1EC5}\\x{1EC7}\\x{1EC9}\\x{1ECB}\\x{1ECD}\\x{1ECF}\\x{1ED1}\\x{1ED3}\\x{1ED5}\\x{1ED7}\\x{1ED9}\\x{1EDB}\\x{1EDD}\\x{1EDF}\\x{1EE1}\\x{1EE3}\\x{1EE5}\\x{1EE7}\\x{1EE9}\\x{1EEB}\\x{1EED}\\x{1EEF}\\x{1EF1}\\x{1EF3}\\x{1EF5}\\x{1EF7}\\x{1EF9}\\x{1EFB}\\x{1EFD}\\x{1EFF}-\\x{1F07}\\x{1F10}-\\x{1F15}\\x{1F20}-\\x{1F27}\\x{1F30}-\\x{1F37}\\x{1F40}-\\x{1F45}\\x{1F50}-\\x{1F57}\\x{1F60}-\\x{1F67}\\x{1F70}-\\x{1F7D}\\x{1F80}-\\x{1F87}\\x{1F90}-\\x{1F97}\\x{1FA0}-\\x{1FA7}\\x{1FB0}-\\x{1FB4}\\x{1FB6}-\\x{1FB7}\\x{1FBE}\\x{1FC2}-\\x{1FC4}\\x{1FC6}-\\x{1FC7}\\x{1FD0}-\\x{1FD3}\\x{1FD6}-\\x{1FD7}\\x{1FE0}-\\x{1FE7}\\x{1FF2}-\\x{1FF4}\\x{1FF6}-\\x{1FF7}\\x{210A}\\x{210E}-\\x{210F}\\x{2113}\\x{212F}\\x{2134}\\x{2139}\\x{213C}-\\x{213D}\\x{2146}-\\x{2149}\\x{214E}\\x{2184}\\x{2C30}-\\x{2C5E}\\x{2C61}\\x{2C65}-\\x{2C66}\\x{2C68}\\x{2C6A}\\x{2C6C}\\x{2C71}\\x{2C73}-\\x{2C74}\\x{2C76}-\\x{2C7B}\\x{2C81}\\x{2C83}\\x{2C85}\\x{2C87}\\x{2C89}\\x{2C8B}\\x{2C8D}\\x{2C8F}\\x{2C91}\\x{2C93}\\x{2C95}\\x{2C97}\\x{2C99}\\x{2C9B}\\x{2C9D}\\x{2C9F}\\x{2CA1}\\x{2CA3}\\x{2CA5}\\x{2CA7}\\x{2CA9}\\x{2CAB}\\x{2CAD}\\x{2CAF}\\x{2CB1}\\x{2CB3}\\x{2CB5}\\x{2CB7}\\x{2CB9}\\x{2CBB}\\x{2CBD}\\x{2CBF}\\x{2CC1}\\x{2CC3}\\x{2CC5}\\x{2CC7}\\x{2CC9}\\x{2CCB}\\x{2CCD}\\x{2CCF}\\x{2CD1}\\x{2CD3}\\x{2CD5}\\x{2CD7}\\x{2CD9}\\x{2CDB}\\x{2CDD}\\x{2CDF}\\x{2CE1}\\x{2CE3}-\\x{2CE4}\\x{2CEC}\\x{2CEE}\\x{2CF3}\\x{2D00}-\\x{2D25}\\x{2D27}\\x{2D2D}\\x{A641}\\x{A643}\\x{A645}\\x{A647}\\x{A649}\\x{A64B}\\x{A64D}\\x{A64F}\\x{A651}\\x{A653}\\x{A655}\\x{A657}\\x{A659}\\x{A65B}\\x{A65D}\\x{A65F}\\x{A661}\\x{A663}\\x{A665}\\x{A667}\\x{A669}\\x{A66B}\\x{A66D}\\x{A681}\\x{A683}\\x{A685}\\x{A687}\\x{A689}\\x{A68B}\\x{A68D}\\x{A68F}\\x{A691}\\x{A693}\\x{A695}\\x{A697}\\x{A699}\\x{A69B}\\x{A723}\\x{A725}\\x{A727}\\x{A729}\\x{A72B}\\x{A72D}\\x{A72F}-\\x{A731}\\x{A733}\\x{A735}\\x{A737}\\x{A739}\\x{A73B}\\x{A73D}\\x{A73F}\\x{A741}\\x{A743}\\x{A745}\\x{A747}\\x{A749}\\x{A74B}\\x{A74D}\\x{A74F}\\x{A751}\\x{A753}\\x{A755}\\x{A757}\\x{A759}\\x{A75B}\\x{A75D}\\x{A75F}\\x{A761}\\x{A763}\\x{A765}\\x{A767}\\x{A769}\\x{A76B}\\x{A76D}\\x{A76F}\\x{A771}-\\x{A778}\\x{A77A}\\x{A77C}\\x{A77F}\\x{A781}\\x{A783}\\x{A785}\\x{A787}\\x{A78C}\\x{A78E}\\x{A791}\\x{A793}-\\x{A795}\\x{A797}\\x{A799}\\x{A79B}\\x{A79D}\\x{A79F}\\x{A7A1}\\x{A7A3}\\x{A7A5}\\x{A7A7}\\x{A7A9}\\x{A7B5}\\x{A7B7}\\x{A7FA}\\x{AB30}-\\x{AB5A}\\x{AB60}-\\x{AB65}\\x{AB70}-\\x{ABBF}\\x{FB00}-\\x{FB06}\\x{FB13}-\\x{FB17}\\x{FF41}-\\x{FF5A}]/"; + $this->peg_c198 = array( "type" => "class", "value" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]", "description" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]" ); + $this->peg_c199 = "/^[\\x{02B0}-\\x{02C1}\\x{02C6}-\\x{02D1}\\x{02E0}-\\x{02E4}\\x{02EC}\\x{02EE}\\x{0374}\\x{037A}\\x{0559}\\x{0640}\\x{06E5}-\\x{06E6}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{081A}\\x{0824}\\x{0828}\\x{0971}\\x{0E46}\\x{0EC6}\\x{10FC}\\x{17D7}\\x{1843}\\x{1AA7}\\x{1C78}-\\x{1C7D}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{2C7C}-\\x{2C7D}\\x{2D6F}\\x{2E2F}\\x{3005}\\x{3031}-\\x{3035}\\x{303B}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A717}-\\x{A71F}\\x{A770}\\x{A788}\\x{A7F8}-\\x{A7F9}\\x{A9CF}\\x{A9E6}\\x{AA70}\\x{AADD}\\x{AAF3}-\\x{AAF4}\\x{AB5C}-\\x{AB5F}\\x{FF70}\\x{FF9E}-\\x{FF9F}]/"; + $this->peg_c200 = array( "type" => "class", "value" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]", "description" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]" ); + $this->peg_c201 = "/^[ªº\\x{01BB}\\x{01C0}-\\x{01C3}\\x{0294}\\x{05D0}-\\x{05EA}\\x{05F0}-\\x{05F2}\\x{0620}-\\x{063F}\\x{0641}-\\x{064A}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D5}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0710}\\x{0712}-\\x{072F}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07CA}-\\x{07EA}\\x{0800}-\\x{0815}\\x{0840}-\\x{0858}\\x{08A0}-\\x{08B4}\\x{0904}-\\x{0939}\\x{093D}\\x{0950}\\x{0958}-\\x{0961}\\x{0972}-\\x{0980}\\x{0985}-\\x{098C}\\x{098F}-\\x{0990}\\x{0993}-\\x{09A8}\\x{09AA}-\\x{09B0}\\x{09B2}\\x{09B6}-\\x{09B9}\\x{09BD}\\x{09CE}\\x{09DC}-\\x{09DD}\\x{09DF}-\\x{09E1}\\x{09F0}-\\x{09F1}\\x{0A05}-\\x{0A0A}\\x{0A0F}-\\x{0A10}\\x{0A13}-\\x{0A28}\\x{0A2A}-\\x{0A30}\\x{0A32}-\\x{0A33}\\x{0A35}-\\x{0A36}\\x{0A38}-\\x{0A39}\\x{0A59}-\\x{0A5C}\\x{0A5E}\\x{0A72}-\\x{0A74}\\x{0A85}-\\x{0A8D}\\x{0A8F}-\\x{0A91}\\x{0A93}-\\x{0AA8}\\x{0AAA}-\\x{0AB0}\\x{0AB2}-\\x{0AB3}\\x{0AB5}-\\x{0AB9}\\x{0ABD}\\x{0AD0}\\x{0AE0}-\\x{0AE1}\\x{0AF9}\\x{0B05}-\\x{0B0C}\\x{0B0F}-\\x{0B10}\\x{0B13}-\\x{0B28}\\x{0B2A}-\\x{0B30}\\x{0B32}-\\x{0B33}\\x{0B35}-\\x{0B39}\\x{0B3D}\\x{0B5C}-\\x{0B5D}\\x{0B5F}-\\x{0B61}\\x{0B71}\\x{0B83}\\x{0B85}-\\x{0B8A}\\x{0B8E}-\\x{0B90}\\x{0B92}-\\x{0B95}\\x{0B99}-\\x{0B9A}\\x{0B9C}\\x{0B9E}-\\x{0B9F}\\x{0BA3}-\\x{0BA4}\\x{0BA8}-\\x{0BAA}\\x{0BAE}-\\x{0BB9}\\x{0BD0}\\x{0C05}-\\x{0C0C}\\x{0C0E}-\\x{0C10}\\x{0C12}-\\x{0C28}\\x{0C2A}-\\x{0C39}\\x{0C3D}\\x{0C58}-\\x{0C5A}\\x{0C60}-\\x{0C61}\\x{0C85}-\\x{0C8C}\\x{0C8E}-\\x{0C90}\\x{0C92}-\\x{0CA8}\\x{0CAA}-\\x{0CB3}\\x{0CB5}-\\x{0CB9}\\x{0CBD}\\x{0CDE}\\x{0CE0}-\\x{0CE1}\\x{0CF1}-\\x{0CF2}\\x{0D05}-\\x{0D0C}\\x{0D0E}-\\x{0D10}\\x{0D12}-\\x{0D3A}\\x{0D3D}\\x{0D4E}\\x{0D5F}-\\x{0D61}\\x{0D7A}-\\x{0D7F}\\x{0D85}-\\x{0D96}\\x{0D9A}-\\x{0DB1}\\x{0DB3}-\\x{0DBB}\\x{0DBD}\\x{0DC0}-\\x{0DC6}\\x{0E01}-\\x{0E30}\\x{0E32}-\\x{0E33}\\x{0E40}-\\x{0E45}\\x{0E81}-\\x{0E82}\\x{0E84}\\x{0E87}-\\x{0E88}\\x{0E8A}\\x{0E8D}\\x{0E94}-\\x{0E97}\\x{0E99}-\\x{0E9F}\\x{0EA1}-\\x{0EA3}\\x{0EA5}\\x{0EA7}\\x{0EAA}-\\x{0EAB}\\x{0EAD}-\\x{0EB0}\\x{0EB2}-\\x{0EB3}\\x{0EBD}\\x{0EC0}-\\x{0EC4}\\x{0EDC}-\\x{0EDF}\\x{0F00}\\x{0F40}-\\x{0F47}\\x{0F49}-\\x{0F6C}\\x{0F88}-\\x{0F8C}\\x{1000}-\\x{102A}\\x{103F}\\x{1050}-\\x{1055}\\x{105A}-\\x{105D}\\x{1061}\\x{1065}-\\x{1066}\\x{106E}-\\x{1070}\\x{1075}-\\x{1081}\\x{108E}\\x{10D0}-\\x{10FA}\\x{10FD}-\\x{1248}\\x{124A}-\\x{124D}\\x{1250}-\\x{1256}\\x{1258}\\x{125A}-\\x{125D}\\x{1260}-\\x{1288}\\x{128A}-\\x{128D}\\x{1290}-\\x{12B0}\\x{12B2}-\\x{12B5}\\x{12B8}-\\x{12BE}\\x{12C0}\\x{12C2}-\\x{12C5}\\x{12C8}-\\x{12D6}\\x{12D8}-\\x{1310}\\x{1312}-\\x{1315}\\x{1318}-\\x{135A}\\x{1380}-\\x{138F}\\x{1401}-\\x{166C}\\x{166F}-\\x{167F}\\x{1681}-\\x{169A}\\x{16A0}-\\x{16EA}\\x{16F1}-\\x{16F8}\\x{1700}-\\x{170C}\\x{170E}-\\x{1711}\\x{1720}-\\x{1731}\\x{1740}-\\x{1751}\\x{1760}-\\x{176C}\\x{176E}-\\x{1770}\\x{1780}-\\x{17B3}\\x{17DC}\\x{1820}-\\x{1842}\\x{1844}-\\x{1877}\\x{1880}-\\x{18A8}\\x{18AA}\\x{18B0}-\\x{18F5}\\x{1900}-\\x{191E}\\x{1950}-\\x{196D}\\x{1970}-\\x{1974}\\x{1980}-\\x{19AB}\\x{19B0}-\\x{19C9}\\x{1A00}-\\x{1A16}\\x{1A20}-\\x{1A54}\\x{1B05}-\\x{1B33}\\x{1B45}-\\x{1B4B}\\x{1B83}-\\x{1BA0}\\x{1BAE}-\\x{1BAF}\\x{1BBA}-\\x{1BE5}\\x{1C00}-\\x{1C23}\\x{1C4D}-\\x{1C4F}\\x{1C5A}-\\x{1C77}\\x{1CE9}-\\x{1CEC}\\x{1CEE}-\\x{1CF1}\\x{1CF5}-\\x{1CF6}\\x{2135}-\\x{2138}\\x{2D30}-\\x{2D67}\\x{2D80}-\\x{2D96}\\x{2DA0}-\\x{2DA6}\\x{2DA8}-\\x{2DAE}\\x{2DB0}-\\x{2DB6}\\x{2DB8}-\\x{2DBE}\\x{2DC0}-\\x{2DC6}\\x{2DC8}-\\x{2DCE}\\x{2DD0}-\\x{2DD6}\\x{2DD8}-\\x{2DDE}\\x{3006}\\x{303C}\\x{3041}-\\x{3096}\\x{309F}\\x{30A1}-\\x{30FA}\\x{30FF}\\x{3105}-\\x{312D}\\x{3131}-\\x{318E}\\x{31A0}-\\x{31BA}\\x{31F0}-\\x{31FF}\\x{3400}-\\x{4DB5}\\x{4E00}-\\x{9FD5}\\x{A000}-\\x{A014}\\x{A016}-\\x{A48C}\\x{A4D0}-\\x{A4F7}\\x{A500}-\\x{A60B}\\x{A610}-\\x{A61F}\\x{A62A}-\\x{A62B}\\x{A66E}\\x{A6A0}-\\x{A6E5}\\x{A78F}\\x{A7F7}\\x{A7FB}-\\x{A801}\\x{A803}-\\x{A805}\\x{A807}-\\x{A80A}\\x{A80C}-\\x{A822}\\x{A840}-\\x{A873}\\x{A882}-\\x{A8B3}\\x{A8F2}-\\x{A8F7}\\x{A8FB}\\x{A8FD}\\x{A90A}-\\x{A925}\\x{A930}-\\x{A946}\\x{A960}-\\x{A97C}\\x{A984}-\\x{A9B2}\\x{A9E0}-\\x{A9E4}\\x{A9E7}-\\x{A9EF}\\x{A9FA}-\\x{A9FE}\\x{AA00}-\\x{AA28}\\x{AA40}-\\x{AA42}\\x{AA44}-\\x{AA4B}\\x{AA60}-\\x{AA6F}\\x{AA71}-\\x{AA76}\\x{AA7A}\\x{AA7E}-\\x{AAAF}\\x{AAB1}\\x{AAB5}-\\x{AAB6}\\x{AAB9}-\\x{AABD}\\x{AAC0}\\x{AAC2}\\x{AADB}-\\x{AADC}\\x{AAE0}-\\x{AAEA}\\x{AAF2}\\x{AB01}-\\x{AB06}\\x{AB09}-\\x{AB0E}\\x{AB11}-\\x{AB16}\\x{AB20}-\\x{AB26}\\x{AB28}-\\x{AB2E}\\x{ABC0}-\\x{ABE2}\\x{AC00}-\\x{D7A3}\\x{D7B0}-\\x{D7C6}\\x{D7CB}-\\x{D7FB}\\x{F900}-\\x{FA6D}\\x{FA70}-\\x{FAD9}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB38}-\\x{FB3C}\\x{FB3E}\\x{FB40}-\\x{FB41}\\x{FB43}-\\x{FB44}\\x{FB46}-\\x{FBB1}\\x{FBD3}-\\x{FD3D}\\x{FD50}-\\x{FD8F}\\x{FD92}-\\x{FDC7}\\x{FDF0}-\\x{FDFB}\\x{FE70}-\\x{FE74}\\x{FE76}-\\x{FEFC}\\x{FF66}-\\x{FF6F}\\x{FF71}-\\x{FF9D}\\x{FFA0}-\\x{FFBE}\\x{FFC2}-\\x{FFC7}\\x{FFCA}-\\x{FFCF}\\x{FFD2}-\\x{FFD7}\\x{FFDA}-\\x{FFDC}]/"; + $this->peg_c202 = array( "type" => "class", "value" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]", "description" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]" ); + $this->peg_c203 = "/^[\\x{01C5}\\x{01C8}\\x{01CB}\\x{01F2}\\x{1F88}-\\x{1F8F}\\x{1F98}-\\x{1F9F}\\x{1FA8}-\\x{1FAF}\\x{1FBC}\\x{1FCC}\\x{1FFC}]/"; + $this->peg_c204 = array( "type" => "class", "value" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]", "description" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]" ); + $this->peg_c205 = "/^[A-ZÀ-ÖØ-Þ\\x{0100}\\x{0102}\\x{0104}\\x{0106}\\x{0108}\\x{010A}\\x{010C}\\x{010E}\\x{0110}\\x{0112}\\x{0114}\\x{0116}\\x{0118}\\x{011A}\\x{011C}\\x{011E}\\x{0120}\\x{0122}\\x{0124}\\x{0126}\\x{0128}\\x{012A}\\x{012C}\\x{012E}\\x{0130}\\x{0132}\\x{0134}\\x{0136}\\x{0139}\\x{013B}\\x{013D}\\x{013F}\\x{0141}\\x{0143}\\x{0145}\\x{0147}\\x{014A}\\x{014C}\\x{014E}\\x{0150}\\x{0152}\\x{0154}\\x{0156}\\x{0158}\\x{015A}\\x{015C}\\x{015E}\\x{0160}\\x{0162}\\x{0164}\\x{0166}\\x{0168}\\x{016A}\\x{016C}\\x{016E}\\x{0170}\\x{0172}\\x{0174}\\x{0176}\\x{0178}-\\x{0179}\\x{017B}\\x{017D}\\x{0181}-\\x{0182}\\x{0184}\\x{0186}-\\x{0187}\\x{0189}-\\x{018B}\\x{018E}-\\x{0191}\\x{0193}-\\x{0194}\\x{0196}-\\x{0198}\\x{019C}-\\x{019D}\\x{019F}-\\x{01A0}\\x{01A2}\\x{01A4}\\x{01A6}-\\x{01A7}\\x{01A9}\\x{01AC}\\x{01AE}-\\x{01AF}\\x{01B1}-\\x{01B3}\\x{01B5}\\x{01B7}-\\x{01B8}\\x{01BC}\\x{01C4}\\x{01C7}\\x{01CA}\\x{01CD}\\x{01CF}\\x{01D1}\\x{01D3}\\x{01D5}\\x{01D7}\\x{01D9}\\x{01DB}\\x{01DE}\\x{01E0}\\x{01E2}\\x{01E4}\\x{01E6}\\x{01E8}\\x{01EA}\\x{01EC}\\x{01EE}\\x{01F1}\\x{01F4}\\x{01F6}-\\x{01F8}\\x{01FA}\\x{01FC}\\x{01FE}\\x{0200}\\x{0202}\\x{0204}\\x{0206}\\x{0208}\\x{020A}\\x{020C}\\x{020E}\\x{0210}\\x{0212}\\x{0214}\\x{0216}\\x{0218}\\x{021A}\\x{021C}\\x{021E}\\x{0220}\\x{0222}\\x{0224}\\x{0226}\\x{0228}\\x{022A}\\x{022C}\\x{022E}\\x{0230}\\x{0232}\\x{023A}-\\x{023B}\\x{023D}-\\x{023E}\\x{0241}\\x{0243}-\\x{0246}\\x{0248}\\x{024A}\\x{024C}\\x{024E}\\x{0370}\\x{0372}\\x{0376}\\x{037F}\\x{0386}\\x{0388}-\\x{038A}\\x{038C}\\x{038E}-\\x{038F}\\x{0391}-\\x{03A1}\\x{03A3}-\\x{03AB}\\x{03CF}\\x{03D2}-\\x{03D4}\\x{03D8}\\x{03DA}\\x{03DC}\\x{03DE}\\x{03E0}\\x{03E2}\\x{03E4}\\x{03E6}\\x{03E8}\\x{03EA}\\x{03EC}\\x{03EE}\\x{03F4}\\x{03F7}\\x{03F9}-\\x{03FA}\\x{03FD}-\\x{042F}\\x{0460}\\x{0462}\\x{0464}\\x{0466}\\x{0468}\\x{046A}\\x{046C}\\x{046E}\\x{0470}\\x{0472}\\x{0474}\\x{0476}\\x{0478}\\x{047A}\\x{047C}\\x{047E}\\x{0480}\\x{048A}\\x{048C}\\x{048E}\\x{0490}\\x{0492}\\x{0494}\\x{0496}\\x{0498}\\x{049A}\\x{049C}\\x{049E}\\x{04A0}\\x{04A2}\\x{04A4}\\x{04A6}\\x{04A8}\\x{04AA}\\x{04AC}\\x{04AE}\\x{04B0}\\x{04B2}\\x{04B4}\\x{04B6}\\x{04B8}\\x{04BA}\\x{04BC}\\x{04BE}\\x{04C0}-\\x{04C1}\\x{04C3}\\x{04C5}\\x{04C7}\\x{04C9}\\x{04CB}\\x{04CD}\\x{04D0}\\x{04D2}\\x{04D4}\\x{04D6}\\x{04D8}\\x{04DA}\\x{04DC}\\x{04DE}\\x{04E0}\\x{04E2}\\x{04E4}\\x{04E6}\\x{04E8}\\x{04EA}\\x{04EC}\\x{04EE}\\x{04F0}\\x{04F2}\\x{04F4}\\x{04F6}\\x{04F8}\\x{04FA}\\x{04FC}\\x{04FE}\\x{0500}\\x{0502}\\x{0504}\\x{0506}\\x{0508}\\x{050A}\\x{050C}\\x{050E}\\x{0510}\\x{0512}\\x{0514}\\x{0516}\\x{0518}\\x{051A}\\x{051C}\\x{051E}\\x{0520}\\x{0522}\\x{0524}\\x{0526}\\x{0528}\\x{052A}\\x{052C}\\x{052E}\\x{0531}-\\x{0556}\\x{10A0}-\\x{10C5}\\x{10C7}\\x{10CD}\\x{13A0}-\\x{13F5}\\x{1E00}\\x{1E02}\\x{1E04}\\x{1E06}\\x{1E08}\\x{1E0A}\\x{1E0C}\\x{1E0E}\\x{1E10}\\x{1E12}\\x{1E14}\\x{1E16}\\x{1E18}\\x{1E1A}\\x{1E1C}\\x{1E1E}\\x{1E20}\\x{1E22}\\x{1E24}\\x{1E26}\\x{1E28}\\x{1E2A}\\x{1E2C}\\x{1E2E}\\x{1E30}\\x{1E32}\\x{1E34}\\x{1E36}\\x{1E38}\\x{1E3A}\\x{1E3C}\\x{1E3E}\\x{1E40}\\x{1E42}\\x{1E44}\\x{1E46}\\x{1E48}\\x{1E4A}\\x{1E4C}\\x{1E4E}\\x{1E50}\\x{1E52}\\x{1E54}\\x{1E56}\\x{1E58}\\x{1E5A}\\x{1E5C}\\x{1E5E}\\x{1E60}\\x{1E62}\\x{1E64}\\x{1E66}\\x{1E68}\\x{1E6A}\\x{1E6C}\\x{1E6E}\\x{1E70}\\x{1E72}\\x{1E74}\\x{1E76}\\x{1E78}\\x{1E7A}\\x{1E7C}\\x{1E7E}\\x{1E80}\\x{1E82}\\x{1E84}\\x{1E86}\\x{1E88}\\x{1E8A}\\x{1E8C}\\x{1E8E}\\x{1E90}\\x{1E92}\\x{1E94}\\x{1E9E}\\x{1EA0}\\x{1EA2}\\x{1EA4}\\x{1EA6}\\x{1EA8}\\x{1EAA}\\x{1EAC}\\x{1EAE}\\x{1EB0}\\x{1EB2}\\x{1EB4}\\x{1EB6}\\x{1EB8}\\x{1EBA}\\x{1EBC}\\x{1EBE}\\x{1EC0}\\x{1EC2}\\x{1EC4}\\x{1EC6}\\x{1EC8}\\x{1ECA}\\x{1ECC}\\x{1ECE}\\x{1ED0}\\x{1ED2}\\x{1ED4}\\x{1ED6}\\x{1ED8}\\x{1EDA}\\x{1EDC}\\x{1EDE}\\x{1EE0}\\x{1EE2}\\x{1EE4}\\x{1EE6}\\x{1EE8}\\x{1EEA}\\x{1EEC}\\x{1EEE}\\x{1EF0}\\x{1EF2}\\x{1EF4}\\x{1EF6}\\x{1EF8}\\x{1EFA}\\x{1EFC}\\x{1EFE}\\x{1F08}-\\x{1F0F}\\x{1F18}-\\x{1F1D}\\x{1F28}-\\x{1F2F}\\x{1F38}-\\x{1F3F}\\x{1F48}-\\x{1F4D}\\x{1F59}\\x{1F5B}\\x{1F5D}\\x{1F5F}\\x{1F68}-\\x{1F6F}\\x{1FB8}-\\x{1FBB}\\x{1FC8}-\\x{1FCB}\\x{1FD8}-\\x{1FDB}\\x{1FE8}-\\x{1FEC}\\x{1FF8}-\\x{1FFB}\\x{2102}\\x{2107}\\x{210B}-\\x{210D}\\x{2110}-\\x{2112}\\x{2115}\\x{2119}-\\x{211D}\\x{2124}\\x{2126}\\x{2128}\\x{212A}-\\x{212D}\\x{2130}-\\x{2133}\\x{213E}-\\x{213F}\\x{2145}\\x{2183}\\x{2C00}-\\x{2C2E}\\x{2C60}\\x{2C62}-\\x{2C64}\\x{2C67}\\x{2C69}\\x{2C6B}\\x{2C6D}-\\x{2C70}\\x{2C72}\\x{2C75}\\x{2C7E}-\\x{2C80}\\x{2C82}\\x{2C84}\\x{2C86}\\x{2C88}\\x{2C8A}\\x{2C8C}\\x{2C8E}\\x{2C90}\\x{2C92}\\x{2C94}\\x{2C96}\\x{2C98}\\x{2C9A}\\x{2C9C}\\x{2C9E}\\x{2CA0}\\x{2CA2}\\x{2CA4}\\x{2CA6}\\x{2CA8}\\x{2CAA}\\x{2CAC}\\x{2CAE}\\x{2CB0}\\x{2CB2}\\x{2CB4}\\x{2CB6}\\x{2CB8}\\x{2CBA}\\x{2CBC}\\x{2CBE}\\x{2CC0}\\x{2CC2}\\x{2CC4}\\x{2CC6}\\x{2CC8}\\x{2CCA}\\x{2CCC}\\x{2CCE}\\x{2CD0}\\x{2CD2}\\x{2CD4}\\x{2CD6}\\x{2CD8}\\x{2CDA}\\x{2CDC}\\x{2CDE}\\x{2CE0}\\x{2CE2}\\x{2CEB}\\x{2CED}\\x{2CF2}\\x{A640}\\x{A642}\\x{A644}\\x{A646}\\x{A648}\\x{A64A}\\x{A64C}\\x{A64E}\\x{A650}\\x{A652}\\x{A654}\\x{A656}\\x{A658}\\x{A65A}\\x{A65C}\\x{A65E}\\x{A660}\\x{A662}\\x{A664}\\x{A666}\\x{A668}\\x{A66A}\\x{A66C}\\x{A680}\\x{A682}\\x{A684}\\x{A686}\\x{A688}\\x{A68A}\\x{A68C}\\x{A68E}\\x{A690}\\x{A692}\\x{A694}\\x{A696}\\x{A698}\\x{A69A}\\x{A722}\\x{A724}\\x{A726}\\x{A728}\\x{A72A}\\x{A72C}\\x{A72E}\\x{A732}\\x{A734}\\x{A736}\\x{A738}\\x{A73A}\\x{A73C}\\x{A73E}\\x{A740}\\x{A742}\\x{A744}\\x{A746}\\x{A748}\\x{A74A}\\x{A74C}\\x{A74E}\\x{A750}\\x{A752}\\x{A754}\\x{A756}\\x{A758}\\x{A75A}\\x{A75C}\\x{A75E}\\x{A760}\\x{A762}\\x{A764}\\x{A766}\\x{A768}\\x{A76A}\\x{A76C}\\x{A76E}\\x{A779}\\x{A77B}\\x{A77D}-\\x{A77E}\\x{A780}\\x{A782}\\x{A784}\\x{A786}\\x{A78B}\\x{A78D}\\x{A790}\\x{A792}\\x{A796}\\x{A798}\\x{A79A}\\x{A79C}\\x{A79E}\\x{A7A0}\\x{A7A2}\\x{A7A4}\\x{A7A6}\\x{A7A8}\\x{A7AA}-\\x{A7AD}\\x{A7B0}-\\x{A7B4}\\x{A7B6}\\x{FF21}-\\x{FF3A}]/"; + $this->peg_c206 = array( "type" => "class", "value" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]", "description" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]" ); + $this->peg_c207 = array("type" => "other", "description" => "unicode superscript/subscript character" ); + $this->peg_c208 = "/^[²³¹\\x{2070}-\\x{209C}\\x{2C7C}\\x{1D62}-\\x{1D6A}]/"; + $this->peg_c209 = array( "type" => "class", "value" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]", "description" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]" ); + $this->peg_c210 = array("type" => "other", "description" => "special unicode chars" ); + $this->peg_c211 = "/^[µ\\x{0370}-\\x{0371}\\x{037F}\\x{0391}-\\x{0392}\\x{0393}-\\x{0394}\\x{0395}-\\x{0396}\\x{0397}-\\x{0398}\\x{0399}-\\x{039A}\\x{039B}-\\x{039C}\\x{039D}-\\x{039E}\\x{039F}-\\x{03A0}\\x{03A1}\\x{03A3}-\\x{03A4}\\x{03A5}-\\x{03A6}\\x{03A7}-\\x{03A8}\\x{03A9}\\x{03B1}-\\x{03B2}\\x{03B3}-\\x{03B4}\\x{03B5}-\\x{03B6}\\x{03B7}-\\x{03B8}\\x{03B9}-\\x{03BA}\\x{03BB}-\\x{03BC}\\x{03BD}-\\x{03BE}\\x{03BF}-\\x{03C0}\\x{03C1}-\\x{03C2}\\x{03C3}-\\x{03C4}\\x{03C5}-\\x{03C6}\\x{03C7}-\\x{03C8}\\x{03C9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03F7}-\\x{03F8}\\x{03FA}-\\x{03FB}\\x{1D26}-\\x{1D27}\\x{1D28}-\\x{1D29}\\x{1D2A}\\x{2102}\\x{2107}\\x{210A}-\\x{210B}\\x{210C}-\\x{210D}\\x{210E}-\\x{210F}\\x{2110}-\\x{2111}\\x{2112}-\\x{2113}\\x{2115}\\x{2119}-\\x{211A}\\x{211B}-\\x{211C}\\x{211D}\\x{2124}\\x{2126}-\\x{2127}\\x{2128}\\x{212B}-\\x{212C}\\x{212D}\\x{212F}-\\x{2130}\\x{2131}\\x{2133}-\\x{2134}\\x{2135}-\\x{2136}\\x{2137}-\\x{2138}\\x{213C}-\\x{213D}\\x{213E}-\\x{213F}\\x{2145}-\\x{2146}\\x{2147}-\\x{2148}\\x{2149}\\x{2205}\\x{221E}\\x{29B0}\\x{AB65}]/"; + $this->peg_c212 = array( "type" => "class", "value" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]", "description" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]" ); $peg_startRuleFunctions = array( 'Root' => array($this, "peg_parseRoot"), 'Equivline' => array($this, "peg_parseEquivline") ); $peg_startRuleFunction = array($this, "peg_parseRoot"); diff --git a/stack/maximaparser/corrective_parser.php b/stack/maximaparser/corrective_parser.php index 05d47c8443ffab2a11dc8ea3141d972969a76037..8865e46d4849ed26c5cebfa4cc41f7304733bedc 100644 --- a/stack/maximaparser/corrective_parser.php +++ b/stack/maximaparser/corrective_parser.php @@ -461,8 +461,8 @@ class maxima_corrective_parser { $exception->expected[4]['type'] === 'end' && $exception->expected[5]['type'] === 'other' && $exception->expected[5]['description'] === 'whitespace') { // This is a sensitive check matching the expectations of the parser.... - // This is extra special, if we have an unencpsulated comma we might be parsing for an evaluation - // flag but not find the assingment of flag value... + // This is extra special, if we have an unencapsulated comma we might be parsing for an evaluation + // flag but not find the assignment of flag value... $errors[] = stack_string('stackCas_unencpsulated_comma'); $answernote[] = 'unencapsulated_comma'; } else if ($nextchar === '' && ($foundchar !== '' && mb_strpos($disallowedfinalchars, $foundchar) !== false)) { diff --git a/stack/questiontest.php b/stack/questiontest.php index 31f27252dc1c0dea6e322657434ee7e4a813859e..c50804b7d00b3f70867d8539a71f4b75c8b9080c 100644 --- a/stack/questiontest.php +++ b/stack/questiontest.php @@ -73,11 +73,6 @@ class stack_question_test { * @return stack_question_test_result the test results. */ public function test_question($questionid, $seed, $context) { - - // We don't permit completely empty test cases. - // Completely empty test cases always pass, which is spurious in the bulk test. - $emptytestcase = true; - // Create a completely clean version of the question usage we will use. // Evaluated state is stored in question variables etc. $question = question_bank::load_question($questionid); @@ -98,6 +93,27 @@ class stack_question_test { $response = self::compute_response($question, $this->inputs); $quba->process_action($slot, $response); + $results = $this->process_results($question, $response); + + if ($this->testcase) { + $this->save_result($question, $results); + } + + return $results; + } + + /** + * Seperate out from Moodle-specific parts of test_question() to allow + * use in the API + * + * @param question_definition $question + * @param array $response + * @return stack_question_test_result + */ + public function process_results($question, $response) { + // We don't permit completely empty test cases. + // Completely empty test cases always pass, which is spurious in the bulk test. + $emptytestcase = true; $results = new stack_question_test_result($this); $results->set_questionpenalty($question->penalty); foreach ($this->inputs as $inputname => $notused) { @@ -138,11 +154,6 @@ class stack_question_test { } $results->emptytestcase = $emptytestcase; - - if ($this->testcase) { - $this->save_result($question, $results); - } - return $results; } diff --git a/stack/questiontestresult.php b/stack/questiontestresult.php index 8e013366152e3a369d751ddc53e8160f499ddee4..779673879295a4c8404e7c282bf048c033b00c00 100644 --- a/stack/questiontestresult.php +++ b/stack/questiontestresult.php @@ -245,6 +245,51 @@ class stack_question_test_result { return true; } + /** + * @return array whether the test passed successfully + outcomes, inputs and reasons for failure. + */ + public function passed_with_reasons() { + $passed = true; + $reason = ''; + $inputs = []; + $outcomes = []; + if ($this->emptytestcase) { + $passed = false; + $reason = stack_string('questiontestempty'); + } else { + foreach ($this->get_input_states() as $inputname => $inputstate) { + $inputval = ($inputstate->input === false) ? '' : $inputstate->input; + $inputs[$inputname] = [ + 'inputexpression' => $inputname, + 'inputentered' => $inputval, + 'inputmodified' => $inputstate->modified, + 'inputdisplayed' => stack_ouput_castext($inputstate->display), + 'inputstatus' => stack_string('inputstatusname' . $inputstate->status), + 'errors' => $inputstate->errors, + ]; + + } + + foreach ($this->get_prt_states() as $prtname => $state) { + $outcomes[$prtname] = [ + 'outcome' => $state->testoutcome, + 'score' => $state->score, + 'penalty' => $state->penalty, + 'answernote' => $state->answernote, + 'expectedscore' => $state->expectedscore, + 'expectedpenalty' => $state->expectedpenalty, + 'expectedanswernote' => $state->expectedanswernote, + 'feedback' => $state->feedback, + 'reason' => $state->reason, + ]; + if (!$state->testoutcome) { + $passed = false; + } + } + } + return ['passed' => $passed, 'reason' => $reason, 'inputs' => $inputs, 'outcomes' => $outcomes]; + } + /** * Create an HTML output of the test result. */ diff --git a/tests/api_controller_test.php b/tests/api_controller_test.php index 562f099ce57eadab182604e68e3888ff7d80761b..f1e95fee86f948b24a9ae8723da4fbad55ee234c 100644 --- a/tests/api_controller_test.php +++ b/tests/api_controller_test.php @@ -29,34 +29,28 @@ require_once(__DIR__ . '../../api/controller/DownloadController.php'); require_once(__DIR__ . '../../api/controller/GradingController.php'); require_once(__DIR__ . '../../api/controller/RenderController.php'); require_once(__DIR__ . '../../api/controller/ValidationController.php'); +require_once(__DIR__ . '../../api/controller/TestController.php'); use api\controller\DownloadController; use api\controller\GradingController; use api\controller\RenderController; use api\controller\ValidationController; +use api\controller\TestController; use api\util\StackIframeHolder; use stack_api_test_data; use Psr\Http\Message\ResponseInterface as ResponseInt; +use Psr\Http\Message\StreamInterface as StreamInt; use Psr\Http\Message\ServerRequestInterface as RequestInt; use qtype_stack_testcase; -/** - * Class to fake the response output object and store the actual JSON - */ -class MockBody { - public object $output; - public function write() { - $this->output = json_decode(func_get_args()[0]); - return $this->output; - } -} - /** * @group qtype_stack * @covers \qtype_stack */ class api_controller_test extends qtype_stack_testcase { + /** @var object used to store output */ + public object $output; /** @var object used to store output */ public object $result; /** @var array the api call data */ @@ -111,11 +105,27 @@ class api_controller_test extends qtype_stack_testcase { ->setMethods($methods) ->getMock(); - $this->result = new MockBody(); + $reflection = new \ReflectionClass(StreamInt::class); + $methods = []; + foreach ($reflection->getMethods() as $method) { + $methods[] = $method->name; + } + + $this->result = $this->getMockBuilder(StreamInt::class) + ->setMockClassName('StreamInterface') + ->setMethods($methods) + ->getMock(); - // The controllers call getBody() on the response object but then call write() on the result. - // We return a MockBody object with a write method which updates the test's result property - // so we can actually perform some asserts. + $this->result->expects($this->any())->method('write')->will($this->returnCallback( + function() { + $this->output = json_decode(func_get_args()[0]); + return 1; + }) + ); + + // The controllers call getBody() on the response object but then call write() on the result + // so we have to mock both. We override the write method to write to a propery of the testsuite + // so we have something easily accessible to perform some asserts on. $this->response->expects($this->any())->method('getBody')->will($this->returnCallback( function() { return $this->result; @@ -138,18 +148,18 @@ class api_controller_test extends qtype_stack_testcase { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->result->output->questionrender); - $this->assertEquals(86, $this->result->output->questionseed); - $this->assertEquals('matrix([35,30],[28,24])', $this->result->output->questioninputs->ans1->samplesolution->_val); + $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->output->questionrender); + $this->assertEquals(86, $this->output->questionseed); + $this->assertEquals('matrix([35,30],[28,24])', $this->output->questioninputs->ans1->samplesolution->_val); $this->assertMatchesRegularExpression('/^<div class="matrixsquarebrackets"><table class="matrixtable"/', - $this->result->output->questioninputs->ans1->render); - $this->assertMatchesRegularExpression('/^<p>To multiply matrices/', $this->result->output->questionsamplesolutiontext); - $this->assertEquals(0, count((array)$this->result->output->questionassets)); - $this->assertContains(86, $this->result->output->questionvariants); - $this->assertContains(219862533, $this->result->output->questionvariants); - $this->assertContains(1167893775, $this->result->output->questionvariants); - $this->assertEquals(3, count($this->result->output->questionvariants)); - $this->assertEquals(0, count($this->result->output->iframes)); + $this->output->questioninputs->ans1->render); + $this->assertMatchesRegularExpression('/^<p>To multiply matrices/', $this->output->questionsamplesolutiontext); + $this->assertEquals(0, count((array)$this->output->questionassets)); + $this->assertContains(86, $this->output->questionvariants); + $this->assertContains(219862533, $this->output->questionvariants); + $this->assertContains(1167893775, $this->output->questionvariants); + $this->assertEquals(3, count($this->output->questionvariants)); + $this->assertEquals(0, count($this->output->iframes)); } public function test_render_specified_seed() { @@ -157,33 +167,33 @@ class api_controller_test extends qtype_stack_testcase { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->result->output->questionrender); - $this->assertEquals(219862533, $this->result->output->questionseed); + $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->output->questionrender); + $this->assertEquals(219862533, $this->output->questionseed); } public function test_render_plots() { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('plots'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertEquals(4, count((array)$this->result->output->questionassets)); - $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-1-0.svg'})); - $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-2-0.svg'})); - $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-3-0.svg'})); - $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-4-0.svg'})); + $this->assertEquals(4, count((array)$this->output->questionassets)); + $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-1-0.svg'})); + $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-2-0.svg'})); + $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-3-0.svg'})); + $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-4-0.svg'})); } public function test_render_iframes() { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('iframes'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertEquals(1, count($this->result->output->iframes)); + $this->assertEquals(1, count($this->output->iframes)); } public function test_render_download() { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('download'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertMatchesRegularExpression('/javascript\:download\(\'data.csv\'\, 1\)/s', $this->result->output->questionrender); + $this->assertMatchesRegularExpression('/javascript\:download\(\'data.csv\'\, 1\)/s', $this->output->questionrender); } public function test_validation() { @@ -193,8 +203,8 @@ class api_controller_test extends qtype_stack_testcase { $vc = new ValidationController(); $vc->__invoke($this->request, $this->response, []); $this->assertMatchesRegularExpression('/\\\[ \\\left\[\\begin\{array\}\{cc\} 1 & 2 \\\\ 3 & 4 \\end{array}\\right\] \\\]/s', - $this->result->output->validation); - $this->assertEquals(0, count($this->result->output->iframes)); + $this->output->validation); + $this->assertEquals(0, count($this->output->iframes)); } public function test_grade() { @@ -203,17 +213,17 @@ class api_controller_test extends qtype_stack_testcase { $this->requestdata['inputName'] = 'ans1'; $gc = new GradingController(); $gc->__invoke($this->request, $this->response, []); - $this->assertEquals(true, $this->result->output->isgradable); - $this->assertEquals(1, $this->result->output->score); - $this->assertEquals(1, $this->result->output->scores->prt1); - $this->assertEquals(1, $this->result->output->scores->total); - $this->assertEquals(1, $this->result->output->scoreweights->prt1); - $this->assertEquals(5, $this->result->output->scoreweights->total); - $this->assertEquals('<p>[[feedback:prt1]]</p>', $this->result->output->specificfeedback); - $this->assertStringContainsString('correct', $this->result->output->prts->prt1); - $this->assertEquals(0, count((array)$this->result->output->gradingassets)); - $this->assertEquals('Seed: 86; ans1: matrix([35,30],[28,24]) [valid]; prt1: !', $this->result->output->responsesummary); - $this->assertEquals(0, count($this->result->output->iframes)); + $this->assertEquals(true, $this->output->isgradable); + $this->assertEquals(1, $this->output->score); + $this->assertEquals(1, $this->output->scores->prt1); + $this->assertEquals(1, $this->output->scores->total); + $this->assertEquals(1, $this->output->scoreweights->prt1); + $this->assertEquals(5, $this->output->scoreweights->total); + $this->assertEquals('<p>[[feedback:prt1]]</p>', $this->output->specificfeedback); + $this->assertStringContainsString('correct', $this->output->prts->prt1); + $this->assertEquals(0, count((array)$this->output->gradingassets)); + $this->assertEquals('Seed: 86; ans1: matrix([35,30],[28,24]) [valid]; prt1: !', $this->output->responsesummary); + $this->assertEquals(0, count($this->output->iframes)); } public function test_grade_scores() { @@ -222,18 +232,18 @@ class api_controller_test extends qtype_stack_testcase { $this->requestdata['inputName'] = 'ans1'; $gc = new GradingController(); $gc->__invoke($this->request, $this->response, []); - $this->assertEquals(true, $this->result->output->isgradable); - $this->assertEqualsWithDelta(0.9, $this->result->output->score, 0.0001); - $this->assertEquals(1, $this->result->output->scores->prt1); - $this->assertEquals(1, $this->result->output->scores->prt2); - $this->assertEquals(0, $this->result->output->scores->prt3); - $this->assertEquals(1, $this->result->output->scores->prt4); - $this->assertEqualsWithDelta(0.9, $this->result->output->scores->total, 0.0001); - $this->assertEqualsWithDelta(0.7, $this->result->output->scoreweights->prt1, 0.0001); - $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt2, 0.0001); - $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt3, 0.0001); - $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt4, 0.0001); - $this->assertEquals(10, $this->result->output->scoreweights->total); + $this->assertEquals(true, $this->output->isgradable); + $this->assertEqualsWithDelta(0.9, $this->output->score, 0.0001); + $this->assertEquals(1, $this->output->scores->prt1); + $this->assertEquals(1, $this->output->scores->prt2); + $this->assertEquals(0, $this->output->scores->prt3); + $this->assertEquals(1, $this->output->scores->prt4); + $this->assertEqualsWithDelta(0.9, $this->output->scores->total, 0.0001); + $this->assertEqualsWithDelta(0.7, $this->output->scoreweights->prt1, 0.0001); + $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt2, 0.0001); + $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt3, 0.0001); + $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt4, 0.0001); + $this->assertEquals(10, $this->output->scoreweights->total); } public function test_download() { @@ -251,4 +261,95 @@ class api_controller_test extends qtype_stack_testcase { $this->expectOutputRegex('/^A,B,C\n0.37,5.04,2.72/s'); } + public function test_test_controller() { + $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices'); + $this->requestdata['filepath'] = 'testpath/test.xml'; + $tc = new TestController(); + $tc->__invoke($this->request, $this->response, []); + $results = $this->output; + $this->assertEquals('test_3_matrix', $results->name); + $this->assertEquals(false, $results->isupgradeerror); + $this->assertEquals(true, $results->isgeneralfeedback ); + $this->assertEquals(true, $results->isdeployedseeds); + $this->assertEquals(true, $results->israndomvariants); + $this->assertEquals(true, $results->istests); + // Three seeds. + $this->assertEquals(3, count(get_object_vars($results->results))); + $this->assertEquals(4, $results->results->{'86'}->passes); + $this->assertEquals(0, $results->results->{'86'}->fails); + $this->assertEquals('', $results->results->{'86'}->messages); + $this->assertEquals(4, count(get_object_vars($results->results->{'86'}->outcomes))); + } + + public function test_test_controller_fail() { + $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test'); + $this->requestdata['filepath'] = 'testpath/test.xml'; + $tc = new TestController(); + $tc->__invoke($this->request, $this->response, []); + $results = $this->output; + $this->assertEquals('Algebraic input', $results->name); + $this->assertEquals(false, $results->isupgradeerror); + $this->assertEquals(false, $results->isgeneralfeedback ); + $this->assertEquals(false, $results->isdeployedseeds); + $this->assertEquals(false, $results->israndomvariants); + $this->assertEquals(true, $results->istests); + // No seeds. + $this->assertEquals(1, count(get_object_vars($results->results))); + $this->assertEquals(0, $results->results->noseed->passes); + $this->assertEquals(2, $results->results->noseed->fails); + $this->assertEquals(stack_string('questiontestempty'), $results->results->noseed->messages); + $this->assertEquals('', $results->messages); + $this->assertEquals(2, count(get_object_vars($results->results->noseed->outcomes))); + } + + public function test_test_controller_upgrade() { + $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test2'); + $this->requestdata['filepath'] = 'testpath/test.xml'; + $tc = new TestController(); + $tc->__invoke($this->request, $this->response, []); + $results = $this->output; + $this->assertEquals('Algebraic input', $results->name); + $this->assertEquals(true, $results->isupgradeerror); + $this->assertEquals(false, $results->isgeneralfeedback ); + $this->assertEquals(false, $results->isdeployedseeds); + $this->assertEquals(false, $results->israndomvariants); + $this->assertEquals(false, $results->istests); + $this->assertStringContainsString('missing or empty', $results->messages); + $this->assertEquals([], $results->results); + } + + public function test_test_controller_default_test_fail() { + $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test3'); + $this->requestdata['filepath'] = 'testpath/test.xml'; + $tc = new TestController(); + $tc->__invoke($this->request, $this->response, []); + $results = $this->output; + $this->assertEquals('Algebraic input', $results->name); + $this->assertEquals(false, $results->isupgradeerror); + $this->assertEquals(false, $results->isgeneralfeedback ); + $this->assertEquals(false, $results->isdeployedseeds); + $this->assertEquals(false, $results->israndomvariants); + $this->assertEquals(false, $results->istests); + $this->assertEquals(stack_string('defaulttestfail'), $results->results->noseed->messages); + $this->assertEquals(1, $results->results->noseed->fails); + $this->assertEquals(0, $results->results->noseed->passes); + } + + public function test_test_controller_default_test_pass() { + $this->requestdata['questionDefinition'] = + str_replace('<tans>wrong</tans>', '<tans>ta</tans>', stack_api_test_data::get_question_string('test3')); + $this->requestdata['filepath'] = 'testpath/test.xml'; + $tc = new TestController(); + $tc->__invoke($this->request, $this->response, []); + $results = $this->output; + $this->assertEquals('Algebraic input', $results->name); + $this->assertEquals(false, $results->isupgradeerror); + $this->assertEquals(false, $results->isgeneralfeedback ); + $this->assertEquals(false, $results->isdeployedseeds); + $this->assertEquals(false, $results->israndomvariants); + $this->assertEquals(false, $results->istests); + $this->assertEquals('', $results->results->noseed->messages); + $this->assertEquals(0, $results->results->noseed->fails); + $this->assertEquals(1, $results->results->noseed->passes); + } } diff --git a/tests/api_stackquestionloader_test.php b/tests/api_stackquestionloader_test.php index 79d9ccacffbf602780ba2402f6de2519bd787d88..586291bbdea0624cf84763e769f0a7022bcbe5a3 100644 --- a/tests/api_stackquestionloader_test.php +++ b/tests/api_stackquestionloader_test.php @@ -40,7 +40,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase { public function test_question_loader() { $xml = stack_api_test_data::get_question_string('matrices'); $ql = new StackQuestionLoader(); - $question = $ql->loadXML($xml); + $question = $ql->loadXML($xml)['question']; // Testing a representative selection of fields. $this->assertEquals('test_3_matrix', $question->name); @@ -66,7 +66,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase { global $CFG; $xml = stack_api_test_data::get_question_string('usedefaults'); $ql = new StackQuestionLoader(); - $question = $ql->loadXML($xml); + $question = $ql->loadXML($xml)['question']; $this->assertEquals($question->options->get_option('decimals'), get_config('qtype_stack', 'decimals')); $this->assertEquals($question->options->get_option('scientificnotation'), get_config('qtype_stack', 'scientificnotation')); @@ -97,7 +97,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase { global $CFG; $xml = stack_api_test_data::get_question_string('optionset'); $ql = new StackQuestionLoader(); - $question = $ql->loadXML($xml); + $question = $ql->loadXML($xml)['question']; $this->assertEquals($question->options->get_option('decimals'), ','); $this->assertEquals($question->options->get_option('scientificnotation'), '*10'); $this->assertEquals($question->options->get_option('assumepos'), true); diff --git a/tests/ast_filter_000_099_common_core_auto_generated_test.php b/tests/ast_filter_000_099_common_core_auto_generated_test.php index 4a50fa813efe92cc2cd206885fa99691b4022be5..dc42bee08e245a2c2cd77c207594e0e9c07ecbc5 100644 --- a/tests/ast_filter_000_099_common_core_auto_generated_test.php +++ b/tests/ast_filter_000_099_common_core_auto_generated_test.php @@ -37,6 +37,11 @@ class ast_filter_000_099_common_core_auto_generated_test extends qtype_stack_ast $this->security = new stack_cas_security(false); $this->filter = stack_parsing_rule_factory::get_filter_pipeline([], [], true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_extraevaluation', 'Illegal_extraevaluation'], + false, true); + $this->expect('(x+2)(x+3)', '(x+2)*(x+3)', ['missing_stars'], @@ -173,6 +178,11 @@ class ast_filter_000_099_common_core_auto_generated_test extends qtype_stack_ast $this->security = new stack_cas_security(true); $this->filter = stack_parsing_rule_factory::get_filter_pipeline([], [], true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_extraevaluation', 'Illegal_extraevaluation'], + false, true); + $this->expect('(x+2)(x+3)', '(x+2)*(x+3)', ['missing_stars'], diff --git a/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php b/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php index f75a2476813bac27dc9f858f0e62b74e553a197b..9c15b0cbc15b7e0e70e943e40a9841769a0f516f 100644 --- a/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php +++ b/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php @@ -139,6 +139,11 @@ class ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ class ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_002_log_candy_auto_generated_test.php b/tests/ast_filter_002_log_candy_auto_generated_test.php index f6b193594375ce44ffeed9e8bbcbd80543655812..601916d45ce23e1e693d1b31679b243cda3fa5f5 100644 --- a/tests/ast_filter_002_log_candy_auto_generated_test.php +++ b/tests/ast_filter_002_log_candy_auto_generated_test.php @@ -159,6 +159,11 @@ class ast_filter_002_log_candy_auto_generated_test extends qtype_stack_ast_testc [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ class ast_filter_002_log_candy_auto_generated_test extends qtype_stack_ast_testc [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_003_no_dot_dot_auto_generated_test.php b/tests/ast_filter_003_no_dot_dot_auto_generated_test.php index 7fecf724c661e55003a8ad792b534a7a6691efbc..fa806c97da624dcc3b70b2b7910f8c0bbdb0ff04 100644 --- a/tests/ast_filter_003_no_dot_dot_auto_generated_test.php +++ b/tests/ast_filter_003_no_dot_dot_auto_generated_test.php @@ -119,6 +119,11 @@ class ast_filter_003_no_dot_dot_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ class ast_filter_003_no_dot_dot_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php b/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php index 613aa2cefc348294f2782bda4d7089a57855cf6f..1c68c1604e5b2f51621fa8343ff21e53f119195f 100644 --- a/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php +++ b/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php @@ -119,6 +119,11 @@ class ast_filter_005_i_is_never_a_function_auto_generated_test extends qtype_sta [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ class ast_filter_005_i_is_never_a_function_auto_generated_test extends qtype_sta [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php b/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php index eee55b4bf944222ecb3292821588b017b7d318fd..e0be35e6efd4629410b67bce8c96f0f527e85081 100644 --- a/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php +++ b/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_022_trig_replace_synonyms_auto_generated_test extends qtype_sta [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_022_trig_replace_synonyms_auto_generated_test extends qtype_sta [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_025_no_trig_power_auto_generated_test.php b/tests/ast_filter_025_no_trig_power_auto_generated_test.php index 9fad3cb998f57b99e12dd2a21663a43db4f95f7d..3d864ad1f668ca0baa503756ff702eb5537adaa1 100644 --- a/tests/ast_filter_025_no_trig_power_auto_generated_test.php +++ b/tests/ast_filter_025_no_trig_power_auto_generated_test.php @@ -109,6 +109,11 @@ class ast_filter_025_no_trig_power_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1880,6 +1885,11 @@ class ast_filter_025_no_trig_power_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_030_no_trig_space_auto_generated_test.php b/tests/ast_filter_030_no_trig_space_auto_generated_test.php index 359cf38ea190019d638556bc112ca1068e84f8e4..f711203e8425fa8548209ab1438e1be40ef123af 100644 --- a/tests/ast_filter_030_no_trig_space_auto_generated_test.php +++ b/tests/ast_filter_030_no_trig_space_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_030_no_trig_space_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_030_no_trig_space_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php b/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php index 58121aae3b30ee56cd449cea88f239159be32de0..6b9b12bc0184de8bc7f8ebe12356d16d5a917632 100644 --- a/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php +++ b/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_031_no_trig_brackets_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_031_no_trig_brackets_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_033_no_extra_evaluation_auto_generated_test.php b/tests/ast_filter_033_no_extra_evaluation_auto_generated_test.php new file mode 100644 index 0000000000000000000000000000000000000000..f0fc5d007f5c1ea223d99132736d890847fc2665 --- /dev/null +++ b/tests/ast_filter_033_no_extra_evaluation_auto_generated_test.php @@ -0,0 +1,3619 @@ +<?php +// This file is part of Stack - http://stack.maths.ed.ac.uk/ +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + +defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); + +// Auto-generated unit tests for AST-filter DO NOT EDIT! +/** + * @group qtype_stack + * @group qtype_stack_ast_filters + * @covers \ast_filter_033_no_extra_evaluation + */ + +class ast_filter_033_no_extra_evaluation_auto_generated_test extends qtype_stack_ast_testcase { + + public function test_affected_no_units() { + $this->security = new stack_cas_security(false); + $this->filter = stack_parsing_rule_factory::get_by_common_name('033_no_extra_evaluation'); + + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_extraevaluation', 'Illegal_extraevaluation'], + false, true); + + } + + public function test_affected_units() { + $this->security = new stack_cas_security(true); + $this->filter = stack_parsing_rule_factory::get_by_common_name('033_no_extra_evaluation'); + + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_extraevaluation', 'Illegal_extraevaluation'], + false, true); + + } + + public function test_non_affected_units() { + $this->security = new stack_cas_security(true); + $this->filter = stack_parsing_rule_factory::get_by_common_name('033_no_extra_evaluation'); + + $this->expect('"+"(a,b)', + '"+"(a,b)', + [], + true, false); + + $this->expect('"1+1"', + '"1+1"', + [], + true, false); + + $this->expect('"Hello world"', + '"Hello world"', + [], + true, false); + + $this->expect('%e^x', + '%e^x', + [], + true, false); + + $this->expect('2pi r^2', + '2*pi*r^2', + [], + true, false); + + $this->expect('2pir^2', + '2*pir^2', + [], + true, false); + + $this->expect("'diff(x,y)", + "'diff(x,y)", + [], + true, false); + + $this->expect("'int(x,y)", + "'int(x,y)", + [], + true, false); + + $this->expect('(()x)', + '(()*x)', + [], + true, false); + + $this->expect('((x))', + '((x))', + [], + true, false); + + $this->expect('()x', + '()*x', + [], + true, false); + + $this->expect('(+1)', + '(+1)', + [], + true, false); + + $this->expect('(-1)', + '(-1)', + [], + true, false); + + $this->expect('(-b+-sqrt(b^2))/(2*a)', + '(-b+-sqrt(b^2))/(2*a)', + [], + true, false); + + $this->expect('(-x)*y', + '(-x)*y', + [], + true, false); + + $this->expect('(1+i)*x', + '(1+i)*x', + [], + true, false); + + $this->expect('(1+i)+x', + '(1+i)+x', + [], + true, false); + + $this->expect('(a,b,c)', + '(a,b,c)', + [], + true, false); + + $this->expect('((a,b),c)', + '((a,b),c)', + [], + true, false); + + $this->expect('(a,(b,c))', + '(a,(b,c))', + [], + true, false); + + $this->expect('{(a,b),(x,y)}', + '{(a,b),(x,y)}', + [], + true, false); + + $this->expect('(a-b)-c', + '(a-b)-c', + [], + true, false); + + $this->expect('(x)', + '(x)', + [], + true, false); + + $this->expect('(x*y)*z', + '(x*y)*z', + [], + true, false); + + $this->expect('(x+2)(x+3)', + '(x+2)(x+3)', + [], + true, false); + + $this->expect('(x+2)3', + '(x+2)*3', + [], + true, false); + + $this->expect('(x+2)y', + '(x+2)*y', + [], + true, false); + + $this->expect('(x+y)+z', + '(x+y)+z', + [], + true, false); + + $this->expect('(x+y)^z', + '(x+y)^z', + [], + true, false); + + $this->expect('(x-y)+z', + '(x-y)+z', + [], + true, false); + + $this->expect('(x/y)/z', + '(x/y)/z', + [], + true, false); + + $this->expect('+-1', + '+-1', + [], + true, false); + + $this->expect('+0.2', + '+0.2', + [], + true, false); + + $this->expect('+1', + '+1', + [], + true, false); + + $this->expect('+e', + '+e', + [], + true, false); + + $this->expect('+i', + '+i', + [], + true, false); + + $this->expect('+pi', + '+pi', + [], + true, false); + + $this->expect('+x', + '+x', + [], + true, false); + + $this->expect('-(1/512) + i(sqrt(3)/512)', + '-(1/512)+i(sqrt(3)/512)', + [], + true, false); + + $this->expect('-1', + '-1', + [], + true, false); + + $this->expect('-1234', + '-1234', + [], + true, false); + + $this->expect('-0.2', + '-0.2', + [], + true, false); + + $this->expect('-10/-1', + '-10/-1', + [], + true, false); + + $this->expect('-3(x+1)', + '-3*(x+1)', + [], + true, false); + + $this->expect('-3+i', + '-3+i', + [], + true, false); + + $this->expect('-3x(1+x)', + '-3*x(1+x)', + [], + true, false); + + $this->expect('-b(5-b)', + '-b(5-b)', + [], + true, false); + + $this->expect('-e', + '-e', + [], + true, false); + + $this->expect('-i', + '-i', + [], + true, false); + + $this->expect('-pi', + '-pi', + [], + true, false); + + $this->expect('-x', + '-x', + [], + true, false); + + $this->expect('-x(1+x)', + '-x(1+x)', + [], + true, false); + + $this->expect('-x[3]', + '-x[3]', + [], + true, false); + + $this->expect('.1', + '.1', + [], + true, false); + + $this->expect('-0.2433 + 0.1111', + '-0.2433+0.1111', + [], + true, false); + + $this->expect('-0.2433e23 + 0.1111e-45 * 0.23e12 / -0.11e-11', + '-0.2433E23+0.1111E-45*0.23E12/-0.11E-11', + [], + true, false); + + $this->expect('-35.3 * 10^23', + '-35.3*10^23', + [], + true, false); + + $this->expect('0..1', + '0. . 1', + [], + true, false); + + $this->expect('0.1..1.2', + '0.1 . .1 . 2', + [], + true, false); + + $this->expect('0.1.1.2', + '0.1 . 1.2', + [], + true, false); + + $this->expect('0.1. 1.2', + '0.1 . 1.2', + [], + true, false); + + $this->expect('1', + '1', + [], + true, false); + + $this->expect('1234', + '1234', + [], + true, false); + + $this->expect('1 x', + '1*x', + [], + true, false); + + $this->expect('1+2i', + '1+2*i', + [], + true, false); + + $this->expect('1+i', + '1+i', + [], + true, false); + + $this->expect('1-x(1+x)', + '1-x(1+x)', + [], + true, false); + + $this->expect('1/0', + '1/0', + [], + true, false); + + $this->expect('1/2', + '1/2', + [], + true, false); + + $this->expect('1/sin(+x)', + '1/sin(+x)', + [], + true, false); + + $this->expect('1<=x<y^2', + '1 <= x < y^2', + [], + true, false); + + $this->expect('1<x<3', + '1 < x < 3', + [], + true, false); + + $this->expect('1E+3', + '1E+3', + [], + true, false); + + $this->expect('1E3', + '1E3', + [], + true, false); + + $this->expect('1 E 3', + '1*E*3', + [], + true, false); + + $this->expect('23.2*x*10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2 x 10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2x10^5', + '23.2*x10^5', + [], + true, false); + + $this->expect('23.2x 10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2 x10^5', + '23.2*x10^5', + [], + true, false); + + $this->expect('1E23*10^45', + '1E23*10^45', + [], + true, false); + + $this->expect('9.81x10^2*m/s', + '9.81*x10^2*m/s', + [], + true, false); + + $this->expect('9.81x*10^2*m/s', + '9.81*x*10^2*m/s', + [], + true, false); + + $this->expect('1x', + '1*x', + [], + true, false); + + $this->expect('2*e', + '2*e', + [], + true, false); + + $this->expect('2*i', + '2*i', + [], + true, false); + + $this->expect('2*i^3', + '2*i^3', + [], + true, false); + + $this->expect('2*pi', + '2*pi', + [], + true, false); + + $this->expect('2+3(x+1)', + '2+3*(x+1)', + [], + true, false); + + $this->expect('2+log_x(1/(x+b))*x^2', + '2+log_x(1/(x+b))*x^2', + [], + true, false); + + $this->expect('2/4', + '2/4', + [], + true, false); + + $this->expect('2^y*x', + '2^y*x', + [], + true, false); + + $this->expect('3(x+1)', + '3*(x+1)', + [], + true, false); + + $this->expect('3-i', + '3-i', + [], + true, false); + + $this->expect('3 5', + '3*5', + [], + true, false); + + $this->expect('3.14 5', + '3.14*5', + [], + true, false); + + $this->expect('3 5.2789', + '3*5.2789', + [], + true, false); + + $this->expect('3.14 5.2789', + '3.14*5.2789', + [], + true, false); + + $this->expect('33 578 32', + '33*578*32', + [], + true, false); + + $this->expect('9 8 7.6', + '9*8*7.6', + [], + true, false); + + $this->expect('9 8.5 7.6', + '9*8.5*7.6', + [], + true, false); + + $this->expect('3b+5/a(x)', + '3*b+5/a(x)', + [], + true, false); + + $this->expect('3beta_47', + '3*beta_47', + [], + true, false); + + $this->expect('3e-2', + '3E-2', + [], + true, false); + + $this->expect('3e2', + '3E2', + [], + true, false); + + $this->expect('3E2', + '3E2', + [], + true, false); + + $this->expect('7x(2+1)', + '7*x(2+1)', + [], + true, false); + + $this->expect('Bgcd(3,2)', + 'Bgcd(3,2)', + [], + true, false); + + $this->expect('In(x)', + 'In(x)', + [], + true, false); + + $this->expect('Sin(x)', + 'Sin(x)', + [], + true, false); + + $this->expect('3.75*Btu', + '3.75*Btu', + [], + true, false); + + $this->expect('X', + 'X', + [], + true, false); + + $this->expect('["a"]', + '["a"]', + [], + true, false); + + $this->expect('[+1,+2]', + '[+1,+2]', + [], + true, false); + + $this->expect('[-1,-2]', + '[-1,-2]', + [], + true, false); + + $this->expect('[1 < x,y < 1 or y > 7]', + '[1 < x,y < 1 or y > 7]', + [], + true, false); + + $this->expect('[1,+2]', + '[1,+2]', + [], + true, false); + + $this->expect('[1,-2]', + '[1,-2]', + [], + true, false); + + $this->expect('[1,2,3.4]', + '[1,2,3.4]', + [], + true, false); + + $this->expect('[1,true,"a"]', + '[1,true,"a"]', + [], + true, false); + + $this->expect('[1<x,1<y<3]', + '[1 < x,1 < y < 3]', + [], + true, false); + + $this->expect('[1<x,x<3]', + '[1 < x,x < 3]', + [], + true, false); + + $this->expect('[1]', + '[1]', + [], + true, false); + + $this->expect('[[1,2],[3,4]]', + '[[1,2],[3,4]]', + [], + true, false); + + $this->expect('[]', + '[]', + [], + true, false); + + $this->expect('[x, y, z ]', + '[x,y,z]', + [], + true, false); + + $this->expect('a ** b', + 'a**b', + [], + true, false); + + $this->expect('a +++ b', + 'a+++b', + [], + true, false); + + $this->expect('a --- b', + 'a---b', + [], + true, false); + + $this->expect('a(x)', + 'a(x)', + [], + true, false); + + $this->expect('a++b', + 'a++b', + [], + true, false); + + $this->expect('a+-b', + 'a+-b', + [], + true, false); + + $this->expect('a,b,c', + 'a,b=true,c=true', + [], + true, false); + + $this->expect('a-(b-c)', + 'a-(b-c)', + [], + true, false); + + $this->expect('a-+b', + 'a-+b', + [], + true, false); + + $this->expect('a/(a(x+1)+2)', + 'a/(a(x+1)+2)', + [], + true, false); + + $this->expect('a/b/c', + 'a/b/c', + [], + true, false); + + $this->expect('a1', + 'a1', + [], + true, false); + + $this->expect('a9b', + 'a9b', + [], + true, false); + + $this->expect('ab98cd', + 'ab98cd', + [], + true, false); + + $this->expect('aXy1', + 'aXy1', + [], + true, false); + + $this->expect('a[1,2]', + 'a[1,2]', + [], + true, false); + + $this->expect('a[2]', + 'a[2]', + [], + true, false); + + $this->expect('a[n+1]', + 'a[n+1]', + [], + true, false); + + $this->expect('a^-b', + 'a^-b', + [], + true, false); + + $this->expect('a^b', + 'a^b', + [], + true, false); + + $this->expect('a_b', + 'a_b', + [], + true, false); + + $this->expect('abs(13)', + 'abs(13)', + [], + true, false); + + $this->expect('abs(x)', + 'abs(x)', + [], + true, false); + + $this->expect('alpha', + 'alpha', + [], + true, false); + + $this->expect('arcsin(x)', + 'arcsin(x)', + [], + true, false); + + $this->expect('asin(x)', + 'asin(x)', + [], + true, false); + + $this->expect('asinh(x)', + 'asinh(x)', + [], + true, false); + + $this->expect('b(b+1)', + 'b(b+1)', + [], + true, false); + + $this->expect('b/a(x)', + 'b/a(x)', + [], + true, false); + + $this->expect('beta', + 'beta', + [], + true, false); + + $this->expect('beta_47', + 'beta_47', + [], + true, false); + + $this->expect('bsin(t)', + 'bsin(t)', + [], + true, false); + + $this->expect('ceiling(x)', + 'ceiling(x)', + [], + true, false); + + $this->expect('chi', + 'chi', + [], + true, false); + + $this->expect('comb(x,y)', + 'comb(x,y)', + [], + true, false); + + $this->expect('cos(2x)(x+1)', + 'cos(2*x)(x+1)', + [], + true, false); + + $this->expect('cos(x)', + 'cos(x)', + [], + true, false); + + $this->expect('cos^2(x)', + 'cos^2*(x)', + [], + true, false); + + $this->expect('cosec(x)', + 'cosec(x)', + [], + true, false); + + $this->expect('cosech(x)', + 'cosech(x)', + [], + true, false); + + $this->expect('cosh(x)', + 'cosh(x)', + [], + true, false); + + $this->expect('cot(x)', + 'cot(x)', + [], + true, false); + + $this->expect('coth(x)', + 'coth(x)', + [], + true, false); + + $this->expect('csc(6*x)^2*(7*sin(6*x)*cos(7*x)-6*cos(6*x)*sin(7*x))', + 'csc(6*x)^2*(7*sin(6*x)*cos(7*x)-6*cos(6*x)*sin(7*x))', + [], + true, false); + + $this->expect('csc(x)', + 'csc(x)', + [], + true, false); + + $this->expect('delta', + 'delta', + [], + true, false); + + $this->expect('diff(sin(x))', + 'diff(sin(x))', + [], + true, false); + + $this->expect('diff(sin(x),x)', + 'diff(sin(x),x)', + [], + true, false); + + $this->expect('diff(x,y)', + 'diff(x,y)', + [], + true, false); + + $this->expect('dosomething(x,y,z)', + 'dosomething(x,y,z)', + [], + true, false); + + $this->expect('e', + 'e', + [], + true, false); + + $this->expect('e*2', + 'e*2', + [], + true, false); + + $this->expect('e^x', + 'e^x', + [], + true, false); + + $this->expect('epsilon', + 'epsilon', + [], + true, false); + + $this->expect('eta', + 'eta', + [], + true, false); + + $this->expect('exp(x)', + 'exp(x)', + [], + true, false); + + $this->expect('f(x)', + 'f(x)', + [], + true, false); + + $this->expect('f(x)(2)', + 'f(x)(2)', + [], + true, false); + + $this->expect('fact(13)', + 'fact(13)', + [], + true, false); + + $this->expect('false', + 'false', + [], + true, false); + + $this->expect('floor(x)', + 'floor(x)', + [], + true, false); + + $this->expect('gamma', + 'gamma', + [], + true, false); + + $this->expect('gcd(x,y)', + 'gcd(x,y)', + [], + true, false); + + $this->expect('gcf(x,y)', + 'gcf(x,y)', + [], + true, false); + + $this->expect('i', + 'i', + [], + true, false); + + $this->expect('i(1+i)', + 'i(1+i)', + [], + true, false); + + $this->expect('i(4)', + 'i(4)', + [], + true, false); + + $this->expect('i*2', + 'i*2', + [], + true, false); + + $this->expect('inf', + 'inf', + [], + true, false); + + $this->expect('int(sin(x))', + 'int(sin(x))', + [], + true, false); + + $this->expect('int(x,y)', + 'int(x,y)', + [], + true, false); + + $this->expect('iota', + 'iota', + [], + true, false); + + $this->expect('j', + 'j', + [], + true, false); + + $this->expect('kappa', + 'kappa', + [], + true, false); + + $this->expect('lambda', + 'lambda', + [], + true, false); + + $this->expect('len(x)', + 'len(x)', + [], + true, false); + + $this->expect('length(x)', + 'length(x)', + [], + true, false); + + $this->expect('lg(10^3)', + 'lg(10^3)', + [], + true, false); + + $this->expect('lg(x)', + 'lg(x)', + [], + true, false); + + $this->expect('lg(x,a)', + 'lg(x,a)', + [], + true, false); + + $this->expect('limit(y,x,3)', + 'limit(y,x,3)', + [], + true, false); + + $this->expect('ln(x)', + 'ln(x)', + [], + true, false); + + $this->expect('ln*x', + 'ln*x', + [], + true, false); + + $this->expect('log(2x)/x+1/2', + 'log(2*x)/x+1/2', + [], + true, false); + + $this->expect('log(x)', + 'log(x)', + [], + true, false); + + $this->expect('log10(x)', + 'log10(x)', + [], + true, false); + + $this->expect('log_10(x)', + 'log_10(x)', + [], + true, false); + + $this->expect('log_2(a)', + 'log_2(a)', + [], + true, false); + + $this->expect('log_a(b)*log_b(c)', + 'log_a(b)*log_b(c)', + [], + true, false); + + $this->expect('log_x(1/(x+b))', + 'log_x(1/(x+b))', + [], + true, false); + + $this->expect('log_x:log_x(a)', + 'log_x:log_x(a)', + [], + true, false); + + $this->expect('matrix([a,b],[c,d])', + 'matrix([a,b],[c,d])', + [], + true, false); + + $this->expect('mod(x,y)', + 'mod(x,y)', + [], + true, false); + + $this->expect('mu', + 'mu', + [], + true, false); + + $this->expect('not x', + 'not x', + [], + true, false); + + $this->expect('nu', + 'nu', + [], + true, false); + + $this->expect('omega', + 'omega', + [], + true, false); + + $this->expect('omicron', + 'omicron', + [], + true, false); + + $this->expect('p=?*s', + 'p = QMCHAR*s', + [], + true, false); + + $this->expect('partialdiff(x,y,1)', + 'partialdiff(x,y,1)', + [], + true, false); + + $this->expect('perm(x,y)', + 'perm(x,y)', + [], + true, false); + + $this->expect('phi', + 'phi', + [], + true, false); + + $this->expect('pi', + 'pi', + [], + true, false); + + $this->expect('pi*2', + 'pi*2', + [], + true, false); + + $this->expect('plot(x^2,[x,-1,1])', + 'plot(x^2,[x,-1,1])', + [], + true, false); + + $this->expect('plot2d(x^2,[x,-1,1])', + 'plot2d(x^2,[x,-1,1])', + [], + true, false); + + $this->expect('product(cos(k*x),k,1,3)', + 'product(cos(k*x),k,1,3)', + [], + true, false); + + $this->expect('psi', + 'psi', + [], + true, false); + + $this->expect('rho', + 'rho', + [], + true, false); + + $this->expect('rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', + 'rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', + [], + true, false); + + $this->expect('root(2,-3)', + 'root(2,-3)', + [], + true, false); + + $this->expect('root(x)', + 'root(x)', + [], + true, false); + + $this->expect('root(x,3)', + 'root(x,3)', + [], + true, false); + + $this->expect('sec(x)', + 'sec(x)', + [], + true, false); + + $this->expect('sech(x)', + 'sech(x)', + [], + true, false); + + $this->expect('set(x, y, z)', + 'set(x,y,z)', + [], + true, false); + + $this->expect('sgn(x)', + 'sgn(x)', + [], + true, false); + + $this->expect('sigma', + 'sigma', + [], + true, false); + + $this->expect('sign(x)', + 'sign(x)', + [], + true, false); + + $this->expect('sim(x)', + 'sim(x)', + [], + true, false); + + $this->expect('sin', + 'sin', + [], + true, false); + + $this->expect('sin x', + 'sin*x', + [], + true, false); + + $this->expect('sin(x)', + 'sin(x)', + [], + true, false); + + $this->expect('sin*2*x', + 'sin*2*x', + [], + true, false); + + $this->expect('sin[2*x]', + 'sin[2*x]', + [], + true, false); + + $this->expect('sin^-1(x)', + 'sin^-1*(x)', + [], + true, false); + + $this->expect('sinh(x)', + 'sinh(x)', + [], + true, false); + + $this->expect('sqr(x)', + 'sqr(x)', + [], + true, false); + + $this->expect('sqrt(+x)', + 'sqrt(+x)', + [], + true, false); + + $this->expect('sqrt(x)', + 'sqrt(x)', + [], + true, false); + + $this->expect('stackvector(a)', + 'stackvector(a)', + [], + true, false); + + $this->expect('sum(k^n,n,0,3)', + 'sum(k^n,n,0,3)', + [], + true, false); + + $this->expect('switch(x,a,y,b,c)', + 'switch(x,a,y,b,c)', + [], + true, false); + + $this->expect('tan(x)', + 'tan(x)', + [], + true, false); + + $this->expect('tanh(x)', + 'tanh(x)', + [], + true, false); + + $this->expect('tau', + 'tau', + [], + true, false); + + $this->expect('theta', + 'theta', + [], + true, false); + + $this->expect('true', + 'true', + [], + true, false); + + $this->expect('upsilon', + 'upsilon', + [], + true, false); + + $this->expect('x', + 'x', + [], + true, false); + + $this->expect('x * y', + 'x*y', + [], + true, false); + + $this->expect('x + 1', + 'x+1', + [], + true, false); + + $this->expect('x + y', + 'x+y', + [], + true, false); + + $this->expect('x - y', + 'x-y', + [], + true, false); + + $this->expect('x / y', + 'x/y', + [], + true, false); + + $this->expect('x < y', + 'x < y', + [], + true, false); + + $this->expect('x <= y', + 'x <= y', + [], + true, false); + + $this->expect('x = y', + 'x = y', + [], + true, false); + + $this->expect('x > y', + 'x > y', + [], + true, false); + + $this->expect('x >= y', + 'x >= y', + [], + true, false); + + $this->expect('x ^ y', + 'x^y', + [], + true, false); + + $this->expect('x and', + 'x*and', + [], + true, false); + + $this->expect('x and y', + 'x and y', + [], + true, false); + + $this->expect('x divides y', + 'x*divides*y', + [], + true, false); + + $this->expect('x or y', + 'x or y', + [], + true, false); + + $this->expect('x xor y', + 'x xor y', + [], + true, false); + + $this->expect('x y', + 'x*y', + [], + true, false); + + $this->expect('x!', + 'x!', + [], + true, false); + + $this->expect('x()', + 'x()', + [], + true, false); + + $this->expect('x(2+1)', + 'x(2+1)', + [], + true, false); + + $this->expect('x(sin(t)+1)', + 'x(sin(t)+1)', + [], + true, false); + + $this->expect('x(t+1)', + 'x(t+1)', + [], + true, false); + + $this->expect('x(x+1)', + 'x(x+1)', + [], + true, false); + + $this->expect('x*(-y)', + 'x*(-y)', + [], + true, false); + + $this->expect('x*(y*z)', + 'x*(y*z)', + [], + true, false); + + $this->expect('x*2^y', + 'x*2^y', + [], + true, false); + + $this->expect('x*divides*y', + 'x*divides*y', + [], + true, false); + + $this->expect('x*i^3', + 'x*i^3', + [], + true, false); + + $this->expect('x*y*z', + 'x*y*z', + [], + true, false); + + $this->expect('x*y^z', + 'x*y^z', + [], + true, false); + + $this->expect('x+ 1', + 'x+1', + [], + true, false); + + $this->expect('x+(y+z)', + 'x+(y+z)', + [], + true, false); + + $this->expect('x+(y^z)', + 'x+(y^z)', + [], + true, false); + + $this->expect('x+1', + 'x+1', + [], + true, false); + + $this->expect('x+y+z', + 'x+y+z', + [], + true, false); + + $this->expect('x-(y+z)', + 'x-(y+z)', + [], + true, false); + + $this->expect('x/(y+z)', + 'x/(y+z)', + [], + true, false); + + $this->expect('x/(y/z)', + 'x/(y/z)', + [], + true, false); + + $this->expect('x/y/z', + 'x/y/z', + [], + true, false); + + $this->expect('x1', + 'x1', + [], + true, false); + + $this->expect('x<1 and x>1', + 'x < 1 and x > 1', + [], + true, false); + + $this->expect('x=+-sqrt(2)', + 'x = +-sqrt(2)', + [], + true, false); + + $this->expect('x=1 or 2', + 'x = 1 or 2', + [], + true, false); + + $this->expect('x=1 or 2 or 3', + 'x = 1 or 2 or 3', + [], + true, false); + + $this->expect('x=1 or x=2', + 'x = 1 or x = 2', + [], + true, false); + + $this->expect('x>1 or (x<1 and t<sin(x))', + 'x > 1 or (x < 1 and t < sin(x))', + [], + true, false); + + $this->expect('x^(-(y+z))', + 'x^(-(y+z))', + [], + true, false); + + $this->expect('x^(-y)', + 'x^(-y)', + [], + true, false); + + $this->expect('x^(y+z)', + 'x^(y+z)', + [], + true, false); + + $this->expect('x^(y/z)', + 'x^(y/z)', + [], + true, false); + + $this->expect('x^-1', + 'x^-1', + [], + true, false); + + $this->expect('x^-y', + 'x^-y', + [], + true, false); + + $this->expect('x^7/7-2*x^6/3-4*x^3/3', + 'x^7/7-2*x^6/3-4*x^3/3', + [], + true, false); + + $this->expect('x^f(x)', + 'x^f(x)', + [], + true, false); + + $this->expect('x^y', + 'x^y', + [], + true, false); + + $this->expect('x^y^z', + 'x^y^z', + [], + true, false); + + $this->expect('x_1', + 'x_1', + [], + true, false); + + $this->expect('Xy_12', + 'Xy_12', + [], + true, false); + + $this->expect('x_y', + 'x_y', + [], + true, false); + + $this->expect('x_y_z', + 'x_y_z', + [], + true, false); + + $this->expect('x_y_1', + 'x_y_1', + [], + true, false); + + $this->expect('x_12_z', + 'x_12_z', + [], + true, false); + + $this->expect('xy_zw', + 'xy_zw', + [], + true, false); + + $this->expect('xy_12', + 'xy_12', + [], + true, false); + + $this->expect('M_2*x^2+M_1*x+M_0', + 'M_2*x^2+M_1*x+M_0', + [], + true, false); + + $this->expect('xi', + 'xi', + [], + true, false); + + $this->expect('xsin(1)', + 'xsin(1)', + [], + true, false); + + $this->expect('xy', + 'xy', + [], + true, false); + + $this->expect('y^2-2*y-0.5', + 'y^2-2*y-0.5', + [], + true, false); + + $this->expect('y^2-2*y-8', + 'y^2-2*y-8', + [], + true, false); + + $this->expect('y^3-2*y^2-8*y', + 'y^3-2*y^2-8*y', + [], + true, false); + + $this->expect('y^z * x', + 'y^z*x', + [], + true, false); + + $this->expect('ycos(2)', + 'ycos(2)', + [], + true, false); + + $this->expect('zeta', + 'zeta', + [], + true, false); + + $this->expect('{1,2,3.4}', + '{1,2,3.4}', + [], + true, false); + + $this->expect('{1}', + '{1}', + [], + true, false); + + $this->expect('{x, y, z }', + '{x,y,z}', + [], + true, false); + + $this->expect('{}', + '{}', + [], + true, false); + + $this->expect('|x|', + 'abs(x)', + [], + true, false); + + $this->expect('rand(["+","-"])(x,y)', + 'rand(["+","-"])(x,y)', + [], + true, false); + + $this->expect('rand(["sin","cos","system"])(x)', + 'rand(["sin","cos","system"])(x)', + [], + true, false); + + $this->expect('1.2*m**2', + '1.2*m**2', + [], + true, false); + + $this->expect('1.2*mˆ2', + '1.2*m^2', + [], + true, false); + + $this->expect('/* Comment */x+1', + '/* Comment */x+1', + [], + true, false); + + $this->expect('/* Comment **/x+1', + '/* Comment **/x+1', + [], + true, false); + + $this->expect('/** Comment */x+1', + '/** Comment */x+1', + [], + true, false); + + $this->expect('/** Comment **/x+1', + '/** Comment **/x+1', + [], + true, false); + + $this->expect('/*@ Comment @*/x+1', + '/*@ Comment @*/x+1', + [], + true, false); + + $this->expect('"A string that needs sanitising <script>bad stuff</script>."', + '"A string that needs sanitising <script>bad stuff</script>."', + [], + true, false); + + } + + public function test_non_affected_no_units() { + $this->security = new stack_cas_security(false); + $this->filter = stack_parsing_rule_factory::get_by_common_name('033_no_extra_evaluation'); + + $this->expect('"+"(a,b)', + '"+"(a,b)', + [], + true, false); + + $this->expect('"1+1"', + '"1+1"', + [], + true, false); + + $this->expect('"Hello world"', + '"Hello world"', + [], + true, false); + + $this->expect('%e^x', + '%e^x', + [], + true, false); + + $this->expect('2pi r^2', + '2*pi*r^2', + [], + true, false); + + $this->expect('2pir^2', + '2*pir^2', + [], + true, false); + + $this->expect("'diff(x,y)", + "'diff(x,y)", + [], + true, false); + + $this->expect("'int(x,y)", + "'int(x,y)", + [], + true, false); + + $this->expect('(()x)', + '(()*x)', + [], + true, false); + + $this->expect('((x))', + '((x))', + [], + true, false); + + $this->expect('()x', + '()*x', + [], + true, false); + + $this->expect('(+1)', + '(+1)', + [], + true, false); + + $this->expect('(-1)', + '(-1)', + [], + true, false); + + $this->expect('(-b+-sqrt(b^2))/(2*a)', + '(-b+-sqrt(b^2))/(2*a)', + [], + true, false); + + $this->expect('(-x)*y', + '(-x)*y', + [], + true, false); + + $this->expect('(1+i)*x', + '(1+i)*x', + [], + true, false); + + $this->expect('(1+i)+x', + '(1+i)+x', + [], + true, false); + + $this->expect('(a,b,c)', + '(a,b,c)', + [], + true, false); + + $this->expect('((a,b),c)', + '((a,b),c)', + [], + true, false); + + $this->expect('(a,(b,c))', + '(a,(b,c))', + [], + true, false); + + $this->expect('{(a,b),(x,y)}', + '{(a,b),(x,y)}', + [], + true, false); + + $this->expect('(a-b)-c', + '(a-b)-c', + [], + true, false); + + $this->expect('(x)', + '(x)', + [], + true, false); + + $this->expect('(x*y)*z', + '(x*y)*z', + [], + true, false); + + $this->expect('(x+2)(x+3)', + '(x+2)(x+3)', + [], + true, false); + + $this->expect('(x+2)3', + '(x+2)*3', + [], + true, false); + + $this->expect('(x+2)y', + '(x+2)*y', + [], + true, false); + + $this->expect('(x+y)+z', + '(x+y)+z', + [], + true, false); + + $this->expect('(x+y)^z', + '(x+y)^z', + [], + true, false); + + $this->expect('(x-y)+z', + '(x-y)+z', + [], + true, false); + + $this->expect('(x/y)/z', + '(x/y)/z', + [], + true, false); + + $this->expect('+-1', + '+-1', + [], + true, false); + + $this->expect('+0.2', + '+0.2', + [], + true, false); + + $this->expect('+1', + '+1', + [], + true, false); + + $this->expect('+e', + '+e', + [], + true, false); + + $this->expect('+i', + '+i', + [], + true, false); + + $this->expect('+pi', + '+pi', + [], + true, false); + + $this->expect('+x', + '+x', + [], + true, false); + + $this->expect('-(1/512) + i(sqrt(3)/512)', + '-(1/512)+i(sqrt(3)/512)', + [], + true, false); + + $this->expect('-1', + '-1', + [], + true, false); + + $this->expect('-1234', + '-1234', + [], + true, false); + + $this->expect('-0.2', + '-0.2', + [], + true, false); + + $this->expect('-10/-1', + '-10/-1', + [], + true, false); + + $this->expect('-3(x+1)', + '-3*(x+1)', + [], + true, false); + + $this->expect('-3+i', + '-3+i', + [], + true, false); + + $this->expect('-3x(1+x)', + '-3*x(1+x)', + [], + true, false); + + $this->expect('-b(5-b)', + '-b(5-b)', + [], + true, false); + + $this->expect('-e', + '-e', + [], + true, false); + + $this->expect('-i', + '-i', + [], + true, false); + + $this->expect('-pi', + '-pi', + [], + true, false); + + $this->expect('-x', + '-x', + [], + true, false); + + $this->expect('-x(1+x)', + '-x(1+x)', + [], + true, false); + + $this->expect('-x[3]', + '-x[3]', + [], + true, false); + + $this->expect('.1', + '.1', + [], + true, false); + + $this->expect('-0.2433 + 0.1111', + '-0.2433+0.1111', + [], + true, false); + + $this->expect('-0.2433e23 + 0.1111e-45 * 0.23e12 / -0.11e-11', + '-0.2433E23+0.1111E-45*0.23E12/-0.11E-11', + [], + true, false); + + $this->expect('-35.3 * 10^23', + '-35.3*10^23', + [], + true, false); + + $this->expect('0..1', + '0. . 1', + [], + true, false); + + $this->expect('0.1..1.2', + '0.1 . .1 . 2', + [], + true, false); + + $this->expect('0.1.1.2', + '0.1 . 1.2', + [], + true, false); + + $this->expect('0.1. 1.2', + '0.1 . 1.2', + [], + true, false); + + $this->expect('1', + '1', + [], + true, false); + + $this->expect('1234', + '1234', + [], + true, false); + + $this->expect('1 x', + '1*x', + [], + true, false); + + $this->expect('1+2i', + '1+2*i', + [], + true, false); + + $this->expect('1+i', + '1+i', + [], + true, false); + + $this->expect('1-x(1+x)', + '1-x(1+x)', + [], + true, false); + + $this->expect('1/0', + '1/0', + [], + true, false); + + $this->expect('1/2', + '1/2', + [], + true, false); + + $this->expect('1/sin(+x)', + '1/sin(+x)', + [], + true, false); + + $this->expect('1<=x<y^2', + '1 <= x < y^2', + [], + true, false); + + $this->expect('1<x<3', + '1 < x < 3', + [], + true, false); + + $this->expect('1E+3', + '1E+3', + [], + true, false); + + $this->expect('1E3', + '1E3', + [], + true, false); + + $this->expect('1 E 3', + '1*E*3', + [], + true, false); + + $this->expect('23.2*x*10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2 x 10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2x10^5', + '23.2*x10^5', + [], + true, false); + + $this->expect('23.2x 10^5', + '23.2*x*10^5', + [], + true, false); + + $this->expect('23.2 x10^5', + '23.2*x10^5', + [], + true, false); + + $this->expect('1E23*10^45', + '1E23*10^45', + [], + true, false); + + $this->expect('9.81x10^2*m/s', + '9.81*x10^2*m/s', + [], + true, false); + + $this->expect('9.81x*10^2*m/s', + '9.81*x*10^2*m/s', + [], + true, false); + + $this->expect('1x', + '1*x', + [], + true, false); + + $this->expect('2*e', + '2*e', + [], + true, false); + + $this->expect('2*i', + '2*i', + [], + true, false); + + $this->expect('2*i^3', + '2*i^3', + [], + true, false); + + $this->expect('2*pi', + '2*pi', + [], + true, false); + + $this->expect('2+3(x+1)', + '2+3*(x+1)', + [], + true, false); + + $this->expect('2+log_x(1/(x+b))*x^2', + '2+log_x(1/(x+b))*x^2', + [], + true, false); + + $this->expect('2/4', + '2/4', + [], + true, false); + + $this->expect('2^y*x', + '2^y*x', + [], + true, false); + + $this->expect('3(x+1)', + '3*(x+1)', + [], + true, false); + + $this->expect('3-i', + '3-i', + [], + true, false); + + $this->expect('3 5', + '3*5', + [], + true, false); + + $this->expect('3.14 5', + '3.14*5', + [], + true, false); + + $this->expect('3 5.2789', + '3*5.2789', + [], + true, false); + + $this->expect('3.14 5.2789', + '3.14*5.2789', + [], + true, false); + + $this->expect('33 578 32', + '33*578*32', + [], + true, false); + + $this->expect('9 8 7.6', + '9*8*7.6', + [], + true, false); + + $this->expect('9 8.5 7.6', + '9*8.5*7.6', + [], + true, false); + + $this->expect('3b+5/a(x)', + '3*b+5/a(x)', + [], + true, false); + + $this->expect('3beta_47', + '3*beta_47', + [], + true, false); + + $this->expect('3e-2', + '3E-2', + [], + true, false); + + $this->expect('3e2', + '3E2', + [], + true, false); + + $this->expect('3E2', + '3E2', + [], + true, false); + + $this->expect('7x(2+1)', + '7*x(2+1)', + [], + true, false); + + $this->expect('Bgcd(3,2)', + 'Bgcd(3,2)', + [], + true, false); + + $this->expect('In(x)', + 'In(x)', + [], + true, false); + + $this->expect('Sin(x)', + 'Sin(x)', + [], + true, false); + + $this->expect('3.75*Btu', + '3.75*Btu', + [], + true, false); + + $this->expect('X', + 'X', + [], + true, false); + + $this->expect('["a"]', + '["a"]', + [], + true, false); + + $this->expect('[+1,+2]', + '[+1,+2]', + [], + true, false); + + $this->expect('[-1,-2]', + '[-1,-2]', + [], + true, false); + + $this->expect('[1 < x,y < 1 or y > 7]', + '[1 < x,y < 1 or y > 7]', + [], + true, false); + + $this->expect('[1,+2]', + '[1,+2]', + [], + true, false); + + $this->expect('[1,-2]', + '[1,-2]', + [], + true, false); + + $this->expect('[1,2,3.4]', + '[1,2,3.4]', + [], + true, false); + + $this->expect('[1,true,"a"]', + '[1,true,"a"]', + [], + true, false); + + $this->expect('[1<x,1<y<3]', + '[1 < x,1 < y < 3]', + [], + true, false); + + $this->expect('[1<x,x<3]', + '[1 < x,x < 3]', + [], + true, false); + + $this->expect('[1]', + '[1]', + [], + true, false); + + $this->expect('[[1,2],[3,4]]', + '[[1,2],[3,4]]', + [], + true, false); + + $this->expect('[]', + '[]', + [], + true, false); + + $this->expect('[x, y, z ]', + '[x,y,z]', + [], + true, false); + + $this->expect('a ** b', + 'a**b', + [], + true, false); + + $this->expect('a +++ b', + 'a+++b', + [], + true, false); + + $this->expect('a --- b', + 'a---b', + [], + true, false); + + $this->expect('a(x)', + 'a(x)', + [], + true, false); + + $this->expect('a++b', + 'a++b', + [], + true, false); + + $this->expect('a+-b', + 'a+-b', + [], + true, false); + + $this->expect('a,b,c', + 'a,b=true,c=true', + [], + true, false); + + $this->expect('a-(b-c)', + 'a-(b-c)', + [], + true, false); + + $this->expect('a-+b', + 'a-+b', + [], + true, false); + + $this->expect('a/(a(x+1)+2)', + 'a/(a(x+1)+2)', + [], + true, false); + + $this->expect('a/b/c', + 'a/b/c', + [], + true, false); + + $this->expect('a1', + 'a1', + [], + true, false); + + $this->expect('a9b', + 'a9b', + [], + true, false); + + $this->expect('ab98cd', + 'ab98cd', + [], + true, false); + + $this->expect('aXy1', + 'aXy1', + [], + true, false); + + $this->expect('a[1,2]', + 'a[1,2]', + [], + true, false); + + $this->expect('a[2]', + 'a[2]', + [], + true, false); + + $this->expect('a[n+1]', + 'a[n+1]', + [], + true, false); + + $this->expect('a^-b', + 'a^-b', + [], + true, false); + + $this->expect('a^b', + 'a^b', + [], + true, false); + + $this->expect('a_b', + 'a_b', + [], + true, false); + + $this->expect('abs(13)', + 'abs(13)', + [], + true, false); + + $this->expect('abs(x)', + 'abs(x)', + [], + true, false); + + $this->expect('alpha', + 'alpha', + [], + true, false); + + $this->expect('arcsin(x)', + 'arcsin(x)', + [], + true, false); + + $this->expect('asin(x)', + 'asin(x)', + [], + true, false); + + $this->expect('asinh(x)', + 'asinh(x)', + [], + true, false); + + $this->expect('b(b+1)', + 'b(b+1)', + [], + true, false); + + $this->expect('b/a(x)', + 'b/a(x)', + [], + true, false); + + $this->expect('beta', + 'beta', + [], + true, false); + + $this->expect('beta_47', + 'beta_47', + [], + true, false); + + $this->expect('bsin(t)', + 'bsin(t)', + [], + true, false); + + $this->expect('ceiling(x)', + 'ceiling(x)', + [], + true, false); + + $this->expect('chi', + 'chi', + [], + true, false); + + $this->expect('comb(x,y)', + 'comb(x,y)', + [], + true, false); + + $this->expect('cos(2x)(x+1)', + 'cos(2*x)(x+1)', + [], + true, false); + + $this->expect('cos(x)', + 'cos(x)', + [], + true, false); + + $this->expect('cos^2(x)', + 'cos^2*(x)', + [], + true, false); + + $this->expect('cosec(x)', + 'cosec(x)', + [], + true, false); + + $this->expect('cosech(x)', + 'cosech(x)', + [], + true, false); + + $this->expect('cosh(x)', + 'cosh(x)', + [], + true, false); + + $this->expect('cot(x)', + 'cot(x)', + [], + true, false); + + $this->expect('coth(x)', + 'coth(x)', + [], + true, false); + + $this->expect('csc(6*x)^2*(7*sin(6*x)*cos(7*x)-6*cos(6*x)*sin(7*x))', + 'csc(6*x)^2*(7*sin(6*x)*cos(7*x)-6*cos(6*x)*sin(7*x))', + [], + true, false); + + $this->expect('csc(x)', + 'csc(x)', + [], + true, false); + + $this->expect('delta', + 'delta', + [], + true, false); + + $this->expect('diff(sin(x))', + 'diff(sin(x))', + [], + true, false); + + $this->expect('diff(sin(x),x)', + 'diff(sin(x),x)', + [], + true, false); + + $this->expect('diff(x,y)', + 'diff(x,y)', + [], + true, false); + + $this->expect('dosomething(x,y,z)', + 'dosomething(x,y,z)', + [], + true, false); + + $this->expect('e', + 'e', + [], + true, false); + + $this->expect('e*2', + 'e*2', + [], + true, false); + + $this->expect('e^x', + 'e^x', + [], + true, false); + + $this->expect('epsilon', + 'epsilon', + [], + true, false); + + $this->expect('eta', + 'eta', + [], + true, false); + + $this->expect('exp(x)', + 'exp(x)', + [], + true, false); + + $this->expect('f(x)', + 'f(x)', + [], + true, false); + + $this->expect('f(x)(2)', + 'f(x)(2)', + [], + true, false); + + $this->expect('fact(13)', + 'fact(13)', + [], + true, false); + + $this->expect('false', + 'false', + [], + true, false); + + $this->expect('floor(x)', + 'floor(x)', + [], + true, false); + + $this->expect('gamma', + 'gamma', + [], + true, false); + + $this->expect('gcd(x,y)', + 'gcd(x,y)', + [], + true, false); + + $this->expect('gcf(x,y)', + 'gcf(x,y)', + [], + true, false); + + $this->expect('i', + 'i', + [], + true, false); + + $this->expect('i(1+i)', + 'i(1+i)', + [], + true, false); + + $this->expect('i(4)', + 'i(4)', + [], + true, false); + + $this->expect('i*2', + 'i*2', + [], + true, false); + + $this->expect('inf', + 'inf', + [], + true, false); + + $this->expect('int(sin(x))', + 'int(sin(x))', + [], + true, false); + + $this->expect('int(x,y)', + 'int(x,y)', + [], + true, false); + + $this->expect('iota', + 'iota', + [], + true, false); + + $this->expect('j', + 'j', + [], + true, false); + + $this->expect('kappa', + 'kappa', + [], + true, false); + + $this->expect('lambda', + 'lambda', + [], + true, false); + + $this->expect('len(x)', + 'len(x)', + [], + true, false); + + $this->expect('length(x)', + 'length(x)', + [], + true, false); + + $this->expect('lg(10^3)', + 'lg(10^3)', + [], + true, false); + + $this->expect('lg(x)', + 'lg(x)', + [], + true, false); + + $this->expect('lg(x,a)', + 'lg(x,a)', + [], + true, false); + + $this->expect('limit(y,x,3)', + 'limit(y,x,3)', + [], + true, false); + + $this->expect('ln(x)', + 'ln(x)', + [], + true, false); + + $this->expect('ln*x', + 'ln*x', + [], + true, false); + + $this->expect('log(2x)/x+1/2', + 'log(2*x)/x+1/2', + [], + true, false); + + $this->expect('log(x)', + 'log(x)', + [], + true, false); + + $this->expect('log10(x)', + 'log10(x)', + [], + true, false); + + $this->expect('log_10(x)', + 'log_10(x)', + [], + true, false); + + $this->expect('log_2(a)', + 'log_2(a)', + [], + true, false); + + $this->expect('log_a(b)*log_b(c)', + 'log_a(b)*log_b(c)', + [], + true, false); + + $this->expect('log_x(1/(x+b))', + 'log_x(1/(x+b))', + [], + true, false); + + $this->expect('log_x:log_x(a)', + 'log_x:log_x(a)', + [], + true, false); + + $this->expect('matrix([a,b],[c,d])', + 'matrix([a,b],[c,d])', + [], + true, false); + + $this->expect('mod(x,y)', + 'mod(x,y)', + [], + true, false); + + $this->expect('mu', + 'mu', + [], + true, false); + + $this->expect('not x', + 'not x', + [], + true, false); + + $this->expect('nu', + 'nu', + [], + true, false); + + $this->expect('omega', + 'omega', + [], + true, false); + + $this->expect('omicron', + 'omicron', + [], + true, false); + + $this->expect('p=?*s', + 'p = QMCHAR*s', + [], + true, false); + + $this->expect('partialdiff(x,y,1)', + 'partialdiff(x,y,1)', + [], + true, false); + + $this->expect('perm(x,y)', + 'perm(x,y)', + [], + true, false); + + $this->expect('phi', + 'phi', + [], + true, false); + + $this->expect('pi', + 'pi', + [], + true, false); + + $this->expect('pi*2', + 'pi*2', + [], + true, false); + + $this->expect('plot(x^2,[x,-1,1])', + 'plot(x^2,[x,-1,1])', + [], + true, false); + + $this->expect('plot2d(x^2,[x,-1,1])', + 'plot2d(x^2,[x,-1,1])', + [], + true, false); + + $this->expect('product(cos(k*x),k,1,3)', + 'product(cos(k*x),k,1,3)', + [], + true, false); + + $this->expect('psi', + 'psi', + [], + true, false); + + $this->expect('rho', + 'rho', + [], + true, false); + + $this->expect('rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', + 'rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', + [], + true, false); + + $this->expect('root(2,-3)', + 'root(2,-3)', + [], + true, false); + + $this->expect('root(x)', + 'root(x)', + [], + true, false); + + $this->expect('root(x,3)', + 'root(x,3)', + [], + true, false); + + $this->expect('sec(x)', + 'sec(x)', + [], + true, false); + + $this->expect('sech(x)', + 'sech(x)', + [], + true, false); + + $this->expect('set(x, y, z)', + 'set(x,y,z)', + [], + true, false); + + $this->expect('sgn(x)', + 'sgn(x)', + [], + true, false); + + $this->expect('sigma', + 'sigma', + [], + true, false); + + $this->expect('sign(x)', + 'sign(x)', + [], + true, false); + + $this->expect('sim(x)', + 'sim(x)', + [], + true, false); + + $this->expect('sin', + 'sin', + [], + true, false); + + $this->expect('sin x', + 'sin*x', + [], + true, false); + + $this->expect('sin(x)', + 'sin(x)', + [], + true, false); + + $this->expect('sin*2*x', + 'sin*2*x', + [], + true, false); + + $this->expect('sin[2*x]', + 'sin[2*x]', + [], + true, false); + + $this->expect('sin^-1(x)', + 'sin^-1*(x)', + [], + true, false); + + $this->expect('sinh(x)', + 'sinh(x)', + [], + true, false); + + $this->expect('sqr(x)', + 'sqr(x)', + [], + true, false); + + $this->expect('sqrt(+x)', + 'sqrt(+x)', + [], + true, false); + + $this->expect('sqrt(x)', + 'sqrt(x)', + [], + true, false); + + $this->expect('stackvector(a)', + 'stackvector(a)', + [], + true, false); + + $this->expect('sum(k^n,n,0,3)', + 'sum(k^n,n,0,3)', + [], + true, false); + + $this->expect('switch(x,a,y,b,c)', + 'switch(x,a,y,b,c)', + [], + true, false); + + $this->expect('tan(x)', + 'tan(x)', + [], + true, false); + + $this->expect('tanh(x)', + 'tanh(x)', + [], + true, false); + + $this->expect('tau', + 'tau', + [], + true, false); + + $this->expect('theta', + 'theta', + [], + true, false); + + $this->expect('true', + 'true', + [], + true, false); + + $this->expect('upsilon', + 'upsilon', + [], + true, false); + + $this->expect('x', + 'x', + [], + true, false); + + $this->expect('x * y', + 'x*y', + [], + true, false); + + $this->expect('x + 1', + 'x+1', + [], + true, false); + + $this->expect('x + y', + 'x+y', + [], + true, false); + + $this->expect('x - y', + 'x-y', + [], + true, false); + + $this->expect('x / y', + 'x/y', + [], + true, false); + + $this->expect('x < y', + 'x < y', + [], + true, false); + + $this->expect('x <= y', + 'x <= y', + [], + true, false); + + $this->expect('x = y', + 'x = y', + [], + true, false); + + $this->expect('x > y', + 'x > y', + [], + true, false); + + $this->expect('x >= y', + 'x >= y', + [], + true, false); + + $this->expect('x ^ y', + 'x^y', + [], + true, false); + + $this->expect('x and', + 'x*and', + [], + true, false); + + $this->expect('x and y', + 'x and y', + [], + true, false); + + $this->expect('x divides y', + 'x*divides*y', + [], + true, false); + + $this->expect('x or y', + 'x or y', + [], + true, false); + + $this->expect('x xor y', + 'x xor y', + [], + true, false); + + $this->expect('x y', + 'x*y', + [], + true, false); + + $this->expect('x!', + 'x!', + [], + true, false); + + $this->expect('x()', + 'x()', + [], + true, false); + + $this->expect('x(2+1)', + 'x(2+1)', + [], + true, false); + + $this->expect('x(sin(t)+1)', + 'x(sin(t)+1)', + [], + true, false); + + $this->expect('x(t+1)', + 'x(t+1)', + [], + true, false); + + $this->expect('x(x+1)', + 'x(x+1)', + [], + true, false); + + $this->expect('x*(-y)', + 'x*(-y)', + [], + true, false); + + $this->expect('x*(y*z)', + 'x*(y*z)', + [], + true, false); + + $this->expect('x*2^y', + 'x*2^y', + [], + true, false); + + $this->expect('x*divides*y', + 'x*divides*y', + [], + true, false); + + $this->expect('x*i^3', + 'x*i^3', + [], + true, false); + + $this->expect('x*y*z', + 'x*y*z', + [], + true, false); + + $this->expect('x*y^z', + 'x*y^z', + [], + true, false); + + $this->expect('x+ 1', + 'x+1', + [], + true, false); + + $this->expect('x+(y+z)', + 'x+(y+z)', + [], + true, false); + + $this->expect('x+(y^z)', + 'x+(y^z)', + [], + true, false); + + $this->expect('x+1', + 'x+1', + [], + true, false); + + $this->expect('x+y+z', + 'x+y+z', + [], + true, false); + + $this->expect('x-(y+z)', + 'x-(y+z)', + [], + true, false); + + $this->expect('x/(y+z)', + 'x/(y+z)', + [], + true, false); + + $this->expect('x/(y/z)', + 'x/(y/z)', + [], + true, false); + + $this->expect('x/y/z', + 'x/y/z', + [], + true, false); + + $this->expect('x1', + 'x1', + [], + true, false); + + $this->expect('x<1 and x>1', + 'x < 1 and x > 1', + [], + true, false); + + $this->expect('x=+-sqrt(2)', + 'x = +-sqrt(2)', + [], + true, false); + + $this->expect('x=1 or 2', + 'x = 1 or 2', + [], + true, false); + + $this->expect('x=1 or 2 or 3', + 'x = 1 or 2 or 3', + [], + true, false); + + $this->expect('x=1 or x=2', + 'x = 1 or x = 2', + [], + true, false); + + $this->expect('x>1 or (x<1 and t<sin(x))', + 'x > 1 or (x < 1 and t < sin(x))', + [], + true, false); + + $this->expect('x^(-(y+z))', + 'x^(-(y+z))', + [], + true, false); + + $this->expect('x^(-y)', + 'x^(-y)', + [], + true, false); + + $this->expect('x^(y+z)', + 'x^(y+z)', + [], + true, false); + + $this->expect('x^(y/z)', + 'x^(y/z)', + [], + true, false); + + $this->expect('x^-1', + 'x^-1', + [], + true, false); + + $this->expect('x^-y', + 'x^-y', + [], + true, false); + + $this->expect('x^7/7-2*x^6/3-4*x^3/3', + 'x^7/7-2*x^6/3-4*x^3/3', + [], + true, false); + + $this->expect('x^f(x)', + 'x^f(x)', + [], + true, false); + + $this->expect('x^y', + 'x^y', + [], + true, false); + + $this->expect('x^y^z', + 'x^y^z', + [], + true, false); + + $this->expect('x_1', + 'x_1', + [], + true, false); + + $this->expect('Xy_12', + 'Xy_12', + [], + true, false); + + $this->expect('x_y', + 'x_y', + [], + true, false); + + $this->expect('x_y_z', + 'x_y_z', + [], + true, false); + + $this->expect('x_y_1', + 'x_y_1', + [], + true, false); + + $this->expect('x_12_z', + 'x_12_z', + [], + true, false); + + $this->expect('xy_zw', + 'xy_zw', + [], + true, false); + + $this->expect('xy_12', + 'xy_12', + [], + true, false); + + $this->expect('M_2*x^2+M_1*x+M_0', + 'M_2*x^2+M_1*x+M_0', + [], + true, false); + + $this->expect('xi', + 'xi', + [], + true, false); + + $this->expect('xsin(1)', + 'xsin(1)', + [], + true, false); + + $this->expect('xy', + 'xy', + [], + true, false); + + $this->expect('y^2-2*y-0.5', + 'y^2-2*y-0.5', + [], + true, false); + + $this->expect('y^2-2*y-8', + 'y^2-2*y-8', + [], + true, false); + + $this->expect('y^3-2*y^2-8*y', + 'y^3-2*y^2-8*y', + [], + true, false); + + $this->expect('y^z * x', + 'y^z*x', + [], + true, false); + + $this->expect('ycos(2)', + 'ycos(2)', + [], + true, false); + + $this->expect('zeta', + 'zeta', + [], + true, false); + + $this->expect('{1,2,3.4}', + '{1,2,3.4}', + [], + true, false); + + $this->expect('{1}', + '{1}', + [], + true, false); + + $this->expect('{x, y, z }', + '{x,y,z}', + [], + true, false); + + $this->expect('{}', + '{}', + [], + true, false); + + $this->expect('|x|', + 'abs(x)', + [], + true, false); + + $this->expect('rand(["+","-"])(x,y)', + 'rand(["+","-"])(x,y)', + [], + true, false); + + $this->expect('rand(["sin","cos","system"])(x)', + 'rand(["sin","cos","system"])(x)', + [], + true, false); + + $this->expect('1.2*m**2', + '1.2*m**2', + [], + true, false); + + $this->expect('1.2*mˆ2', + '1.2*m^2', + [], + true, false); + + $this->expect('/* Comment */x+1', + '/* Comment */x+1', + [], + true, false); + + $this->expect('/* Comment **/x+1', + '/* Comment **/x+1', + [], + true, false); + + $this->expect('/** Comment */x+1', + '/** Comment */x+1', + [], + true, false); + + $this->expect('/** Comment **/x+1', + '/** Comment **/x+1', + [], + true, false); + + $this->expect('/*@ Comment @*/x+1', + '/*@ Comment @*/x+1', + [], + true, false); + + $this->expect('"A string that needs sanitising <script>bad stuff</script>."', + '"A string that needs sanitising <script>bad stuff</script>."', + [], + true, false); + + } +} diff --git a/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php b/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php index 0df850d1707ce6f6f2a0d2434834a606abcb98b4..74778ea16be95e8d9ce23f73aa68b67562172219 100644 --- a/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php +++ b/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php @@ -119,6 +119,11 @@ class ast_filter_050_no_chained_inequalities_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ class ast_filter_050_no_chained_inequalities_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php b/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php index d12604d7fb06a8052dcc7df0414f9f5d208c6e60..4304cb85f284d69b804e3ea237946f7bcdfb77d3 100644 --- a/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php +++ b/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_090_special_forbidden_characters_auto_generated_test extends qt [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_090_special_forbidden_characters_auto_generated_test extends qt [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_101_no_floats_auto_generated_test.php b/tests/ast_filter_101_no_floats_auto_generated_test.php index d47940bc9480d03dbfb264a117cea4ff61ebe48a..477c4a1d340c7b5af22af621c49522e2fe4044fd 100644 --- a/tests/ast_filter_101_no_floats_auto_generated_test.php +++ b/tests/ast_filter_101_no_floats_auto_generated_test.php @@ -429,6 +429,11 @@ class ast_filter_101_no_floats_auto_generated_test extends qtype_stack_ast_testc [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2040,6 +2045,11 @@ class ast_filter_101_no_floats_auto_generated_test extends qtype_stack_ast_testc [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_102_no_strings_auto_generated_test.php b/tests/ast_filter_102_no_strings_auto_generated_test.php index 8f18277a489473a57238d99e557d000e6024a084..7b2a9f18b06902a5cb1e242f0fc748b953254a0a 100644 --- a/tests/ast_filter_102_no_strings_auto_generated_test.php +++ b/tests/ast_filter_102_no_strings_auto_generated_test.php @@ -154,6 +154,11 @@ class ast_filter_102_no_strings_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ class ast_filter_102_no_strings_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_103_no_lists_auto_generated_test.php b/tests/ast_filter_103_no_lists_auto_generated_test.php index d240b5e28eaa71f4c1595cf7f780dd9fea9341a8..8bb08555e5420e2334d28812ae88df2cc07fde21 100644 --- a/tests/ast_filter_103_no_lists_auto_generated_test.php +++ b/tests/ast_filter_103_no_lists_auto_generated_test.php @@ -339,6 +339,11 @@ class ast_filter_103_no_lists_auto_generated_test extends qtype_stack_ast_testca [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1995,6 +2000,11 @@ class ast_filter_103_no_lists_auto_generated_test extends qtype_stack_ast_testca [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_104_no_sets_auto_generated_test.php b/tests/ast_filter_104_no_sets_auto_generated_test.php index b5d61d6fb98c9dd07c3912ff69b1ae3d4a60abb2..73237887e5d74194570db2d09456b6876263f1e1 100644 --- a/tests/ast_filter_104_no_sets_auto_generated_test.php +++ b/tests/ast_filter_104_no_sets_auto_generated_test.php @@ -139,6 +139,11 @@ class ast_filter_104_no_sets_auto_generated_test extends qtype_stack_ast_testcas [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ class ast_filter_104_no_sets_auto_generated_test extends qtype_stack_ast_testcas [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_105_no_grouppings_auto_generated_test.php b/tests/ast_filter_105_no_grouppings_auto_generated_test.php index 96fb4d92316638af9a55d687d9fa27767514bbf9..feac69855dfd2c1d63763024e0a5a3738b386d3c 100644 --- a/tests/ast_filter_105_no_grouppings_auto_generated_test.php +++ b/tests/ast_filter_105_no_grouppings_auto_generated_test.php @@ -509,6 +509,11 @@ class ast_filter_105_no_grouppings_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('()x', '()*x', [], @@ -2080,6 +2085,11 @@ class ast_filter_105_no_grouppings_auto_generated_test extends qtype_stack_ast_t [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('()x', '()*x', [], diff --git a/tests/ast_filter_106_no_control_flow_auto_generated_test.php b/tests/ast_filter_106_no_control_flow_auto_generated_test.php index 2e2c836c8b2f328be64b40e26661ce870b32654d..a6e4ce0cc769d88e7c609a670ac88a20e41212f3 100644 --- a/tests/ast_filter_106_no_control_flow_auto_generated_test.php +++ b/tests/ast_filter_106_no_control_flow_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_106_no_control_flow_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_106_no_control_flow_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_120_no_arc_auto_generated_test.php b/tests/ast_filter_120_no_arc_auto_generated_test.php index 08bfe4c0bdec104ff8f7e8be07298719bf77964d..37120c127e3766ba17e38172af42c3398a85ce33 100644 --- a/tests/ast_filter_120_no_arc_auto_generated_test.php +++ b/tests/ast_filter_120_no_arc_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_120_no_arc_auto_generated_test extends qtype_stack_ast_testcase [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_120_no_arc_auto_generated_test extends qtype_stack_ast_testcase [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_150_replace_unicode_letters_auto_generated_test.php b/tests/ast_filter_150_replace_unicode_letters_auto_generated_test.php index 2b8105b8d65f8f35b28d88aed3f8740175c39d5c..fcdfbfda81fe46d103dedb0f0f101555f13891ea 100644 --- a/tests/ast_filter_150_replace_unicode_letters_auto_generated_test.php +++ b/tests/ast_filter_150_replace_unicode_letters_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_150_replace_unicode_letters_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_150_replace_unicode_letters_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_180_char_based_superscripts_auto_generated_test.php b/tests/ast_filter_180_char_based_superscripts_auto_generated_test.php index cbf64117c0d3f1afa0a0b4899ee85963b150b5d8..bab988d840baf94aee6e587b69abfed2dd890ae7 100644 --- a/tests/ast_filter_180_char_based_superscripts_auto_generated_test.php +++ b/tests/ast_filter_180_char_based_superscripts_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_180_char_based_superscripts_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_180_char_based_superscripts_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php b/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php index b9217990d7829ce54f9cfe7e64055895ce428d21..607571bbbba04027d887c776c9ac3deecbb5ab6a 100644 --- a/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php +++ b/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php @@ -77,6 +77,11 @@ class ast_filter_201_sig_figs_validation_auto_generated_test extends qtype_stack [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1803,6 +1808,11 @@ class ast_filter_201_sig_figs_validation_auto_generated_test extends qtype_stack [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php b/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php index 6e7dbc36c315f62c1458ca90d4087b3ad983f895..fac898c7e91cab8901b2d99b5a76e955f6ef66ed 100644 --- a/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php +++ b/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php @@ -77,6 +77,11 @@ class ast_filter_202_decimal_places_validation_auto_generated_test extends qtype [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1858,6 +1863,11 @@ class ast_filter_202_decimal_places_validation_auto_generated_test extends qtype [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php b/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php index d5f91a8ac0db0f82232b039481696c038e8e1354..54c14e3214224be03f0f487c73107f044f50a936 100644 --- a/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php +++ b/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php @@ -159,6 +159,11 @@ class ast_filter_210_x_used_as_multiplication_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ class ast_filter_210_x_used_as_multiplication_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php b/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php index d70fe26a396d241bd1e5c7d2f35d798e68eb9978..d7102eae8c81191975556dd791d07f491eb403a3 100644 --- a/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php +++ b/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php @@ -149,6 +149,11 @@ class ast_filter_402_split_prefix_from_common_function_name_auto_generated_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1900,6 +1905,11 @@ class ast_filter_402_split_prefix_from_common_function_name_auto_generated_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php b/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php index bfe8aeed0585a8842136d850d9b3f3b835aa0233..15fc4bc5b5138a4b5ebcb78a67058e3759357203 100644 --- a/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php +++ b/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php @@ -119,6 +119,11 @@ class ast_filter_403_split_at_number_letter_boundary_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ class ast_filter_403_split_at_number_letter_boundary_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php b/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php index d4f8cffe3c2d25b26ebbfb24d5a02b92bb9bfdf6..ad047239c96625dd131ca0b0748f37a39ad831b8 100644 --- a/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php +++ b/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php @@ -169,6 +169,11 @@ class ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1910,6 +1915,11 @@ class ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php b/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php index 042de6228dcc2d77bbecf95a96fc4cc37d23c11b..ef98119405c49586927b9c75c821f32c434017d7 100644 --- a/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php +++ b/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php @@ -179,6 +179,11 @@ class ast_filter_406_split_implied_variable_names_auto_generated_test extends qt [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1915,6 +1920,11 @@ class ast_filter_406_split_implied_variable_names_auto_generated_test extends qt [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_410_single_char_vars_auto_generated_test.php b/tests/ast_filter_410_single_char_vars_auto_generated_test.php index 4f0daa617ca182426ea51fe1723403466ace8de1..6f224340f874bae424bc240fa576260a500c350b 100644 --- a/tests/ast_filter_410_single_char_vars_auto_generated_test.php +++ b/tests/ast_filter_410_single_char_vars_auto_generated_test.php @@ -324,6 +324,11 @@ class ast_filter_410_single_char_vars_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1985,6 +1990,11 @@ class ast_filter_410_single_char_vars_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php b/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php index da531d3d8c58363685011a71fa64ab969faf018b..caf616d867e849a30ce914a2b5e78451213f6af5 100644 --- a/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php +++ b/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php @@ -149,6 +149,11 @@ class ast_filter_420_consolidate_subscripts_auto_generated_test extends qtype_st [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1900,6 +1905,11 @@ class ast_filter_420_consolidate_subscripts_auto_generated_test extends qtype_st [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php b/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php index 6be46f3077fb45396a1689b5095b4cc6315bebe1..f36aa678c194e38f3cdfe82e4bf4bcc40186e51f 100644 --- a/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php +++ b/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php @@ -529,6 +529,11 @@ class ast_filter_441_split_unknown_functions_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2090,6 +2095,11 @@ class ast_filter_441_split_unknown_functions_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_442_split_all_functions_auto_generated_test.php b/tests/ast_filter_442_split_all_functions_auto_generated_test.php index 4d7e3b0c1b4d04bf3b215f538dd5b242134a8873..e2013fbf9b5241b072649ff868d18608f6740a2f 100644 --- a/tests/ast_filter_442_split_all_functions_auto_generated_test.php +++ b/tests/ast_filter_442_split_all_functions_auto_generated_test.php @@ -47,6 +47,11 @@ class ast_filter_442_split_all_functions_auto_generated_test extends qtype_stack [], true, false); + $this->expect("''diff(x,y)", + "''diff*(x,y)", + [], + true, false); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-sqrt*(b^2))/(2*a)', [], @@ -578,6 +583,11 @@ class ast_filter_442_split_all_functions_auto_generated_test extends qtype_stack [], true, false); + $this->expect("''diff(x,y)", + "''diff*(x,y)", + [], + true, false); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-sqrt*(b^2))/(2*a)', [], diff --git a/tests/ast_filter_450_split_floats_auto_generated_test.php b/tests/ast_filter_450_split_floats_auto_generated_test.php index 07aedd15f351cacb28e622237f00db79c37bb19f..8a04fc64449a1f46ffeca01e1ed36dd8aa906eb0 100644 --- a/tests/ast_filter_450_split_floats_auto_generated_test.php +++ b/tests/ast_filter_450_split_floats_auto_generated_test.php @@ -159,6 +159,11 @@ class ast_filter_450_split_floats_auto_generated_test extends qtype_stack_ast_te [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ class ast_filter_450_split_floats_auto_generated_test extends qtype_stack_ast_te [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_502_replace_pm_auto_generated_test.php b/tests/ast_filter_502_replace_pm_auto_generated_test.php index 495a7fcd8eb2d8c7a48ee9f6394fecc339772e19..d1f46651d6ca607f95afd01d61fe902eeeda58b5 100644 --- a/tests/ast_filter_502_replace_pm_auto_generated_test.php +++ b/tests/ast_filter_502_replace_pm_auto_generated_test.php @@ -129,6 +129,11 @@ class ast_filter_502_replace_pm_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ class ast_filter_502_replace_pm_auto_generated_test extends qtype_stack_ast_test [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php b/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php index 44094912f259c2f33c885e3a6e44bef7c6af3989..0c6cbabd7fae27fb87109850cb7e673604f9c011 100644 --- a/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php +++ b/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php @@ -129,6 +129,11 @@ class ast_filter_504_insert_tuples_for_groups_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ class ast_filter_504_insert_tuples_for_groups_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php b/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php index 87fc0f1a3ea0493cd7c21bc8773a78b7828c54c1..f75e0d9cdd483d507e954080c275b3efa352e555 100644 --- a/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php +++ b/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php @@ -129,6 +129,11 @@ class ast_filter_505_no_evaluation_groups_auto_generated_test extends qtype_stac [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ class ast_filter_505_no_evaluation_groups_auto_generated_test extends qtype_stac [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php b/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php index 11551cc9ee63f98703417f39e6d190e4df7da76e..57d7fab196b91c0d5e1d84f33bbbdecbc9c7fbcb 100644 --- a/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php +++ b/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php @@ -109,6 +109,11 @@ class ast_filter_520_no_equality_with_logic_auto_generated_test extends qtype_st [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1880,6 +1885,11 @@ class ast_filter_520_no_equality_with_logic_auto_generated_test extends qtype_st [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php b/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php index 51054a8aa227f4304353a64632077d32f68b5284..155843eb8842db1efe3cec2a54e3bf0dabab33c5 100644 --- a/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php +++ b/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php @@ -574,6 +574,11 @@ class ast_filter_541_no_unknown_functions_auto_generated_test extends qtype_stac [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2110,6 +2115,11 @@ class ast_filter_541_no_unknown_functions_auto_generated_test extends qtype_stac [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php b/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php index 7d176fadb679cade33006442aceb6ef824e334bb..8c07f031c66c8ee7238c10424f677d83103265de 100644 --- a/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php +++ b/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php @@ -52,6 +52,11 @@ class ast_filter_542_no_functions_at_all_auto_generated_test extends qtype_stack ['noFunction'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['noFunction'], + false, true); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-sqrt(b^2))/(2*a)', ['noFunction'], @@ -593,6 +598,11 @@ class ast_filter_542_no_functions_at_all_auto_generated_test extends qtype_stack ['noFunction'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['noFunction'], + false, true); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-sqrt(b^2))/(2*a)', ['noFunction'], diff --git a/tests/ast_filter_601_castext_auto_generated_test.php b/tests/ast_filter_601_castext_auto_generated_test.php index 88f295bfbee43b715e468ae744854e6b77ed648b..b884fd71dc1e6659f600243a66bc2d5ee5cccb19 100644 --- a/tests/ast_filter_601_castext_auto_generated_test.php +++ b/tests/ast_filter_601_castext_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_601_castext_auto_generated_test extends qtype_stack_ast_testcas [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_601_castext_auto_generated_test extends qtype_stack_ast_testcas [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_602_castext_simplifier_auto_generated_test.php b/tests/ast_filter_602_castext_simplifier_auto_generated_test.php index a69d0ba2a5836c98ce098a0d1009dc36d1a09bd5..50ada1a3868bb0bb0f353ad0ddfaf060fc641863 100644 --- a/tests/ast_filter_602_castext_simplifier_auto_generated_test.php +++ b/tests/ast_filter_602_castext_simplifier_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_602_castext_simplifier_auto_generated_test extends qtype_stack_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_602_castext_simplifier_auto_generated_test extends qtype_stack_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_610_castext_static_string_extractor_auto_generated_test.php b/tests/ast_filter_610_castext_static_string_extractor_auto_generated_test.php index c4f12259feabe7618916139c3ded41b325c822f4..dc4c727068f5d43356b6491eb47cbfd099480039 100644 --- a/tests/ast_filter_610_castext_static_string_extractor_auto_generated_test.php +++ b/tests/ast_filter_610_castext_static_string_extractor_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_610_castext_static_string_extractor_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_610_castext_static_string_extractor_auto_generated_test extends [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_680_gcl_sconcat_auto_generated_test.php b/tests/ast_filter_680_gcl_sconcat_auto_generated_test.php index 39f54d7a2a49191f9f152133bec1b122705ee923..69d90fc48680c499766ceec77a9585ac8e646fa6 100644 --- a/tests/ast_filter_680_gcl_sconcat_auto_generated_test.php +++ b/tests/ast_filter_680_gcl_sconcat_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_680_gcl_sconcat_auto_generated_test extends qtype_stack_ast_tes [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_680_gcl_sconcat_auto_generated_test extends qtype_stack_ast_tes [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_801_singleton_numeric_auto_generated_test.php b/tests/ast_filter_801_singleton_numeric_auto_generated_test.php index f8b4b41221bd1b7a5021f5d14fef8b68061999e6..f9c7feaf6e0583c28467443192bd8d2ed5ba37b3 100644 --- a/tests/ast_filter_801_singleton_numeric_auto_generated_test.php +++ b/tests/ast_filter_801_singleton_numeric_auto_generated_test.php @@ -77,6 +77,11 @@ class ast_filter_801_singleton_numeric_auto_generated_test extends qtype_stack_a ['Illegal_form'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_form'], + false, true); + $this->expect('(()x)', '(()*x)', ['Illegal_form'], @@ -1788,6 +1793,11 @@ class ast_filter_801_singleton_numeric_auto_generated_test extends qtype_stack_a ['Illegal_form'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['Illegal_form'], + false, true); + $this->expect('(()x)', '(()*x)', ['Illegal_form'], diff --git a/tests/ast_filter_802_singleton_units_auto_generated_test.php b/tests/ast_filter_802_singleton_units_auto_generated_test.php index 1c8335bc352ec902459207da3aa378a3a3f4470e..90353f262e609f9dd8eafdea1bed28933701cf62 100644 --- a/tests/ast_filter_802_singleton_units_auto_generated_test.php +++ b/tests/ast_filter_802_singleton_units_auto_generated_test.php @@ -77,6 +77,11 @@ class ast_filter_802_singleton_units_auto_generated_test extends qtype_stack_ast [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1843,6 +1848,11 @@ class ast_filter_802_singleton_units_auto_generated_test extends qtype_stack_ast [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_901_remove_comments_auto_generated_test.php b/tests/ast_filter_901_remove_comments_auto_generated_test.php index 44145fdfbdbcd37d1a4d3eb0d019478eac5aff50..e205ed02ad03f44af7f1f6417c1cf8ec6804a43c 100644 --- a/tests/ast_filter_901_remove_comments_auto_generated_test.php +++ b/tests/ast_filter_901_remove_comments_auto_generated_test.php @@ -139,6 +139,11 @@ class ast_filter_901_remove_comments_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ class ast_filter_901_remove_comments_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php b/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php index 11654acb7b50b7349c086a452dd84e7a6a97f851..acc8499b5167fb95e6e17a75681fcec383d3f74b 100644 --- a/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php +++ b/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php @@ -429,6 +429,11 @@ class ast_filter_910_inert_float_for_display_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2040,6 +2045,11 @@ class ast_filter_910_inert_float_for_display_auto_generated_test extends qtype_s [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_912_inert_string_for_display_auto_generated_test.php b/tests/ast_filter_912_inert_string_for_display_auto_generated_test.php index fa586cbb115fff1075d44ff5155902397b13be26..ad45e0f5c52b216818eff34db7cc1c7cf63cc7ae 100644 --- a/tests/ast_filter_912_inert_string_for_display_auto_generated_test.php +++ b/tests/ast_filter_912_inert_string_for_display_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_912_inert_string_for_display_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_912_inert_string_for_display_auto_generated_test extends qtype_ [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php b/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php index 35315529cb2573b09b82cd48a172844a86b786c3..07b7cf4f3459f907566d33cc650f339437105f92 100644 --- a/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php +++ b/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php @@ -254,6 +254,11 @@ class ast_filter_990_no_fixing_spaces_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1950,6 +1955,11 @@ class ast_filter_990_no_fixing_spaces_auto_generated_test extends qtype_stack_as [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php b/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php index c984f8d29ac844c3fd7dacc5288e3295b4724eaf..c0d042fa2f11b66eb383e2f445cf0a9799cd7264 100644 --- a/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php +++ b/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php @@ -309,6 +309,11 @@ class ast_filter_991_no_fixing_stars_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], @@ -1975,6 +1980,11 @@ class ast_filter_991_no_fixing_stars_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], diff --git a/tests/ast_filter_995_ev_modification_auto_generated_test.php b/tests/ast_filter_995_ev_modification_auto_generated_test.php index fc7158ea8ba254a12b5195db658556069269df86..e4dbbf0b8562fa90c464bc18daa2edbade142988 100644 --- a/tests/ast_filter_995_ev_modification_auto_generated_test.php +++ b/tests/ast_filter_995_ev_modification_auto_generated_test.php @@ -89,6 +89,11 @@ class ast_filter_995_ev_modification_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ class ast_filter_995_ev_modification_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_996_call_modification_auto_generated_test.php b/tests/ast_filter_996_call_modification_auto_generated_test.php index f3b230607fbde35b3000c3d4a722714e38e33498..3f4e4426c3b9951d024f5fb9bf3be0867841f548 100644 --- a/tests/ast_filter_996_call_modification_auto_generated_test.php +++ b/tests/ast_filter_996_call_modification_auto_generated_test.php @@ -42,6 +42,11 @@ class ast_filter_996_call_modification_auto_generated_test extends qtype_stack_a [], true, false); + $this->expect("''diff(x,y)", + "''%_E((%_C(diff),%_E(diff(x,y))))", + [], + true, false); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-(%_C(sqrt),sqrt(b^2)))/(2*a)', [], @@ -573,6 +578,11 @@ class ast_filter_996_call_modification_auto_generated_test extends qtype_stack_a [], true, false); + $this->expect("''diff(x,y)", + "''%_E((%_C(diff),%_E(diff(x,y))))", + [], + true, false); + $this->expect('(-b+-sqrt(b^2))/(2*a)', '(-b+-(%_C(sqrt),sqrt(b^2)))/(2*a)', [], diff --git a/tests/ast_filter_997_string_security_auto_generated_test.php b/tests/ast_filter_997_string_security_auto_generated_test.php index 0c26b0838004c0fc89c398b5ea07ba947440ca8f..00ac2fc7260f749962094ae0a5347a32b9e3f8d9 100644 --- a/tests/ast_filter_997_string_security_auto_generated_test.php +++ b/tests/ast_filter_997_string_security_auto_generated_test.php @@ -99,6 +99,11 @@ class ast_filter_997_string_security_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ class ast_filter_997_string_security_auto_generated_test extends qtype_stack_ast [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], diff --git a/tests/ast_filter_998_security_auto_generated_test.php b/tests/ast_filter_998_security_auto_generated_test.php index 3082373bd56b65e44d4db2af56f9200d7b2d966f..666c2befde42ebee9a69415cbbe2766a5485fc79 100644 --- a/tests/ast_filter_998_security_auto_generated_test.php +++ b/tests/ast_filter_998_security_auto_generated_test.php @@ -52,6 +52,11 @@ class ast_filter_998_security_auto_generated_test extends qtype_stack_ast_testca ['apostrophe'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['apostrophe'], + false, true); + $this->expect('(()x)', '(()*x)', ['emptyParens'], @@ -283,6 +288,11 @@ class ast_filter_998_security_auto_generated_test extends qtype_stack_ast_testca ['apostrophe'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['apostrophe'], + false, true); + $this->expect('(()x)', '(()*x)', ['emptyParens'], diff --git a/tests/ast_filter_999_strict_auto_generated_test.php b/tests/ast_filter_999_strict_auto_generated_test.php index c1ad2044504e6dd151b4673ac0a6836c3e72fb4b..a5a26ba23feddd6882fb794bf85cfa331b602be3 100644 --- a/tests/ast_filter_999_strict_auto_generated_test.php +++ b/tests/ast_filter_999_strict_auto_generated_test.php @@ -459,6 +459,11 @@ class ast_filter_999_strict_auto_generated_test extends qtype_stack_ast_testcase [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], @@ -2050,6 +2055,11 @@ class ast_filter_999_strict_auto_generated_test extends qtype_stack_ast_testcase [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], diff --git a/tests/caskeyval_test.php b/tests/caskeyval_test.php index db398a15653fe42a30665b1cc908ad2bbd9cb3a2..f8a5a1dcbb5fb4639f3a81d06b65434a9a5250ce 100644 --- a/tests/caskeyval_test.php +++ b/tests/caskeyval_test.php @@ -77,6 +77,7 @@ class caskeyval_test extends qtype_stack_testcase { // In the new setup the parsing of the keyvals does not match the sessions created above. // This is because of a failure to split the text into statements. // This is a serious drawback when we try to identify which statement is throwing an error! + ["a:x^2$ b:(x+1)^2", true, $cs1], ["a:x^2) \n b:(x+1)^2", false, $cs0], ['a:x^2); b:(x+1)^2', false, $cs0], ['a:1/0', true, $cs2], @@ -107,6 +108,16 @@ class caskeyval_test extends qtype_stack_testcase { $this->assertEquals($s->get_by_key('ta3')->get_evaluationform(), 'ta3:x = 1 nounor x = 2'); } + public function test_equations_2() { + $at1 = new stack_cas_keyval('ta1 : x=1$ ta2 : x^2-2*x=1$ ta3:x=1 nounor x=2', null, 123); + $at1->instantiate(); + $s = $at1->get_session(); + $s->instantiate(); + $this->assertEquals($s->get_by_key('ta1')->get_evaluationform(), 'ta1:x = 1'); + $this->assertEquals($s->get_by_key('ta2')->get_evaluationform(), 'ta2:x^2-2*x = 1'); + $this->assertEquals($s->get_by_key('ta3')->get_evaluationform(), 'ta3:x = 1 nounor x = 2'); + } + public function test_keyval_session_keyval_0() { $kvin = ""; $at1 = new stack_cas_keyval($kvin, null, 123); @@ -228,7 +239,7 @@ class caskeyval_test extends qtype_stack_testcase { $kv = new stack_cas_keyval($tests); $this->assertFalse($kv->get_valid()); - $expected = ['The characters @, $ and \ are not allowed in CAS input.']; + $expected = ['The characters @ and \ are not allowed in CAS input.']; $this->assertEquals($expected, $kv->get_errors()); } @@ -318,4 +329,45 @@ class caskeyval_test extends qtype_stack_testcase { ]; $this->assertEquals($expected, $kv->get_errors()); } + + public function test_stack_compile() { + $tests = 'stack_reset_vars(true);ordergreat(i,j,k);p:matrix([-7],[2],[-3]);' . + 'q:matrix([i],[j],[k]);v:dotproduct(p,q);'; + $kv = new stack_cas_keyval($tests); + $this->assertTrue($kv->get_valid()); + $expected = [ + ]; + $compiled = $kv->compile('kv-test'); + + $expected = '(_EC(errcatch(stack_reset_vars(true)),"kv-test/1:1-1:2"),' . + '_EC(errcatch(ordergreat(i,j,k)),"kv-test/1:24-1:2"),true)'; + $this->assertEquals($expected, $compiled['blockexternal']); + $expected = '(_EC(errcatch(p:(%_C(matrix),matrix([-7],[2],[-3]))),"kv-test/1:42-1:2"),' . + '_EC(errcatch(q:(%_C(matrix),matrix([i],[j],[k]))),"kv-test/1:66-1:2"),' . + '_EC(errcatch(v:(%_C(dotproduct),dotproduct(p,q))),"kv-test/1:88-1:2"),true)'; + $this->assertEquals($expected, $compiled['statement']); + $expected = null; + $this->assertEquals($expected, $compiled['contextvariables']); + } + + public function test_stack_compile_preamble_end1() { + $tests = 'stack_reset_vars(true);n1:1;ordergreat(i,j,k);%_stack_preamble_end;' . + 'p:matrix([-7],[2],[-3]);' . + 'q:matrix([i],[j],[k]);v:dotproduct(p,q);'; + $kv = new stack_cas_keyval($tests); + $this->assertTrue($kv->get_valid()); + $expected = [ + ]; + $compiled = $kv->compile('kv-test'); + + $expected = '(_EC(errcatch(stack_reset_vars(true)),"kv-test/1:1-1:2"),' . + '_EC(errcatch(ordergreat(i,j,k)),"kv-test/1:29-1:2"),true)'; + $this->assertEquals($expected, $compiled['blockexternal']); + $expected = '(_EC(errcatch(p:(%_C(matrix),matrix([-7],[2],[-3]))),"kv-test/1:68-1:2"),' . + '_EC(errcatch(q:(%_C(matrix),matrix([i],[j],[k]))),"kv-test/1:92-1:2"),' . + '_EC(errcatch(v:(%_C(dotproduct),dotproduct(p,q))),"kv-test/1:114-1:2"),true)'; + $this->assertEquals($expected, $compiled['statement']); + $expected = '(_EC(errcatch(n1:1),"kv-test/1:24-1:2"),true)'; + $this->assertEquals($expected, $compiled['contextvariables']); + } } diff --git a/tests/cassession2_test.php b/tests/cassession2_test.php index af25a617a7412a28fc5f30ec5902d0c3a0302aa7..a1c41ded756c21074a3f3ba8ac162396c0fb150c 100644 --- a/tests/cassession2_test.php +++ b/tests/cassession2_test.php @@ -2493,10 +2493,12 @@ class cassession2_test extends qtype_stack_testcase { $s1 = []; $t1 = []; // Block external commands, such as ordergreat, are pulled out the front. - $t1[] = ['f:x*y*z', 'z*y*x']; - $t1[] = ['ordergreat(x,y,z)', 'done']; - $t1[] = ['g:x*y*z', 'z*y*x']; - $t1[] = ['h:exdowncase(X*Y*Z)', 'z*y*x']; + // So they apply to the whole session. + $t1[] = ['f:x*y*z+a', 'y*z*x+a']; + $t1[] = ['ordergreat(x,z,y)', '__s1']; + $t1[] = ['g:x*y*z+1', 'y*z*x+1']; + $t1[] = ['h:exdowncase(X*Y*Z)', 'y*z*x']; + $t1[] = ['k:ev(exdowncase(X*Y*Z),simp)', 'y*z*x']; $t1[] = ['ATAlgEquiv(exdowncase(x),x)', '[true,true,"",""]']; foreach ($t1 as $i => $case) { @@ -2511,7 +2513,8 @@ class cassession2_test extends qtype_stack_testcase { foreach ($s->get_contextvariables() as $i => $v) { $a[$i] = $v->get_evaluationform(); } - $this->assertEquals(['(%_C(ordergreat),ordergreat(x,y,z))'], $a); + // Note that ordergreat is no longer a context variable. It's in the preamble. + $this->assertEquals([], $a); foreach ($t1 as $i => $t) { $this->assertEquals($t[1], $s1[$i]->get_value()); @@ -2690,6 +2693,7 @@ class cassession2_test extends qtype_stack_testcase { '\left( 1+\mathrm{i} \right)\cdot x^2+\left( 1-\mathrm{i} \right)', ]; $cases[] = ['disp_select(a+b)+c', '\color{red}{\underline{a+b}}+c']; + $cases[] = ['disp_select(a+b)^3', '{\color{red}{\underline{a+b}}}^3']; $cases[] = ['remove_disp(disp_select(a+b)+c)', 'a+b+c']; $s1 = []; diff --git a/tests/castext_test.php b/tests/castext_test.php index 421384cfefba912933ee035d0b699f6d15419c4a..89c22f15420aa03d66996798ac307e32b10c094a 100644 --- a/tests/castext_test.php +++ b/tests/castext_test.php @@ -816,7 +816,8 @@ class castext_test extends qtype_stack_testcase { } $cs2 = new stack_cas_session2($s2, null, 0); - $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,2)@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, {@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); + $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,2)@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, ' . + '{@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); $this->assertTrue($at1->get_valid()); $cs2->add_statement($at1); $cs2->instantiate(); @@ -835,12 +836,14 @@ class castext_test extends qtype_stack_testcase { } $cs2 = new stack_cas_session2($s2, null, 0); - $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, {@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); + $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, ' . + '{@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); $this->assertTrue($at1->get_valid()); $cs2->add_statement($at1); $cs2->instantiate(); - $this->assertEquals('\({3\cdot x^2}\), \({-4.000}\), \({-4.000}\), \({3}\), \({1}\)', $at1->get_rendered()); + $this->assertEquals('\({3\cdot x^2}\), \({-4.000}\), \({-4.000}\), \({3}\), \({1}\)', + $at1->get_rendered()); } /** @@ -854,7 +857,8 @@ class castext_test extends qtype_stack_testcase { } $cs2 = new stack_cas_session2($s2, null, 0); - $at1 = castext2_evaluatable::make_from_source('{@dispdp(a1,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, {@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); + $at1 = castext2_evaluatable::make_from_source('{@dispdp(a1,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, ' . + '{@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case'); $this->assertTrue($at1->get_valid()); $cs2->add_statement($at1); $cs2->instantiate(); @@ -2025,6 +2029,24 @@ class castext_test extends qtype_stack_testcase { $this->assertEquals('\({bigcup_{k = 1}^{\infty } {A}_{k}}\)', $at2->get_rendered()); } + /** + * @covers \qtype_stack\stack_cas_castext2_latex + * @covers \qtype_stack\stack_cas_keyval + */ + public function test_texput_hat() { + $vars = 'texput(hat, lambda([ex], sconcat("\\\\hat{", tex1(first(ex)), "}")));'; + $at1 = new stack_cas_keyval($vars, null, 123); + $this->assertTrue($at1->get_valid()); + + $cs2 = $at1->get_session(); + $at2 = castext2_evaluatable::make_from_source('{@1+hat(s)@}', 'test-case'); + $this->assertTrue($at2->get_valid()); + $cs2->add_statement($at2); + $cs2->instantiate(); + + $this->assertEquals('\({\hat{s}+1}\)', $at2->get_rendered()); + } + /** * @covers \qtype_stack\stack_cas_castext2_latex * @covers \qtype_stack\stack_cas_keyval @@ -2332,4 +2354,45 @@ class castext_test extends qtype_stack_testcase { $this->assertEquals('Underscore characters are not permitted in this input.', $at2->get_rendered()); } + + /** + * @covers \qtype_stack\stack_cas_castext2_latex + * @covers \qtype_stack\stack_cas_keyval + */ + public function test_unary_minus_zeros() { + $options = new stack_options(); + $options->set_option('simplify', false); + $cs2 = new stack_cas_session2([], $options, 123456); + + $textinput = "{@x-0@}, {@x-0.0@}, {@x*(-0.0)@}, {@-27@}."; + $at1 = castext2_evaluatable::make_from_source($textinput, 'test-case'); + $this->assertTrue($at1->get_valid()); + $cs2->add_statement($at1); + $cs2->instantiate(); + + $this->assertEquals('\({x-0}\), \({x-0.0}\), \({x\cdot \left(-0.0\right)}\), \({-27}\).', + $at1->get_rendered()); + } + + /** + * @covers \qtype_stack\stack_cas_castext2_latex + * @covers \qtype_stack\stack_cas_keyval + */ + public function test_make_mult_sgn_stackunits() { + $options = new stack_options(); + $options->set_option('simplify', false); + $cs2 = new stack_cas_session2([], $options, 123456); + + $textinput = '{@stackunits(10,m/s)@}, ' . + '{@(texput(multsgnstackunits, "\\\\cdot "), stackunits(1, s^-1))@}, ' . + '{@(texput(multsgnstackunits, "\\\\, "), stackunits(1, s^-1))@}. ' . + 'Multiplication unaffected: {@(texput(multsgnstackunits, "\\\\, "), a*b)@}.'; + $at1 = castext2_evaluatable::make_from_source($textinput, 'test-case'); + $this->assertTrue($at1->get_valid()); + $cs2->add_statement($at1); + $cs2->instantiate(); + + $this->assertEquals('\({10\, \frac{m}{s}}\), \({1\cdot s^ {- 1 }}\), \({1\, s^ {- 1 }}\). ' . + 'Multiplication unaffected: \({a\cdot b}\).', $at1->get_rendered()); + } } diff --git a/tests/fixtures/answertestfixtures.class.php b/tests/fixtures/answertestfixtures.class.php index b5d0972920820ad63ba4972a9918d79dde21201c..e48551c329003c155c96fa99c1bb60d92382a1b1 100644 --- a/tests/fixtures/answertestfixtures.class.php +++ b/tests/fixtures/answertestfixtures.class.php @@ -114,6 +114,9 @@ class stack_answertest_test_data { ['AlgEquiv', '', 'x^(1/2)', 'sqrt(x)', 1, '', 'Powers and roots'], ['AlgEquiv', '', 'x', 'sqrt(x^2)', 0, '', ''], + ['AlgEquiv', '', '\'root(x)', 'x^(1/2)', 1, '', ''], + ['AlgEquiv', '', '\'root(x,m)', 'x^(1/m)', 1, '', ''], + ['AlgEquiv', '', 'x', '\'root(x^2)', 0, '', ''], ['AlgEquiv', '', 'abs(x)', 'sqrt(x^2)', 1, '', ''], ['AlgEquiv', '', '1/abs(x)^(1/3)', '(abs(x)^(1/3)/abs(x))^(1/2)', 1, '', ''], ['AlgEquiv', '', 'sqrt((x-3)*(x-5))', 'sqrt(x-3)*sqrt(x-5)', 0, '', ''], diff --git a/tests/fixtures/apifixtures.class.php b/tests/fixtures/apifixtures.class.php index ed1d53eb39601f7880297145fb2d84f3bc5d093e..3dffd7eae8056ecf396e01428e213ebcc4708b37 100644 --- a/tests/fixtures/apifixtures.class.php +++ b/tests/fixtures/apifixtures.class.php @@ -1392,6 +1392,344 @@ class stack_api_test_data { </qtest> </question> </quiz>', + 'test' => ' + <quiz> + <question type="stack"> + <name> + <text>Algebraic input</text> + </name> + <questiontext format="html"> + <text><![CDATA[<p>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p> + <p>(Note, this assumes single variable variable names)</p>]]></text> + </questiontext> + <generalfeedback format="html"> + <text></text> + </generalfeedback> + <defaultgrade>1.0000000</defaultgrade> + <penalty>0.1000000</penalty> + <hidden>0</hidden> + <idnumber></idnumber> + <stackversion> + <text>2020123000</text> + </stackversion> + <questionvariables> + <text>ta:a*b</text> + </questionvariables> + <specificfeedback format="html"> + <text>[[feedback:prt1]]</text> + </specificfeedback> + <questionnote> + <text></text> + </questionnote> + <questionsimplify>1</questionsimplify> + <assumepositive>0</assumepositive> + <assumereal>0</assumereal> + <prtcorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:green;"> + <i class="fa fa-check"></i></span> Correct answer, well done.]]></text> + </prtcorrect> + <prtpartiallycorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:orange;"> + <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text> + </prtpartiallycorrect> + <prtincorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:red;"> + <i class="fa fa-times"></i></span> Incorrect answer.]]></text> + </prtincorrect> + <multiplicationsign>dot</multiplicationsign> + <sqrtsign>1</sqrtsign> + <complexno>i</complexno> + <inversetrig>cos-1</inversetrig> + <logicsymbol>lang</logicsymbol> + <matrixparens>[</matrixparens> + <variantsselectionseed></variantsselectionseed> + <input> + <name>ans1</name> + <type>algebraic</type> + <tans>ta</tans> + <boxsize>15</boxsize> + <strictsyntax>1</strictsyntax> + <insertstars>2</insertstars> + <syntaxhint></syntaxhint> + <syntaxattribute>0</syntaxattribute> + <forbidwords>solve</forbidwords> + <allowwords></allowwords> + <forbidfloat>1</forbidfloat> + <requirelowestterms>0</requirelowestterms> + <checkanswertype>1</checkanswertype> + <mustverify>1</mustverify> + <showvalidation>1</showvalidation> + <options></options> + </input> + <prt> + <name>prt1</name> + <value>1.0000000</value> + <autosimplify>1</autosimplify> + <feedbackstyle>1</feedbackstyle> + <feedbackvariables> + <text></text> + </feedbackvariables> + <node> + <name>0</name> + <answertest>AlgEquiv</answertest> + <sans>ans1</sans> + <tans>ta</tans> + <testoptions></testoptions> + <quiet>0</quiet> + <truescoremode>=</truescoremode> + <truescore>1.0000000</truescore> + <truepenalty></truepenalty> + <truenextnode>-1</truenextnode> + <trueanswernote>prt1-1-T</trueanswernote> + <truefeedback format="html"> + <text></text> + </truefeedback> + <falsescoremode>=</falsescoremode> + <falsescore>0.0000000</falsescore> + <falsepenalty></falsepenalty> + <falsenextnode>-1</falsenextnode> + <falseanswernote>prt1-1-F</falseanswernote> + <falsefeedback format="html"> + <text></text> + </falsefeedback> + </node> + </prt> + <qtest> + <testcase>1</testcase> + <testinput> + <name>ans1</name> + <value>37</value> + </testinput> + <expected> + <name>prt1</name> + <expectedscore>1.0000000</expectedscore> + <expectedpenalty>0.0000000</expectedpenalty> + <expectedanswernote>prt1-1-T</expectedanswernote> + </expected> + </qtest> + <qtest> + <testcase>2</testcase> + <testinput> + <name>ans1</name> + <value></value> + </testinput> + <expected> + <name>prt1</name> + <expectedscore>1.0000000</expectedscore> + <expectedpenalty>0.0000000</expectedpenalty> + <expectedanswernote>NULL</expectedanswernote> + </expected> + </qtest> + </question> + </quiz>', + 'test2' => ' + <quiz> + <question type="stack"> + <name> + <text>Algebraic input</text> + </name> + <questiontext format="html"> + <text><![CDATA[<p><img src="test.png"></img>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p> + <p>(Note, this assumes single variable variable names)</p>]]></text> + </questiontext> + <generalfeedback format="html"> + <text></text> + </generalfeedback> + <defaultgrade>1.0000000</defaultgrade> + <penalty>0.1000000</penalty> + <hidden>0</hidden> + <idnumber></idnumber> + <stackversion> + <text>2020123000</text> + </stackversion> + <questionvariables> + <text>ta:a*b</text> + </questionvariables> + <specificfeedback format="html"> + <text>[[feedback:prt1]]</text> + </specificfeedback> + <questionnote> + <text></text> + </questionnote> + <questionsimplify>1</questionsimplify> + <assumepositive>0</assumepositive> + <assumereal>0</assumereal> + <prtcorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:green;"> + <i class="fa fa-check"></i></span> Correct answer, well done.]]></text> + </prtcorrect> + <prtpartiallycorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:orange;"> + <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text> + </prtpartiallycorrect> + <prtincorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:red;"> + <i class="fa fa-times"></i></span> Incorrect answer.]]></text> + </prtincorrect> + <multiplicationsign>dot</multiplicationsign> + <sqrtsign>1</sqrtsign> + <complexno>i</complexno> + <inversetrig>cos-1</inversetrig> + <logicsymbol>lang</logicsymbol> + <matrixparens>[</matrixparens> + <variantsselectionseed></variantsselectionseed> + <input> + <name>ans1</name> + <type>algebraic</type> + <tans>ta</tans> + <boxsize>15</boxsize> + <strictsyntax>1</strictsyntax> + <insertstars>2</insertstars> + <syntaxhint></syntaxhint> + <syntaxattribute>0</syntaxattribute> + <forbidwords>solve</forbidwords> + <allowwords></allowwords> + <forbidfloat>1</forbidfloat> + <requirelowestterms>0</requirelowestterms> + <checkanswertype>1</checkanswertype> + <mustverify>1</mustverify> + <showvalidation>1</showvalidation> + <options></options> + </input> + <prt> + <name>prt1</name> + <value>1.0000000</value> + <autosimplify>1</autosimplify> + <feedbackstyle>1</feedbackstyle> + <feedbackvariables> + <text></text> + </feedbackvariables> + <node> + <name>0</name> + <answertest>AlgEquiv</answertest> + <sans>ans1</sans> + <tans>ta</tans> + <testoptions></testoptions> + <quiet>0</quiet> + <truescoremode>=</truescoremode> + <truescore>1.0000000</truescore> + <truepenalty></truepenalty> + <truenextnode>-1</truenextnode> + <trueanswernote>prt1-1-T</trueanswernote> + <truefeedback format="html"> + <text></text> + </truefeedback> + <falsescoremode>=</falsescoremode> + <falsescore>0.0000000</falsescore> + <falsepenalty></falsepenalty> + <falsenextnode>-1</falsenextnode> + <falseanswernote>prt1-1-F</falseanswernote> + <falsefeedback format="html"> + <text></text> + </falsefeedback> + </node> + </prt> + </question> + </quiz>', + 'test3' => ' + <quiz> + <question type="stack"> + <name> + <text>Algebraic input</text> + </name> + <questiontext format="html"> + <text><![CDATA[<p>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p> + <p>(Note, this assumes single variable variable names)</p>]]></text> + </questiontext> + <generalfeedback format="html"> + <text></text> + </generalfeedback> + <defaultgrade>1.0000000</defaultgrade> + <penalty>0.1000000</penalty> + <hidden>0</hidden> + <idnumber></idnumber> + <stackversion> + <text>2020123000</text> + </stackversion> + <questionvariables> + <text>ta:a*b</text> + </questionvariables> + <specificfeedback format="html"> + <text>[[feedback:prt1]]</text> + </specificfeedback> + <questionnote> + <text></text> + </questionnote> + <questionsimplify>1</questionsimplify> + <assumepositive>0</assumepositive> + <assumereal>0</assumereal> + <prtcorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:green;"> + <i class="fa fa-check"></i></span> Correct answer, well done.]]></text> + </prtcorrect> + <prtpartiallycorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:orange;"> + <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text> + </prtpartiallycorrect> + <prtincorrect format="html"> + <text><![CDATA[<span style="font-size: 1.5em; color:red;"> + <i class="fa fa-times"></i></span> Incorrect answer.]]></text> + </prtincorrect> + <multiplicationsign>dot</multiplicationsign> + <sqrtsign>1</sqrtsign> + <complexno>i</complexno> + <inversetrig>cos-1</inversetrig> + <logicsymbol>lang</logicsymbol> + <matrixparens>[</matrixparens> + <variantsselectionseed></variantsselectionseed> + <input> + <name>ans1</name> + <type>algebraic</type> + <tans>ta</tans> + <boxsize>15</boxsize> + <strictsyntax>1</strictsyntax> + <insertstars>2</insertstars> + <syntaxhint></syntaxhint> + <syntaxattribute>0</syntaxattribute> + <forbidwords>solve</forbidwords> + <allowwords></allowwords> + <forbidfloat>1</forbidfloat> + <requirelowestterms>0</requirelowestterms> + <checkanswertype>1</checkanswertype> + <mustverify>1</mustverify> + <showvalidation>1</showvalidation> + <options></options> + </input> + <prt> + <name>prt1</name> + <value>1.0000000</value> + <autosimplify>1</autosimplify> + <feedbackstyle>1</feedbackstyle> + <feedbackvariables> + <text></text> + </feedbackvariables> + <node> + <name>0</name> + <answertest>AlgEquiv</answertest> + <sans>ans1</sans> + <tans>wrong</tans> + <testoptions></testoptions> + <quiet>0</quiet> + <truescoremode>=</truescoremode> + <truescore>1.0000000</truescore> + <truepenalty></truepenalty> + <truenextnode>-1</truenextnode> + <trueanswernote>prt1-1-T</trueanswernote> + <truefeedback format="html"> + <text></text> + </truefeedback> + <falsescoremode>=</falsescoremode> + <falsescore>0.0000000</falsescore> + <falsepenalty></falsepenalty> + <falsenextnode>-1</falsenextnode> + <falseanswernote>prt1-1-F</falseanswernote> + <falsefeedback format="html"> + <text></text> + </falsefeedback> + </node> + </prt> + </question> + </quiz>', ]; protected static array $answers = [ diff --git a/tests/fixtures/inputfixtures.class.php b/tests/fixtures/inputfixtures.class.php index ce0a6f69610c569bba8f65dfa5e3b9f053cadaf5..b14c038b14d6e622c492cd11559377b3a66a5632 100644 --- a/tests/fixtures/inputfixtures.class.php +++ b/tests/fixtures/inputfixtures.class.php @@ -143,6 +143,7 @@ class stack_inputvalidation_test_data { 'missing_stars | Variable_function', "", ], ["f''(x)", 'php_false', '' , '', '', 'apostrophe', "Apostrophies again..."], + ["''diff(f,x)", 'php_false', '' , '', '', 'Illegal_extraevaluation', ""], [ 'dosomething(x,y,z)', 'php_false', '', '', '', 'forbiddenFunction', "Students have a restricted list of function names. Teachers are less restricted.", @@ -408,19 +409,22 @@ class stack_inputvalidation_test_data { ], ['ycos(2)', 'php_true', 'y*cos(2)', 'cas_true', 'y\cdot \cos \left( 2 \right)', 'missing_stars', ""], ['Bgcd(3,2)', 'php_true', 'B*gcd(3,2)', 'cas_true', 'B\cdot 1', 'missing_stars', ""], - ['+1', 'php_true', '+1', 'cas_true', '1', '', "Unary plus"], - ['+0.200', 'php_true', '+dispdp(0.200,3)', 'cas_true', '0.200', '', ""], - ['+e', 'php_true', '+e', 'cas_true', 'e', '', ""], - ['+pi', 'php_true', '+pi', 'cas_true', '\pi', '', ""], - ['+i', 'php_true', '+i', 'cas_true', '\mathrm{i}', '', ""], - ['+x', 'php_true', '+x', 'cas_true', 'x', '', ""], - ['sqrt(+x)', 'php_true', 'sqrt(+x)', 'cas_true', '\sqrt{x}', '', ""], + ['+1', 'php_true', '+1', 'cas_true', '+1', '', "Unary plus"], + // Note: no + in front of the LaTeX below. + ['+0.200', 'php_true', '+dispdp(0.200,3)', 'cas_true', '+0.200', '', ""], + ['+e', 'php_true', '+e', 'cas_true', '+e', '', ""], + ['+pi', 'php_true', '+pi', 'cas_true', '+\pi', '', ""], + ['+i', 'php_true', '+i', 'cas_true', '+\mathrm{i}', '', ""], + ['+x', 'php_true', '+x', 'cas_true', '+x', '', ""], + // The example below is an "odd" output from Maxima. + ['sqrt(+x)', 'php_true', 'sqrt(+x)', 'cas_true', '+\sqrt{x}', '', ""], ['sqrt(x)^3', 'php_true', 'sqrt(x)^3', 'cas_true', '{\sqrt{x}}^3', '', ""], - ['1/sin(+x)', 'php_true', '1/sin(+x)', 'cas_true', '\frac{1}{\sin \left( x \right)}', '', ""], + // The example below is an "odd" output from Maxima. I'm not planning to fix this! + ['1/sin(+x)', 'php_true', '1/sin(+x)', 'cas_true', '\frac{1+}{\sin \left( x \right)}', '', ""], ['"+"(a,b)', 'php_true', '"+"(a,b)', 'cas_true', 'a+b', '', "This is Maxima specific syntax."], - ['(+1)', 'php_true', '(+1)', 'cas_true', '1', '', ""], - ['[1,+2]', 'php_true', '[1,+2]', 'cas_true', '\left[ 1 , 2 \right]', '', ""], - ['[+1,+2]', 'php_true', '[+1,+2]', 'cas_true', '\left[ 1 , 2 \right]', '', ""], + ['(+1)', 'php_true', '(+1)', 'cas_true', '+1', '', ""], + ['[1,+2]', 'php_true', '[1,+2]', 'cas_true', '\left[ 1 , +2 \right]', '', ""], + ['[+1,+2]', 'php_true', '[+1,+2]', 'cas_true', '\left[ +1 , +2 \right]', '', ""], ['-1', 'php_true', '-1', 'cas_true', '-1', '', "Unary minus"], ['-0.200', 'php_true', '-dispdp(0.200,3)', 'cas_true', '-0.200', '', ""], ['-e', 'php_true', '-e', 'cas_true', '-e', '', ""], @@ -444,7 +448,7 @@ class stack_inputvalidation_test_data { '\frac{{-b \pm \sqrt{b^2}}}{2\cdot a}', '', "", ], ['a+-b', 'php_true', 'a+-b', 'cas_true', '{a \pm b}', '', ""], - ['a-+b', 'php_true', 'a-+b', 'cas_true', 'a-b', '', ""], + ['a-+b', 'php_true', 'a-+b', 'cas_true', 'a+-\left(b\right)', '', ""], ['x & y', 'php_false', 'x & y', '', '', 'spuriousop', "Synonyms"], ['x && y', 'php_false', 'x && y', '', '', 'spuriousop', ""], ['x and y', 'php_true', 'x and y', 'cas_true', 'x\,{\text{ and }}\, y', '', ""], @@ -459,8 +463,8 @@ class stack_inputvalidation_test_data { "There is an option to display this as \(x^{1/2}|\).", ], ['root(x)', 'php_true', 'root(x)', 'cas_true', '\sqrt{x}', '', ''], - ['root(x,3)', 'php_true', 'root(x,3)', 'cas_true', 'x^{\frac{1}{3}}', '', ''], - ['root(2,-3)', 'php_true', 'root(2,-3)', 'cas_true', '2^{\frac{1}{-3}}', '', ''], + ['root(x,3)', 'php_true', 'root(x,3)', 'cas_true', '\sqrt[3]{x}', '', ''], + ['root(2,-3)', 'php_true', 'root(2,-3)', 'cas_true', '\sqrt[-3]{2}', '', ''], // Parser rules in 4.3, identify cases where known functions (cf) are prefixed with single letter variables. ['bsin(t)', 'php_true', 'b*sin(t)', 'cas_true', 'b\cdot \sin \left( t \right)', 'missing_stars', ""], // So we have added gcf as a function so it is not g*cf... @@ -645,10 +649,10 @@ class stack_inputvalidation_test_data { '\frac{\ln \left( 2\cdot x \right)}{x}+\frac{1}{2}', 'missing_stars', "", ], [ - 'a++b', 'php_true', 'a++b', 'cas_true', 'a+b', '', + 'a++b', 'php_true', 'a++b', 'cas_true', 'a++\left(b\right)', '', "The extra plusses or minuses are interpreted as unary operators on b", ], - ['a +++ b', 'php_true', 'a+++b', 'cas_true', 'a+b', '', ""], + ['a +++ b', 'php_true', 'a+++b', 'cas_true', 'a+++\left(\left(b\right)\right)', '', ""], ['a --- b', 'php_true', 'a---b', 'cas_true', 'a-\left(-\left(-b\right)\right)', '', ""], [ 'rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', 'php_true', 'rho*z*V/(4*pi*epsilon[0]*(R^2+z^2)^(3/2))', 'cas_true', @@ -666,7 +670,7 @@ class stack_inputvalidation_test_data { ['\sqrt{2+x}', 'php_false', '\sqrt{2+x}', 'cas_false', '', 'illegalcaschars', "Student uses LaTeX"], [ 'sin(x),cos(y)', 'php_false', 'sin(x),cos(y)', 'cas_true', '', - 'unencapsulated_comma', "", + 'ParseError', "", ], ['sum(k^n,n,0,3)', 'php_true', 'sum(k^n,n,0,3)', 'cas_true', '\sum_{n=0}^{3}{k^{n}}', '', "Sums and products"], [ diff --git a/tests/fixtures/test_strings.json b/tests/fixtures/test_strings.json index 3714ebb8672939c1e03514247cec6e659a4907f0..9a3f783d903162ed7224219c9169dfbe8a72ba4c 100644 --- a/tests/fixtures/test_strings.json +++ b/tests/fixtures/test_strings.json @@ -8,6 +8,7 @@ "2%e^x", "'diff(x,y)", "'int(x,y)", + "''diff(x,y)", "(()x)", "((x))", "()x", diff --git a/tests/helper.php b/tests/helper.php index b0f83073849d3fca6ae4f6ff99b878a77f4700d5..d28a605af4ba7233624f5aa91b902f09697dfd48 100644 --- a/tests/helper.php +++ b/tests/helper.php @@ -72,6 +72,8 @@ class qtype_stack_test_helper extends question_test_helper { 'block_locals', // Make sure local variables within a block are still permitted student input. 'validator', // Test teacher-defined input validators and language. 'feedback', // Test teacher-defined input feedback and complex numbers. + 'ordergreat', // Test the ordergreat function at the question level, e.g. keyvals. + 'exdowncase', // Test the ordergreat function with exdowncase. // Test questions for all the various input types. 'algebraic_input', 'algebraic_input_right', @@ -3536,7 +3538,10 @@ class qtype_stack_test_helper extends question_test_helper { $q->stackversion = '2020112300'; $q->name = 'contextvars'; - $q->questionvariables = "texput(blob, \"\\\\diamond\");\n assume(x>2);\n texput(log, \"\\\\log \", prefix);"; + $q->questionvariables = "tuptex(z):= block([a,b], [a,b]:args(z), " . + "sconcat(\"\\\\left[\",tex1(a),\",\",tex1(b),\"\\\\right)\"));texput(tup, tuptex);" . + "vec(ex):=stackvector(ex);%_stack_preamble_end;" . + "texput(blob, \"\\\\diamond\");\n assume(x>2);\n texput(log, \"\\\\log \", prefix);"; $q->questiontext = 'What is {@blob@}? [[input:ans1]] [[validation:ans1]]'; $q->generalfeedback = 'You should be able to type in {@blob@} as <code>blob</code>.'; @@ -3544,7 +3549,7 @@ class qtype_stack_test_helper extends question_test_helper { $q->penalty = 0.35; // Non-zero and not the default. $q->inputs['ans1'] = stack_input_factory::make( - 'algebraic', 'ans1', 'blob', null, ['boxWidth' => 5, 'allowWords' => 'blob']); + 'algebraic', 'ans1', 'blob', null, ['boxWidth' => 5, 'allowWords' => 'blob,vec,tup']); $q->options->set_option('simplify', true); @@ -4026,6 +4031,160 @@ class qtype_stack_test_helper extends question_test_helper { return $q; } + /** + * @return qtype_stack_question. + */ + public static function make_stack_question_ordergreat() { + $q = self::make_a_stack_question(); + + $q->name = 'ordergreat'; + $q->questionvariables = "ordergreat(x,y);\nta:5*y+3*x=1"; + $q->questiontext = "What is {@ta@}? [[input:ansq]][[validation:ansq]]" . + // Below checks this is still a real float. + '{@dispdp(float(pi),4)@}'; + $q->generalfeedback = ''; + $q->questionnote = ''; + + $q->specificfeedback = '[[feedback:firsttree]]'; + $q->penalty = 0.25; // Non-zero and not the default. + + $q->inputs['ansq'] = stack_input_factory::make( + 'algebraic', 'ansq', 'ta', null, + [ + 'boxWidth' => 20, 'forbidWords' => '' + ]); + + // By setting simp:true (the default) we check the re-ordering really happens. + $q->options->set_option('simplify', true); + + $prt = new stdClass; + $prt->name = 'firsttree'; + $prt->id = 0; + $prt->value = 1; + $prt->feedbackstyle = 1; + $prt->feedbackvariables = ''; + $prt->firstnodename = '0'; + $prt->nodes = []; + $prt->autosimplify = false; + + $newnode = new stdClass; + $newnode->id = '0'; + $newnode->nodename = '0'; + $newnode->description = ''; + $newnode->sans = 'ansq'; + $newnode->tans = 'ta'; + $newnode->answertest = 'CasEqual'; + $newnode->testoptions = ''; + $newnode->quiet = false; + $newnode->falsescore = '0'; + $newnode->falsescoremode = '='; + $newnode->falsepenalty = $q->penalty; + $newnode->falsefeedback = ""; + $newnode->falsefeedbackformat = '1'; + $newnode->falseanswernote = 'firsttree-0-0'; + $newnode->falsenextnode = '-1'; + $newnode->truescore = '1'; + $newnode->truescoremode = '='; + $newnode->truepenalty = $q->penalty; + $newnode->truefeedback = ""; + $newnode->truefeedbackformat = '1'; + $newnode->trueanswernote = 'firsttree-0-1'; + $newnode->truenextnode = '-1'; + $prt->nodes[] = $newnode; + + $q->prts[$prt->name] = new stack_potentialresponse_tree_lite($prt, $prt->value, $q); + + return $q; + } + + /** + * @return qtype_stack_question. + */ + public static function make_stack_question_exdowncase() { + $q = self::make_a_stack_question(); + + $q->name = 'exdowncase'; + $q->questionvariables = "ordergreat(x);\nveq: 5*y^2-8*x*y+13*x^2 = 49;"; + $q->questiontext = "What is {@veq@}? [[input:ansq]][[validation:ansq]]"; + $q->generalfeedback = ''; + $q->questionnote = ''; + + $q->specificfeedback = '[[feedback:firsttree]]'; + $q->penalty = 0.25; // Non-zero and not the default. + + $q->inputs['ansq'] = stack_input_factory::make( + 'algebraic', 'ansq', 'veq', null, + [ + 'boxWidth' => 20, 'forbidWords' => '' + ]); + + // By setting simp:true (the default) we check the re-ordering really happens. + $q->options->set_option('simplify', true); + + $prt = new stdClass; + $prt->name = 'firsttree'; + $prt->id = 0; + $prt->value = 1; + $prt->feedbackstyle = 1; + $prt->feedbackvariables = 'loweranseq:exdowncase(ansq);'; + $prt->firstnodename = '0'; + $prt->nodes = []; + $prt->autosimplify = true; + + $newnode = new stdClass; + $newnode->id = '0'; + $newnode->nodename = '0'; + $newnode->description = 'Use CasEqual as the test'; + $newnode->sans = 'loweranseq'; + $newnode->tans = 'veq'; + $newnode->answertest = 'CasEqual'; + $newnode->testoptions = ''; + $newnode->quiet = false; + $newnode->falsescore = '0'; + $newnode->falsescoremode = '='; + $newnode->falsepenalty = $q->penalty; + $newnode->falsefeedback = ""; + $newnode->falsefeedbackformat = '1'; + $newnode->falseanswernote = 'firsttree-0-0'; + $newnode->falsenextnode = '1'; + $newnode->truescore = '1'; + $newnode->truescoremode = '='; + $newnode->truepenalty = $q->penalty; + $newnode->truefeedback = ""; + $newnode->truefeedbackformat = '1'; + $newnode->trueanswernote = 'firsttree-0-1'; + $newnode->truenextnode = '1'; + $prt->nodes[] = $newnode; + $newnode = new stdClass; + $newnode->id = '1'; + $newnode->nodename = '1'; + $newnode->description = 'Use AlgEquiv as the test'; + $newnode->sans = 'loweranseq'; + $newnode->tans = 'veq'; + $newnode->answertest = 'AlgEquiv'; + $newnode->testoptions = ''; + $newnode->quiet = false; + $newnode->falsescore = '0'; + $newnode->falsescoremode = '='; + $newnode->falsepenalty = $q->penalty; + $newnode->falsefeedback = ""; + $newnode->falsefeedbackformat = '1'; + $newnode->falseanswernote = 'firsttree-1-0'; + $newnode->falsenextnode = '-1'; + $newnode->truescore = '1'; + $newnode->truescoremode = '='; + $newnode->truepenalty = $q->penalty; + $newnode->truefeedback = ""; + $newnode->truefeedbackformat = '1'; + $newnode->trueanswernote = 'firsttree-1-1'; + $newnode->truenextnode = '-1'; + $prt->nodes[] = $newnode; + + $q->prts[$prt->name] = new stack_potentialresponse_tree_lite($prt, $prt->value, $q); + + return $q; + } + /** * Make the data what would be received from the editing form for an algebraic input question. * diff --git a/tests/input_algebraic_test.php b/tests/input_algebraic_test.php index 7e99025a96629dc32ff104b054b0558e4bb4c05c..f726f0da6e88d4bbd773e5ffaa12746ece8a4316 100644 --- a/tests/input_algebraic_test.php +++ b/tests/input_algebraic_test.php @@ -344,6 +344,30 @@ class input_algebraic_test extends qtype_stack_testcase { $this->assertEquals('Lowest_Terms', $state->note); } + public function test_validate_student_response_with_minus_zero() { + $options = new stack_options(); + $el = stack_input_factory::make('algebraic', 'sans1', '1/2'); + $el->set_parameter('forbidFloats', false); + + $state = $el->validate_student_response(['sans1' => "x-0"], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assertEquals('x-0', $state->contentsmodified); + $this->assertEquals('\[ x-0 \]', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + + $state = $el->validate_student_response(['sans1' => "x-0.0"], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assertEquals('x-0.0', $state->contentsmodified); + $this->assertEquals('\[ x-0.0 \]', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + + $state = $el->validate_student_response(['sans1' => "x*(-0.0)"], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assertEquals('x*(-0.0)', $state->contentsmodified); + $this->assertEquals('\[ x\cdot \left(-0.0\right) \]', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + } + public function test_validate_student_response_with_rationalized() { $options = new stack_options(); $el = stack_input_factory::make('algebraic', 'sans1', '1/2'); @@ -436,7 +460,8 @@ class input_algebraic_test extends qtype_stack_testcase { new stack_cas_security(false, '', '', ['ta'])); $this->assertEquals(stack_input::VALID, $state->status); $this->assertEquals('2*sqrt(+2)/3', $state->contentsmodified); - $this->assertEquals('\[ \frac{2\cdot \sqrt{2}}{3} \]', $state->contentsdisplayed); + // Maxima's TeX code pulls out the + to outside the sqrt. Known edge case. + $this->assertEquals('\[ \frac{2\cdot +\sqrt{2}}{3} \]', $state->contentsdisplayed); $this->assertEquals('The answer <span class="filter_mathjaxloader_equation">' . '<span class="nolink">\( \frac{2\cdot \sqrt{2}}{3} \)</span></span>, which can be typed as ' . '<code>2*sqrt(2)/3</code>, would be correct.', @@ -595,6 +620,21 @@ class input_algebraic_test extends qtype_stack_testcase { '\sin \left( 3\cdot x \right) \]', $state->contentsdisplayed); } + public function test_validate_student_response_extra_evaluation() { + $options = new stack_options(); + $el = stack_input_factory::make('algebraic', 'sans1', 'noundiff(y/x^2,x,1)-(2*y)/x = x^3*sin(3*x)'); + $el->set_parameter('sameType', false); + $state = $el->validate_student_response(['sans1' => "''diff(y/x^2,x,1)"], + $options, 'diff(y/x^2,x,1)-(2*y)/x = x^3*sin(3*x)', new stack_cas_security()); + $this->assertEquals(stack_input::INVALID, $state->status); + $this->assertEquals('Illegal_extraevaluation', $state->note); + $this->assertEquals("Maxima's extra evaluation operator <code>''</code> is not supported by STACK.", + $state->errors); + $this->assertEquals("''%_E(%_E(noundiff(y/x^2,x,1)))", $state->contentsmodified); + $this->assertEquals("<span class=\"stacksyntaxexample\">''diff(y/x^2,x,1)</span>", + $state->contentsdisplayed); + } + public function test_validate_student_response_single_var_chars_on() { // Check the single variable character option is tested. $options = new stack_options(); @@ -960,6 +1000,40 @@ class input_algebraic_test extends qtype_stack_testcase { $el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed)); } + public function test_validate_student_response_with_allowempty_stars() { + $options = new stack_options(); + $el = stack_input_factory::make('algebraic', 'sans1', '1/2'); + $el->set_parameter('options', 'allowempty'); + + $el->set_parameter('insertStars', 1); + $state = $el->validate_student_response(['sans1' => ''], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::SCORE, $state->status); + $this->assertEquals('EMPTYANSWER', $state->contentsmodified); + $this->assertEquals('', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + $this->assertEquals('This input can be left blank.', + $el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed)); + + // Assuming single character variable names. + $el->set_parameter('insertStars', 2); + $state = $el->validate_student_response(['sans1' => ''], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::SCORE, $state->status); + $this->assertEquals('EMPTYANSWER', $state->contentsmodified); + $this->assertEquals('', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + $this->assertEquals('This input can be left blank.', + $el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed)); + + $el->set_parameter('insertStars', 5); + $state = $el->validate_student_response(['sans1' => ''], $options, '3.14', new stack_cas_security()); + $this->assertEquals(stack_input::SCORE, $state->status); + $this->assertEquals('EMPTYANSWER', $state->contentsmodified); + $this->assertEquals('', $state->contentsdisplayed); + $this->assertEquals('', $state->errors); + $this->assertEquals('This input can be left blank.', + $el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed)); + } + public function test_validate_string_same_type_invalid_division_zero() { $options = new stack_options(); $el = stack_input_factory::make('algebraic', 'sans1', 'x^3'); @@ -1555,6 +1629,22 @@ class input_algebraic_test extends qtype_stack_testcase { '\[ \left( a,\, b\right] \]'); } + public function test_validate_student_response_root() { + $options = new stack_options(); + $el = stack_input_factory::make('algebraic', 'sans1', 'x^(1/n)'); + $el->set_parameter('sameType', true); + + // We don't require intervals to have real numbers in them. + $state = $el->validate_student_response(['sans1' => 'root(x,n)'], $options, 'x^(1/n)', + new stack_cas_security(false, '', '', ['ta'])); + $this->assertEquals($state->status, stack_input::VALID); + $this->assertEquals('', $state->note); + $this->assertEquals('', $state->errors); + $this->assertEquals($state->contentsmodified, '\'root(x,n)'); + $this->assertEquals($state->contentsdisplayed, + '\[ \sqrt[n]{x} \]'); + } + public function test_validate_student_response_tex() { $options = new stack_options(); $el = stack_input_factory::make('algebraic', 'sans1', '{}'); @@ -1563,7 +1653,7 @@ class input_algebraic_test extends qtype_stack_testcase { new stack_cas_security(false, '', '', ['ta'])); $this->assertEquals($state->status, stack_input::INVALID); $this->assertEquals('illegalcaschars', $state->note); - $this->assertEquals('The characters @, $ and \ are not allowed in CAS input.', $state->errors); + $this->assertEquals('The characters @ and \ are not allowed in CAS input.', $state->errors); $this->assertEquals($state->contentsmodified, ''); // This appears to the student to display correctly, since the TeX is picked up by MathJax. $this->assertEquals($state->contentsdisplayed, diff --git a/tests/input_numerical_test.php b/tests/input_numerical_test.php index eac617261b669fdcce05f232a886c27ea6ca6a49..141432bdca38520627c5850c7b136061e4d1e95c 100644 --- a/tests/input_numerical_test.php +++ b/tests/input_numerical_test.php @@ -787,4 +787,41 @@ class input_numerical_test extends qtype_stack_testcase { $this->assertEquals('Your answer should be an expression, not an equation, inequality, list, set or matrix.', $state->errors); } + + public function test_validate_student_response_power_dispdp() { + $options = new stack_options(); + $el = stack_input_factory::make('numerical', 'sans1', '1729'); + $state = $el->validate_student_response(['sans1' => "9.000^3+10.00^3"], $options, '1729', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assert_equals_ignore_spaces_and_e('9.000^3+10.00^3', $state->contentsmodified); + $this->assertEquals('\[ {9.000}^3+{10.00}^3 \]', $state->contentsdisplayed); + $this->assertEquals('', $state->note); + } + + public function test_validate_student_response_simp() { + $options = new stack_options(); + $el = stack_input_factory::make('numerical', 'sans1', '1729.0'); + $el->set_parameter('options', 'simp'); + // Simplification is applied to integers. + $state = $el->validate_student_response(['sans1' => '9^3+10^3'], $options, + '', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assertEquals('', $state->note); + $this->assertEquals('', $state->errors); + $content = $state->contentsmodified; + $this->assertEquals('9^3+10^3', $content); + $this->assertEquals('\[ 1729 \]', + $state->contentsdisplayed); + + // Simplification is not currently applied to floats, which have their significant protected. + $state = $el->validate_student_response(['sans1' => '9.0^3+10^3'], $options, + '', new stack_cas_security()); + $this->assertEquals(stack_input::VALID, $state->status); + $this->assertEquals('', $state->note); + $this->assertEquals('', $state->errors); + $content = $state->contentsmodified; + $this->assertEquals('9.0^3+10^3', $content); + $this->assertEquals('\[ {9.0}^3+1000 \]', + $state->contentsdisplayed); + } } diff --git a/tests/vle_specific_test.php b/tests/vle_specific_test.php new file mode 100644 index 0000000000000000000000000000000000000000..2314b94538759c2b9d1b78a06cc1cffb9ad761fa --- /dev/null +++ b/tests/vle_specific_test.php @@ -0,0 +1,81 @@ +<?php +// This file is part of STACK - http://stack.maths.ed.ac.uk// +// +// Stack is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Stack is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Stack. If not, see <http://www.gnu.org/licenses/>. + +namespace qtype_stack; + +use qtype_stack_testcase; + +defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/fixtures/test_base.php'); +require_once(__DIR__ . '/../vle_specific.php'); + +/** + * Test Moodle VLE specific functions. + * + * @copyright 2023 The University of Edinburgh. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. + */ + +/** + * @group qtype_stack + * @covers \vle_specific + */ +class vle_specific_test extends qtype_stack_testcase { + + public function test_mathjaxurl() { + $this->resetAfterTest(); + + // Parameters but no config. + set_config('httpsurl', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?one=1&two=two', 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML&one=1&two=two', + $result); + + // No setting at all. + set_config('httpsurl', '', 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML', + $result); + + // Config already set and other parameter. + set_config('httpsurl', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=alreadyhere&one=1', + 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=alreadyhere&one=1', $result); + + // Config already set. + set_config('httpsurl', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=alreadyhere', + 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=alreadyhere', $result); + + // Parameter with question mark. + set_config('httpsurl', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=already?here', + 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=already%3Fhere', $result); + + // Nothing. NB Setting the config to the following at the start of the test will lead to cache problems + // as it matches the default and so doesn't invalidate the cache. + set_config('httpsurl', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js', 'filter_mathjaxloader'); + $result = stack_get_mathjax_url(); + $this->assertEquals('https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML', $result); + + } +} + + diff --git a/tests/walkthrough_adaptive_test.php b/tests/walkthrough_adaptive_test.php index 57a9158886b734c3bd0d65a331dde2c9546c1a6c..7bef19bec6345763593b3c27c974c374d00fbccb 100644 --- a/tests/walkthrough_adaptive_test.php +++ b/tests/walkthrough_adaptive_test.php @@ -432,7 +432,6 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { // @codingStandardsIgnoreEnd // Now use the correct answer. - $ta = $q->get_correct_response(); $sa = $ta['ans1']; $this->process_submission(['ans1' => $sa, '-submit' => 1]); @@ -1312,7 +1311,6 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { $this->check_current_output( new question_no_pattern_expectation('/Your answer is partially correct./') ); - } public function test_test3_save_invalid_response_correct_then_stubmit() { @@ -4026,9 +4024,36 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { $this->get_no_hint_visible_expectation() ); + // Process a validate request with a texput function. + $this->process_submission(['ans1' => 'vec(x)', '-submit' => 1]); + $this->check_current_state(question_state::$todo); + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + $this->check_output_contains_text_input('ans1', 'vec(x)'); + $this->check_output_contains_input_validation('ans1'); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->assert_content_with_maths_contains('\[ {\bf x} \]', $this->currentoutput); + $expected = 'Seed: 1; ans1: vec(x) [valid]; firsttree: !'; + $this->check_response_summary($expected); + + // Process a validate request with a texput function. + $this->process_submission(['ans1' => 'tup(3,4)', '-submit' => 1]); + $this->check_current_state(question_state::$todo); + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + $this->check_output_contains_text_input('ans1', 'tup(3,4)'); + $this->check_output_contains_input_validation('ans1'); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->assert_content_with_maths_contains('\[ \left[3,4\right) \]', $this->currentoutput); + $expected = 'Seed: 1; ans1: tup(3,4) [valid]; firsttree: !'; + $this->check_response_summary($expected); + // Process a validate request. $this->process_submission(['ans1' => 'log(blob)', '-submit' => 1]); - $this->check_current_state(question_state::$todo); $this->check_current_mark(null); $this->check_prt_score('firsttree', null, null); @@ -4037,6 +4062,9 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { $this->check_output_contains_input_validation('ans1'); $this->check_output_does_not_contain_prt_feedback(); $this->check_output_does_not_contain_stray_placeholders(); + $this->assert_content_with_maths_contains('\[ \log \left( \diamond \right) \]', $this->currentoutput); + $expected = 'Seed: 1; ans1: log(blob) [valid]; firsttree: !'; + $this->check_response_summary($expected); // Process a submition of an incorrect answer. $this->process_submission(['ans1' => 'log(blob)', 'ans1_val' => 'log(blob)', '-submit' => 1]); @@ -4044,6 +4072,9 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { $this->check_current_mark(0); $this->check_prt_score('firsttree', 0, 0.35); $this->check_answer_note('firsttree', 'firsttree-1-F | firsttree-2-F'); + $this->assert_content_with_maths_contains('\[ \log \left( \diamond \right) \]', $this->currentoutput); + $expected = 'Seed: 1; ans1: log(blob) [score]; firsttree: # = 0 | firsttree-1-F | firsttree-2-F'; + $this->check_response_summary($expected); // Process the correct answer. Needs the assumption x>2 for ATAlgEquiv to correctly work. $this->process_submission(['ans1' => '6*((x-2)^2)^k', '-submit' => 1]); @@ -4723,4 +4754,137 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base { // This vaidation output is the result of a texput command with a lambda function. $this->assert_content_with_maths_contains('\\frac{x}{y}', $this->currentoutput); } + + public function test_input_validator_ordergreat() { + $q = test_question_maker::make_question('stack', 'ordergreat'); + $this->start_attempt_at_question($q, 'adaptive', 1); + + // Check the initial state. + $this->check_current_state(question_state::$todo); + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + $this->check_output_contains_text_input('ansq'); + $this->check_output_does_not_contain_input_validation(); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->check_current_output( + new question_pattern_expectation('/What is/'), + $this->get_does_not_contain_feedback_expectation(), + $this->get_does_not_contain_num_parts_correct(), + $this->get_no_hint_visible_expectation() + ); + $this->assert_content_with_maths_contains('\({3\cdot x+5\cdot y=1}\)', $this->currentoutput); + + // Process a validate request. + $ia = '7*y+3*x=1'; + $this->process_submission(['ansq' => $ia, '-submit' => 1]); + + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + + // Check order of variables in validation of answer matches what students type. + $expected = 'Seed: 1; ansq: 7*y+3*x=1 [valid]; firsttree: !'; + $this->check_response_summary($expected); + $this->check_output_contains_text_input('ansq', $ia); + $this->check_output_contains_input_validation('ansq'); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->assert_content_with_maths_contains('\[ 7\cdot y+3\cdot x=1', $this->currentoutput); + // Checks {@pi@} is the value of the constant. + $this->assert_content_with_maths_contains('\({3.1416}\)', $this->currentoutput); + + // Jump to score requests for different answers. + $ia = '7*y+3*x=1'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 7\cdot y+3\cdot x=1', $this->currentoutput); + $expected = 'Seed: 1; ansq: 7*y+3*x=1 [score]; firsttree: # = 0 | ATCASEqual_false. | firsttree-0-0'; + $this->check_response_summary($expected); + + $ia = '5*y+3*x=1'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 5\cdot y+3\cdot x=1', $this->currentoutput); + $expected = 'Seed: 1; ansq: 5*y+3*x=1 [score]; firsttree: # = 0 | ATCASEqual (AlgEquiv-true)ATEquation_sides. ' . + '| firsttree-0-0'; + $this->check_response_summary($expected); + + $ia = '3*x+5*y=1'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 3\cdot x+5\cdot y=1', $this->currentoutput); + $expected = 'Seed: 1; ansq: 3*x+5*y=1 [score]; firsttree: # = 1 | ATCASEqual_true. | firsttree-0-1'; + $this->check_response_summary($expected); + } + + public function test_input_validator_exdowncase() { + $q = test_question_maker::make_question('stack', 'exdowncase'); + $this->start_attempt_at_question($q, 'adaptive', 1); + + // Check the initial state. + $this->check_current_state(question_state::$todo); + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + $this->check_output_contains_text_input('ansq'); + $this->check_output_does_not_contain_input_validation(); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->check_current_output( + new question_pattern_expectation('/What is/'), + $this->get_does_not_contain_feedback_expectation(), + $this->get_does_not_contain_num_parts_correct(), + $this->get_no_hint_visible_expectation() + ); + $this->assert_content_with_maths_contains('\({13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49}\)', + $this->currentoutput); + + // Process a validate request. + $ia = '13*x^2-8*y*x+5*y^2 = 49'; + $this->process_submission(['ansq' => $ia, '-submit' => 1]); + + $this->check_current_mark(null); + $this->check_prt_score('firsttree', null, null); + $this->render(); + + // Check order of variables in validation of answer matches what students type. + $expected = 'Seed: 1; ansq: 13*x^2-8*y*x+5*y^2 = 49 [valid]; firsttree: !'; + $this->check_response_summary($expected); + $this->check_output_contains_text_input('ansq', $ia); + $this->check_output_contains_input_validation('ansq'); + $this->check_output_does_not_contain_prt_feedback(); + $this->check_output_does_not_contain_stray_placeholders(); + $this->assert_content_with_maths_contains('\[ 13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49', + $this->currentoutput); + $ia = '13*x^2-8*y*x+5*y^2 = 49'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49', + $this->currentoutput); + $expected = 'Seed: 1; ansq: 13*x^2-8*y*x+5*y^2 = 49 [score]; firsttree: # = 1 | ' . + 'ATCASEqual_true. | firsttree-0-1 | ATEquation_sides | firsttree-1-1'; + $this->check_response_summary($expected); + + // New answer with upper case. + $ia = '13*X^2-8*y*x+5*y^2 = 49'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 13\cdot X^2-8\cdot y\cdot x+5\cdot y^2=49', + $this->currentoutput); + $expected = 'Seed: 1; ansq: 13*X^2-8*y*x+5*y^2 = 49 [score]; firsttree: # = 1 | ' . + 'ATCASEqual_true. | firsttree-0-1 | ATEquation_sides | firsttree-1-1'; + $this->check_response_summary($expected); + + // New answer which is wrong. + $ia = '13*X^2-8*y*x+5*y^2 = 48'; + $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]); + $this->render(); + $this->assert_content_with_maths_contains('\[ 13\cdot X^2-8\cdot y\cdot x+5\cdot y^2=48', + $this->currentoutput); + $expected = 'Seed: 1; ansq: 13*X^2-8*y*x+5*y^2 = 48 [score]; firsttree: # = 0 | ' . + 'ATCASEqual_false. | firsttree-0-0 | ATEquation_lhs_notrhs | firsttree-1-0'; + $this->check_response_summary($expected); + } } diff --git a/version.php b/version.php index 10bdf94bddba7e96e394b79256d865b91f52b9e3..3ad00ac5550a095aa1047deb82104b70975db144 100644 --- a/version.php +++ b/version.php @@ -24,12 +24,12 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024060300; +$plugin->version = 2025072400; $plugin->requires = 2022041900; $plugin->cron = 0; $plugin->component = 'qtype_stack'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '4.6.0 for Moodle 4.0+'; +$plugin->release = '4.7.0 for Moodle 4.0+'; $plugin->dependencies = [ 'qbehaviour_adaptivemultipart' => 2020103000, diff --git a/vle_specific.php b/vle_specific.php index 7b5651159c45f6b24bcfb7738fe497eca7e1942b..d62e8172170c4e15db9a25b0747d2729a9bd7f47 100644 --- a/vle_specific.php +++ b/vle_specific.php @@ -196,7 +196,24 @@ function stack_cors_link(string $filename): string { */ function stack_get_mathjax_url(): string { // TO-DO: figure out how to support VLE local with CORS. - return 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; + $mathjaxconfigurl = get_config('filter_mathjaxloader', 'httpsurl'); + if ($mathjaxconfigurl) { + $questionpos = strpos($mathjaxconfigurl, '?'); + if ($questionpos !== false) { + $querystring = substr($mathjaxconfigurl, $questionpos + 1); + $urlstring = substr($mathjaxconfigurl, 0, $questionpos); + parse_str($querystring, $queryparams); + $queryparams = array_merge(['config' => 'TeX-AMS-MML_HTMLorMML'], $queryparams); + $querystring = http_build_query($queryparams, '', '&', PHP_QUERY_RFC3986); + $url = $urlstring . '?' . $querystring; + } else { + $url = $mathjaxconfigurl . '?config=TeX-AMS-MML_HTMLorMML'; + } + + return $url; + } else { + return 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML'; + } } /*