diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 4288298334b..70640034cb4 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 7c0350e3233..671ccd8ac7f 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 4c3eace2d5d..021b9b0bc4c 100644 --- a/adminui/caschat.php +++ b/adminui/caschat.php @@ -132,6 +132,9 @@ 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 09f05bec0b2..382b470bc7a 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=/]*>([\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")}}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;i0?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;i0&&langInput[0].value&&(language=langInput[0].value);for(var allok=!0,i=0;i]*>([\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")}}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;i0?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;i0&&langInput[0].value&&(language=langInput[0].value);for(var allok=!0,i=0;i.\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 = /]*>([\\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
here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('
');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container
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
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
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
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
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 .\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 = /]*>([\\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
here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('
');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container
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
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
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
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
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 a3273ac408a..4a62dade5f2 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 d36ee63faa7..9d7b2aebf49 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 ``. + +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 ea478cf19ae..2b1d936bdef 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 a6aabb900f4..170dc1046f0 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 7f82639ae2d..65020a242a2 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 . -// 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 517b6aa9955..1b7adaf0039 100644 --- a/api/controller/DownloadController.php +++ b/api/controller/DownloadController.php @@ -41,7 +41,7 @@ public function __invoke(Request $request, Response $response, array $args): Res $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 a1e9029db01..ac92728e00a 100644 --- a/api/controller/GradingController.php +++ b/api/controller/GradingController.php @@ -44,7 +44,7 @@ public function __invoke(Request $request, Response $response, array $args): Res // 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 a89da53a5d9..a17bb9b7b93 100644 --- a/api/controller/RenderController.php +++ b/api/controller/RenderController.php @@ -45,7 +45,7 @@ public function __invoke(Request $request, Response $response, array $args): Res // 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 00000000000..1f60dada4d8 --- /dev/null +++ b/api/controller/TestController.php @@ -0,0 +1,223 @@ +. + +// 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 b10545e2eec..4eb1c732e22 100644 --- a/api/controller/ValidationController.php +++ b/api/controller/ValidationController.php @@ -42,7 +42,7 @@ public function __invoke(Request $request, Response $response, array $args): Res // 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 268a66b5103..548f6fc2215 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 df97a5a405c..054c3dee214 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 00000000000..e5e86f82b3d --- /dev/null +++ b/api/dtos/StackTestResponse.php @@ -0,0 +1,45 @@ +. + +/** + * 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 86593cd21ee..ae8cbf908de 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 00000000000..a50e7f4b48b --- /dev/null +++ b/api/public/bulktest.php @@ -0,0 +1,415 @@ +. + +// 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(); +?> + + + + + + + + + +
+
+ + : + +
+ +
+
+
+
+
+ +

+ +
+ + + + diff --git a/api/public/index.php b/api/public/index.php index 4b010f3b239..2ba9a78eebe 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -25,6 +25,7 @@ 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->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 8656b4a67ff..dade32f92f7 100644 --- a/api/public/stack.php +++ b/api/public/stack.php @@ -137,16 +137,18 @@ function processNodes(res, nodes) { // 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 @@ function send() { question = question.replace(`[[validation:${name}]]`, ``); if (input.samplesolutionrender && name !== 'remember') { // Display render of answer and matching user input to produce the answer. - correctAnswers += `

A correct answer is: \\[{${input.samplesolutionrender}}\\], - which can be typed as follows: `; + correctAnswers += `

+ \\[{${input.samplesolutionrender}}\\], + : `; for (const [name, solution] of Object.entries(input.samplesolution)) { if (name.indexOf('_val') === -1) { correctAnswers += `${solution}`; @@ -221,7 +224,8 @@ function send() { 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 @@ function send() { // 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 @@ function validate(element) { 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 @@ function validate(element) { 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 @@ function validate(element) { // 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 @@ function answer() { 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.'; + = ' '; 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) + + ' ' + 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 @@ function answer() { if (elements.length > 0) { const element = elements[0]; if (json.scores[name] !== undefined) { - fb = fb + `

Marks for this submission: + fb = fb + `
: ${(json.scores[name] * json.scoreweights[name] * json.scoreweights.total).toFixed(2)} / ${(json.scoreweights[name] * json.scoreweights.total).toFixed(2)}.
`; } @@ -335,7 +345,8 @@ function answer() { 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 @@ function answer() { 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 @@ function download(filename, fileid) { link.click(); } catch(e) { - document.getElementById('output').innerText = http.responseText; + document.getElementById('errors').innerText = http.responseText; + return; } } }; @@ -458,7 +470,7 @@ function createQuestionList(fileContents) { 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 = ": "; holder.appendChild(selectQuestion); let firstquestion = null for (const question of xmlDoc.getElementsByTagName("question")) { @@ -493,9 +505,9 @@ function setQuestion(question) {
- Choose a STACK sample file: + : - Or select a file of your own: + :
-

Question XML

+

-

Seed:

+

- - Read Only + +
+
- +
diff --git a/api/util/StackQuestionLoader.php b/api/util/StackQuestionLoader.php index 719ab1c729c..ac3c0565fed 100644 --- a/api/util/StackQuestionLoader.php +++ b/api/util/StackQuestionLoader.php @@ -23,13 +23,15 @@ 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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { $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 @@ public static function loadxml($xml) { } $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 37dc9a4ecde..383c8ed159a 100644 --- a/backup/moodle2/backup_qtype_stack_plugin.class.php +++ b/backup/moodle2/backup_qtype_stack_plugin.class.php @@ -47,6 +47,7 @@ protected function define_question_plugin_structure() { $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 071c25bb6a0..4849a9757be 100644 --- a/deploy.php +++ b/deploy.php @@ -61,9 +61,7 @@ $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 @@ // 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)) { $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 @@ } // 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 908be6522f8..c3c39dc8f39 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)) 0 + + AlgEquiv + +
'root(x)
+
x^(1/2)
+ + 1 + + + + AlgEquiv + +
'root(x,m)
+
x^(1/m)
+ + 1 + + + + AlgEquiv + +
x
+
'root(x^2)
+ + 0 + + AlgEquiv diff --git a/doc/en/Authoring/Options.md b/doc/en/Authoring/Options.md index e7a89777946..c04f24e1d58 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 d00d786f59c..0228b096d40 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 9da591f0bc7..8cdadef312b 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 90e6fd9f62f..f98864acd61 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 c4fd6ac9451..dcc451aa644 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 7c4550bc4c2..7d1a597bc5a 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 a994ccac92e..af4404c5d99 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 bb7b8918a71..454a986b667 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 7b18a471fc2..31acd903333 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 c355cb8dd87..91073a89fa2 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 b4361fa17da..fcd4fa2963d 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])@}

Putting the axes in the middle

{@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])@} +

Example with ticks, colour and alt-text

+ {@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 20d775e7a57..451eef9aa54 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 4d1f3ea493b..6e6f33d4678 100644 --- a/lang/de/qtype_stack.php +++ b/lang/de/qtype_stack.php @@ -546,7 +546,7 @@ \\[\\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 0ef0872ec48..60284828992 100644 --- a/lang/en/qtype_stack.php +++ b/lang/en/qtype_stack.php @@ -161,7 +161,7 @@ $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['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['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_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_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 if-conditional or the do-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 '' 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_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 @@ - // 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 8fc7081bfeb..5a7868f71d1 100644 --- a/question.php +++ b/question.php @@ -378,7 +378,8 @@ public function initialise_question_from_seed() { } 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 @@ protected function adapt_inputs() { 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 @@ public function get_generalfeedback_castext() { 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 @@ public function get_questiondescription_castext() { 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 @@ public function get_prt_result($index, $response, $acceptvalid) { } 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 a4ff85d8f3a..1ceec928f09 100644 --- a/questiontestrun.php +++ b/questiontestrun.php @@ -176,27 +176,12 @@ // 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 @@ echo html_writer::end_tag('form'); } +if (empty($testscases)) { + echo "\n
\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
\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 @@ function sort_by_note($a1, $b1) { 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 @@ function sort_by_note($a1, $b1) { ]); 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 8dae8fd8313..83c91487d88 100644 --- a/stack/bulktester.class.php +++ b/stack/bulktester.class.php @@ -450,6 +450,18 @@ public function qtype_stack_test_question($context, $qid, $tests, $outputmode, $ 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 @@ public function print_overall_result($allpassed, $failing) { 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 a7d280acb07..9bdec031deb 100644 --- a/stack/cas/cassession2.class.php +++ b/stack/cas/cassession2.class.php @@ -332,8 +332,9 @@ public function instantiate(): bool { $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 747589d28d6..a8df15152f3 100644 --- a/stack/cas/castext2/blocks/parsons.block.php +++ b/stack/cas/castext2/blocks/parsons.block.php @@ -234,14 +234,14 @@ public function compile($format, $options): ? MP_Node { // 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 @@ public function compile($format, $options): ? MP_Node { $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 @@ public function compile($format, $options): ? MP_Node { $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 @@ public function compile($format, $options): ? MP_Node { ) );' . "\n"; - $code .= 'sortableAvailable.option("onSort", + $code .= 'sortableAvailable.option("onSort", () => { stackSortable.update_state(sortableUsed, sortableAvailable); stackSortable.update_grid_empty_css();});' . "\n"; @@ -353,10 +352,10 @@ public function compile($format, $options): ? MP_Node { 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 @@ public function validate ( $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 @@ public function validate ( } } - // 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 @@ public function validate ( } } - // 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 @@ public function validate ( } } - // 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 @@ public function validate ( } } - // 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 d34bbf9b204..8552b254a65 100644 --- a/stack/cas/keyval.class.php +++ b/stack/cas/keyval.class.php @@ -104,9 +104,8 @@ private function validate($inputs) { $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 @@ public function compile(string $contextname, castext2_static_replacer $map = nul 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 @@ public function compile(string $contextname, castext2_static_replacer $map = nul 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 00000000000..6bbd683bf9a --- /dev/null +++ b/stack/cas/parsingrules/033_no_extra_evaluation.filter.php @@ -0,0 +1,41 @@ +. + +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 59717b122ca..83c5d6fc3e8 100644 --- a/stack/cas/parsingrules/996_call_modification.filter.php +++ b/stack/cas/parsingrules/996_call_modification.filter.php @@ -87,7 +87,7 @@ public function filter(MP_Node $ast, array &$errors, array &$answernotes, stack_ // 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 a6943fd9aaf..1aacd11149b 100644 --- a/stack/cas/parsingrules/parsingrule.factory.php +++ b/stack/cas/parsingrules/parsingrule.factory.php @@ -27,6 +27,7 @@ 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 @@ private static function build_from_name(string $name): stack_cas_astfilter { 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 @@ public static function get_by_common_name(string $name): stack_cas_astfilter { '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 281a45c4923..4e2c4274b09 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 @@ public function __construct(string $securedcode, string $fromwhere='') { $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 @@ public function get_errors($raw = 'implode') { 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 bac110da349..37a3a62fcf3 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 07f945f8d9b..3225e270bd3 100644 --- a/stack/input/inputbase.class.php +++ b/stack/input/inputbase.class.php @@ -458,7 +458,7 @@ public function adapt_to_model_answer($teacheranswer) { 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 @@ private function extra_option_variables($questionvariables) { $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 @@ private function extra_option_variables($questionvariables) { 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 c78d10c4169..965c1a16df5 100644 --- a/stack/mathsoutput/mathsoutputapi.class.php +++ b/stack/mathsoutput/mathsoutputapi.class.php @@ -47,7 +47,7 @@ public function process_display_castext($text, $replacedollars, qtype_stack_rend $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 560fc2ef99e..fe7b2bdf3f8 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 cc5c1e70615..0b91af3b203 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 3406ce251a3..ce0fa764113 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 c508ece7487..7d5d8e56f6a 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 585ac1fed67..065ec93b500 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 505c730213c..d9b7bfeeb44 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^ is how a^^n looks. (defun tex-mexpt (x l r) diff --git a/stack/maxima/stackunits.mac b/stack/maxima/stackunits.mac index 3ddb9cd4acc..f24075b6e4b 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 bd425e264f4..444af8f7dfa 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 206d7cdea7f..557bedf7d22 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 _? ';' {/** **/ return s;} + = __? s:Statement _? [;$] {/** **/ return s;} / Comment Integer "integer" diff --git a/stack/maximaparser/autogen/parser.mbstring.php b/stack/maximaparser/autogen/parser.mbstring.php index ec5bb49fd18..46541e64a5c 100644 --- a/stack/maximaparser/autogen/parser.mbstring.php +++ b/stack/maximaparser/autogen/parser.mbstring.php @@ -439,6 +439,8 @@ private function peg_buildException($message, $expected, $pos) { 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 @@ private function peg_parseLine() { $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 @@ private function peg_parseAnnotationDetail() { $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 @@ private function peg_parseAnnotationDetail() { } 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 @@ private function peg_parseAnnotationDetail() { $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 @@ private function peg_parseAnnotationDetail() { $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 @@ private function peg_parseAnnotationDetail() { } 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 @@ private function peg_parseAnnotationDetail() { $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 @@ private function peg_parseIdentifier() { 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 @@ private function peg_parseIdentifierStart() { 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 @@ private function peg_parseEvaluationFlag() { $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 @@ private function peg_parseEvaluationFlag() { } } 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 @@ private function peg_parseIf() { } $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { } 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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { } 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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { $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 @@ private function peg_parseIf() { } 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 @@ private function peg_parseIf() { $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 @@ private function peg_parseLoop() { $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 @@ private function peg_parseLoop() { $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 @@ private function peg_parseLoopBit() { } $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 @@ private function peg_parseLoopBit() { } 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 @@ private function peg_parseLoopBit() { } } 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 @@ private function peg_parseLoopBit() { $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 @@ private function peg_parsePrefixOp() { 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 @@ private function peg_parsePrefixOp() { $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 @@ private function peg_parsePostfixOp() { 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 @@ private function peg_parseInfixOp() { 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 @@ private function peg_parseInfixOp() { } } 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 @@ private function peg_parseInfixOp() { $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 @@ private function peg_parseInfixOp() { } } 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 @@ private function peg_parseUnaryOp() { } 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 @@ private function peg_parseUnaryOp() { } 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 @@ private function peg_parseGroup() { } $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 @@ private function peg_parseGroup() { $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 @@ private function peg_parseGroup() { $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 @@ private function peg_parseGroup() { $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 @@ private function peg_parseGroup() { } 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 @@ private function peg_parseGroup() { $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 @@ private function peg_parseFunctionCall() { } 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 @@ private function peg_parseFunctionCall() { $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 @@ private function peg_parseList() { } $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 @@ private function peg_parseList() { $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 @@ private function peg_parseList() { $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 @@ private function peg_parseList() { $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 @@ private function peg_parseList() { } 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 @@ private function peg_parseList() { $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 @@ private function peg_parseSet() { } $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 @@ private function peg_parseSet() { $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 @@ private function peg_parseSet() { $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 @@ private function peg_parseSet() { $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 @@ private function peg_parseSet() { } 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 @@ private function peg_parseSet() { $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 @@ private function peg_parse_() { $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 @@ private function peg_parse_() { $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 @@ private function peg_parse_() { $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 @@ private function peg_parse_() { } 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 @@ private function peg_parse_() { 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 @@ private function peg_parse__() { $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 @@ private function peg_parse__() { 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 @@ private function peg_parseULetter() { } $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 @@ private function peg_parseULetter() { 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 @@ private function peg_parseUSubscriptSuperscript() { } $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 @@ private function peg_parseUSpecial() { } $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 @@ public function parse($input) { $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 @@ public function parse($input) { $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 05d47c8443f..8865e46d484 100644 --- a/stack/maximaparser/corrective_parser.php +++ b/stack/maximaparser/corrective_parser.php @@ -461,8 +461,8 @@ public static function handle_parse_error($exception, $string, &$errors, &$answe $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 31f27252dc1..c50804b7d00 100644 --- a/stack/questiontest.php +++ b/stack/questiontest.php @@ -73,11 +73,6 @@ public function add_expected_result($prtname, stack_potentialresponse_tree_state * @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 @@ public function test_question($questionid, $seed, $context) { $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 @@ public function test_question($questionid, $seed, $context) { } $results->emptytestcase = $emptytestcase; - - if ($this->testcase) { - $this->save_result($question, $results); - } - return $results; } diff --git a/stack/questiontestresult.php b/stack/questiontestresult.php index 8e013366152..77967387929 100644 --- a/stack/questiontestresult.php +++ b/stack/questiontestresult.php @@ -245,6 +245,51 @@ public function passed() { 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 562f099ce57..f1e95fee86f 100644 --- a/tests/api_controller_test.php +++ b/tests/api_controller_test.php @@ -29,34 +29,28 @@ 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 @@ function() { ->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 @@ public function test_render() { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertMatchesRegularExpression('/^

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('/^

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('/^

result->output->questioninputs->ans1->render); - $this->assertMatchesRegularExpression('/^

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('/^

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 @@ public function test_render_specified_seed() { $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices'); $rc = new RenderController(); $rc->__invoke($this->request, $this->response, []); - $this->assertMatchesRegularExpression('/^

Calculate/', $this->result->output->questionrender); - $this->assertEquals(219862533, $this->result->output->questionseed); + $this->assertMatchesRegularExpression('/^

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 @@ public function test_validation() { $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 @@ public function test_grade() { $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('

[[feedback:prt1]]

', $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('

[[feedback:prt1]]

', $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 @@ public function test_grade_scores() { $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 @@ public function test_download() { $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('wrong', 'ta', 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 79d9ccacffb..586291bbdea 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 @@ public function test_question_loader_use_defaults() { 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 @@ public function test_question_loader_do_not_use_defaults() { 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 4a50fa813ef..dc42bee08e2 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 @@ public function test_affected_no_units() { $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 @@ public function test_affected_units() { $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 f75a2476813..9c15b0cbc15 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ public function test_non_affected_no_units() { [], 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 f6b19359437..601916d45ce 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ public function test_non_affected_no_units() { [], 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 7fecf724c66..fa806c97da6 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ public function test_non_affected_no_units() { [], 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 613aa2cefc3..1c68c1604e5 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ public function test_non_affected_no_units() { [], 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 eee55b4bf94..e0be35e6efd 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 9fad3cb998f..3d864ad1f66 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1880,6 +1885,11 @@ public function test_non_affected_no_units() { [], 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 359cf38ea19..f711203e842 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 58121aae3b3..6b9b12bc018 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 00000000000..f0fc5d007f5 --- /dev/null +++ b/tests/ast_filter_033_no_extra_evaluation_auto_generated_test.php @@ -0,0 +1,3619 @@ +. + +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<=xexpect('1expect('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('[1expect('[1expect('[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 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 ."', + '"A string that needs sanitising ."', + [], + 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<=xexpect('1expect('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('[1expect('[1expect('[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 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 ."', + '"A string that needs sanitising ."', + [], + 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 0df850d1707..74778ea16be 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ public function test_non_affected_no_units() { [], 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 d12604d7fb0..4304cb85f28 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 d47940bc948..477c4a1d340 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2040,6 +2045,11 @@ public function test_non_affected_no_units() { [], 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 8f18277a489..7b2a9f18b06 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ public function test_non_affected_no_units() { [], 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 d240b5e28ea..8bb08555e54 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1995,6 +2000,11 @@ public function test_non_affected_no_units() { [], 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 b5d61d6fb98..73237887e5d 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ public function test_non_affected_no_units() { [], 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 96fb4d92316..feac69855df 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('()x', '()*x', [], @@ -2080,6 +2085,11 @@ public function test_non_affected_no_units() { [], 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 2e2c836c8b2..a6e4ce0cc76 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 08bfe4c0bde..37120c127e3 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 2b8105b8d65..fcdfbfda81f 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 cbf64117c0d..bab988d840b 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 b9217990d78..607571bbbba 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 @@ public function test_affected_no_units() { [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1803,6 +1808,11 @@ public function test_affected_units() { [], 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 6e7dbc36c31..fac898c7e91 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 @@ public function test_affected_no_units() { [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1858,6 +1863,11 @@ public function test_affected_units() { [], 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 d5f91a8ac0d..54c14e32142 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ public function test_non_affected_no_units() { [], 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 d70fe26a396..d7102eae8c8 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1900,6 +1905,11 @@ public function test_non_affected_no_units() { [], 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 bfe8aeed058..15fc4bc5b51 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1885,6 +1890,11 @@ public function test_non_affected_no_units() { [], 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 d4f8cffe3c2..ad047239c96 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1910,6 +1915,11 @@ public function test_non_affected_no_units() { [], 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 042de6228dc..ef98119405c 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1915,6 +1920,11 @@ public function test_non_affected_no_units() { [], 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 4f0daa617ca..6f224340f87 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1985,6 +1990,11 @@ public function test_non_affected_no_units() { [], 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 da531d3d8c5..caf616d867e 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1900,6 +1905,11 @@ public function test_non_affected_no_units() { [], 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 6be46f3077f..f36aa678c19 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2090,6 +2095,11 @@ public function test_non_affected_no_units() { [], 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 4d7e3b0c1b4..e2013fbf9b5 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 @@ public function test_affected_no_units() { [], 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 @@ public function test_affected_units() { [], 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 07aedd15f35..8a04fc64449 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1905,6 +1910,11 @@ public function test_non_affected_no_units() { [], 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 495a7fcd8eb..d1f46651d6c 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ public function test_non_affected_no_units() { [], 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 44094912f25..0c6cbabd7fa 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ public function test_non_affected_no_units() { [], 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 87fc0f1a3ea..f75e0d9cdd4 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1890,6 +1895,11 @@ public function test_non_affected_no_units() { [], 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 11551cc9ee6..57d7fab196b 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1880,6 +1885,11 @@ public function test_non_affected_no_units() { [], 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 51054a8aa22..155843eb884 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2110,6 +2115,11 @@ public function test_non_affected_no_units() { [], 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 7d176fadb67..8c07f031c66 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 @@ public function test_affected_no_units() { ['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 @@ public function test_affected_units() { ['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 88f295bfbee..b884fd71dc1 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 a69d0ba2a58..50ada1a3868 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 c4f12259fea..dc4c727068f 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 39f54d7a2a4..69d90fc4868 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 f8b4b41221b..f9c7feaf6e0 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 @@ public function test_affected_no_units() { ['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 @@ public function test_affected_units() { ['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 1c8335bc352..90353f262e6 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 @@ public function test_affected_no_units() { [], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + false, true); + $this->expect('(()x)', '(()*x)', [], @@ -1843,6 +1848,11 @@ public function test_affected_units() { [], 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 44145fdfbdb..e205ed02ad0 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1895,6 +1900,11 @@ public function test_non_affected_no_units() { [], 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 11654acb7b5..acc8499b516 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -2040,6 +2045,11 @@ public function test_non_affected_no_units() { [], 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 fa586cbb115..ad45e0f5c52 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 35315529cb2..07b7cf4f345 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1950,6 +1955,11 @@ public function test_non_affected_no_units() { [], 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 c984f8d29ac..c0d042fa2f1 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], @@ -1975,6 +1980,11 @@ public function test_non_affected_no_units() { [], 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 fc7158ea8ba..e4dbbf0b856 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1870,6 +1875,11 @@ public function test_non_affected_no_units() { [], 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 f3b230607fb..3f4e4426c3b 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 @@ public function test_affected_no_units() { [], 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 @@ public function test_affected_units() { [], 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 0c26b083800..00ac2fc7260 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('(()x)', '(()*x)', [], @@ -1875,6 +1880,11 @@ public function test_non_affected_no_units() { [], 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 3082373bd56..666c2befde4 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 @@ public function test_affected_no_units() { ['apostrophe'], false, true); + $this->expect("''diff(x,y)", + "''diff(x,y)", + ['apostrophe'], + false, true); + $this->expect('(()x)', '(()*x)', ['emptyParens'], @@ -283,6 +288,11 @@ public function test_affected_units() { ['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 c1ad2044504..a5a26ba23fe 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 @@ public function test_non_affected_units() { [], true, false); + $this->expect("''diff(x,y)", + "''diff(x,y)", + [], + true, false); + $this->expect('((x))', '((x))', [], @@ -2050,6 +2055,11 @@ public function test_non_affected_no_units() { [], 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 db398a15653..f8a5a1dcbb5 100644 --- a/tests/caskeyval_test.php +++ b/tests/caskeyval_test.php @@ -77,6 +77,7 @@ public function test_get_valid() { // 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 @@ public function test_equations_1() { $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 @@ public function test_ampersand_outside_strings() { $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 @@ public function test_stack_seed_redef() { ]; $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 af25a617a74..a1c41ded756 100644 --- a/tests/cassession2_test.php +++ b/tests/cassession2_test.php @@ -2493,10 +2493,12 @@ public function test_stack_blockexternal() { $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 @@ public function test_stack_blockexternal() { 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 @@ public function test_parens_delect_display() { '\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 421384cfefb..89c22f15420 100644 --- a/tests/castext_test.php +++ b/tests/castext_test.php @@ -816,7 +816,8 @@ public function test_disp_decimalplaces() { } $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 @@ public function test_disp_decimalplaces2() { } $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 @@ public function test_disp_decimalplaces_error() { } $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 @@ public function test_texput_complex_function() { $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 @@ public function test_include_local() { $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 b5d09729208..e48551c3290 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 ed1d53eb396..3dffd7eae80 100644 --- a/tests/fixtures/apifixtures.class.php +++ b/tests/fixtures/apifixtures.class.php @@ -1392,6 +1392,344 @@ class stack_api_test_data { ', + 'test' => ' + + + + Algebraic input + + + Type in {@ta@}.

[[input:ans1]] [[validation:ans1]]

+

(Note, this assumes single variable variable names)

]]>
+
+ + + + 1.0000000 + 0.1000000 + 0 + + + 2020123000 + + + ta:a*b + + + [[feedback:prt1]] + + + + + 1 + 0 + 0 + + + Correct answer, well done.]]> + + + + Your answer is partially correct.]]> + + + + Incorrect answer.]]> + + dot + 1 + i + cos-1 + lang + [ + + + ans1 + algebraic + ta + 15 + 1 + 2 + + 0 + solve + + 1 + 0 + 1 + 1 + 1 + + + + prt1 + 1.0000000 + 1 + 1 + + + + + 0 + AlgEquiv + ans1 + ta + + 0 + = + 1.0000000 + + -1 + prt1-1-T + + + + = + 0.0000000 + + -1 + prt1-1-F + + + + + + + 1 + + ans1 + 37 + + + prt1 + 1.0000000 + 0.0000000 + prt1-1-T + + + + 2 + + ans1 + + + + prt1 + 1.0000000 + 0.0000000 + NULL + + +
+
', + 'test2' => ' + + + + Algebraic input + + + Type in {@ta@}.

[[input:ans1]] [[validation:ans1]]

+

(Note, this assumes single variable variable names)

]]>
+
+ + + + 1.0000000 + 0.1000000 + 0 + + + 2020123000 + + + ta:a*b + + + [[feedback:prt1]] + + + + + 1 + 0 + 0 + + + Correct answer, well done.]]> + + + + Your answer is partially correct.]]> + + + + Incorrect answer.]]> + + dot + 1 + i + cos-1 + lang + [ + + + ans1 + algebraic + ta + 15 + 1 + 2 + + 0 + solve + + 1 + 0 + 1 + 1 + 1 + + + + prt1 + 1.0000000 + 1 + 1 + + + + + 0 + AlgEquiv + ans1 + ta + + 0 + = + 1.0000000 + + -1 + prt1-1-T + + + + = + 0.0000000 + + -1 + prt1-1-F + + + + + +
+
', + 'test3' => ' + + + + Algebraic input + + + Type in {@ta@}.

[[input:ans1]] [[validation:ans1]]

+

(Note, this assumes single variable variable names)

]]>
+
+ + + + 1.0000000 + 0.1000000 + 0 + + + 2020123000 + + + ta:a*b + + + [[feedback:prt1]] + + + + + 1 + 0 + 0 + + + Correct answer, well done.]]> + + + + Your answer is partially correct.]]> + + + + Incorrect answer.]]> + + dot + 1 + i + cos-1 + lang + [ + + + ans1 + algebraic + ta + 15 + 1 + 2 + + 0 + solve + + 1 + 0 + 1 + 1 + 1 + + + + prt1 + 1.0000000 + 1 + 1 + + + + + 0 + AlgEquiv + ans1 + wrong + + 0 + = + 1.0000000 + + -1 + prt1-1-T + + + + = + 0.0000000 + + -1 + prt1-1-F + + + + + +
+
', ]; protected static array $answers = [ diff --git a/tests/fixtures/inputfixtures.class.php b/tests/fixtures/inputfixtures.class.php index ce0a6f69610..b14c038b14d 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 @@ function at a point \(f(x)\). Maybe a 'gocha' for the question author....", ], ['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 @@ function at a point \(f(x)\). Maybe a 'gocha' for the question author....", '\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 @@ function at a point \(f(x)\). Maybe a 'gocha' for the question author....", "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 @@ function at a point \(f(x)\). Maybe a 'gocha' for the question author....", '\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 @@ function at a point \(f(x)\). Maybe a 'gocha' for the question author....", ['\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 3714ebb8672..9a3f783d903 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 b0f83073849..d28a605af4b 100644 --- a/tests/helper.php +++ b/tests/helper.php @@ -72,6 +72,8 @@ public function get_test_questions() { '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 @@ public static function make_stack_question_contextvars() { $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 blob.'; @@ -3544,7 +3549,7 @@ public static function make_stack_question_contextvars() { $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 @@ public static function make_stack_question_feedback() { 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 7e99025a966..f726f0da6e8 100644 --- a/tests/input_algebraic_test.php +++ b/tests/input_algebraic_test.php @@ -344,6 +344,30 @@ public function test_validate_student_lowest_terms_2() { $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 @@ public function test_validate_student_response_insertstars_sqrt_1() { 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 ' . '\( \frac{2\cdot \sqrt{2}}{3} \), which can be typed as ' . '2*sqrt(2)/3, would be correct.', @@ -595,6 +620,21 @@ public function test_validate_student_response_display_noundiff() { '\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 '' is not supported by STACK.", + $state->errors); + $this->assertEquals("''%_E(%_E(noundiff(y/x^2,x,1)))", $state->contentsmodified); + $this->assertEquals("''diff(y/x^2,x,1)", + $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 @@ public function test_validate_student_response_with_allowempty() { $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 @@ public function test_validate_student_response_realsets_sametype_ok() { '\[ \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 @@ public function test_validate_student_response_tex() { 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 eac617261b6..141432bdca3 100644 --- a/tests/input_numerical_test.php +++ b/tests/input_numerical_test.php @@ -787,4 +787,41 @@ public function test_validate_student_response_boolean() { $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 00000000000..2314b945387 --- /dev/null +++ b/tests/vle_specific_test.php @@ -0,0 +1,81 @@ +. + +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 57a9158886b..7bef19bec63 100644 --- a/tests/walkthrough_adaptive_test.php +++ b/tests/walkthrough_adaptive_test.php @@ -432,7 +432,6 @@ public function test_test1_validate_then_submit_right_first_time() { // @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 @@ public function test_test3_submit_wrong_response_correct_then_stubmit() { $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 @@ public function test_test_contextvars() { $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 @@ public function test_test_contextvars() { $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 @@ public function test_test_contextvars() { $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 @@ public function test_input_validator_texput() { // 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 10bdf94bddb..3ad00ac5550 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 7b5651159c4..d62e8172170 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'; + } } /*