diff --git a/adminui/caschat.php b/adminui/caschat.php
index 4c3eace2d5de2fd9487f9742662d4adee89f0564..021b9b0bc4c977f0bd3696dec3b0d6da1911bf8f 100644
--- a/adminui/caschat.php
+++ b/adminui/caschat.php
@@ -132,6 +132,9 @@ if ($string) {
         if ($keyvals->get_valid()) {
             $kvcode = $keyvals->compile('test');
             $statements = [];
+            if ($kvcode['blockexternal']) {
+                $statements[] = new stack_secure_loader($kvcode['blockexternal'], 'caschat', 'blockexternal');
+            }
             if ($kvcode['contextvariables']) {
                 $statements[] = new stack_secure_loader($kvcode['contextvariables'], 'caschat');
             }
diff --git a/api/README.md b/api/README.md
index d36ee63faa7a98e7f0aa58a95e896857c6f33885..9d7b2aebf4949be54640b4bab240ee54b7b0282a 100644
--- a/api/README.md
+++ b/api/README.md
@@ -15,7 +15,7 @@ E.g. see `https://hub.docker.com/r/mathinstitut/goemaxima` for images.
 The image requires maxima to be available via http. The URL can be configured via the environment variable `MAXIMA_URL` and defaults to `http://maxima:8080/maxima`. An example docker-compose file deploying both stack and maxima in the goemaxima variant is provided below:
 
 ```
-version: "3.9"
+version: "4.0"
 services:
   maxima:
     image: mathinstitut/goemaxima:2023121100-latest
@@ -48,11 +48,13 @@ The application can also be installed manually, although this variant has only u
 
 ## Usage instructions
 
-The STACK service implemented in this repository provides a stateless REST-API with three distinct routes, which all expect and produce `application/json` requests/responses:
+The STACK service implemented in this repository provides a stateless REST-API with five distinct routes, which all expect and produce `application/json` requests/responses:
 
-- POST /render: Render a stack question
+- POST /render: Render a STACK question
 - POST /grade: Grade user input for a question
 - POST /validate: Validate a user's input
+- POST /download: Serves a file for questions that have download links
+- POST /test: Run a questions tests against all deployed variants
 
 ### Render route
 
@@ -141,6 +143,75 @@ The `POST /download` route is used to download files created by questions.
 
 The requested file is returned.
 
+### Test route
+
+The `POST /test` route is used to run a question's test cases.
+
+- `questionDefinition`: The Moodle-XML-Export of a single STACK question.
+
+The grading route returns the following fields:
+
+- string: `name`: The name of the question.
+- string: `messages`: Question level error messages.
+- boolean: `isupgradeerror`: Are there any issues related to questions being non-compliant with a STACK upgrade?
+- boolean: `isgeneralfeedback`: Does the question have general feedback?
+- boolean: `isdeployedseeds`: Does the question have deployed seeds?
+- boolean: `israndomvariants`: Does the question use random variants?
+- boolean: `istests`: Does the question have tests?
+- object: `results`: The test results for each each seed, keyed by seed. If the question does not have random variants, there will be a single entry keyed `noseed`.
+
+In the `results` object, each seed will key an object:
+- int|null: `passes`: Number of tests passed.
+- int|null: `fails`: Number of tests failed.
+- string: `messages`: Seed level error message. Includes summaries from the test, runtime errors and general feedback errors.
+- object: `outcomes`: Gives detailed breakdown of test result. Entries keyed by `<testcase>`. 
+
+In the outcomes object, each test will key an object:
+- boolean: `passed`: Did the test pass?
+- string: `reason`: Reason for failure. A test empty message or the part of the output (e.g. score) which doesn't match the expected result.
+- object: `inputs`: Keyed by input name. Details of the inputs and their values.
+- object: `outcomes`: Keyed by PRT name. Details of the outcomes and expected outcomes for each PRT.
+
+Example result object:
+```
+"563119235": {
+    "passes": 1,
+    "fails": 0,
+    "messages": "",
+    "outcomes": {
+        "1": {
+            "passed": true,
+            "reason": "",
+            "inputs": {
+                "ans1": {
+                    "inputexpression": "ans1",
+                    "inputentered": "1.6486",
+                    "inputmodified": "1.6486",
+                    "inputdisplayed": "\\[ 1.6486 \\]",
+                    "inputstatus": "Score",
+                    "errors": ""
+                }
+            },
+            "outcomes": {
+                "prt1": {
+                    "outcome": true,
+                    "score": 1,
+                    "penalty": 0,
+                    "answernote": "prt1-1-T",
+                    "expectedscore": 1,
+                    "expectedpenalty": 0,
+                    "expectedanswernote": "prt1-1-T",
+                    "feedback": "",
+                    "reason": ""
+                }
+            }
+        }
+    }
+}
+  ```
+
+If a question has no tests, a default test will be run to check if the model answers return a score of 1.
+
 ### Rendered CASText format
 
 The API returns rendered CASText as parts of its responses in multiple places. The CASText is output as a single string in an intermediate format, which cannot be directly fed to browsers for display, and requires further processing. Applications using the API have to handle the following cases:
@@ -164,7 +235,6 @@ If an error occurs during processing of a request, a response with a single JSON
 
 ### Limitations
 
-- Questions requiring custom javascript are not supported. This includes questions using JSXGraph.
 - If a question uses randomization, it has to contain deployed variants.
 - Grading is only done if all inputs are present and valid (which implies non-empty in most cases).
 
@@ -195,7 +265,7 @@ To ease the development process, the Dockerfile contained in the repository cont
     docker compose -f docker-compose.dev.yml build
     docker compose -f docker-compose.dev.yml up
 
-The required development image will automatically be build. After the stack started, you will be able to access the service via http://localhost:3080. Any performed changes in the PHP code will be visible live. Note, that Maxima is provided by a geomaxima docker image, and this image will _not_ reflect local changes.  The development build also contains the xdebug extension, which is configured to connect to `host.docker.internal` as a debugger, which will resolve to the locale machines ip address when using docker desktop. Please note that the performance of the development setup will be significantly worse than in production.
+The required development image will automatically be built. After the stack started, you will be able to access the service via http://localhost:3080. Any performed changes in the PHP code will be visible live. Note, that Maxima is provided by a geomaxima docker image, and this image will _not_ reflect local changes.  The development build also contains the xdebug extension, which is configured to connect to `host.docker.internal` as a debugger, which will resolve to the locale machines ip address when using docker desktop. Please note that the performance of the development setup will be significantly worse than in production.
 
 ### Docker production setup
 
@@ -238,6 +308,8 @@ To allow the stack-moodle-plugin to work standalone, some classes and functions
 
 A basic frontend is provided at `http://localhost:3080/stack.php`. This should allow you to load the STACK sample questions and try them out. This requires API specific versions of `cors.php` and `stackjsvle.js` (to access files and create iframes) which are in the public folder.
 
+`http://localhost:3080/bulktest.php` provides a front end for selecting a folder of STACK question files and running their included tests, similar to the STACK bulk test functionality in Moodle.
+
 ### Modifications of existing STACK code
 
 The implementation of the standalone api required some modifications to existing STACK code, which could cause issues with future upstream patches. All performed modifications are documented in this section.
@@ -262,7 +334,7 @@ To be accessible directly, the following property/method visibility have been pr
 #### Minor changes in STACK 4.6.0
 
 - Some new language keys have been added.
-- Some imports inside the `question.php` and `mathsoutputfilterbase.class.php` files have been wrapped inside an if statement, to only be performed in non api contexts.
+- Some imports inside the `question.php` and `mathsoutputfilterbase.class.php` files have been wrapped inside an if statement, to only be performed in non-API contexts.
 - A new `get_ta_render_for_input` function has been added to the `qtype_stack_question` class.
 - A new `pluginfiles` property has been added to the `qtype_stack_question` class.
 - `iframe.block.php` handles plot URLs and iframe creation conditional on context (i.e API vs not API).
diff --git a/api/composer.json b/api/composer.json
index ea478cf19ae6e3c44022d134b2863ed802c83500..2b1d936bdefaf6bd90ea3a0b188222bd6ae5f144 100644
--- a/api/composer.json
+++ b/api/composer.json
@@ -3,7 +3,7 @@
     "type": "project",
     "require": {
         "slim/slim": "4.*",
-        "slim/psr7": "^1.6",
+        "slim/psr7": "^1.6.1",
         "erusev/parsedown": "^1.7.4"
     },
     "authors": [
diff --git a/api/composer.lock b/api/composer.lock
index a6aabb900f45668afecf2b11c1652922f0bfec52..170dc1046f05762ca5740eb276be4a046b6b39b8 100644
--- a/api/composer.lock
+++ b/api/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "86ccba856047aba257c6695db856ecde",
+    "content-hash": "f163e5500e1e8d33e543a427654239e2",
     "packages": [
         {
             "name": "erusev/parsedown",
@@ -217,21 +217,21 @@
         },
         {
             "name": "psr/http-factory",
-            "version": "1.0.1",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-factory.git",
-                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
-                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.0.0",
-                "psr/http-message": "^1.0"
+                "php": ">=7.1",
+                "psr/http-message": "^1.0 || ^2.0"
             },
             "type": "library",
             "extra": {
@@ -251,10 +251,10 @@
             "authors": [
                 {
                     "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "homepage": "https://www.php-fig.org/"
                 }
             ],
-            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
             "keywords": [
                 "factory",
                 "http",
@@ -266,31 +266,31 @@
                 "response"
             ],
             "support": {
-                "source": "https://github.com/php-fig/http-factory/tree/master"
+                "source": "https://github.com/php-fig/http-factory"
             },
-            "time": "2019-04-30T12:38:16+00:00"
+            "time": "2024-04-15T12:06:14+00:00"
         },
         {
             "name": "psr/http-message",
-            "version": "1.0.1",
+            "version": "1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-message.git",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+                "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+                "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "php": "^7.2 || ^8.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "1.1.x-dev"
                 }
             },
             "autoload": {
@@ -319,27 +319,27 @@
                 "response"
             ],
             "support": {
-                "source": "https://github.com/php-fig/http-message/tree/master"
+                "source": "https://github.com/php-fig/http-message/tree/1.1"
             },
-            "time": "2016-08-06T14:39:51+00:00"
+            "time": "2023-04-04T09:50:52+00:00"
         },
         {
             "name": "psr/http-server-handler",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-server-handler.git",
-                "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7"
+                "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
-                "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+                "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4",
+                "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.0",
-                "psr/http-message": "^1.0"
+                "psr/http-message": "^1.0 || ^2.0"
             },
             "type": "library",
             "extra": {
@@ -359,7 +359,7 @@
             "authors": [
                 {
                     "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "homepage": "https://www.php-fig.org/"
                 }
             ],
             "description": "Common interface for HTTP server-side request handler",
@@ -375,28 +375,27 @@
                 "server"
             ],
             "support": {
-                "issues": "https://github.com/php-fig/http-server-handler/issues",
-                "source": "https://github.com/php-fig/http-server-handler/tree/master"
+                "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2"
             },
-            "time": "2018-10-30T16:46:14+00:00"
+            "time": "2023-04-10T20:06:20+00:00"
         },
         {
             "name": "psr/http-server-middleware",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-server-middleware.git",
-                "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5"
+                "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5",
-                "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+                "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
+                "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.0",
-                "psr/http-message": "^1.0",
+                "psr/http-message": "^1.0 || ^2.0",
                 "psr/http-server-handler": "^1.0"
             },
             "type": "library",
@@ -417,7 +416,7 @@
             "authors": [
                 {
                     "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "homepage": "https://www.php-fig.org/"
                 }
             ],
             "description": "Common interface for HTTP server-side middleware",
@@ -433,36 +432,36 @@
             ],
             "support": {
                 "issues": "https://github.com/php-fig/http-server-middleware/issues",
-                "source": "https://github.com/php-fig/http-server-middleware/tree/master"
+                "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2"
             },
-            "time": "2018-10-30T17:12:04+00:00"
+            "time": "2023-04-11T06:14:47+00:00"
         },
         {
             "name": "psr/log",
-            "version": "3.0.0",
+            "version": "1.1.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.0.0"
+                "php": ">=5.3.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.x-dev"
+                    "dev-master": "1.1.x-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Psr\\Log\\": "src"
+                    "Psr\\Log\\": "Psr/Log/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -483,9 +482,9 @@
                 "psr-3"
             ],
             "support": {
-                "source": "https://github.com/php-fig/log/tree/3.0.0"
+                "source": "https://github.com/php-fig/log/tree/1.1.4"
             },
-            "time": "2021-07-14T16:46:02+00:00"
+            "time": "2021-05-03T11:20:27+00:00"
         },
         {
             "name": "ralouphie/getallheaders",
@@ -533,16 +532,16 @@
         },
         {
             "name": "slim/psr7",
-            "version": "1.6",
+            "version": "1.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim-Psr7.git",
-                "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d"
+                "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
-                "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
+                "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/72d2b2bac94ab4575d369f605dbfafbe168d3163",
+                "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163",
                 "shasum": ""
             },
             "require": {
@@ -561,7 +560,7 @@
                 "adriansuter/php-autoload-override": "^1.3",
                 "ext-json": "*",
                 "http-interop/http-factory-tests": "^0.9.0",
-                "php-http/psr7-integration-tests": "dev-master",
+                "php-http/psr7-integration-tests": "1.1",
                 "phpspec/prophecy": "^1.15",
                 "phpspec/prophecy-phpunit": "^2.0",
                 "phpstan/phpstan": "^1.8",
@@ -609,22 +608,22 @@
             ],
             "support": {
                 "issues": "https://github.com/slimphp/Slim-Psr7/issues",
-                "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6"
+                "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6.1"
             },
-            "time": "2022-11-05T18:50:24+00:00"
+            "time": "2023-04-17T16:02:20+00:00"
         },
         {
             "name": "slim/slim",
-            "version": "4.11.0",
+            "version": "4.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim.git",
-                "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7"
+                "reference": "5943393b88716eb9e82c4161caa956af63423913"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim/zipball/b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7",
-                "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/5943393b88716eb9e82c4161caa956af63423913",
+                "reference": "5943393b88716eb9e82c4161caa956af63423913",
                 "shasum": ""
             },
             "require": {
@@ -632,28 +631,29 @@
                 "nikic/fast-route": "^1.3",
                 "php": "^7.4 || ^8.0",
                 "psr/container": "^1.0 || ^2.0",
-                "psr/http-factory": "^1.0",
-                "psr/http-message": "^1.0",
+                "psr/http-factory": "^1.1",
+                "psr/http-message": "^1.1 || ^2.0",
                 "psr/http-server-handler": "^1.0",
                 "psr/http-server-middleware": "^1.0",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "require-dev": {
-                "adriansuter/php-autoload-override": "^1.3",
+                "adriansuter/php-autoload-override": "^1.4",
                 "ext-simplexml": "*",
-                "guzzlehttp/psr7": "^2.4",
-                "httpsoft/http-message": "^1.0",
-                "httpsoft/http-server-request": "^1.0",
-                "laminas/laminas-diactoros": "^2.17",
-                "nyholm/psr7": "^1.5",
-                "nyholm/psr7-server": "^1.0",
-                "phpspec/prophecy": "^1.15",
-                "phpspec/prophecy-phpunit": "^2.0",
-                "phpstan/phpstan": "^1.8",
-                "phpunit/phpunit": "^9.5",
-                "slim/http": "^1.2",
-                "slim/psr7": "^1.5",
-                "squizlabs/php_codesniffer": "^3.7"
+                "guzzlehttp/psr7": "^2.6",
+                "httpsoft/http-message": "^1.1",
+                "httpsoft/http-server-request": "^1.1",
+                "laminas/laminas-diactoros": "^2.17 || ^3",
+                "nyholm/psr7": "^1.8",
+                "nyholm/psr7-server": "^1.1",
+                "phpspec/prophecy": "^1.19",
+                "phpspec/prophecy-phpunit": "^2.1",
+                "phpstan/phpstan": "^1.11",
+                "phpunit/phpunit": "^9.6",
+                "slim/http": "^1.3",
+                "slim/psr7": "^1.6",
+                "squizlabs/php_codesniffer": "^3.10",
+                "vimeo/psalm": "^5.24"
             },
             "suggest": {
                 "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
@@ -726,20 +726,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-11-06T16:33:39+00:00"
+            "time": "2024-06-13T08:54:48+00:00"
         },
         {
             "name": "symfony/polyfill-php80",
-            "version": "v1.27.0",
+            "version": "v1.29.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
-                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
                 "shasum": ""
             },
             "require": {
@@ -747,9 +747,6 @@
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.27-dev"
-                },
                 "thanks": {
                     "name": "symfony/polyfill",
                     "url": "https://github.com/symfony/polyfill"
@@ -793,7 +790,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
             },
             "funding": [
                 {
@@ -809,7 +806,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-11-03T14:55:06+00:00"
+            "time": "2024-01-29T20:11:03+00:00"
         }
     ],
     "packages-dev": [],
diff --git a/api/config_sample.txt b/api/config_sample.txt
index 8d2ec6623e34a3e1daf8d81997a9c691b3b9f494..dd5bbaa0da563c4fa88daff0de6c1f76954cd2e5 100644
--- a/api/config_sample.txt
+++ b/api/config_sample.txt
@@ -14,8 +14,6 @@
 // You should have received a copy of the GNU General Public License
 // along with Stack.  If not, see <http://www.gnu.org/licenses/>.
 
-// This script handles the various deploy/undeploy actions from questiontestrun.php.
-//
 // @copyright  2023 RWTH Aachen
 // @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
 
@@ -101,5 +99,5 @@ $CFG->mathsdisplay = 'api';
 
 $CFG->libdir = $CFG->dirroot . '/emulation/libdir';
 
-// MathJax URL
+// MathJax URL.
 $CFG->httpsurl = 'https://cdn.jsdelivr.net/npm/mathjax@2.7.9/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
diff --git a/api/controller/DownloadController.php b/api/controller/DownloadController.php
index 517b6aa99559c3984a400497532f69e16a742dcf..1b7adaf00392ea0a387d04726569f886842edd81 100644
--- a/api/controller/DownloadController.php
+++ b/api/controller/DownloadController.php
@@ -41,7 +41,7 @@ class DownloadController {
         $name = $data['filename'];
         $tdid = $data['fileid'];
 
-        $question = StackQuestionLoader::loadxml($data["questionDefinition"]);
+        $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question'];
 
         StackSeedHelper::initialize_seed($question, $data["seed"]);
 
diff --git a/api/controller/GradingController.php b/api/controller/GradingController.php
index a1e9029db01a80f9a0195f0f7a17b470e5c65434..ac92728e00a35bf6a7d40e5d4a1e37de57f28b45 100644
--- a/api/controller/GradingController.php
+++ b/api/controller/GradingController.php
@@ -44,7 +44,7 @@ class GradingController {
         // TO-DO: Validate.
         $data = $request->getParsedBody();
 
-        $question = StackQuestionLoader::loadxml($data["questionDefinition"]);
+        $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question'];
 
         StackSeedHelper::initialize_seed($question, $data["seed"]);
 
diff --git a/api/controller/RenderController.php b/api/controller/RenderController.php
index a89da53a5d95bd506504bd4a9985b2bdaac03417..a17bb9b7b9330a0eb58a06de2c64b7841ee0039b 100644
--- a/api/controller/RenderController.php
+++ b/api/controller/RenderController.php
@@ -45,7 +45,7 @@ class RenderController {
         // TO-DO: Validate.
         $data = $request->getParsedBody();
 
-        $question = StackQuestionLoader::loadxml($data["questionDefinition"]);
+        $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question'];
 
         StackSeedHelper::initialize_seed($question, $data["seed"]);
 
diff --git a/api/controller/TestController.php b/api/controller/TestController.php
new file mode 100644
index 0000000000000000000000000000000000000000..ccf2ad7c14532aba5f7381d82fd70df091542845
--- /dev/null
+++ b/api/controller/TestController.php
@@ -0,0 +1,223 @@
+<?php
+// This file is part of Stack - http://stack.maths.ed.ac.uk/
+//
+// Stack is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Stack is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Stack.  If not, see <http://www.gnu.org/licenses/>.
+
+// This script handles the running of question tests for a supplied question
+//
+// @copyright  2024 University of Edinburgh
+// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
+
+namespace api\controller;
+defined('MOODLE_INTERNAL') || die();
+require_once(__DIR__ . '/../dtos/StackTestResponse.php');
+require_once(__DIR__ . '/../util/StackQuestionLoader.php');
+require_once(__DIR__ . '/../util/StackSeedHelper.php');
+require_once(__DIR__ . '/../../stack/questiontestresult.php');
+
+use api\util\StackQuestionLoader;
+use api\util\StackSeedHelper;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use api\dtos\StackTestResponse;
+
+/**
+ * Handles the running of question tests for a supplied question
+ *
+ * Based heavily on bulktester.class.php and questiontest.php but they rely on
+ * Moodle context and create HTML. Here we're just getting test results and
+ * leaving display for the front end.
+ */
+class TestController {
+    /**
+     * @throws \stack_exception
+     * @throws \Exception
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response {
+        // TO-DO: Validate.
+        $data = $request->getParsedBody();
+
+        list('question' => $question, 'testcases' => $testcases) = StackQuestionLoader::loadxml($data["questionDefinition"], true);
+        $question->castextprocessor = new \castext2_qa_processor(new \stack_outofcontext_process());
+
+        $testresponse = new StackTestResponse();
+        $testresponse->name = $question->name;
+
+        // We want to flag if the question is missing general feedback, has deployed seeds,
+        // has random variants and/or has tests. It's up to the front end to decide what to do with that info.
+        if (trim($question->generalfeedback) !== '') {
+            $testresponse->isgeneralfeedback = true;
+        }
+
+        if (!empty($question->deployedseeds)) {
+            $testresponse->isdeployedseeds = true;
+        }
+
+        if ($question->has_random_variants()) {
+            $testresponse->israndomvariants = true;
+        }
+
+        if ($testcases) {
+            $testresponse->istests = true;
+        }
+
+        // If the question uses random variants but has no deployed seeds we can't even initialise
+        // the question so return response.
+        if ($testresponse->israndomvariants && !$testresponse->isdeployedseeds) {
+            $testresponse->results = [];
+            $response->getBody()->write(json_encode($testresponse));
+            return $response->withHeader('Content-Type', 'application/json');
+        } else {
+            StackSeedHelper::initialize_seed($question, $data["seed"]);
+            $question->initialise_question_from_seed();
+        }
+
+        // Check for upgrade errors and return response immediately if so.
+        // Errors will be listed in overall response messages.
+        $dummycontext = new \stdClass(); // Required for unit tests.
+        $dummycontext->id = 0;
+        $upgradeerrors = $question->validate_against_stackversion($dummycontext);
+        if ($upgradeerrors != '') {
+            $testresponse->isupgradeerror = true;
+            $testresponse->messages = $upgradeerrors;
+            $testresponse->results = [];
+            $response->getBody()->write(json_encode($testresponse));
+            return $response->withHeader('Content-Type', 'application/json');
+        }
+
+        // Create test results for each deployed seed. If no random variants, then use 'noseed' as
+        // array index.
+        if (empty($question->deployedseeds)) {
+            try {
+                $testresponse->results = [
+                    'noseed' => $this->qtype_stack_test_question($question, $testcases, null),
+                ];
+            } catch (\stack_exception $e) {
+                $testresponse->results['noseed'] = [
+                        'passes' => null,
+                        'fails' => null,
+                        'messages' => stack_string('errors') . ' : ' . $e,
+                        'outcomes' => null,
+                    ];
+            }
+        } else {
+            foreach ($question->deployedseeds as $seed) {
+                try {
+                    $testresponse->results[$seed] = $this->qtype_stack_test_question($question, $testcases, $seed);
+                } catch (\stack_exception $e) {
+                    $testresponse->results[$seed] = [
+                        'passes' => null,
+                        'fails' => null,
+                        'messages' => stack_string('errors') . ' : ' . $e,
+                        'outcomes' => null,
+                    ];
+                }
+            }
+        }
+        $response->getBody()->write(json_encode($testresponse));
+        return $response->withHeader('Content-Type', 'application/json');
+    }
+
+    /**
+     * Run the tests for one variant of one question and display the results.
+     *
+     * @param object $question the question to test.
+     * @param array $testcases the questions tests.
+     * @param int|null $seed if we want to force a particular version.
+     * @return array with elements:
+     *              int passes - number of tests passed.
+     *              int fails - number of tests failed.
+     *              string messages - error messages.
+     *              array outcomes - detailed info on the outcomes of the test.
+     *                  (See stack_question_test_result->passed_with_reasons.
+     *                   TO-DO Is it worth creating a class for this?)
+     */
+    public function qtype_stack_test_question($question, $testcases, $seed = null) {
+        if (!is_null($seed)) {
+            $question->seed = (int) $seed;
+        }
+        // Execute the tests for each seed.
+        // Return number of passed tests, number of failed tests, any error messages
+        // and outcomes - an array of summaries of the test results.
+        $passes = 0;
+        $fails = 0;
+        $message = '';
+        $outcomes = [];
+        $question->options->set_option('decimals', '.');
+        foreach ($testcases as $testcase) {
+            $response = \stack_question_test::compute_response($question, $testcase->inputs);
+            $results = $testcase->process_results($question, $response);
+            $summary = $results->passed_with_reasons();
+            $outcomes[$testcase->testcase] = $summary;
+            if ($summary['passed']) {
+                $passes += 1;
+            } else {
+                $fails += 1;
+                $message .= $summary['reason'];
+            }
+        }
+
+        // If we don't have any tests, check to see if the model answers give a score of 1.
+        if (count($testcases) === 0 && count($question->prts) > 0) {
+            $inputs = [];
+            foreach ($question->inputs as $inputname => $input) {
+                $inputs[$inputname] = $input->get_teacher_answer_testcase();
+            }
+            $qtest = new \stack_question_test(stack_string('autotestcase'), $inputs);
+            $response = \stack_question_test::compute_response($question, $inputs);
+
+            foreach ($question->prts as $prtname => $prt) {
+                $result = $question->get_prt_result($prtname, $response, false);
+                // We could just check if score === 1 at this point but by creating
+                // a test and running it we get the full outcomes in the same
+                // format as above.
+                $answernotes = $result->get_answernotes();
+                $answernote = [end($answernotes)];
+                $qtest->add_expected_result($prtname, new \stack_potentialresponse_tree_state(
+                    1, true, 1, 0, '', $answernote));
+            }
+            $results = $qtest->process_results($question, $response);
+            $summary = $results->passed_with_reasons();
+            $outcomes[$qtest->testcase] = $summary;
+            if ($summary['passed']) {
+                $passes = 1;
+            } else {
+                $fails = 1;
+                $message = stack_string('default_test_fail');
+            }
+        }
+
+        $generalfeedback = $question->get_generalfeedback_castext();
+
+        $generalfeedback->get_rendered($question->castextprocessor);
+        if ($generalfeedback->get_errors() != '') {
+            $s = stack_string('stackInstall_testsuite_errors') . '  ' .
+                stack_string('generalfeedback') . ': ' . $generalfeedback->get_errors();
+            $message .= $s;
+        }
+
+        if (!empty($question->runtimeerrors)) {
+            $s = stack_string('stackInstall_testsuite_errors') . ' ' .
+                implode(' ', array_keys($question->runtimeerrors));
+            $message .= $s;
+        }
+
+        return [
+            'passes' => $passes,
+            'fails' => $fails,
+            'messages' => $message,
+            'outcomes' => $outcomes,
+        ];
+    }
+}
diff --git a/api/controller/ValidationController.php b/api/controller/ValidationController.php
index b10545e2eec067c3dbced95321db1a0b1d132765..4eb1c732e22752370f72f9acbb69ee8e9376a087 100644
--- a/api/controller/ValidationController.php
+++ b/api/controller/ValidationController.php
@@ -42,7 +42,7 @@ class ValidationController {
         // TO-DO: Validate.
         $data = $request->getParsedBody();
 
-        $question = StackQuestionLoader::loadxml($data["questionDefinition"]);
+        $question = StackQuestionLoader::loadxml($data["questionDefinition"])['question'];
 
         StackSeedHelper::initialize_seed($question, $data["seed"]);
 
diff --git a/api/dtos/StackTestResponse.php b/api/dtos/StackTestResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5e86f82b3dc3d542a567f4020a8150a063096a0
--- /dev/null
+++ b/api/dtos/StackTestResponse.php
@@ -0,0 +1,45 @@
+<?php
+// This file is part of Stack - http://stack.maths.ed.ac.uk/
+//
+// Stack is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Stack is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Stack.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Response to a question test request
+ *
+ * @copyright  2024 Uuniversity of Edinburgh
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
+ */
+
+namespace api\dtos;
+
+class StackTestResponse {
+    /** @var string */
+    public $name = '';
+    /** @var string */
+    public $messages = '';
+    /** @var bool */
+    public $isupgradeerror = false;
+    /** @var bool */
+    public $isgeneralfeedback = false;
+    /** @var bool */
+    public $isdeployedseeds = false;
+    /** @var bool */
+    public $israndomvariants = false;
+    /** @var bool */
+    public $istests = false;
+    /** @var array
+     * Array keyed by seed (or 'noseed'). Subarrays have 'passes' , 'fails', 'messages[]', 'outcomes'.
+     */
+    public $results = [];
+}
diff --git a/api/emulation/MoodleEmulation.php b/api/emulation/MoodleEmulation.php
index 86593cd21eeb943d822c4bf728f79b03635900e0..ae8cbf908de5dd768d7db6518d647e7cfd48bf8a 100644
--- a/api/emulation/MoodleEmulation.php
+++ b/api/emulation/MoodleEmulation.php
@@ -89,6 +89,15 @@ function require_login() {
     return;
 }
 
+function get_file_storage() {
+    $storage = new class {
+        public function get_area_files($x, $y, $z, $a) {
+            return [];
+        }
+    };
+    return $storage;
+}
+
 // Specialized emulations.
 require_once('Constants.php');
 require_once('Localization.php');
diff --git a/api/public/bulktest.php b/api/public/bulktest.php
new file mode 100644
index 0000000000000000000000000000000000000000..08c1b84e63d8719113457a2b6f530bcd47a51348
--- /dev/null
+++ b/api/public/bulktest.php
@@ -0,0 +1,415 @@
+<?php
+// This file is part of Stack - http://stack.maths.ed.ac.uk/
+//
+// Stack is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Stack is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Stack.  If not, see <http://www.gnu.org/licenses/>.
+
+// This script handles the various deploy/undeploy actions from questiontestrun.php.
+//
+// @copyright  2023 University of Edinburgh
+// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
+require_once('../config.php');
+require_once(__DIR__ . '../../emulation/MoodleEmulation.php');
+// Required to pass Moodle code check. Uses emulation stub.
+require_login();
+?>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" />
+    <style>
+      .feedback {
+        color: black;
+        background-color: #fcf2d4;
+        border-radius: 4px;
+        border: 1px solid #7d5a2933;
+        padding: 5px;
+        margin-left: 10px;
+        width: fit-content;
+      }
+      .passed {
+        background-color: lightgreen;
+      }
+      .failed {
+        background-color: pink;
+      }
+      .seed {
+        color: darkblue;
+      }
+      .question-title {
+        margin-top: 20px;
+      }
+      .path-title {
+        color: grey;
+      }
+      a.nav-link:link, a.nav-link:visited, a.nav-link:hover, a.nav-link:active {
+        color:black;
+        text-decoration:none;
+      }
+    </style>
+  </head>
+  <body>
+    <script>
+      // Keep track of all requests sent to the server so we can check they're all complete.
+      var requests = [];
+      var filesToProcess = [];
+      // Keep an array for which questions have failed for each reason for easy display of summary.
+      var noFeedbackArray = [];
+      var noTestsArray = [];
+      var upgradeIssueArray = [];
+      var noDeployedSeedsArray = [];
+      var failedTestsArray = [];
+      var generalErrorArray = [];
+
+      /**
+      * Send a question to the server for testing. Filepath required
+      * for ordering the output by folder.
+      */
+      function send(filepath, questionxml) {
+        const http = new XMLHttpRequest();
+        requests.push(http);
+        document.getElementById('bulktest-button').setAttribute('disabled', true);
+        document.getElementById('bulktest-spinner').removeAttribute('hidden');
+        const url = window.location.origin + '/test';
+        http.open("POST", url, true);
+        http.setRequestHeader('Content-Type', 'application/json');
+
+        // Create nested <div>s with ids and titles representing the file structure in
+        // preparation for displaying results.
+        // Files being sent in sorted order so we don't need to sort again.
+        const pathArray = filepath.split('/');
+        let currentDiv = '';
+        for (const part of pathArray) {
+          let prevDiv = currentDiv;
+          currentDiv += (currentDiv) ? '/' : '';
+          currentDiv += part;
+          if (!document.getElementById(currentDiv)) {
+            const newDivEl = document.createElement("div");
+            newDivEl.setAttribute('id', currentDiv);
+            newDivEl.innerHTML = '<h5 class="path-title">' + currentDiv + '</h5>';
+            if (prevDiv) {
+              const prevDivEl = document.getElementById(prevDiv);
+              newDivEl.setAttribute('style', 'margin-left: 10px;');
+              prevDivEl.appendChild(newDivEl);
+            } else {
+              document.getElementById('output').appendChild(newDivEl);
+            }
+          }
+        }
+        http.onreadystatechange = function() {
+          if(http.readyState == 4) {
+            // Create div to show results of an individual question.
+            const resultDiv = document.createElement("div");
+            resultDiv.setAttribute('style', 'margin-left: 10px;');
+            try {
+              // If there's a JSON error, display output then this whole question has a problem somewhere.
+              // Add to general erros and give up.
+              const json = JSON.parse(http.responseText);
+              if (json.message) {
+                resultDiv.innerHTML = '<p class="feedback failed">' + json.error + ' - JSON: ' + http.responseText + '</p>';
+                const parentDivEl = document.getElementById(filepath);
+                parentDivEl.appendChild(resultDiv);
+                generalErrorArray.push(filepath);
+              } else {
+                let resultHtml = '<h3 class="question-title">' + json.name + '</h3>';
+                resultDiv.setAttribute('id', json.name);
+
+                // Display issues based on returned flags.
+                resultHtml += (json.isgeneralfeedback) ?
+                    '' : '<p class="feedback"><?php echo stack_string('bulktestnogeneralfeedback')?></p>';
+                resultHtml += (json.istests) ? '' : '<p class="feedback"><?php echo stack_string('bulktestnotests')?></p>';
+                resultHtml += (json.israndomvariants && !json.isdeployedseeds) ?
+                    '<p class="feedback"><?php echo stack_string('bulktestnodeployedseeds')?></p>' : '';
+                resultHtml += (json.israndomvariants && json.isdeployedseeds) ?
+                    '<div style="margin-left: 20px">' : ''; // Open div for seeds.
+                for (seed in json.results) {
+                  // If there are no random variants, there should be one result indexed as 'noseed'.
+                  if (seed !== 'noseed') {
+                    resultHtml += '<h5 class="seed"><?php echo stack_string('seedx', '')?>' + seed + '</h5>';
+                  }
+                  if (json.istests && json.results[seed].passes !== null) {
+                    // If tests have been run, displays number of passes and fails.
+                    resultHtml += '<p class="feedback' + ((json.results[seed].fails === 0) ? ' passed' :' failed') +  '">'
+                        + json.results[seed].passes + ' <?php echo stack_string('api_passes')?>, '
+                        + json.results[seed].fails + ' <?php echo stack_string('api_failures')?>.</p>';
+                    if ((json.results[seed].fails !== 0) || json.results[seed].messages) {
+                      failedTestsArray.push({'name': json.name, 'seed': seed, 'filepath': filepath,
+                          'passes': json.results[seed].passes, 'fails': json.results[seed].fails,
+                          'message': json.results[seed].messages});
+                      for (const testname in json.results[seed].outcomes) {
+                        const outcome = json.results[seed].outcomes[testname];
+                        // Display outcomes of failed tests if available. There should be a reason if not.
+                        // Reason will be displayed as part of messages.
+                        if (!outcome.passed) {
+                          if (!outcome.reason) {
+                            resultHtml += '<p>' + testname + ' : ' + JSON.stringify(outcome.inputs) + '</p>';
+                            resultHtml += '<p>' + testname + ' : ' + JSON.stringify(outcome.outcomes) + '</p>';
+                          }
+                        }
+                      }
+                    }
+                  }
+                  if (!json.istests && json.results[seed].passes == 1) {
+                    resultHtml += '<p class="feedback passed">' + '<?php echo stack_string('default_test_pass')?>' + '</p>';
+                  }
+                  // Display seed level messages - will be exceptions.
+                  if (json.results[seed].messages) {
+                    resultHtml += '<p class="feedback failed">' + json.results[seed].messages + '</p>';
+                  }
+                  // If we've got no tests but a failed test, then our fallback test of using the teacher's
+                  // answer and expecting a score of 1 has failed.
+                  if (!json.istests && json.results[seed].fails) {
+                    failedTestsArray.push({'name': json.name, 'seed': seed, 'filepath': filepath,
+                          'message': json.results[seed].messages});
+                  }
+                }
+                resultHtml += (json.israndomvariants && json.isdeployedseeds) ? '</div>' : '';  // Close div for seeds.
+                // Display question level messages. (Upgrade errors).
+                resultHtml += (json.messages) ? '<p class="feedback failed">' + json.messages + '</p>' : '';
+                resultDiv.innerHTML = resultHtml;
+                // Append result to correct div then sort questions by name. (Calls are async so we may not
+                // get the results back in the correct order).
+                const parentDivEl = document.getElementById(filepath);
+                parentDivEl.appendChild(resultDiv);
+                parentDivEl.replaceChildren(...Array.from(parentDivEl.children).sort((a,b) => a.id.localeCompare(b.id)));
+
+                // Update the lists of failed tests in each category.
+                const overallUpdate = [
+                          [!json.istests, noTestsArray],
+                          [!json.isgeneralfeedback, noFeedbackArray],
+                          [json.israndomvariants && !json.isdeployedseeds, noDeployedSeedsArray],
+                          [json.isupgradeerror, upgradeIssueArray],
+                          [json.message && !json.isupgradeerror, generalErrorArray],
+                ]
+                for (const update of overallUpdate) {
+                  if (update[0] === true) {
+                    update[1].push({'name': json.name, 'filepath': filepath})
+                  }
+                }
+              }
+            } catch(e) {
+              // Something has gone very wrong.
+              resultDiv.innerText = e.message + ' - JSON: ' + http.responseText;
+              resultDiv.innerHTML += '<br><br>';
+              document.getElementById('errors').appendChild(resultDiv);
+              document.getElementById('errors').removeAttribute('hidden');
+              generalErrorArray.push(filepath);
+            }
+
+            // Remove current request from pending array
+            requests = requests.filter(req => req !== http);
+            if (requests.length === 0 && filesToProcess.length === 0) {
+              displayOverallResults();
+            }
+          }
+        };
+        http.send(JSON.stringify({'questionDefinition': questionxml}));
+      }
+
+      /**
+       * Display the overall pass/fail message and the collections of failed
+       * tests by category of failure. We need to have processed all the files
+       * and got a response to all the requests before running this.
+       *
+       * @return void
+       */
+      function displayOverallResults() {
+        // All done. Display final lists of failed questions by category.
+        let overallPass = true;
+        document.getElementById('bulktest-button').removeAttribute('disabled');
+        document.getElementById('bulktest-spinner').setAttribute('hidden', true);
+        document.getElementById('overall-results').removeAttribute('hidden');
+        const displayUpdate = [
+                [noTestsArray, 'no-tests'],
+                [noFeedbackArray, 'no-feedback'],
+                [upgradeIssueArray, 'upgrade-fail'],
+                [noDeployedSeedsArray, 'no-deployed-seeds'],
+                [failedTestsArray, 'failed-tests'],
+                [generalErrorArray, 'general-error'],
+        ]
+        for (const update of displayUpdate) {
+          const targetTitle = document.getElementById(update[1] + '-title')
+          if (update[0].length === 0) {
+            targetTitle.setAttribute('hidden', true);
+            continue;
+          }
+          overallPass = false;
+          targetTitle.removeAttribute('hidden');
+          const targetDiv = document.getElementById(update[1]);
+          targetDiv.innerHTML = '';
+          const listEl = document.createElement('ul');
+          for (const issue of update[0]) {
+            const itemEl = document.createElement('li');
+            itemEl.innerHTML = issue.filepath
+            itemEl.innerHTML += (issue.name !== undefined) ? ' : ' + issue.name : '';
+            itemEl.innerHTML += (issue.seed !== undefined && issue.seed !== 'noseed') ?
+                ' : <?php echo stack_string('seedx', '')?>' + issue.seed : '';
+            itemEl.innerHTML += (issue.passes !== undefined) ?
+                ' - (' + issue.passes + ' <?php echo stack_string('api_passes')?>, ' +
+                issue.fails + ' <?php echo stack_string('api_failures')?>)' : '';
+            itemEl.innerHTML += (issue.message !== undefined) ? '<br>' + issue.message : '';
+            listEl.appendChild(itemEl);
+          }
+          listEl.replaceChildren(...Array.from(listEl.children).sort((a,b) => a.innerHTML.localeCompare(b.innerHTML)));
+          targetDiv.appendChild(listEl);
+          document.getElementById('overall-result').innerHTML = (overallPass) ?
+              '<div class="feedback passed"><?php echo stack_string('stackInstall_testsuite_pass')?></div><br>' :
+              '<div class="feedback failed"><?php echo stack_string('stackInstall_testsuite_fail')?></div><br>';
+        }
+      }
+
+      /**
+       * Initialise output and sort selected files.
+       * Keeps track of files processed so far to avoid race condition possibility
+       * between the calls to the server and the reading/parsing of a long file.
+       *
+       * @return void
+       */
+      function testFolder() {
+        let files = document.getElementById('local-folder').files;
+        if (!files.length) {
+          return;
+        }
+        document.getElementById('bulktest-button').setAttribute('disabled', true);
+        document.getElementById('bulktest-spinner').removeAttribute('hidden');
+        document.getElementById('overall-results').setAttribute('hidden', true);
+        document.getElementById('errors').setAttribute('hidden', true);
+        document.getElementById('errors').innerHTML = '<h1><?php echo stack_string('api_errors')?></h1><br>';
+        document.getElementById('output').innerHTML = '';
+        requests = [];
+        filesToProcess = [];
+        noFeedbackArray = [];
+        noTestsArray = [];
+        upgradeIssueArray = [];
+        noDeployedSeedsArray = [];
+        failedTestsArray = [];
+        generalErrorArray = [];
+        readingFile = true;
+        files = Array.from(files).sort((a,b) => a.webkitRelativePath.localeCompare(b.webkitRelativePath));
+        for (const file of files) {
+          filesToProcess.push(file.webkitRelativePath);
+        }
+        for (const file of files) {
+          if (file.type === 'application/xml' || file.type === 'text/xml') {
+            getLocalQuestionFile(file);
+          } else {
+            filesToProcess = filesToProcess.filter(item => item !== file.webkitRelativePath);
+          }
+        }
+        if (requests.length === 0 && filesToProcess.length === 0) {
+          document.getElementById('bulktest-button').removeAttribute('disabled');
+          document.getElementById('bulktest-spinner').setAttribute('hidden', true);
+        }
+      }
+
+      /**
+       * Read a file
+       */
+      function getLocalQuestionFile(file) {
+        if (file) {
+          const reader = new FileReader();
+          reader.readAsText(file, "UTF-8");
+          reader.onload = function (evt) {
+            sendQuestionsFromFile(file.webkitRelativePath, evt.target.result);
+            filesToProcess = filesToProcess.filter(item => item !== file.webkitRelativePath);
+            // Maybe we're done. Check if so and display the results if appropriate.
+            // This is unlikely but maybe we finished with a large file with no
+            // STACK questions and so all the requests are already complete.
+            if (requests.length === 0 && filesToProcess.length === 0) {
+              displayOverallResults();
+            }
+          }
+        }
+      }
+
+      /**
+       * Parse an XML file, chop into stack questions and send test requests for each one.
+       */
+      function sendQuestionsFromFile(filepath, fileContents) {
+        const parser = new DOMParser();
+        const xmlDoc = parser.parseFromString(fileContents, "text/xml");
+        const errorNode = xmlDoc.querySelector("parsererror");
+        if (errorNode) {
+          const resultDiv = document.createElement("div");
+          resultDiv.innerHTML += '<p class="feedback failed">' + filepath + ': ' + errorNode.innerHTML + '</p><br><br>';
+          document.getElementById('errors').appendChild(resultDiv);
+          document.getElementById('errors').removeAttribute('hidden');
+          generalErrorArray.push(filepath);
+          return;
+        }
+        let questions = xmlDoc.getElementsByTagName("question");
+        for (const question of questions) {
+          if (question.getAttribute('type').toLowerCase() === 'stack') {
+            send(filepath, '<quiz>\n' + question.outerHTML + '\n</quiz>');
+          }
+        }
+      }
+
+    </script>
+
+    <div class="container-fluid que stack">
+      <div class="vstack gap-3 ms-3 col-lg-8">
+        <div>
+          <a href="https://stack-assessment.org/" class="nav-link">
+            <span style="display: flex; align-items: center; font-size: 20px">
+              <span style="display: flex; align-items: center;">
+                <img src="logo_large.png" style="height: 50px;">
+                <span style="font-size: 50px;"><b>STACK </b></span>
+              </span>
+              &nbsp;| Online assessment
+            </span>
+          </a>
+        </div>
+          <?php echo stack_string('api_choose_folder')?>:
+        <input type="file" id="local-folder" accept=".xml" name="local-folder" webkitdirectory directory multiple/>
+        <div>
+          <button id="bulktest-button" onclick="testFolder()"  class="btn btn-primary" type="button">
+            <span id="bulktest-spinner" class="spinner-border spinner-border-sm" role="status" aria-hidden="true" hidden></span>
+            Test
+          </button>
+        </div>
+      </div>
+      <br>
+      <div id='output'>
+      </div>
+      <div id='errors' hidden>
+      </div>
+      <br><br>
+      <div id="overall-results" hidden>
+        <h1>Overall Results</h1>
+        <div id="overall-result">
+        </div>
+        <h3 id="failed-tests-title"><?php echo stack_string('stackInstall_testsuite_failingtests')?></h3>
+        <div id="failed-tests">
+        </div>
+        <h3 id="upgrade-fail-title"><?php echo stack_string('stackInstall_testsuite_failingupgrades')?></h3>
+        <div id="upgrade-fail">
+        </div>
+        <h3 id="no-tests-title"><?php echo stack_string('stackInstall_testsuite_notests')?></h3>
+        <div id="no-tests">
+        </div>
+        <h3 id="no-feedback-title"><?php echo stack_string('stackInstall_testsuite_nogeneralfeedback')?></h3>
+        <div id="no-feedback">
+        </div>
+        <h3 id="no-deployed-seeds-title"><?php echo stack_string('stackInstall_testsuite_nodeployedseeds')?></h3>
+        <div id="no-deployed-seeds">
+        </div>
+        <h3 id="general-error-title"><?php echo stack_string('api_general_errors')?></h3>
+        <div id="general-error">
+        </div>
+      </div>
+    <br>
+
+  </body>
+</html>
+
diff --git a/api/public/index.php b/api/public/index.php
index 4b010f3b239f153ff607139191b7e486fa28e269..2ba9a78eebe990c137f1253e0b31c28b7fa830cf 100644
--- a/api/public/index.php
+++ b/api/public/index.php
@@ -25,6 +25,7 @@ require_once(__DIR__ . '../../emulation/MoodleEmulation.php');
 require_login();
 use api\controller\GradingController;
 use api\controller\RenderController;
+use api\controller\TestController;
 use api\controller\ValidationController;
 use api\controller\DownloadController;
 use api\util\ErrorRenderer;
@@ -43,6 +44,7 @@ $errorhandler = $errormiddleware->getDefaultErrorHandler();
 $errorhandler->forceContentType("application/json");
 $errorhandler->registerErrorRenderer('application/json', ErrorRenderer::class);
 $app->post('/render', RenderController::class);
+$app->post('/test', TestController::class);
 $app->post('/grade', GradingController::class);
 $app->post('/validate', ValidationController::class);
 $app->post('/download', DownloadController::class);
diff --git a/api/public/stack.php b/api/public/stack.php
index 8656b4a67ff57aa5d5bbb7ca059a8c4450311d73..dade32f92f7b956dbdeeec2e97d732e40fa60728 100644
--- a/api/public/stack.php
+++ b/api/public/stack.php
@@ -137,16 +137,18 @@ require_login();
       // Display rendered question and solution.
       function send() {
         const http = new XMLHttpRequest();
-        const url = "http://localhost:3080/render";
+        const url = window.location.origin + '/render';
         http.open("POST", url, true);
         http.setRequestHeader('Content-Type', 'application/json');
         http.onreadystatechange = function() {
           if(http.readyState == 4) {
             try {
               const json = JSON.parse(http.responseText);
-              if (json.error) {
-                document.getElementById('output').innerText = http.responseText;
+              if (json.message) {
+                document.getElementById('errors').innerText = json.message;
                 return;
+              } else {
+                document.getElementById('errors').innerText = '';
               }
               renameIframeHolders();
               let question = json.questionrender;
@@ -158,8 +160,9 @@ require_login();
                 question = question.replace(`[[validation:${name}]]`, `<span name='${validationPrefix + name}'></span>`);
                 if (input.samplesolutionrender && name !== 'remember') {
                   // Display render of answer and matching user input to produce the answer.
-                  correctAnswers += `<p>A correct answer is: \\[{${input.samplesolutionrender}}\\],
-                    which can be typed as follows: `;
+                  correctAnswers += `<p>
+                    <?php echo stack_string('teacheranswershow_mcq', '')?> \\[{${input.samplesolutionrender}}\\],
+                    <?php echo stack_string('api_which_typed')?>: `;
                   for (const [name, solution] of Object.entries(input.samplesolution)) {
                     if (name.indexOf('_val') === -1) {
                       correctAnswers += `<span class='correct-answer'>${solution}</span>`;
@@ -221,7 +224,8 @@ require_login();
               MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
             }
             catch(e) {
-              document.getElementById('output').innerText = http.responseText;
+              document.getElementById('errors').innerText = http.responseText;
+              return;
             }
           }
         };
@@ -231,7 +235,7 @@ require_login();
       // Validate an input. Called a set amount of time after an input is last updated.
       function validate(element) {
         const http = new XMLHttpRequest();
-        const url = "http://localhost:3080/validate";
+        const url = window.location.origin + '/validate';
         http.open("POST", url, true);
         // Remove API prefix and subanswer id.
         const answerName = element.name.slice(15).split('_', 1)[0];
@@ -240,9 +244,11 @@ require_login();
           if(http.readyState == 4) {
             try {
               const json = JSON.parse(http.responseText);
-              if (json.error) {
-                document.getElementById('output').innerText = http.responseText;
+              if (json.message) {
+                document.getElementById('errors').innerText = json.message;
                 return;
+              } else {
+                document.getElementById('errors').innerText = '';
               }
               renameIframeHolders();
               const validationHTML = json.validation;
@@ -257,7 +263,8 @@ require_login();
               MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
             }
             catch(e) {
-              document.getElementById('output').innerText = http.responseText;
+              document.getElementById('errors').innerText = http.responseText;
+              return;
             }
           }
         };
@@ -270,7 +277,7 @@ require_login();
       // Submit answers.
       function answer() {
         const http = new XMLHttpRequest();
-        const url = "http://localhost:3080/grade";
+        const url = window.location.origin + '/grade';
         http.open("POST", url, true);
 
         if (!document.getElementById('output').innerText) {
@@ -282,18 +289,21 @@ require_login();
           if(http.readyState == 4) {
             try {
               const json = JSON.parse(http.responseText);
-              if (json.error) {
-                document.getElementById('output').innerText = http.responseText;
+              if (json.message) {
+                document.getElementById('errors').innerText = json.message;
                 return;
+              } else {
+                document.getElementById('errors').innerText = '';
               }
               if (!json.isgradable) {
                 document.getElementById('stackapi_validity').innerText
-                  = ' Please enter valid answers for all parts of the question.';
+                  = ' <?php echo stack_string('api_valid_all_parts')?>';
                 return;
               }
               renameIframeHolders();
               document.getElementById('score').innerText
-                = (json.score * json.scoreweights.total).toFixed(2) + ' out of ' + json.scoreweights.total;
+                = (json.score * json.scoreweights.total).toFixed(2) +
+                ' <?php echo stack_string('api_out_of')?> ' + json.scoreweights.total;
               document.getElementById('stackapi_score').style.display = 'block';
               document.getElementById('response_summary').innerText = json.responsesummary;
               document.getElementById('stackapi_summary').style.display = 'block';
@@ -319,7 +329,7 @@ require_login();
                 if (elements.length > 0) {
                   const element = elements[0];
                   if (json.scores[name] !== undefined) {
-                    fb = fb + `<div>Marks for this submission:
+                    fb = fb + `<div><?php echo stack_string('api_marks_sub')?>:
                       ${(json.scores[name] * json.scoreweights[name] * json.scoreweights.total).toFixed(2)}
                         / ${(json.scoreweights[name] * json.scoreweights.total).toFixed(2)}.</div>`;
                   }
@@ -335,7 +345,8 @@ require_login();
               MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
             }
             catch(e) {
-              document.getElementById('output').innerText = http.responseText;
+              document.getElementById('errors').innerText = http.responseText;
+              return;
             }
           }
         };
@@ -357,7 +368,7 @@ require_login();
 
       function download(filename, fileid) {
         const http = new XMLHttpRequest();
-        const url = "http://localhost:3080/download";
+        const url = window.location.origin + '/download';
         http.open("POST", url, true);
         http.setRequestHeader('Content-Type', 'application/json');
         // Something funky going on with closures and callbacks. This seems
@@ -379,7 +390,8 @@ require_login();
               link.click();
             }
             catch(e) {
-              document.getElementById('output').innerText = http.responseText;
+              document.getElementById('errors').innerText = http.responseText;
+              return;
             }
           }
         };
@@ -458,7 +470,7 @@ require_login();
         selectQuestion.setAttribute("onchange", "setQuestion(this.value)");
         selectQuestion.id = "stackapi_question_select";
         const holder = document.getElementById("stackapi_question_select_holder");
-        holder.innerHTML = "Select a question: ";
+        holder.innerHTML = "<?php echo stack_string('api_q_select')?>: ";
         holder.appendChild(selectQuestion);
         let firstquestion = null
         for (const question of xmlDoc.getElementsByTagName("question")) {
@@ -493,9 +505,9 @@ require_login();
             </span>
           </a>
         </div>
-        Choose a STACK sample file:
+        <?php echo stack_string('api_choose_q')?>:
         <select id="file_selector" placeholder="Select question" autocomplete="off" onchange="getQuestionFile(this.value)">
-          <option value="" selected>Please select a question file</option>
+          <option value="" selected><?php echo stack_string('api_choose_file')?></option>
         <?php
         $filenames = scandir('../../samplequestions');
         foreach ($filenames as $filename) {
@@ -505,35 +517,36 @@ require_login();
         }
         ?>
         </select>
-        Or select a file of your own:
+        <?php echo stack_string('api_local_file')?>:
         <input type="file" id="local-file" name="local-file" accept=".xml" onchange="getLocalQuestionFile(this.files[0])"/>
         <div id="stackapi_question_select_holder"></div>
-        <h2>Question XML</h2>
+        <h2><?php echo stack_string('api_q_xml')?></h2>
         <textarea id="xml" cols="100" rows="10"></textarea>
-        <h2>Seed: <input id="seed" type="number"></h2>
+        <h2><?php echo stack_string('seedx', '')?> <input id="seed" type="number"></h2>
         <div>
-          <input type="button" onclick="send()" class="btn btn-primary" value="Display Question"/>
-          <input type="checkbox" id="readOnly" style="margin-left: 10px"/> Read Only
+          <input type="button" onclick="send()" class="btn btn-primary" value="<?php echo stack_string('api_display')?>"/>
+          <input type="checkbox" id="readOnly" style="margin-left: 10px"/> <?php echo stack_string('api_read_only')?>
         </div>
+        <div id='errors'></div>
         <div id="stackapi_qtext" class="col-lg-8" style="display: none">
-          <h2>Question text:</h2>
+          <h2><?php echo stack_string('questiontext')?>:</h2>
           <div id="output" class="formulation"></div>
           <div id="specificfeedback"></div>
           <br>
-          <input type="button" onclick="answer()" class="btn btn-primary" value="Submit Answers"/>
+          <input type="button" onclick="answer()" class="btn btn-primary" value="<?php echo stack_string('api_submit')?>"/>
           <span id="stackapi_validity" style="color:darkred"></span>
         </div>
         <div id="stackapi_generalfeedback" class="col-lg-8" style="display: none">
-          <h2>General feedback:</h2>
+          <h2><?php echo stack_string('generalfeedback')?>:</h2>
           <div id="generalfeedback" class="feedback"></div>
         </div>
-        <h2 id="stackapi_score" style="display: none">Score: <span id="score"></span></h2>
+        <h2 id="stackapi_score" style="display: none"><?php echo stack_string('score')?>: <span id="score"></span></h2>
         <div id="stackapi_summary" class="col-lg-10" style="display: none">
-          <h2>Response summary:</h2>
+          <h2><?php echo stack_string('api_response')?>:</h2>
           <div id="response_summary" class="feedback"></div>
         </div>
         <div id="stackapi_correct" class="col-lg-10" style="display: none">
-          <h2>Correct answers:</h2>
+          <h2><?php echo stack_string('api_correct')?>:</h2>
           <div id="formatcorrectresponse" class="feedback"></div>
         </div>
       </div>
diff --git a/api/util/StackQuestionLoader.php b/api/util/StackQuestionLoader.php
index 719ab1c729c2514589085422ef0da64a3ef67b4d..ac3c0565fed4eac7f01dd2efc5eeecd6781f94fe 100644
--- a/api/util/StackQuestionLoader.php
+++ b/api/util/StackQuestionLoader.php
@@ -23,13 +23,15 @@ namespace api\util;
 use SimpleXMLElement;
 defined('MOODLE_INTERNAL') || die();
 require_once(__DIR__ . '/../../question.php');
+require_once(__DIR__ . '/../../stack/questiontest.php');
+require_once(__DIR__ . '/../../stack/potentialresponsetreestate.class.php');
 
 /**
  * TO-DO: Rework, dont use legacy classes
  * Converts question xml into usable format
  */
 class StackQuestionLoader {
-    public static function loadxml($xml) {
+    public static function loadxml($xml, $includetests=false) {
         // TO-DO: Consider defaults.
         try {
             $xmldata = new SimpleXMLElement($xml);
@@ -66,8 +68,8 @@ class StackQuestionLoader {
         $question->questiontextformat = (string) $xmldata->question->questiontext['format'];
         $question->generalfeedback = (string) $xmldata->question->generalfeedback->text;
         $question->generalfeedbackformat = (string) $xmldata->question->generalfeedback['format'];
-        $question->defaultmark = isset($xmldata->question->defaultgrade) ? (float) $xmldata->question->defaultgrade : 1.0;
-        $question->penalty = isset($xmldata->question->penalty) ? (float) $xmldata->question->penalty : 0.1;
+        $question->defaultmark = (array) $xmldata->question->defaultgrade ? (float) $xmldata->question->defaultgrade : 1.0;
+        $question->penalty = (array) $xmldata->question->penalty ? (float) $xmldata->question->penalty : 0.1;
 
         // Based on initialise_question_instance from questiontype.php.
         $question->stackversion              = (string) $xmldata->question->stackversion->text;
@@ -75,6 +77,8 @@ class StackQuestionLoader {
         $question->questionnote              = (string) $xmldata->question->questionnote->text;
         $question->specificfeedback          = (string) $xmldata->question->specificfeedback->text;
         $question->specificfeedbackformat    = (string) $xmldata->question->specificfeedback['format'];
+        $question->questiondescription       = (string) $xmldata->question->questiondescription;
+        $question->questiondescriptionformat = (string) $xmldata->question->questiondescription['format'];
         if (isset($xmldata->question->prtcorrect->text)) {
             $question->prtcorrect                = (string) $xmldata->question->prtcorrect->text;
             $question->prtcorrectformat          = (string) $xmldata->question->prtcorrect['format'];
@@ -102,56 +106,57 @@ class StackQuestionLoader {
         $question->options = new \stack_options();
         $question->options->set_option(
             'multiplicationsign',
-            isset($xmldata->question->multiplicationsign) ?
+            (array) $xmldata->question->multiplicationsign ?
                 (string) $xmldata->question->multiplicationsign : get_config('qtype_stack', 'multiplicationsign')
         );
         $question->options->set_option(
             'complexno',
-            isset($xmldata->question->complexno) ?
+            (array) $xmldata->question->complexno ?
                 (string) $xmldata->question->complexno : get_config('qtype_stack', 'complexno')
         );
         $question->options->set_option(
             'inversetrig',
-            isset($xmldata->question->inversetrig) ?
+            (array) $xmldata->question->inversetrig ?
                 (string) $xmldata->question->inversetrig : get_config('qtype_stack', 'inversetrig')
         );
         $question->options->set_option(
             'logicsymbol',
-            isset($xmldata->question->logicsymbol) ?
+            (array) $xmldata->question->logicsymbol ?
                 (string) $xmldata->question->logicsymbol : get_config('qtype_stack', 'logicsymbol')
         );
         $question->options->set_option(
             'matrixparens',
-            isset($xmldata->question->matrixparens) ?
+            (array) $xmldata->question->matrixparens ?
                 (string) $xmldata->question->matrixparens : get_config('qtype_stack', 'matrixparens')
         );
         $question->options->set_option(
             'sqrtsign',
-            isset($xmldata->question->sqrtsign) ?
+            (array) $xmldata->question->sqrtsign ?
                 self::parseboolean($xmldata->question->sqrtsign) : (bool) get_config('qtype_stack', 'sqrtsign')
         );
         $question->options->set_option(
             'simplify',
-            isset($xmldata->question->questionsimplify) ?
+            (array) $xmldata->question->questionsimplify ?
                 self::parseboolean($xmldata->question->questionsimplify) : (bool) get_config('qtype_stack', 'questionsimplify')
         );
         $question->options->set_option(
             'assumepos',
-            isset($xmldata->question->assumepositive) ?
+            (array) $xmldata->question->assumepositive ?
                 self::parseboolean($xmldata->question->assumepositive) : (bool) get_config('qtype_stack', 'assumepositive')
         );
         $question->options->set_option(
             'assumereal',
-            isset($xmldata->question->assumereal) ?
+            (array) $xmldata->question->assumereal ?
                 self::parseboolean($xmldata->question->assumereal) : (bool) get_config('qtype_stack', 'assumereal')
         );
         $question->options->set_option(
             'decimals',
-            isset($xmldata->question->decimals) ? (string) $xmldata->question->decimals : get_config('qtype_stack', 'decimals')
+            (array) $xmldata->question->decimals ?
+                (string) $xmldata->question->decimals : get_config('qtype_stack', 'decimals')
         );
         $question->options->set_option(
             'scientificnotation',
-            isset($xmldata->question->scientificnotation) ?
+            (array) $xmldata->question->scientificnotation ?
                                 (string) $xmldata->question->scientificnotation : get_config('qtype_stack', 'scientificnotation')
         );
 
@@ -163,25 +168,25 @@ class StackQuestionLoader {
         $requiredparams = \stack_input_factory::get_parameters_used();
         foreach ($inputmap as $name => $inputdata) {
             $allparameters = [
-                'boxWidth'        => isset($inputdata->boxsize) ?
+                'boxWidth'        => (array) $inputdata->boxsize ?
                     (int) $inputdata->boxsize : get_config('qtype_stack', 'inputboxsize'),
-                'insertStars'     => isset($inputdata->insertstars) ?
+                'insertStars'     => (array) $inputdata->insertstars ?
                     (int) $inputdata->insertstars : get_config('qtype_stack', 'inputinsertstars'),
                 'syntaxHint'      => isset($inputdata->syntaxhint) ? (string) $inputdata->syntaxhint : '',
-                'syntaxAttribute' => isset($inputdata->syntaxattribute) ? (int) $inputdata->syntaxattribute : 0,
+                'syntaxAttribute' => (array) $inputdata->syntaxattribute ? (int) $inputdata->syntaxattribute : 0,
                 'forbidWords'     => isset($inputdata->forbidwords) ?
                     (string) $inputdata->forbidwords : get_config('qtype_stack', 'inputforbidwords'),
                 'allowWords'      => isset($inputdata->allowwords) ? (string) $inputdata->allowwords : '',
-                'forbidFloats'    => isset($inputdata->forbidfloat) ?
+                'forbidFloats'    => (array) $inputdata->forbidfloat ?
                     self::parseboolean($inputdata->forbidfloat) : (bool) get_config('qtype_stack', 'inputforbidfloat'),
-                'lowestTerms'     => isset($inputdata->requirelowestterms) ?
+                'lowestTerms'     => (array) $inputdata->requirelowestterms ?
                     self::parseboolean($inputdata->requirelowestterms) :
                     (bool) get_config('qtype_stack', 'inputrequirelowestterms'),
-                'sameType'        => isset($inputdata->checkanswertype) ?
+                'sameType'        => (array) $inputdata->checkanswertype ?
                     self::parseboolean($inputdata->checkanswertype) : (bool) get_config('qtype_stack', 'inputcheckanswertype'),
-                'mustVerify'      => isset($inputdata->mustverify) ?
+                'mustVerify'      => (array) $inputdata->mustverify ?
                     self::parseboolean($inputdata->mustverify) : (bool) get_config('qtype_stack', 'inputmustverify'),
-                'showValidation'  => isset($inputdata->showvalidation) ?
+                'showValidation'  => (array) $inputdata->showvalidation ?
                     (int) $inputdata->showvalidation : get_config('qtype_stack', 'inputshowvalidation'),
                 'options'         => isset($inputdata->options) ? (string) $inputdata->options : '',
             ];
@@ -219,9 +224,9 @@ class StackQuestionLoader {
 
             $data = new \stdClass();
             $data->name = (string) $prtdata->name;
-            $data->autosimplify = isset($prtdata->autosimplify) ? self::parseboolean($prtdata->autosimplify) : true;
-            $data->feedbackstyle = isset($prtdata->feedbackstyle) ? (int) $prtdata->feedbackstyle : 1;
-            $data->value = isset($prtdata->value) ? (float) $prtdata->value : 1.0;
+            $data->autosimplify = (array) $prtdata->autosimplify ? self::parseboolean($prtdata->autosimplify) : true;
+            $data->feedbackstyle = (array) $prtdata->feedbackstyle ? (int) $prtdata->feedbackstyle : 1;
+            $data->value = (array) $prtdata->value ? (float) $prtdata->value : 1.0;
             $data->firstnodename = null;
 
             $data->feedbackvariables = (string) $prtdata->feedbackvariables->text;
@@ -238,18 +243,18 @@ class StackQuestionLoader {
                 $newnode->testoptions = (string) $node->testoptions;
                 $newnode->quiet = self::parseboolean($node->quiet);
 
-                $newnode->truescoremode = isset($node->truescoremode) ? (string) $node->truescoremode : 'add';
-                $newnode->truescore = isset($node->truescore) ? (float) $node->truescore : 1.0;
-                $newnode->truepenalty = isset($node->truepenalty) ? (float) $node->truepenalty : 0.0;
-                $newnode->truenextnode = isset($node->truenextnode) ? (string) $node->truenextnode : '-1';
+                $newnode->truescoremode = (array) $node->truescoremode ? (string) $node->truescoremode : '+';
+                $newnode->truescore = (array) $node->truescore ? (string) $node->truescore : 1.0;
+                $newnode->truepenalty = (array) $node->truepenalty ? (string) $node->truepenalty : null;
+                $newnode->truenextnode = (array) $node->truenextnode ? (string) $node->truenextnode : '-1';
                 $newnode->trueanswernote = (string) $node->trueanswernote;
                 $newnode->truefeedback = (string) $node->truefeedback->text;
                 $newnode->truefeedbackformat = (string) $node->truefeedback['format'];
 
-                $newnode->falsescoremode = isset($node->falsescoremode) ? (string) $node->falsescoremode : 'equals';
-                $newnode->falsescore = isset($node->falsescore) ? (float) $node->falsescore : 0.0;
-                $newnode->falsepenalty = isset($node->falsepenalty) ? (float) $node->falsepenalty : 0.0;
-                $newnode->falsenextnode = isset($node->falsenextnode) ? (string) $node->falsenextnode : '-1';
+                $newnode->falsescoremode = (array) $node->falsescoremode ? (string) $node->falsescoremode : '=';
+                $newnode->falsescore = (array) $node->falsescore ? (string) $node->falsescore : 0.0;
+                $newnode->falsepenalty = (array) $node->falsepenalty ? (string) $node->falsepenalty : null;
+                $newnode->falsenextnode = (array) $node->falsenextnode ? (string) $node->falsenextnode : '-1';
                 $newnode->falseanswernote = (string) $node->falseanswernote;
                 $newnode->falsefeedback = (string) $node->falsefeedback->text;
                 $newnode->falsefeedbackformat = (string) $node->falsefeedback['format'];
@@ -267,8 +272,28 @@ class StackQuestionLoader {
         }
 
         $question->deployedseeds = $deployedseeds;
+        $testcases = [];
+        if ($includetests) {
+            foreach ($xmldata->question->qtest as $test) {
+                $testinputs = [];
+                foreach ($test->testinput as $testinput) {
+                    $testinputs[(string) $testinput->name] = (string) $testinput->value;
+                }
+                $testcase = new \stack_question_test((string) $test->description, $testinputs, (string) $test->testcase);
+                foreach ($test->expected as $expected) {
+                    $testcase->add_expected_result((string) $expected->name,
+                            new \stack_potentialresponse_tree_state(1, true,
+                                (array) $expected->expectedscore ?
+                                    (string) $expected->expectedscore : null,
+                                (array) $expected->expectedpenalty ?
+                                    (string) $expected->expectedpenalty : null,
+                                    '', [(string) $expected->expectedanswernote]));
+                }
+                $testcases[] = $testcase;
+            }
+        }
 
-        return $question;
+        return ['question' => $question, 'testcases' => $testcases];
     }
 
     private static function handlefiles(\SimpleXMLElement $files) {
diff --git a/deploy.php b/deploy.php
index 071c25bb6a0cf98ed2586031294398fc82c092c9..4849a9757be671fe7e4b5f1bc5200cb906b61ad7 100644
--- a/deploy.php
+++ b/deploy.php
@@ -61,9 +61,7 @@ if (!is_null($deploy)) {
 $undeploy = optional_param('undeploy', null, PARAM_INT);
 if (!is_null($undeploy)) {
     $question->undeploy_variant($undeploy);
-
-    // As we redirect, switch to the undeployed variant, so it easy to re-deploy
-    // if you just made a mistake.
+    // As we redirect, switch to the undeployed variant, so it easy to re-deploy if you just made a mistake.
     $nexturl->param('seed', $undeploy);
     redirect($nexturl);
 }
@@ -81,7 +79,11 @@ if (!is_null($undeploy) && $question->deployedseeds) {
 // Process undeployall if applicable.
 $deployfromlist = optional_param('deployfromlist', null, PARAM_INT);
 $deploysystematic = optional_param('deploysystematic', null, PARAM_INT);
-if (!is_null($deployfromlist) || !is_null($deploysystematic)) {
+$deploysystematicfrom = optional_param('deploysystematicfrom', null, PARAM_INT);
+$deploysystematicto = optional_param('deploysystematicto', null, PARAM_INT);
+$usefromtofeature = false;
+if (!is_null($deployfromlist) || !is_null($deploysystematic) || (!is_null($deploysystematicfrom) &&
+    !is_null($deploysystematicto))) {
 
     // Check data integrity.
     $dataproblem = false;
@@ -89,6 +91,9 @@ if (!is_null($deployfromlist) || !is_null($deploysystematic)) {
     if (!is_null($deployfromlist)) {
         $deploytxt = optional_param('deployfromlist', null, PARAM_TEXT);
         $baseseeds = explode("\n", trim($deploytxt));
+    } else if (!is_null($deploysystematicfrom) && !is_null($deploysystematicto)) {
+        $baseseeds = range($deploysystematicfrom, $deploysystematicto);
+        $usefromtofeature = true;
     } else {
         $baseseeds = range(1, $deploysystematic);
     }
@@ -132,9 +137,18 @@ if (!is_null($deployfromlist) || !is_null($deploysystematic)) {
     }
 
     // Undeploy all existing variants.
+    // If the deploy-from-to feature is used, only undeploy variants that already exist.
     if ($question->deployedseeds) {
-        foreach ($question->deployedseeds as $seed) {
-            $question->undeploy_variant($seed);
+        if ($usefromtofeature) {
+            foreach ($question->deployedseeds as $seed) {
+                if (in_array($seed, $newseeds)) {
+                    $question->undeploy_variant($seed);
+                }
+            }
+        } else {
+            foreach ($question->deployedseeds as $seed) {
+                $question->undeploy_variant($seed);
+            }
         }
     }
     // Deploy all new variants.
diff --git a/doc/en/AbInitio/Authoring_quick_start_1.md b/doc/en/AbInitio/Authoring_quick_start_1.md
index e8c63f959b1bddc4f6b978bb1ce0d4926aa0c5aa..8793b5cd73e2a420c6674b1a42015bb784ca027c 100644
--- a/doc/en/AbInitio/Authoring_quick_start_1.md
+++ b/doc/en/AbInitio/Authoring_quick_start_1.md
@@ -11,6 +11,7 @@ We assume the following:
 
 1. You have access to a course with STACK installed.
 2. You are familiar with simple \(\LaTeX\) formatting for mathematics.  Some basic examples are provided in the [CASText](../Authoring/CASText.md) documentation.
+3. __We strongly recommend you do not use an HTML-aware editor when editing STACK questions containing GeoGebra.__  Instead turn off the editor within Moodle and edit the raw HTML.  Individual users can set their editor preferences by following: `User Dashboard > Preferences > Editor preferences > Manage editors`
 
 ## Creating a minimal STACK question
 
diff --git a/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md b/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md
index 908be6522f8d0ae4ba5d2df047e8af0ab8420af2..9f47e219954ce991a0aeafb58905ee09db1463fa 100644
--- a/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md
+++ b/doc/en/Authoring/Answer_Tests/Results/AlgEquiv.md
@@ -487,6 +487,33 @@ i/15))</pre></td>
   <td class="cell c5">0</td>
   <td class="cell c6"></td>
 </tr>
+<tr class="pass">
+  <td class="cell c0">AlgEquiv</td>
+  <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td>
+  <td class="cell c2"><pre>&#039;root(x)</pre></td>
+  <td class="cell c3"><pre>x^(1/2)</pre></td>
+  <td class="cell c4"></td>
+  <td class="cell c5">1</td>
+  <td class="cell c6"></td>
+</tr>
+<tr class="pass">
+  <td class="cell c0">AlgEquiv</td>
+  <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td>
+  <td class="cell c2"><pre>&#039;root(x,m)</pre></td>
+  <td class="cell c3"><pre>x^(1/m)</pre></td>
+  <td class="cell c4"></td>
+  <td class="cell c5">1</td>
+  <td class="cell c6"></td>
+</tr>
+<tr class="pass">
+  <td class="cell c0">AlgEquiv</td>
+  <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td>
+  <td class="cell c2"><pre>x</pre></td>
+  <td class="cell c3"><pre>&#039;root(x^2)</pre></td>
+  <td class="cell c4"></td>
+  <td class="cell c5">0</td>
+  <td class="cell c6"></td>
+</tr>
 <tr class="pass">
   <td class="cell c0">AlgEquiv</td>
   <td class="cell c1"><span style="color:green;"><i class="fa fa-check"></i></span></td>
@@ -1661,7 +1688,7 @@ i,i),i,8)</pre></td>
 </tr>
 <tr class="pass">
   <td class="cell c0"><td colspan="2"></td></td>
-  <td class="cell c1"><td colspan="4">The following entries are incorrect, although they may appear in a simplified form from that which you actually entered. <span class="filter_mathjaxloader_equation"><span class="nolink">\[\left \{5-x &gt; 0\,{\text{ and }}\, x-1 > 0 \right \}\]</span></span></td></td>
+  <td class="cell c1"><td colspan="4">The following entries are incorrect, although they may appear in a simplified form from that which you actually entered. <span class="filter_mathjaxloader_equation"><span class="nolink">\[\left \{5-x > 0\,{\text{ and }}\, x-1 > 0 \right \}\]</span></span></td></td>
 </tr>
 <tr class="notes">
   <td class="cell c0"><td colspan="6">Equivalence for elements of sets is different from expressions: see docs.</td></td>
diff --git a/doc/en/Authoring/GeoGebra.md b/doc/en/Authoring/GeoGebra.md
index acd97be9f86dc4929707d47be6623896167b277a..a8ce718dc1e090c42d2efae1d0ae4d89c1b9cb04 100644
--- a/doc/en/Authoring/GeoGebra.md
+++ b/doc/en/Authoring/GeoGebra.md
@@ -123,7 +123,7 @@ With the "watch" sub-tag someone can listen to values and points in GeoGebra. Th
 General notes for watched objects
 
 1. Points, e.g. `A`, _must_ be an algebraic-input and you _must_ allow floats!
-2. You can access `A` in STACK for feedback as a list of values for points `A[0]->x-value`, `A[1]->y-value`
+2. You can access `A` in STACK for feedback as a list of values for points `A[1]->x-value`, `A[2]->y-value`
 3. Numbers/angles e.g. `b` can be an algebraic or numerical input, and you _must_ allow floats!
 4. You can access `b` in STACK as value. If `b` represents an angle then `b` is in radians.
 
diff --git a/doc/en/Authoring/Inputs.md b/doc/en/Authoring/Inputs.md
index 3e14c19f784f4021a5ad4d27324b69c1525d529d..ea04ff050474440533cd9242ccecd2fcff7a8002 100644
--- a/doc/en/Authoring/Inputs.md
+++ b/doc/en/Authoring/Inputs.md
@@ -266,7 +266,12 @@ Do not use this option in questions in place of the normal quiz settings.
 
 ### Extra option: allowempty ###
 
-Normally a _blank_, i.e. empty, answer has a special status and are not considered "valid".  Hence, a PRT relying on an input left blank will not be traversed.  Answers consisting only of whitespace are also considered as empty.  The extra option `allowempty` allows the input to be empty.  Internally an empty answer will be replaced by the Maxima atom `EMPTYANSWER`.  Internally it is essential that the variable name of the input, (e.g. `ans1`) is really assigned a specific value. The teacher will need to deal with `EMPTYANSWER` tags in the PRT.
+Normally a _blank_, i.e. empty, answer has a special status and are not considered "valid".  Hence, a PRT relying on an input left blank will not be traversed.  Answers consisting only of whitespace are also considered as empty.  The extra option `allowempty` allows the input to be empty.  Internally it is essential that the variable name of the input, (e.g. `ans1`) is really assigned a specific value.
+
+* Most inputs, including the algebraic input, an empty answer will be replaced by the Maxima atom `EMPTYANSWER`.  The teacher will need to deal with `EMPTYANSWER` tags in the PRT.
+* String inputs will return the empty string `""` as an empty answer (to avoid a type-mismatch).
+* Textarea inputs will return `[EMPTYANSWER]` to make sure the answer is always a list (to avoid a type-mismatch).
+* Matrix inputs will return the correct size matrix filled with `null` atoms, e.g. `matrix([null,null],[null,null])`.
 
 We strongly recommend (with many years of experience) that teachers do not use this option without very careful thought!
 
diff --git a/doc/en/Authoring/Languages.md b/doc/en/Authoring/Languages.md
index 6278503efbccfc44bba38aad75ce855b8be433ad..8e54e42fdaad5086db1c2edd7bae774732b4bdf3 100644
--- a/doc/en/Authoring/Languages.md
+++ b/doc/en/Authoring/Languages.md
@@ -1,7 +1,11 @@
 # Producing multilingual content
 
-There are many ways for, the multilang-filter that comes with Moodle is often preferred as it is available. But people do seem to prefer multilang2 when dealign with richer content that needs to work with scripting and other syntax. As dealing with the localisation can also affect the way STACK does some special things we have added yet another way as a built-in alternative for those cases where the language needs to be passed into places that traditional Moodle-filters do not see.
+Multilingual content can be developed using two systems.
 
+1. The multilang-filter that comes with Moodle.
+2. STACK's own language blocks (recommended).
+
+Please note that the TinyMCE editor considers paragraph tags (`<p>..</p>`) inside any span tags (e.g. `<span lang="en" class="multilang">...</span>`) to be invalud. The TinyMCE editor will potentially "clean up" (i.e. ruin) your multilingual content if using both the Moodle multilang filter and TinyMCE(as of June 2024).  This is a known issue, and one reason we recommend against using TinyMCE for editing STACK content. (It does nasty things to Javascript content as well).
 
 ## Using the built-in castext block in STACK
 
diff --git a/doc/en/Authoring/Options.md b/doc/en/Authoring/Options.md
index d2354de241a0b09fb14736da7d41cecba3d298cb..c04f24e1d58448dc82c5373fadd572a9212b10cc 100644
--- a/doc/en/Authoring/Options.md
+++ b/doc/en/Authoring/Options.md
@@ -75,9 +75,9 @@ The expression `(make_multsgn("cross"), a*b)` uses parentheses as an abbreviatio
 
 The value of this option `onum` will only put a multiplication sign between numbers.  This means you will see \(3\times 5\, x\) and not \(3\, 5\, x\) as you would if you have "none".
 
-There is a special atom which controls the multiplication symbol.  If you would like a dot then define
+There is a special atom which controls the multiplication symbol used with option `onum`.  If you would like a dot then define
 
-    texput(multsgnonlyfornumberssym, "\\times");
+    texput(multsgnonlyfornumberssym, "\\cdot");
 
 in the question variables.
 
@@ -113,7 +113,7 @@ 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)`.
+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} ###
 
diff --git a/doc/en/Authoring/Variables.md b/doc/en/Authoring/Variables.md
index d00d786f59cdcdc2ecc52aef0a412f2586c045b9..0228b096d407703d76d2a991298983abecc77aa0 100644
--- a/doc/en/Authoring/Variables.md
+++ b/doc/en/Authoring/Variables.md
@@ -46,9 +46,9 @@ The question variables are evaluated when a variant of a question is created.
 * General feedback (also known as the worked solution).
 * All fields in each of the [potential response tree](Potential_response_trees.md).
 * Each input when testing the item.
-* Question variables are not available to inputs when a student is validating their answer, unless special ``context variables'' are defined.
+* Question variables are not available to inputs when a student is validating their answer, unless special ``context variables'' are defined in a preamble.
 
-### Context variables
+### Question variables preamble and context variables
 
 If the following commands appear within the question variables they will be available in every part of the question, in particular these commands will affect how students' input is validated.  This enables teachers to affect the display of the student's answer validation, and add assumptions to PRTs.
 
@@ -58,16 +58,29 @@ If the following commands appear within the question variables they will be avai
 
 This collection of special variables are called "context variables".
 
-Only single texput commands are gathered into the context variables.  You cannot use other variables or other functions defined in the question variables.  So, `texput(blob, "\\diamond")` is fine, but passing a function to texput to display more complex output is not currently supported.
+STACK has a special constant `%_stack_preamble_end`.  Any variables _before_ this constant will be included within the context variables.  This enables you to define functions, e.g. to use with `textput`.  
 
-For example, to redefine how the logarithm is displayed, use `texput(log, "\\log ", prefix);`.
+Note, that students are not permitted to use any variable name defined by the teacher in the question variables.  This includes both the context variables, and the regular remaining question variables.  It is not possible to define variables which a student can then use.  Students _can_ use function names defined in the preamble. e.g. you can put `vec(ex):=stackvector(ex);` into the preamble.
 
-It is possible to use an unnamed `lambda` function.  E.g. if you have a function `tup` then
+For example, `texput(blob, "\\diamond")` is simple.  You can also define a function and use this function in texput.
+
+```
+tuptex(z):= block([a,b], [a,b]:args(z), sconcat("\\left[",tex1(a),",",tex1(b),"\\right)"));
+texput(tup, tuptex); 
+%_stack_preamble_end;
+```
+
+It is also possible to use an unnamed `lambda` function.  E.g. if you have a function `tup` then
 
     texput(tup,  lambda([z], block([a,b], [a,b]:args(z), sconcat("\\left[",tex1(a),",",tex1(b),"\\right)")))); 
 
 will display `tup(a,b)` as \( \left[a,b\right) \).
 
+To create a function `hat` so that input `hat(x)` is displayed as \(\hat{x}\) you can use:
+
+    /* In question variables. */
+    texput(hat, lambda([ex], sconcat("\\hat{", tex1(first(ex)), "}")));
+
 As a more complicated example, to typeset `u(A_k,k,1,inf)` as \({\bigcup_{k = 1}^{\infty } {A}_{k}}\) you can use the following:
 
     texput(u,lambda([ex],if length(ex)<4 then return("\\bigcup_{?=?}^{?} ? ") else
diff --git a/doc/en/CAS/Numbers.md b/doc/en/CAS/Numbers.md
index f1bbec4a889b4f69f76c919a541f675a9b0c3943..c8315f013448d8949aca5fb535c4e946e9274447 100644
--- a/doc/en/CAS/Numbers.md
+++ b/doc/en/CAS/Numbers.md
@@ -22,7 +22,7 @@ Optionally, depending on the question settings, you have
     i: %i
     j: %i
 
-Sometimes you need to use \(e\), or other constants, as an abstract symbol not a number.  The Maxima solution is to use the `kill()` command, but for security reasons users of STACK are not permitted to use this function. Instead use `stack_reset_vars(true)` in the question variables.  This resets all the special constants defined by STACK so the symbols can be redefined in an individual STACK question.  (On Maxima 5.42.1 (and possibly others) `stack_reset_vars(true)` also resets `ordergreat`, so if you need to use `stack_reset_vars(true)` it must be the first command the question variables.  Since this has been fixed in Maxima 5.44.0, it was probably a bug in Maxima.)
+Sometimes you need to use \(e\), or other constants, as an abstract symbol not a number.  The Maxima solution is to use the `kill()` command, but for security reasons users of STACK are not permitted to use this function. Instead use `stack_reset_vars(true)` in the question variables.  This resets all the special constants defined by STACK so the symbols can be redefined in an individual STACK question.  (On Maxima 5.42.1 (and possibly others) `stack_reset_vars(true)` also resets `ordergreat`, so if you need to use `stack_reset_vars(true)` it must be the first command in the question variables.  Since this has been fixed in Maxima 5.44.0, it was probably a bug in Maxima.)
 
 If you want to change the display of the constant \(e\) you need to refer to the `%e%` value, e.g. `texput(%e, "\mathrm{e}");`.
 
diff --git a/doc/en/CAS/Simplification.md b/doc/en/CAS/Simplification.md
index 66375ea6a7c63b81bfe460c65cd17726e0f620d9..f915a8f6d883fc5838595ff89cbb0034eca9e142 100644
--- a/doc/en/CAS/Simplification.md
+++ b/doc/en/CAS/Simplification.md
@@ -269,7 +269,7 @@ The first of these does not pull out a numerical denominator.  The second does.
 
 ### Trig simplification ###
 
-Maxima does have the ability to make assumptions, e.g. to assume that \(n\) is an integer and then simplify \(3\cos(n\pi/2)^2\) to \( \frac{3}{2}(1+(-1)^n)\).  Assume the student's answer is `ans1` then then define the following feedback variables:
+Maxima does have the ability to make assumptions, e.g. to assume that \(n\) is an integer and then simplify \(3\cos(n\pi/2)^2\) to \( \frac{3}{2}(1+(-1)^n)\).  Assume the student's answer is `ans1` then define the following feedback variables:
 
     declare(n,integer);
     sans1:ev(trigrat(ans1),simp);
diff --git a/doc/en/CAS/Systematic_deployment.md b/doc/en/CAS/Systematic_deployment.md
index 90e6fd9f62f5180ff794f905ca25c8679ee07607..f98864acd61dc92a013a19c6844512e81c2f83a2 100644
--- a/doc/en/CAS/Systematic_deployment.md
+++ b/doc/en/CAS/Systematic_deployment.md
@@ -32,7 +32,7 @@ It is your responsibility to make sure the index remains within range!  You can
 
 It is sensible to always ensure your `stack_seed` does not create run-time errors.  Notice that although the `mod` function does return `0` we have avoided possible zero indexes when defining `n1`.
 
-Of course, there are many other ways to map deployed seeds onto systematic deployment of variants.  Using consecutive integers from \(1, \ldots, n\) as the starting point is probably simplest and easiest to maintain.  For this reason there is a special option to do this on the deploy variants page.
+Of course, there are many other ways to map deployed seeds onto systematic deployment of variants.  Using consecutive integers from \(1, \ldots, n\) as the starting point is probably simplest and easiest to maintain.  For this reason there is a special option to do this on the deploy variants page.  There is also an option to use consecutive integers from \(n, \ldots, m\).
 
 Notes
 
diff --git a/doc/en/Developer/Development_track.md b/doc/en/Developer/Development_track.md
index 1bd9b8a340845b01f4176598b44df7f0735c91e1..a4b34a74923b4b79422c0b0a50f09d8ab1e01dd4 100644
--- a/doc/en/Developer/Development_track.md
+++ b/doc/en/Developer/Development_track.md
@@ -10,7 +10,10 @@ We use the [github issue tracker](https://github.com/maths/moodle-qtype_stack/is
 DONE
 
 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.
 
 Issues with [github milestone 4.7.0](https://github.com/maths/moodle-qtype_stack/issues?q=is%3Aissue+milestone%3A4.7.0) include
 
diff --git a/doc/en/Developer/Security_map.md b/doc/en/Developer/Security_map.md
index 696b35b3a233bbf094a430e535358dac7b3acf01..62c39ab438b57fb4460d5c6d9c4bd615a746cc3f 100644
--- a/doc/en/Developer/Security_map.md
+++ b/doc/en/Developer/Security_map.md
@@ -10,8 +10,8 @@ for somewhat obvious reasons!  Hence, we need to restrict the availability of ce
 2. Teacher.  Teacher's answers cannot contain these, but they are not a security risk.  Usually these have side effects within the Maxima code, e.g. setting a global variable which might cause problems later/elsewhere.
 3. Student.  Student's expressions can only contain these.
 
-Since STACK 4.3 the Maxima statement parser infrastruture uses a JSON file
-describing all identifiers of functions,  variables, constants, and operators
+Since STACK 4.3 the Maxima statement parser infrastructure uses a JSON file
+describing all identifiers of functions,  variables, constants and operators
 and features we attach to them. The catalogue is stored in
 
     stack/cas/security-map.json
diff --git a/doc/en/Installation/Mathjax.md b/doc/en/Installation/Mathjax.md
index ea3ca424231b7102dabd16b1795ad877b99d99b4..98b708535512eb42e054ba38c889d37377e9099b 100644
--- a/doc/en/Installation/Mathjax.md
+++ b/doc/en/Installation/Mathjax.md
@@ -13,7 +13,9 @@ These are notes on configuring the MathJax filter options for use with STACK.
 
 ## Accessibility ##
 
-The accessibility features supported by MathJax are given detailed [here](http://www.mathjax.org/resources/articles-and-presentations/accessible-pages-with-mathjax/).
+Among other things, MathJax allows screenreaders to read mathematics in a meaningful way which is critical for students who rely on this technology, or simply find it easier to learn with an aural option. For this to work, information must be typed up, not contained in a screenshot.
+
+The accessibility features supported by MathJax are given detailed in the MathJax [documentation](https://docs.mathjax.org/en/latest/basic/accessibility.html) and [YouTube](https://www.youtube.com/watch?v=6GSgTjorewQ). 
 
 ## Adding MathJax to additional HTML
 
diff --git a/doc/en/Plots/Plots.md b/doc/en/Plots/Plots.md
index b4361fa17dae32bdfc98a542ee5eb8599a6beadf..fcd4fa2963d878268e0de2bcc04e449f4445751d 100644
--- a/doc/en/Plots/Plots.md
+++ b/doc/en/Plots/Plots.md
@@ -222,3 +222,6 @@ The following CASText gives representative examples of the plot2d features suppo
     {@plot([parametric, (exp(cos(t))-2*cos(4*t)-sin(t/12)^5)*sin(t), (exp(cos(t))-2*cos(4*t)-sin(t/12)^5)*cos(t), [t, -8*%pi, 8*%pi]], [nticks, 100], [box,false])@}
     <h3>Putting the axes in the middle</h3>
     {@plot([x^2/(1+x^2),2*x/(1+x^2)^2], [x, -2, 2], [y,-2.1,2.1], [box, false], [yx_ratio, 1], [axes, solid], [xtics, -2, 0.5, 2],[ytics, -2, 0.5, 2])@}
+    <h3>Example with ticks, colour and alt-text</h3>
+    {@plot([6*x,6^x,x^6,x^(1/6)], [x, -2.2, 2.2], [y, -5.2, 5.2], [box, false], [yx_ratio, 1], [axes, solid], [xtics, -5, 1, 5],[ytics, -5, 1, 5], cons(legend, ["f", "F", "g", "G"]), [alt, "Graph Of Multiple Functions"], [style, [linespoints, 1, 1.5]], [nticks, 5], [color, "#785EF0", "#DC267F", "#FE6100", "#648FFF"], [adapt_depth, 0]);@}
+
diff --git a/doc/en/Topics/Units.md b/doc/en/Topics/Units.md
index 20d775e7a5770afb7e5d8399c46f5ae268d82b04..451eef9aa544a99251e627e86b9e7ecbf59d9ebd 100644
--- a/doc/en/Topics/Units.md
+++ b/doc/en/Topics/Units.md
@@ -159,6 +159,14 @@ try to split the expression into units and numbers, and the return the units and
 
 The function `stack_units_split` is deprecated.  DO NOT USE.
 
+## Fine-tuning the display ##
+
+By default STACK's TeX function prints out `stackunits(10,m/s)` as \( 10\, m/s\).  That is, without any multiplication sign between the numerical part and the units.  In some edge cases you might want to add this multiplication sign in.  To do this, use
+
+    texput(multsgnstackunits, "\\cdot");
+
+in the question variables.  In castext you can use, e.g. `{@(texput(multsgnstackunits, "\\cdot "), stackunits(1, s^-1))@}` to create output \({1\cdot s^ {- 1 }}\).
+
 ## Custom units ##
 
 The teacher may want to use their own units. For example, the core `unit` package in Maxima does not include `mm` (millimetre), it is defined there as a word `millimetre`.  This is one reason for creating our own custom units package.
diff --git a/lang/de/qtype_stack.php b/lang/de/qtype_stack.php
index 4d1f3ea493b1509d03a71f0f6ac3c1535cb115d2..6e6f33d467835ece99954bedbb922ef126831e03 100644
--- a/lang/de/qtype_stack.php
+++ b/lang/de/qtype_stack.php
@@ -546,7 +546,7 @@ $string['hyp_inverse_functions_fact'] = '\\[\\cosh^{-1}(x)=\\ln\\left(x+\\sqrt{x
 \\[\\sinh^{-1}(x)=\\ln\\left(x+\\sqrt{x^2+1}\\right)\\]
 \\[\\tanh^{-1}(x) = \\frac{1}{2}\\ln\\left({1+x\\over 1-x}\\right) \\quad \\mbox{ for } -1< x < 1\\]';
 $string['hyp_inverse_functions_name'] = 'Inverse hyperbolische Funktionen';
-$string['illegalcaschars'] = 'Die Zeichen @, $ und \\ sind in der CAS-Eingabe nicht erlaubt.';
+$string['illegalcaschars'] = 'Die Zeichen @ und \\ sind in der CAS-Eingabe nicht erlaubt.';
 $string['inputdisplayed'] = 'Angezeigt als';
 $string['inputentered'] = 'Eingegebener Wert';
 $string['inputexpression'] = 'Test-Eingabe';
diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php
index 10ce3c12fd6a280bd4338d12df9689824493d8b2..7265141ba68dc9d5e6d38613470cbe8092d781c4 100644
--- a/lang/en/qtype_stack.php
+++ b/lang/en/qtype_stack.php
@@ -161,7 +161,7 @@ $string['showvalidationcompact'] = 'Yes, compact';
 $string['inputinvalidparamater'] = 'Invalid parameter';
 $string['mustverifyshowvalidation'] = 'You cannot choose to require two step validation but not show the results of validation to the student after the first step.  This puts the student in an impossible position.';
 $string['htmlfragment'] = 'You appear to have some HTML elements in your expression.';
-$string['illegalcaschars'] = 'The characters @, $ and \\ are not allowed in CAS input.';
+$string['illegalcaschars'] = 'The characters @ and \\ are not allowed in CAS input.';
 $string['inputextraoptions'] = 'Extra options';
 $string['inputextraoptions_help'] = 'Some input types require extra options in order to work. You can enter them here. This value is a CAS expression.';
 $string['inputextraoptions_link'] = '%%WWWROOT%%/question/type/stack/doc/doc.php/Authoring/Inputs.md#Extra options';
@@ -533,6 +533,8 @@ $string['deployedvariantsn'] = 'Deployed variants ({$a})';
 $string['deploymanybtn'] = 'Deploy # of variants:';
 $string['deploymanyerror'] = 'Error in user input: cannot deploy "{$a->err}" variants.';
 $string['deploysystematicbtn'] = 'Deploy seeds from 1 to: ';
+$string['deploysystematicfrombtn'] = 'Deploy seeds from: ';
+$string['deploysystematicto'] = 'to: ';
 $string['deployduplicateerror'] = 'Duplicate question notes detected in the deployed variants. We strongly recommend each question note is only deployed once, otherwise you will have difficulty collecting meaningful stats when grouping by variant.  Please consider deleting some variants with duplicate notes.';
 $string['deploytoomanyerror'] = 'STACK will try to deploy up to at most 100 new variants in any one request.  No new variants deployed.';
 $string['deploymanynonew'] = 'Too many repeated existing question notes were generated.';
@@ -952,20 +954,20 @@ $string['stackBlock_parsons_unknown_named_version'] = 'The Parson\'s block only
 $string['stackBlock_parsons_unknown_mathjax_version'] = 'The Parson\'s block only supports MathJax versions {$a->mjversion} for the mathjax parameter.';
 $string['stackBlock_parsons_ref']         = 'The Parson\'s block only supports referencing inputs present in the same CASText section \'{$a->var}\' does not exist here.';
 $string['stackBlock_parsons_param']       = 'The Parson\'s block supports only these parameters in this context: \'{$a->param}\'.';
-$string['stackBlock_parsons_contents']    = 'The contents of a Parson\'s block must be a either a JSON of the form {#stackjson_stringify(steps)#}, where `steps` is the two-dimensional Maxima array containing key, value pairs of items, or of the form {\'steps\' : {#stackjson_stringify(steps)#}, \'options\' : {JSON containing Sortable options}, \'header\' : [List of headers], \'available_header\' : \'string containing header for the available list\', \'index\' : [List containing the index]}, where the \'options\', \'header\', \'available_header\', and \'index\' keys are optional. Alternatively, the contents of the Parsons block may contain raw JSON equivalents. Make sure that the `steps` Maxima variable is of the correct format. Note that all steps must be strings. See https://docs.stack-assessment.org/en/Authoring/Parsons/ for details.';
+$string['stackBlock_parsons_contents']    = 'The contents of a Parson\'s block must be a either a JSON of the form {#stackjson_stringify(steps)#}, where \'steps\' is the two-dimensional Maxima array containing key, value pairs of items, or of the form {\'steps\' : {#stackjson_stringify(steps)#}, \'options\' : {JSON containing Sortable options}, \'header\' : [List of headers], \'available_header\' : \'string containing header for the available list\', \'index\' : [List containing the index]}, where the \'options\', \'header\', \'available_header\', and \'index\' keys are optional. Alternatively, the contents of the Parsons block may contain raw JSON equivalents. Make sure that the \'steps\' Maxima variable is of the correct format. Note that all steps must be strings. See https://docs.stack-assessment.org/en/Authoring/Parsons/ for details.';
 $string['stackBlock_incorrect_header_length'] = 'The list of headers should have the same length as the number of columns passed to the block header.';
 $string['stackBlock_incorrect_available_header_type'] = 'The header for the available list should be passed as a string or a list of length one.';
 $string['stackBlock_incorrect_index_length'] = 'The length of the index should be one more than the number of rows passed to the block header. An item in the top-left corner should always go in the index';
 $string['stackBlock_incorrect_index_type'] = 'Index should be an array containing strings.';
 $string['stackBlock_incorrect_header_type'] = 'Headers should be an array containing strings.';
-$string['stackBlock_parsons_invalid_columns_value'] = 'The value of `columns` in the Parson\'s block header should be a string containing a positive integer.';
-$string['stackBlock_parsons_invalid_rows_value'] = 'The value of `rows` in the Parson\'s block header should be a string containing a positive integer.';
-$string['stackBlock_parsons_invalid_item-height_value'] = 'The value of `item-height` in the Parson\'s block header should be a string containing a positive integer.';
-$string['stackBlock_parsons_invalid_item-width_value'] = 'The value of `item-width` in the Parson\'s block header should be a string containing a positive integer.';
+$string['stackBlock_parsons_invalid_columns_value'] = 'The value of \'columns\' in the Parson\'s block header should be a string containing a positive integer.';
+$string['stackBlock_parsons_invalid_rows_value'] = 'The value of \'rows\' in the Parson\'s block header should be a string containing a positive integer.';
+$string['stackBlock_parsons_invalid_item-height_value'] = 'The value of \'item-height\' in the Parson\'s block header should be a string containing a positive integer.';
+$string['stackBlock_parsons_invalid_item-width_value'] = 'The value of \'item-width\' in the Parson\'s block header should be a string containing a positive integer.';
 $string['stackBlock_unknown_sortable_option'] = 'Unknown Sortable options found, the following are being ignored: ';
 $string['stackBlock_overwritten_sortable_option'] = 'Unchangeable Sortable options found, the following are being ignored: ';
 $string['stackBlock_parsons_unknown_transpose_value'] = 'Transpose must be one of \'true\' or \'false\'.';
-$string['stackBlock_parsons_underdefined_grid'] = 'When defining `rows` for a Parson\'s block one must also define `columns`.';
+$string['stackBlock_parsons_underdefined_grid'] = 'When defining \'rows\' for a Parson\'s block one must also define \'columns\'.';
 $string['stackBlock_proof_mode_index'] = 'The use of \'index\' is not supported when using the Parson\'s block for proof assessment.';
 $string['stackBlock_proof_incorrect_header_length'] = 'Headers should be an array containing a single header; use \'available_header\' to update the header for the available list.';
 
@@ -1528,7 +1530,27 @@ $string['castext_error_unevaluated'] = 'This text content was never evaluated.';
 
 
 
-
+$string['default_test_fail'] = 'Default test using the model answers does not return a score of 1.';
+$string['default_test_pass'] = 'Default test using the model answers returns a score of 1.';
 // API strings.
+$string['api_choose_file'] = 'Please select a question file';
+$string['api_choose_folder'] = 'Choose a STACK folder';
+$string['api_choose_q'] = 'Choose a STACK sample file';
+$string['api_correct'] = 'Correct answers';
+$string['api_display'] = 'Display Question';
+$string['api_errors'] = 'Errors';
+$string['api_failures'] = 'failures';
+$string['api_general_errors'] = 'General errors e.g. broken XML';
+$string['api_local_file'] = 'Or select a file of your own';
+$string['api_marks_sub'] = 'Marks for this submission';
 $string['api_no_deployed_variants'] = 'The question XML does not contain deployed variants';
+$string['api_out_of'] = 'out of';
+$string['api_passes'] = 'passes';
+$string['api_q_select'] = 'Select a question';
+$string['api_q_xml'] = 'Question XML';
+$string['api_read_only'] = 'Read Only';
+$string['api_response'] = 'Response summary';
 $string['api_seed_not_in_variants'] = 'The specified seed belongs to no deployed variant';
+$string['api_submit'] = 'Submit Answers';
+$string['api_valid_all_parts'] = 'Please enter valid answers for all parts of the question.';
+$string['api_which_typed'] = 'which can be typed as follows';
diff --git a/question.php b/question.php
index 8fc7081bfeb77ff6ca55bde0c67f1de3beb4f251..5a7868f71d1eb22b4989eafa8005aa64d4bf39c3 100644
--- a/question.php
+++ b/question.php
@@ -378,7 +378,8 @@ class qtype_stack_question extends question_graded_automatically_with_countback
             }
 
             if ($this->get_cached('preamble-qv') !== null) {
-                $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble'));
+                $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb',
+                    'blockexternal'));
             }
             // Context variables should be first.
             if ($this->get_cached('contextvariables-qv') !== null) {
@@ -550,6 +551,10 @@ class qtype_stack_question extends question_graded_automatically_with_countback
             if ($this->tas[$name]->is_correctly_evaluated()) {
                 $teacheranswer = $this->tas[$name]->get_value();
             }
+            if ($this->get_cached('preamble-qv') !== null) {
+                $input->add_contextsession(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb',
+                    'blockexternal'));
+            }
             if ($this->get_cached('contextvariables-qv') !== null) {
                 $input->add_contextsession(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv'));
             }
@@ -622,7 +627,7 @@ class qtype_stack_question extends question_graded_automatically_with_countback
                 stack_utils::php_string_to_maxima_string($selected), 'language setting'), false);
         }
         if ($this->get_cached('preamble-qv') !== null) {
-            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble'));
+            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', 'blockexternal'));
         }
         if ($this->get_cached('contextvariables-qv') !== null) {
             $session->add_statement(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv'));
@@ -675,7 +680,8 @@ class qtype_stack_question extends question_graded_automatically_with_countback
                 stack_utils::php_string_to_maxima_string($selected), 'language setting'), false);
         }
         if ($this->get_cached('preamble-qv') !== null) {
-            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble'));
+            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb',
+                'blockexternal'));
         }
         if ($this->get_cached('contextvariables-qv') !== null) {
             $session->add_statement(new stack_secure_loader($this->get_cached('contextvariables-qv'), '/qv'));
@@ -1200,12 +1206,12 @@ class qtype_stack_question extends question_graded_automatically_with_countback
         }
 
         if ($this->get_cached('preamble-qv') !== null) {
-            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), 'preamble'));
+            $session->add_statement(new stack_secure_loader($this->get_cached('preamble-qv'), '/pb', 'blockexternal'));
         }
         // Add preamble from PRTs as well.
         foreach ($this->get_cached('prt-preamble') as $name => $stmt) {
             if (isset($prts[$name])) {
-                $session->add_statement(new stack_secure_loader($stmt, 'preamble PRT: ' . $name));
+                $session->add_statement(new stack_secure_loader($stmt, 'preamble PRT: ' . $name, 'blockexternal'));
             }
         }
 
diff --git a/questiontestrun.php b/questiontestrun.php
index 896df2c63e2e3ebcee700b312b0d54d34b84cdec..8f0259292e841db10db0faf6dc8dbfb94dc4e6ee 100644
--- a/questiontestrun.php
+++ b/questiontestrun.php
@@ -421,7 +421,7 @@ if ($question->has_random_variants()) {
         echo ' ' . stack_string('deploymanynotes');
         echo html_writer::end_tag('form');
 
-        // Systematic deployment of variants.
+        // Systematic deployment of variants (from 1 to ...).
         echo html_writer::start_tag('form', [
             'method' => 'get', 'class' => 'deploysystematic',
             'action' => new moodle_url('/question/type/stack/deploy.php', $urlparams),
@@ -437,6 +437,27 @@ if ($question->has_random_variants()) {
         ]);
         echo html_writer::end_tag('form');
 
+        // Systematic deployment of variants (from ... to ...).
+        echo html_writer::start_tag('form', [
+            'method' => 'get', 'class' => 'deploysystematicfromto',
+            'action' => new moodle_url('/question/type/stack/deploy.php', $urlparams),
+        ]);
+        echo html_writer::input_hidden_params(new moodle_url($PAGE->url, ['sesskey' => sesskey()]), ['seed']);
+        echo ' ' . html_writer::empty_tag('input', [
+            'type' => 'submit', 'class' => 'btn btn-secondary',
+            'value' => stack_string('deploysystematicfrombtn'),
+        ]);
+        echo ' ' . html_writer::empty_tag('input', [
+            'type' => 'text', 'size' => 3,
+            'id' => 'deploysystematicfromfield', 'name' => 'deploysystematicfrom', 'value' => '',
+        ]);
+        echo ' ' . stack_string('deploysystematicto');
+        echo ' ' . html_writer::empty_tag('input', [
+            'type' => 'text', 'size' => 3,
+            'id' => 'deploysystematictofield', 'name' => 'deploysystematicto', 'value' => '',
+        ]);
+        echo html_writer::end_tag('form');
+
         // Deploy many from a CS list of integer seeds.
         echo "\n" . html_writer::start_tag('form', [
             'method' => 'get', 'class' => 'deployfromlist',
diff --git a/stack/cas/cassession2.class.php b/stack/cas/cassession2.class.php
index a7d280acb073f4f1d3fd59f0cf20f526fa8a946f..9bdec031deb2390e282b7b3e5a4f79f154c5a6d6 100644
--- a/stack/cas/cassession2.class.php
+++ b/stack/cas/cassession2.class.php
@@ -332,8 +332,9 @@ class stack_cas_session2 {
             $line .= stack_utils::php_string_to_maxima_string($statement->get_source_context());
             $line .= ')';
 
-            if (method_exists($statement, 'is_toplevel_property') && $statement->is_toplevel_property('blockexternal')) {
-                $preblock .= $line . "$\n";
+            if (($statement instanceof stack_secure_loader && $statement->get_blockexternal()) ||
+                (method_exists($statement, 'is_toplevel_property') && $statement->is_toplevel_property('blockexternal'))) {
+                $preblock .= 'errcatch(' . $ef . ")$\n";
             } else {
                 $command .= self::SEP . $line;
             }
diff --git a/stack/cas/keyval.class.php b/stack/cas/keyval.class.php
index d34bbf9b2043824db75d495c8c4caf6093847e3d..8552b254a65d70d23d5992d37edec14fb552db4a 100644
--- a/stack/cas/keyval.class.php
+++ b/stack/cas/keyval.class.php
@@ -104,9 +104,8 @@ class stack_cas_keyval {
 
         $str = str_replace('?', 'QMCHAR', $str);
 
-        // CAS keyval may not contain @ or $ outside strings.
-        // We should certainly prevent the $ to make sure statements are separated by ;, although Maxima does allow $.
-        if (strpos($str, '@') !== false || strpos($str, '$') !== false) {
+        // CAS keyval may not contain @ outside strings.
+        if (strpos($str, '@') !== false) {
             $this->errors[] = new $this->errclass(stack_string('illegalcaschars'), $this->context);
             $this->valid = false;
             return false;
@@ -387,12 +386,22 @@ class stack_cas_keyval {
                 if ($item->statement instanceof MP_FunctionCall) {
                     $op = $item->statement->name->value;
                 }
-                if (stack_cas_security::get_feature($op, 'blockexternal') !== null) {
-                    $bestatements[] = $statement;
-                }
-                // Note that stack_reet_vars needs to be both blockexternal and a contextvariable.
+                // Notes on ordergreat and stack_reset_vars.
+                // We must have ordergreat/orderless outside the main block, so we need blockexternals.
+                // If we use stack_reset_vars after an ordergreat it "kills" the effects of the order change.
+                // Hence, we can't have stack_reset_vars in both the context variables and the blockexternals.
+                // This is the edge case where we re-order i,j,k to be i+j+k, not the Maxima default k+j+i.
                 if (stack_cas_security::get_feature($op, 'contextvariable') !== null) {
                     $contextvariables[] = $statement;
+                }
+                // Test for end of context variables.
+                if ($item->statement instanceof MP_Identifier) {
+                    if ($item->statement->value == '%_stack_preamble_end') {
+                        $contextvariables = array_merge($contextvariables, $statements);
+                        $statements = [];
+                    }
+                } else if (stack_cas_security::get_feature($op, 'blockexternal') !== null) {
+                    $bestatements[] = $statement;
                 } else {
                     $statements[] = $statement;
                 }
@@ -412,7 +421,6 @@ class stack_cas_keyval {
         if (count($bestatements) == 0) {
             $bestatements = null;
         } else {
-            // These statement groups always end with a 'true' to ensure minimal output.
             $bestatements = '(' . implode(',', $bestatements) . ',true)';
         }
         if (count($statements) == 0) {
diff --git a/stack/cas/secure_loader.class.php b/stack/cas/secure_loader.class.php
index 281a45c49238816313ade7e5705bd139ce0bfc10..4e2c4274b09185ad7eb3dbb72fec37f7953f4c9d 100644
--- a/stack/cas/secure_loader.class.php
+++ b/stack/cas/secure_loader.class.php
@@ -31,8 +31,9 @@ class stack_secure_loader implements cas_evaluatable {
     private $code;
     private $errors;
     private $context;
+    private $blockexternal;
 
-    public function __construct(string $securedcode, string $fromwhere='') {
+    public function __construct(string $securedcode, string $fromwhere = '', string $blockexternal = '') {
         if ($securedcode === null) {
             throw new stack_exception('secure_loader: the code must not be null.');
         }
@@ -42,6 +43,10 @@ class stack_secure_loader implements cas_evaluatable {
         $this->context = $fromwhere;
         $this->code = $securedcode;
         $this->errors = [];
+        $this->blockexternal = false;
+        if ($blockexternal === 'blockexternal') {
+            $this->blockexternal = true;
+        }
     }
 
     public function get_valid(): bool {
@@ -80,6 +85,10 @@ class stack_secure_loader implements cas_evaluatable {
     public function get_key(): string {
         return '';
     }
+
+    public function get_blockexternal(): bool {
+        return $this->blockexternal;
+    }
 }
 
 class stack_secure_loader_value extends stack_secure_loader implements cas_value_extractor {
diff --git a/stack/cas/security-map.json b/stack/cas/security-map.json
index 47d39ff569be62e1707ef3dbbfb8dd5f192504fd..37a3a62fcf320efbcbf57f29fb715d9f8f0bfdee 100644
--- a/stack/cas/security-map.json
+++ b/stack/cas/security-map.json
@@ -128,6 +128,9 @@
   "%s": {
       "function": "?"
   },
+  "%_stack_preamble_end": {
+      "constant": "t"
+  },
   "%stmt": {
       "variable": "f"
   },
@@ -5195,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"
@@ -7311,8 +7312,7 @@
   },
   "stack_reset_vars": {
       "function": "?",
-      "blockexternal": "true",
-      "contextvariable": "true"
+      "blockexternal": "true"
   },
   "stack_validate": {
       "function": "s"
diff --git a/stack/input/inputbase.class.php b/stack/input/inputbase.class.php
index 07f945f8d9b7d534161da04eb8690de3ccff7e5d..3225e270bd3f87b0835fc0b313cbfa5e35ddbcaa 100644
--- a/stack/input/inputbase.class.php
+++ b/stack/input/inputbase.class.php
@@ -458,7 +458,7 @@ abstract class stack_input {
     public function add_contextsession($contextsession) {
         if ($contextsession != null) {
             // Always make this the start of an array.
-            $this->contextsession = [$contextsession];
+            $this->contextsession = array_merge($this->contextsession, [$contextsession]);
         }
     }
 
@@ -1091,6 +1091,13 @@ abstract class stack_input {
 
         $additionalvars = [];
 
+        if ($questionvariables) {
+            if ($questionvariables['preamble-qv'] !== null) {
+                $additionalvars['preamble-qv'] = new stack_secure_loader($questionvariables['preamble-qv'],
+                    'preamble', 'blockexternal');
+            }
+        }
+
         if (array_key_exists('floatnum', $this->extraoptions) && $this->extraoptions['floatnum']) {
             $additionalvars['floatnum'] = stack_ast_container::make_from_teacher_source('simp_floatnump('.$this->name.')',
                     '', new stack_cas_security(), []);
@@ -1136,9 +1143,6 @@ abstract class stack_input {
         if ((array_key_exists('validator', $this->extraoptions) && $this->extraoptions['validator']) ||
             (array_key_exists('feedback', $this->extraoptions) && $this->extraoptions['feedback'])) {
             if ($questionvariables) {
-                if ($questionvariables['preamble-qv'] !== null) {
-                    $additionalvars['preamble-qv'] = new stack_secure_loader($questionvariables['preamble-qv'], 'preamble');
-                }
                 if ($questionvariables['contextvariables-qv'] !== null) {
                     $additionalvars['contextvariables-qv'] = new stack_secure_loader($questionvariables['contextvariables-qv'],
                         'contextvariables');
diff --git a/stack/mathsoutput/mathsoutputapi.class.php b/stack/mathsoutput/mathsoutputapi.class.php
index c78d10c416998d6a13d33b23d69f118617230dcb..965c1a16df53db75ed58470997ef57f4b099f401 100644
--- a/stack/mathsoutput/mathsoutputapi.class.php
+++ b/stack/mathsoutput/mathsoutputapi.class.php
@@ -47,7 +47,7 @@ class stack_maths_output_api extends stack_maths_output_filter_base {
             $text = $this->replace_dollars($text);
         }
 
-        $text = stack_fact_sheets::display($text, new \qtype_stack_renderer());
+        $text = stack_fact_sheets::display($text ?? '', new \qtype_stack_renderer());
 
         return $text;
     }
diff --git a/stack/maxima/assessment.mac b/stack/maxima/assessment.mac
index ced83ab1081c2ccedb13b7b779cb3915f81e926a..fe7b2bdf3f831c76fa8b6f5fbe876dc0b59339e1 100644
--- a/stack/maxima/assessment.mac
+++ b/stack/maxima/assessment.mac
@@ -743,8 +743,14 @@ decimalplacesfun(ex, n, dispdps) := block([ex2],
     ex2:ev(float(round(10^n*float(ex))/(10^n)), lg=logbasesimp, simp),
     if dispdps then ex2:displaydp(ex2, n),
     return(ex2)
-    )$
-decimalplaces(ex, n) := decimalplacesfun(ex, n, false)$
+)$
+
+decimalplaces(ex, n):= block(
+    if n=0 then return(round(ex)), 
+    if integerp(ex) then return(ex),
+    decimalplacesfun(ex, n, false)
+)$
+
 dispdp(ex, n) := block(
     if not(real_numberp(ex)) then error("dispdp requires a real number argument."),
     if not(integerp(n)) then error("dispdp cannot create a non-integer number of decimal places."),
diff --git a/stack/maxima/stackmaxima.mac b/stack/maxima/stackmaxima.mac
index adb64de4613f40258451f54e7145c850c87b73d2..286d1269d5729c92f0a786d91f4eabe242144d1e 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
 )$
 
@@ -898,12 +898,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.                                                     */
diff --git a/stack/maxima/stackunits.mac b/stack/maxima/stackunits.mac
index 3ddb9cd4accee1f482454796e5e9511cd9c3cc39..f24075b6e4ba63015804d6dd5dcd2f9c2499f847 100644
--- a/stack/maxima/stackunits.mac
+++ b/stack/maxima/stackunits.mac
@@ -392,8 +392,10 @@ stack_validate_units(expr, LowestTerms, TAns, fracdisp) := block( [simp:false, e
   return(expr)
 )$
 
+texput(multsgnstackunits, "\\, ");
+
 /* Finer control over display of units, separating out the number from the units. */
-stackunitstex(ex) := block ([a, b, c, astr, bstr],
+stackunitstex(ex) := block([a, b, c, astr, bstr],
   a:first(args(ex)),
   b:second(args(ex)),
   if scientific_notationp(a) then make_multsgn("cross"),
@@ -410,8 +412,9 @@ stackunitstex(ex) := block ([a, b, c, astr, bstr],
   bstr:tex1(b),
   if is(strim(" ", astr)="") then return(bstr),
   if is(strim(" ", bstr)="") then return(astr),
-  sconcat(astr,"\\, ", bstr)
+  sconcat(astr, tex1(multsgnstackunits), bstr)
 )$
+
 texput(stackunits, stackunitstex);
 texput(NULLUNITS, "");
 texput(NULLNUM, "");
diff --git a/stack/maximaparser/autogen/gen.js b/stack/maximaparser/autogen/gen.js
index bd425e264f4a3b66777b72b7832c2568344f2689..444af8f7dfa18bf9a37ce5a71356241a6ca27771 100644
--- a/stack/maximaparser/autogen/gen.js
+++ b/stack/maximaparser/autogen/gen.js
@@ -5,7 +5,7 @@
 let fs = require('fs');
 let pegjs = require('pegjs');
 let phpegjs = require('phpegjs');
-let tspegjs = require('ts-pegjs');
+// let tspegjs = require('ts-pegjs');
 
 
 var parserCode = fs.readFile('./parser-grammar.pegjs','utf8',function
@@ -23,7 +23,7 @@ var parserCode = fs.readFile('./parser-grammar.pegjs','utf8',function
    let TSparser = pegjs.generate(data, {
        output: 'source',
        cache: true,
-       plugins: [tspegjs],
+//       plugins: [tspegjs],
        allowedStartRules: ["Root", "Equivline"],
        tspegjs: {
          customHeader: 'import {MPNode, MPOperation, MPAtom, MPInteger, MPFloat, MPString, MPBoolean, MPIdentifier, MPComment, MPFunctionCall, MPGroup, MPSet, MPList, MPPrefixOp, MPPostfixOp, MPIndexing, MPIf, MPLoop, MPLoopBit, MPEvaluationFlag, MPStatement, MPRoot, MPAnnotation} from \'./MP_classes\';'
diff --git a/stack/maximaparser/autogen/parser-grammar.pegjs b/stack/maximaparser/autogen/parser-grammar.pegjs
index 206d7cdea7f366da70eceff84447b1652068f4a8..557bedf7d223861f55db8e52af66a330677dfb4b 100644
--- a/stack/maximaparser/autogen/parser-grammar.pegjs
+++ b/stack/maximaparser/autogen/parser-grammar.pegjs
@@ -2,7 +2,6 @@
  * Grammar for parsing STACK-Maxima commands/statements coming from keyval or casstring fields.
  * Not a complete Maxima syntax parser, but probably not that far from such.
  *  Known missing parts, i.e., stuff that I did not bother to add (yet):
- *   - '$' silent line terminator
  *   - end condition for "for ... in ... do"
  *
  *  Also includes the STACK specific |x| => abs(x) syntax trick. But at the cost of the infix operator |.
@@ -242,7 +241,7 @@ Equivline
   }
 
 Line
- = __? s:Statement _? ';' {/** <?php return $s; ?> **/ return s;}
+ = __? s:Statement _? [;$] {/** <?php return $s; ?> **/ return s;}
  / Comment
 
 Integer "integer"
diff --git a/stack/maximaparser/autogen/parser.mbstring.php b/stack/maximaparser/autogen/parser.mbstring.php
index ec5bb49fd18c803f80680a6ddf039a6125ad7464..46541e64a5ca4bbfcd06e52b89147ea44ed978f0 100644
--- a/stack/maximaparser/autogen/parser.mbstring.php
+++ b/stack/maximaparser/autogen/parser.mbstring.php
@@ -439,6 +439,8 @@ class MP_Parser {
     private $peg_c208;
     private $peg_c209;
     private $peg_c210;
+    private $peg_c211;
+    private $peg_c212;
 
     private function peg_f0($lines, $final) {
       $items = array();
@@ -1081,8 +1083,8 @@ class MP_Parser {
             $s3 = null;
           }
           if ($s3 !== $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) {
-              $s4 = $this->peg_c6;
+            if (peg_regex_test($this->peg_c6, $this->input_substr($this->peg_currPos, 1))) {
+              $s4 = $this->input_substr($this->peg_currPos, 1);
               $this->peg_currPos++;
             } else {
               $s4 = $this->peg_FAILED;
@@ -2050,13 +2052,13 @@ class MP_Parser {
             $s3 = null;
           }
           if ($s3 !== $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) {
-              $s4 = $this->peg_c6;
+            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) {
+              $s4 = $this->peg_c52;
               $this->peg_currPos++;
             } else {
               $s4 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c7);
+                  $this->peg_fail($this->peg_c53);
               }
             }
             if ($s4 !== $this->peg_FAILED) {
@@ -2081,13 +2083,13 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c52) {
-          $s1 = $this->peg_c52;
+        if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c54) {
+          $s1 = $this->peg_c54;
           $this->peg_currPos += 8;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c53);
+              $this->peg_fail($this->peg_c55);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -2100,13 +2102,13 @@ class MP_Parser {
                 $s4 = null;
               }
               if ($s4 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c54) {
-                  $s5 = $this->peg_c54;
+                if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c56) {
+                  $s5 = $this->peg_c56;
                   $this->peg_currPos += 2;
                 } else {
                   $s5 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c55);
+                      $this->peg_fail($this->peg_c57);
                   }
                 }
                 if ($s5 !== $this->peg_FAILED) {
@@ -2122,13 +2124,13 @@ class MP_Parser {
                         $s8 = null;
                       }
                       if ($s8 !== $this->peg_FAILED) {
-                        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) {
-                          $s9 = $this->peg_c6;
+                        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) {
+                          $s9 = $this->peg_c52;
                           $this->peg_currPos++;
                         } else {
                           $s9 = $this->peg_FAILED;
                           if ($this->peg_silentFails === 0) {
-                              $this->peg_fail($this->peg_c7);
+                              $this->peg_fail($this->peg_c53);
                           }
                         }
                         if ($s9 !== $this->peg_FAILED) {
@@ -2173,13 +2175,13 @@ class MP_Parser {
         }
         if ($s0 === $this->peg_FAILED) {
           $s0 = $this->peg_currPos;
-          if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c56) {
-            $s1 = $this->peg_c56;
+          if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c58) {
+            $s1 = $this->peg_c58;
             $this->peg_currPos += 6;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c57);
+                $this->peg_fail($this->peg_c59);
             }
           }
           if ($s1 !== $this->peg_FAILED) {
@@ -2214,13 +2216,13 @@ class MP_Parser {
                           $s8 = null;
                         }
                         if ($s8 !== $this->peg_FAILED) {
-                          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c6) {
-                            $s9 = $this->peg_c6;
+                          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c52) {
+                            $s9 = $this->peg_c52;
                             $this->peg_currPos++;
                           } else {
                             $s9 = $this->peg_FAILED;
                             if ($this->peg_silentFails === 0) {
-                                $this->peg_fail($this->peg_c7);
+                                $this->peg_fail($this->peg_c53);
                             }
                           }
                           if ($s9 !== $this->peg_FAILED) {
@@ -2307,7 +2309,7 @@ class MP_Parser {
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c58);
+            $this->peg_fail($this->peg_c60);
         }
       }
 
@@ -2326,33 +2328,33 @@ class MP_Parser {
         return $cached["result"];
       }
 
-      if (peg_regex_test($this->peg_c59, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c61, $this->input_substr($this->peg_currPos, 1))) {
         $s0 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c60);
+            $this->peg_fail($this->peg_c62);
         }
       }
       if ($s0 === $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c61) {
-          $s0 = $this->peg_c61;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c63) {
+          $s0 = $this->peg_c63;
           $this->peg_currPos++;
         } else {
           $s0 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c62);
+              $this->peg_fail($this->peg_c64);
           }
         }
         if ($s0 === $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c63) {
-            $s0 = $this->peg_c63;
+          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
+            $s0 = $this->peg_c65;
             $this->peg_currPos++;
           } else {
             $s0 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c64);
+                $this->peg_fail($this->peg_c66);
             }
           }
           if ($s0 === $this->peg_FAILED) {
@@ -2416,13 +2418,13 @@ class MP_Parser {
         $s1 = null;
       }
       if ($s1 !== $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-          $s2 = $this->peg_c65;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+          $s2 = $this->peg_c67;
           $this->peg_currPos++;
         } else {
           $s2 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c66);
+              $this->peg_fail($this->peg_c68);
           }
         }
         if ($s2 !== $this->peg_FAILED) {
@@ -2444,13 +2446,13 @@ class MP_Parser {
                 }
               }
               if ($s6 === $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
-                  $s6 = $this->peg_c67;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c69) {
+                  $s6 = $this->peg_c69;
                   $this->peg_currPos++;
                 } else {
                   $s6 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c68);
+                      $this->peg_fail($this->peg_c70);
                   }
                 }
               }
@@ -2638,13 +2640,13 @@ class MP_Parser {
       }
 
       $s0 = $this->peg_currPos;
-      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) {
-        $s1 = $this->peg_c69;
+      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) {
+        $s1 = $this->peg_c71;
         $this->peg_currPos += 2;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c70);
+            $this->peg_fail($this->peg_c72);
         }
       }
       if ($s1 !== $this->peg_FAILED) {
@@ -2660,13 +2662,13 @@ class MP_Parser {
               $s4 = null;
             }
             if ($s4 !== $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                $s5 = $this->peg_c71;
+              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                $s5 = $this->peg_c73;
                 $this->peg_currPos += 4;
               } else {
                 $s5 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c72);
+                    $this->peg_fail($this->peg_c74);
                 }
               }
               if ($s5 !== $this->peg_FAILED) {
@@ -2684,13 +2686,13 @@ class MP_Parser {
                       $s10 = null;
                     }
                     if ($s10 !== $this->peg_FAILED) {
-                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) {
-                        $s11 = $this->peg_c73;
+                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) {
+                        $s11 = $this->peg_c75;
                         $this->peg_currPos += 6;
                       } else {
                         $s11 = $this->peg_FAILED;
                         if ($this->peg_silentFails === 0) {
-                            $this->peg_fail($this->peg_c74);
+                            $this->peg_fail($this->peg_c76);
                         }
                       }
                       if ($s11 !== $this->peg_FAILED) {
@@ -2706,13 +2708,13 @@ class MP_Parser {
                               $s14 = null;
                             }
                             if ($s14 !== $this->peg_FAILED) {
-                              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                                $s15 = $this->peg_c71;
+                              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                                $s15 = $this->peg_c73;
                                 $this->peg_currPos += 4;
                               } else {
                                 $s15 = $this->peg_FAILED;
                                 if ($this->peg_silentFails === 0) {
-                                    $this->peg_fail($this->peg_c72);
+                                    $this->peg_fail($this->peg_c74);
                                 }
                               }
                               if ($s15 !== $this->peg_FAILED) {
@@ -2766,13 +2768,13 @@ class MP_Parser {
                           $s10 = null;
                         }
                         if ($s10 !== $this->peg_FAILED) {
-                          if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) {
-                            $s11 = $this->peg_c73;
+                          if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) {
+                            $s11 = $this->peg_c75;
                             $this->peg_currPos += 6;
                           } else {
                             $s11 = $this->peg_FAILED;
                             if ($this->peg_silentFails === 0) {
-                                $this->peg_fail($this->peg_c74);
+                                $this->peg_fail($this->peg_c76);
                             }
                           }
                           if ($s11 !== $this->peg_FAILED) {
@@ -2788,13 +2790,13 @@ class MP_Parser {
                                   $s14 = null;
                                 }
                                 if ($s14 !== $this->peg_FAILED) {
-                                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                                    $s15 = $this->peg_c71;
+                                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                                    $s15 = $this->peg_c73;
                                     $this->peg_currPos += 4;
                                   } else {
                                     $s15 = $this->peg_FAILED;
                                     if ($this->peg_silentFails === 0) {
-                                        $this->peg_fail($this->peg_c72);
+                                        $this->peg_fail($this->peg_c74);
                                     }
                                   }
                                   if ($s15 !== $this->peg_FAILED) {
@@ -2849,13 +2851,13 @@ class MP_Parser {
                         $s9 = null;
                       }
                       if ($s9 !== $this->peg_FAILED) {
-                        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c75) {
-                          $s10 = $this->peg_c75;
+                        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c77) {
+                          $s10 = $this->peg_c77;
                           $this->peg_currPos += 4;
                         } else {
                           $s10 = $this->peg_FAILED;
                           if ($this->peg_silentFails === 0) {
-                              $this->peg_fail($this->peg_c76);
+                              $this->peg_fail($this->peg_c78);
                           }
                         }
                         if ($s10 !== $this->peg_FAILED) {
@@ -2919,13 +2921,13 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) {
-          $s1 = $this->peg_c69;
+        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) {
+          $s1 = $this->peg_c71;
           $this->peg_currPos += 2;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c70);
+              $this->peg_fail($this->peg_c72);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -2941,13 +2943,13 @@ class MP_Parser {
                 $s4 = null;
               }
               if ($s4 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                  $s5 = $this->peg_c71;
+                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                  $s5 = $this->peg_c73;
                   $this->peg_currPos += 4;
                 } else {
                   $s5 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c72);
+                      $this->peg_fail($this->peg_c74);
                   }
                 }
                 if ($s5 !== $this->peg_FAILED) {
@@ -2965,13 +2967,13 @@ class MP_Parser {
                         $s10 = null;
                       }
                       if ($s10 !== $this->peg_FAILED) {
-                        if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) {
-                          $s11 = $this->peg_c73;
+                        if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) {
+                          $s11 = $this->peg_c75;
                           $this->peg_currPos += 6;
                         } else {
                           $s11 = $this->peg_FAILED;
                           if ($this->peg_silentFails === 0) {
-                              $this->peg_fail($this->peg_c74);
+                              $this->peg_fail($this->peg_c76);
                           }
                         }
                         if ($s11 !== $this->peg_FAILED) {
@@ -2987,13 +2989,13 @@ class MP_Parser {
                                 $s14 = null;
                               }
                               if ($s14 !== $this->peg_FAILED) {
-                                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                                  $s15 = $this->peg_c71;
+                                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                                  $s15 = $this->peg_c73;
                                   $this->peg_currPos += 4;
                                 } else {
                                   $s15 = $this->peg_FAILED;
                                   if ($this->peg_silentFails === 0) {
-                                      $this->peg_fail($this->peg_c72);
+                                      $this->peg_fail($this->peg_c74);
                                   }
                                 }
                                 if ($s15 !== $this->peg_FAILED) {
@@ -3047,13 +3049,13 @@ class MP_Parser {
                             $s10 = null;
                           }
                           if ($s10 !== $this->peg_FAILED) {
-                            if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c73) {
-                              $s11 = $this->peg_c73;
+                            if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c75) {
+                              $s11 = $this->peg_c75;
                               $this->peg_currPos += 6;
                             } else {
                               $s11 = $this->peg_FAILED;
                               if ($this->peg_silentFails === 0) {
-                                  $this->peg_fail($this->peg_c74);
+                                  $this->peg_fail($this->peg_c76);
                               }
                             }
                             if ($s11 !== $this->peg_FAILED) {
@@ -3069,13 +3071,13 @@ class MP_Parser {
                                     $s14 = null;
                                   }
                                   if ($s14 !== $this->peg_FAILED) {
-                                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                                      $s15 = $this->peg_c71;
+                                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                                      $s15 = $this->peg_c73;
                                       $this->peg_currPos += 4;
                                     } else {
                                       $s15 = $this->peg_FAILED;
                                       if ($this->peg_silentFails === 0) {
-                                          $this->peg_fail($this->peg_c72);
+                                          $this->peg_fail($this->peg_c74);
                                       }
                                     }
                                     if ($s15 !== $this->peg_FAILED) {
@@ -3162,13 +3164,13 @@ class MP_Parser {
         }
         if ($s0 === $this->peg_FAILED) {
           $s0 = $this->peg_currPos;
-          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) {
-            $s1 = $this->peg_c69;
+          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) {
+            $s1 = $this->peg_c71;
             $this->peg_currPos += 2;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c70);
+                $this->peg_fail($this->peg_c72);
             }
           }
           if ($s1 !== $this->peg_FAILED) {
@@ -3184,13 +3186,13 @@ class MP_Parser {
                   $s4 = null;
                 }
                 if ($s4 !== $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                    $s5 = $this->peg_c71;
+                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                    $s5 = $this->peg_c73;
                     $this->peg_currPos += 4;
                   } else {
                     $s5 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c72);
+                        $this->peg_fail($this->peg_c74);
                     }
                   }
                   if ($s5 !== $this->peg_FAILED) {
@@ -3206,13 +3208,13 @@ class MP_Parser {
                           $s8 = null;
                         }
                         if ($s8 !== $this->peg_FAILED) {
-                          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c75) {
-                            $s9 = $this->peg_c75;
+                          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c77) {
+                            $s9 = $this->peg_c77;
                             $this->peg_currPos += 4;
                           } else {
                             $s9 = $this->peg_FAILED;
                             if ($this->peg_silentFails === 0) {
-                                $this->peg_fail($this->peg_c76);
+                                $this->peg_fail($this->peg_c78);
                             }
                           }
                           if ($s9 !== $this->peg_FAILED) {
@@ -3272,13 +3274,13 @@ class MP_Parser {
           }
           if ($s0 === $this->peg_FAILED) {
             $s0 = $this->peg_currPos;
-            if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c69) {
-              $s1 = $this->peg_c69;
+            if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c71) {
+              $s1 = $this->peg_c71;
               $this->peg_currPos += 2;
             } else {
               $s1 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c70);
+                  $this->peg_fail($this->peg_c72);
               }
             }
             if ($s1 !== $this->peg_FAILED) {
@@ -3294,13 +3296,13 @@ class MP_Parser {
                     $s4 = null;
                   }
                   if ($s4 !== $this->peg_FAILED) {
-                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c71) {
-                      $s5 = $this->peg_c71;
+                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c73) {
+                      $s5 = $this->peg_c73;
                       $this->peg_currPos += 4;
                     } else {
                       $s5 = $this->peg_FAILED;
                       if ($this->peg_silentFails === 0) {
-                          $this->peg_fail($this->peg_c72);
+                          $this->peg_fail($this->peg_c74);
                       }
                     }
                     if ($s5 !== $this->peg_FAILED) {
@@ -3369,13 +3371,13 @@ class MP_Parser {
         $s2 = $this->peg_parseLoopBit();
       }
       if ($s1 !== $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c77) {
-          $s2 = $this->peg_c77;
+        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c79) {
+          $s2 = $this->peg_c79;
           $this->peg_currPos += 2;
         } else {
           $s2 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c78);
+              $this->peg_fail($this->peg_c80);
           }
         }
         if ($s2 !== $this->peg_FAILED) {
@@ -3411,13 +3413,13 @@ class MP_Parser {
           $s2 = $this->peg_parseLoopBit();
         }
         if ($s1 !== $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c77) {
-            $s2 = $this->peg_c77;
+          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c79) {
+            $s2 = $this->peg_c79;
             $this->peg_currPos += 2;
           } else {
             $s2 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c78);
+                $this->peg_fail($this->peg_c80);
             }
           }
           if ($s2 !== $this->peg_FAILED) {
@@ -3456,83 +3458,83 @@ class MP_Parser {
       }
 
       $s0 = $this->peg_currPos;
-      if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c79) {
-        $s1 = $this->peg_c79;
+      if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c81) {
+        $s1 = $this->peg_c81;
         $this->peg_currPos += 3;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c80);
+            $this->peg_fail($this->peg_c82);
         }
       }
       if ($s1 === $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c81) {
-          $s1 = $this->peg_c81;
+        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) {
+          $s1 = $this->peg_c83;
           $this->peg_currPos += 4;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c82);
+              $this->peg_fail($this->peg_c84);
           }
         }
         if ($s1 === $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) {
-            $s1 = $this->peg_c83;
+          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) {
+            $s1 = $this->peg_c85;
             $this->peg_currPos += 4;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c84);
+                $this->peg_fail($this->peg_c86);
             }
           }
           if ($s1 === $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) {
-              $s1 = $this->peg_c85;
+            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c87) {
+              $s1 = $this->peg_c87;
               $this->peg_currPos += 4;
             } else {
               $s1 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c86);
+                  $this->peg_fail($this->peg_c88);
               }
             }
             if ($s1 === $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c87) {
-                $s1 = $this->peg_c87;
+              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c89) {
+                $s1 = $this->peg_c89;
                 $this->peg_currPos += 2;
               } else {
                 $s1 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c88);
+                    $this->peg_fail($this->peg_c90);
                 }
               }
               if ($s1 === $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c89) {
-                  $s1 = $this->peg_c89;
+                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c91) {
+                  $s1 = $this->peg_c91;
                   $this->peg_currPos += 4;
                 } else {
                   $s1 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c90);
+                      $this->peg_fail($this->peg_c92);
                   }
                 }
                 if ($s1 === $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c91) {
-                    $s1 = $this->peg_c91;
+                  if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c93) {
+                    $s1 = $this->peg_c93;
                     $this->peg_currPos += 5;
                   } else {
                     $s1 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c92);
+                        $this->peg_fail($this->peg_c94);
                     }
                   }
                   if ($s1 === $this->peg_FAILED) {
-                    if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c93) {
-                      $s1 = $this->peg_c93;
+                    if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c95) {
+                      $s1 = $this->peg_c95;
                       $this->peg_currPos += 6;
                     } else {
                       $s1 = $this->peg_FAILED;
                       if ($this->peg_silentFails === 0) {
-                          $this->peg_fail($this->peg_c94);
+                          $this->peg_fail($this->peg_c96);
                       }
                     }
                   }
@@ -3573,83 +3575,83 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c79) {
-          $s1 = $this->peg_c79;
+        if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c81) {
+          $s1 = $this->peg_c81;
           $this->peg_currPos += 3;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c80);
+              $this->peg_fail($this->peg_c82);
           }
         }
         if ($s1 === $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c81) {
-            $s1 = $this->peg_c81;
+          if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) {
+            $s1 = $this->peg_c83;
             $this->peg_currPos += 4;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c82);
+                $this->peg_fail($this->peg_c84);
             }
           }
           if ($s1 === $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c83) {
-              $s1 = $this->peg_c83;
+            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) {
+              $s1 = $this->peg_c85;
               $this->peg_currPos += 4;
             } else {
               $s1 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c84);
+                  $this->peg_fail($this->peg_c86);
               }
             }
             if ($s1 === $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c85) {
-                $s1 = $this->peg_c85;
+              if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c87) {
+                $s1 = $this->peg_c87;
                 $this->peg_currPos += 4;
               } else {
                 $s1 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c86);
+                    $this->peg_fail($this->peg_c88);
                 }
               }
               if ($s1 === $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c87) {
-                  $s1 = $this->peg_c87;
+                if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c89) {
+                  $s1 = $this->peg_c89;
                   $this->peg_currPos += 2;
                 } else {
                   $s1 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c88);
+                      $this->peg_fail($this->peg_c90);
                   }
                 }
                 if ($s1 === $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c89) {
-                    $s1 = $this->peg_c89;
+                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c91) {
+                    $s1 = $this->peg_c91;
                     $this->peg_currPos += 4;
                   } else {
                     $s1 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c90);
+                        $this->peg_fail($this->peg_c92);
                     }
                   }
                   if ($s1 === $this->peg_FAILED) {
-                    if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c91) {
-                      $s1 = $this->peg_c91;
+                    if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c93) {
+                      $s1 = $this->peg_c93;
                       $this->peg_currPos += 5;
                     } else {
                       $s1 = $this->peg_FAILED;
                       if ($this->peg_silentFails === 0) {
-                          $this->peg_fail($this->peg_c92);
+                          $this->peg_fail($this->peg_c94);
                       }
                     }
                     if ($s1 === $this->peg_FAILED) {
-                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c93) {
-                        $s1 = $this->peg_c93;
+                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c95) {
+                        $s1 = $this->peg_c95;
                         $this->peg_currPos += 6;
                       } else {
                         $s1 = $this->peg_FAILED;
                         if ($this->peg_silentFails === 0) {
-                            $this->peg_fail($this->peg_c94);
+                            $this->peg_fail($this->peg_c96);
                         }
                       }
                     }
@@ -3660,13 +3662,13 @@ class MP_Parser {
           }
         }
         if ($s1 !== $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) {
-            $s2 = $this->peg_c95;
+          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
+            $s2 = $this->peg_c97;
             $this->peg_currPos++;
           } else {
             $s2 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c96);
+                $this->peg_fail($this->peg_c98);
             }
           }
           if ($s2 !== $this->peg_FAILED) {
@@ -3682,13 +3684,13 @@ class MP_Parser {
                   $s5 = null;
                 }
                 if ($s5 !== $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
-                    $s6 = $this->peg_c97;
+                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) {
+                    $s6 = $this->peg_c99;
                     $this->peg_currPos++;
                   } else {
                     $s6 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c98);
+                        $this->peg_fail($this->peg_c100);
                     }
                   }
                   if ($s6 !== $this->peg_FAILED) {
@@ -3745,24 +3747,24 @@ class MP_Parser {
         return $cached["result"];
       }
 
-      if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c99) {
-        $s0 = $this->peg_c99;
+      if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c101) {
+        $s0 = $this->peg_c101;
         $this->peg_currPos += 4;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c100);
+            $this->peg_fail($this->peg_c102);
         }
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c101) {
-          $s1 = $this->peg_c101;
+        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c103) {
+          $s1 = $this->peg_c103;
           $this->peg_currPos += 2;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c102);
+              $this->peg_fail($this->peg_c104);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -3786,103 +3788,103 @@ class MP_Parser {
           $s0 = $this->peg_FAILED;
         }
         if ($s0 === $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c103) {
-            $s0 = $this->peg_c103;
+          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) {
+            $s0 = $this->peg_c105;
             $this->peg_currPos++;
           } else {
             $s0 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c104);
+                $this->peg_fail($this->peg_c106);
             }
           }
           if ($s0 === $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) {
-              $s0 = $this->peg_c105;
+            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c107) {
+              $s0 = $this->peg_c107;
               $this->peg_currPos++;
             } else {
               $s0 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c106);
+                  $this->peg_fail($this->peg_c108);
               }
             }
             if ($s0 === $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c107) {
-                $s0 = $this->peg_c107;
+              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c109) {
+                $s0 = $this->peg_c109;
                 $this->peg_currPos += 2;
               } else {
                 $s0 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c108);
+                    $this->peg_fail($this->peg_c110);
                 }
               }
               if ($s0 === $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c109) {
-                  $s0 = $this->peg_c109;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c111) {
+                  $s0 = $this->peg_c111;
                   $this->peg_currPos++;
                 } else {
                   $s0 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c110);
+                      $this->peg_fail($this->peg_c112);
                   }
                 }
                 if ($s0 === $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c111) {
-                    $s0 = $this->peg_c111;
+                  if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c113) {
+                    $s0 = $this->peg_c113;
                     $this->peg_currPos += 4;
                   } else {
                     $s0 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c112);
+                        $this->peg_fail($this->peg_c114);
                     }
                   }
                   if ($s0 === $this->peg_FAILED) {
-                    if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c113) {
-                      $s0 = $this->peg_c113;
+                    if ($this->input_substr($this->peg_currPos, 8) === $this->peg_c115) {
+                      $s0 = $this->peg_c115;
                       $this->peg_currPos += 8;
                     } else {
                       $s0 = $this->peg_FAILED;
                       if ($this->peg_silentFails === 0) {
-                          $this->peg_fail($this->peg_c114);
+                          $this->peg_fail($this->peg_c116);
                       }
                     }
                     if ($s0 === $this->peg_FAILED) {
-                      if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c115) {
-                        $s0 = $this->peg_c115;
+                      if ($this->input_substr($this->peg_currPos, 5) === $this->peg_c117) {
+                        $s0 = $this->peg_c117;
                         $this->peg_currPos += 5;
                       } else {
                         $s0 = $this->peg_FAILED;
                         if ($this->peg_silentFails === 0) {
-                            $this->peg_fail($this->peg_c116);
+                            $this->peg_fail($this->peg_c118);
                         }
                       }
                       if ($s0 === $this->peg_FAILED) {
-                        if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c117) {
-                          $s0 = $this->peg_c117;
+                        if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c119) {
+                          $s0 = $this->peg_c119;
                           $this->peg_currPos += 3;
                         } else {
                           $s0 = $this->peg_FAILED;
                           if ($this->peg_silentFails === 0) {
-                              $this->peg_fail($this->peg_c118);
+                              $this->peg_fail($this->peg_c120);
                           }
                         }
                         if ($s0 === $this->peg_FAILED) {
-                          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c119) {
-                            $s0 = $this->peg_c119;
+                          if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c121) {
+                            $s0 = $this->peg_c121;
                             $this->peg_currPos += 2;
                           } else {
                             $s0 = $this->peg_FAILED;
                             if ($this->peg_silentFails === 0) {
-                                $this->peg_fail($this->peg_c120);
+                                $this->peg_fail($this->peg_c122);
                             }
                           }
                           if ($s0 === $this->peg_FAILED) {
-                            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c121) {
-                              $s0 = $this->peg_c121;
+                            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c123) {
+                              $s0 = $this->peg_c123;
                               $this->peg_currPos++;
                             } else {
                               $s0 = $this->peg_FAILED;
                               if ($this->peg_silentFails === 0) {
-                                  $this->peg_fail($this->peg_c122);
+                                  $this->peg_fail($this->peg_c124);
                               }
                             }
                           }
@@ -3912,23 +3914,23 @@ class MP_Parser {
         return $cached["result"];
       }
 
-      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c123) {
-        $s0 = $this->peg_c123;
+      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c125) {
+        $s0 = $this->peg_c125;
         $this->peg_currPos += 2;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c124);
+            $this->peg_fail($this->peg_c126);
         }
       }
       if ($s0 === $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c125) {
-          $s0 = $this->peg_c125;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c127) {
+          $s0 = $this->peg_c127;
           $this->peg_currPos++;
         } else {
           $s0 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c126);
+              $this->peg_fail($this->peg_c128);
           }
         }
       }
@@ -3948,33 +3950,33 @@ class MP_Parser {
         return $cached["result"];
       }
 
-      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c127) {
-        $s0 = $this->peg_c127;
+      if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c129) {
+        $s0 = $this->peg_c129;
         $this->peg_currPos += 2;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c128);
+            $this->peg_fail($this->peg_c130);
         }
       }
       if ($s0 === $this->peg_FAILED) {
-        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c129) {
-          $s0 = $this->peg_c129;
+        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c131) {
+          $s0 = $this->peg_c131;
           $this->peg_currPos += 2;
         } else {
           $s0 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c130);
+              $this->peg_fail($this->peg_c132);
           }
         }
         if ($s0 === $this->peg_FAILED) {
-          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c131) {
-            $s0 = $this->peg_c131;
+          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c133) {
+            $s0 = $this->peg_c133;
             $this->peg_currPos++;
           } else {
             $s0 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c132);
+                $this->peg_fail($this->peg_c134);
             }
           }
           if ($s0 === $this->peg_FAILED) {
@@ -3998,24 +4000,24 @@ class MP_Parser {
                 }
               }
               if ($s0 === $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c99) {
-                  $s0 = $this->peg_c99;
+                if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c101) {
+                  $s0 = $this->peg_c101;
                   $this->peg_currPos += 4;
                 } else {
                   $s0 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c100);
+                      $this->peg_fail($this->peg_c102);
                   }
                 }
                 if ($s0 === $this->peg_FAILED) {
                   $s0 = $this->peg_currPos;
-                  if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c101) {
-                    $s1 = $this->peg_c101;
+                  if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c103) {
+                    $s1 = $this->peg_c103;
                     $this->peg_currPos += 2;
                   } else {
                     $s1 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c102);
+                        $this->peg_fail($this->peg_c104);
                     }
                   }
                   if ($s1 !== $this->peg_FAILED) {
@@ -4039,223 +4041,223 @@ class MP_Parser {
                     $s0 = $this->peg_FAILED;
                   }
                   if ($s0 === $this->peg_FAILED) {
-                    if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c103) {
-                      $s0 = $this->peg_c103;
+                    if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) {
+                      $s0 = $this->peg_c105;
                       $this->peg_currPos++;
                     } else {
                       $s0 = $this->peg_FAILED;
                       if ($this->peg_silentFails === 0) {
-                          $this->peg_fail($this->peg_c104);
+                          $this->peg_fail($this->peg_c106);
                       }
                     }
                     if ($s0 === $this->peg_FAILED) {
-                      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c105) {
-                        $s0 = $this->peg_c105;
+                      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c107) {
+                        $s0 = $this->peg_c107;
                         $this->peg_currPos++;
                       } else {
                         $s0 = $this->peg_FAILED;
                         if ($this->peg_silentFails === 0) {
-                            $this->peg_fail($this->peg_c106);
+                            $this->peg_fail($this->peg_c108);
                         }
                       }
                       if ($s0 === $this->peg_FAILED) {
-                        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c133) {
-                          $s0 = $this->peg_c133;
+                        if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c135) {
+                          $s0 = $this->peg_c135;
                           $this->peg_currPos += 4;
                         } else {
                           $s0 = $this->peg_FAILED;
                           if ($this->peg_silentFails === 0) {
-                              $this->peg_fail($this->peg_c134);
+                              $this->peg_fail($this->peg_c136);
                           }
                         }
                         if ($s0 === $this->peg_FAILED) {
-                          if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c135) {
-                            $s0 = $this->peg_c135;
+                          if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c137) {
+                            $s0 = $this->peg_c137;
                             $this->peg_currPos += 3;
                           } else {
                             $s0 = $this->peg_FAILED;
                             if ($this->peg_silentFails === 0) {
-                                $this->peg_fail($this->peg_c136);
+                                $this->peg_fail($this->peg_c138);
                             }
                           }
                           if ($s0 === $this->peg_FAILED) {
-                            if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c137) {
-                              $s0 = $this->peg_c137;
+                            if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c139) {
+                              $s0 = $this->peg_c139;
                               $this->peg_currPos += 3;
                             } else {
                               $s0 = $this->peg_FAILED;
                               if ($this->peg_silentFails === 0) {
-                                  $this->peg_fail($this->peg_c138);
+                                  $this->peg_fail($this->peg_c140);
                               }
                             }
                             if ($s0 === $this->peg_FAILED) {
-                              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c139) {
-                                $s0 = $this->peg_c139;
+                              if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c141) {
+                                $s0 = $this->peg_c141;
                                 $this->peg_currPos += 2;
                               } else {
                                 $s0 = $this->peg_FAILED;
                                 if ($this->peg_silentFails === 0) {
-                                    $this->peg_fail($this->peg_c140);
+                                    $this->peg_fail($this->peg_c142);
                                 }
                               }
                               if ($s0 === $this->peg_FAILED) {
-                                if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c141) {
-                                  $s0 = $this->peg_c141;
+                                if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c143) {
+                                  $s0 = $this->peg_c143;
                                   $this->peg_currPos += 7;
                                 } else {
                                   $s0 = $this->peg_FAILED;
                                   if ($this->peg_silentFails === 0) {
-                                      $this->peg_fail($this->peg_c142);
+                                      $this->peg_fail($this->peg_c144);
                                   }
                                 }
                                 if ($s0 === $this->peg_FAILED) {
-                                  if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c143) {
-                                    $s0 = $this->peg_c143;
+                                  if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c145) {
+                                    $s0 = $this->peg_c145;
                                     $this->peg_currPos += 6;
                                   } else {
                                     $s0 = $this->peg_FAILED;
                                     if ($this->peg_silentFails === 0) {
-                                        $this->peg_fail($this->peg_c144);
+                                        $this->peg_fail($this->peg_c146);
                                     }
                                   }
                                   if ($s0 === $this->peg_FAILED) {
-                                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c145) {
-                                      $s0 = $this->peg_c145;
+                                    if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c147) {
+                                      $s0 = $this->peg_c147;
                                       $this->peg_currPos += 4;
                                     } else {
                                       $s0 = $this->peg_FAILED;
                                       if ($this->peg_silentFails === 0) {
-                                          $this->peg_fail($this->peg_c146);
+                                          $this->peg_fail($this->peg_c148);
                                       }
                                     }
                                     if ($s0 === $this->peg_FAILED) {
-                                      if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c147) {
-                                        $s0 = $this->peg_c147;
+                                      if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c149) {
+                                        $s0 = $this->peg_c149;
                                         $this->peg_currPos += 3;
                                       } else {
                                         $s0 = $this->peg_FAILED;
                                         if ($this->peg_silentFails === 0) {
-                                            $this->peg_fail($this->peg_c148);
+                                            $this->peg_fail($this->peg_c150);
                                         }
                                       }
                                       if ($s0 === $this->peg_FAILED) {
-                                        if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c149) {
-                                          $s0 = $this->peg_c149;
+                                        if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c151) {
+                                          $s0 = $this->peg_c151;
                                           $this->peg_currPos += 7;
                                         } else {
                                           $s0 = $this->peg_FAILED;
                                           if ($this->peg_silentFails === 0) {
-                                              $this->peg_fail($this->peg_c150);
+                                              $this->peg_fail($this->peg_c152);
                                           }
                                         }
                                         if ($s0 === $this->peg_FAILED) {
-                                          if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c151) {
-                                            $s0 = $this->peg_c151;
+                                          if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c153) {
+                                            $s0 = $this->peg_c153;
                                             $this->peg_currPos += 3;
                                           } else {
                                             $s0 = $this->peg_FAILED;
                                             if ($this->peg_silentFails === 0) {
-                                                $this->peg_fail($this->peg_c152);
+                                                $this->peg_fail($this->peg_c154);
                                             }
                                           }
                                           if ($s0 === $this->peg_FAILED) {
-                                            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c153) {
-                                              $s0 = $this->peg_c153;
+                                            if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c155) {
+                                              $s0 = $this->peg_c155;
                                               $this->peg_currPos += 4;
                                             } else {
                                               $s0 = $this->peg_FAILED;
                                               if ($this->peg_silentFails === 0) {
-                                                  $this->peg_fail($this->peg_c154);
+                                                  $this->peg_fail($this->peg_c156);
                                               }
                                             }
                                             if ($s0 === $this->peg_FAILED) {
-                                              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c155) {
-                                                $s0 = $this->peg_c155;
+                                              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c157) {
+                                                $s0 = $this->peg_c157;
                                                 $this->peg_currPos++;
                                               } else {
                                                 $s0 = $this->peg_FAILED;
                                                 if ($this->peg_silentFails === 0) {
-                                                    $this->peg_fail($this->peg_c156);
+                                                    $this->peg_fail($this->peg_c158);
                                                 }
                                               }
                                               if ($s0 === $this->peg_FAILED) {
-                                                if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c157) {
-                                                  $s0 = $this->peg_c157;
+                                                if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c159) {
+                                                  $s0 = $this->peg_c159;
                                                   $this->peg_currPos += 3;
                                                 } else {
                                                   $s0 = $this->peg_FAILED;
                                                   if ($this->peg_silentFails === 0) {
-                                                      $this->peg_fail($this->peg_c158);
+                                                      $this->peg_fail($this->peg_c160);
                                                   }
                                                 }
                                                 if ($s0 === $this->peg_FAILED) {
-                                                  if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c159) {
-                                                    $s0 = $this->peg_c159;
+                                                  if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c161) {
+                                                    $s0 = $this->peg_c161;
                                                     $this->peg_currPos += 2;
                                                   } else {
                                                     $s0 = $this->peg_FAILED;
                                                     if ($this->peg_silentFails === 0) {
-                                                        $this->peg_fail($this->peg_c160);
+                                                        $this->peg_fail($this->peg_c162);
                                                     }
                                                   }
                                                   if ($s0 === $this->peg_FAILED) {
-                                                    if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c161) {
-                                                      $s0 = $this->peg_c161;
+                                                    if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c163) {
+                                                      $s0 = $this->peg_c163;
                                                       $this->peg_currPos += 2;
                                                     } else {
                                                       $s0 = $this->peg_FAILED;
                                                       if ($this->peg_silentFails === 0) {
-                                                          $this->peg_fail($this->peg_c162);
+                                                          $this->peg_fail($this->peg_c164);
                                                       }
                                                     }
                                                     if ($s0 === $this->peg_FAILED) {
-                                                      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
-                                                        $s0 = $this->peg_c67;
+                                                      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c69) {
+                                                        $s0 = $this->peg_c69;
                                                         $this->peg_currPos++;
                                                       } else {
                                                         $s0 = $this->peg_FAILED;
                                                         if ($this->peg_silentFails === 0) {
-                                                            $this->peg_fail($this->peg_c68);
+                                                            $this->peg_fail($this->peg_c70);
                                                         }
                                                       }
                                                       if ($s0 === $this->peg_FAILED) {
-                                                        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c163) {
-                                                          $s0 = $this->peg_c163;
+                                                        if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c165) {
+                                                          $s0 = $this->peg_c165;
                                                           $this->peg_currPos += 2;
                                                         } else {
                                                           $s0 = $this->peg_FAILED;
                                                           if ($this->peg_silentFails === 0) {
-                                                              $this->peg_fail($this->peg_c164);
+                                                              $this->peg_fail($this->peg_c166);
                                                           }
                                                         }
                                                         if ($s0 === $this->peg_FAILED) {
-                                                          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c165) {
-                                                            $s0 = $this->peg_c165;
+                                                          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c167) {
+                                                            $s0 = $this->peg_c167;
                                                             $this->peg_currPos++;
                                                           } else {
                                                             $s0 = $this->peg_FAILED;
                                                             if ($this->peg_silentFails === 0) {
-                                                                $this->peg_fail($this->peg_c166);
+                                                                $this->peg_fail($this->peg_c168);
                                                             }
                                                           }
                                                           if ($s0 === $this->peg_FAILED) {
-                                                            if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c167) {
-                                                              $s0 = $this->peg_c167;
+                                                            if ($this->input_substr($this->peg_currPos, 2) === $this->peg_c169) {
+                                                              $s0 = $this->peg_c169;
                                                               $this->peg_currPos += 2;
                                                             } else {
                                                               $s0 = $this->peg_FAILED;
                                                               if ($this->peg_silentFails === 0) {
-                                                                  $this->peg_fail($this->peg_c168);
+                                                                  $this->peg_fail($this->peg_c170);
                                                               }
                                                             }
                                                             if ($s0 === $this->peg_FAILED) {
-                                                              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c169) {
-                                                                $s0 = $this->peg_c169;
+                                                              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c171) {
+                                                                $s0 = $this->peg_c171;
                                                                 $this->peg_currPos++;
                                                               } else {
                                                                 $s0 = $this->peg_FAILED;
                                                                 if ($this->peg_silentFails === 0) {
-                                                                    $this->peg_fail($this->peg_c170);
+                                                                    $this->peg_fail($this->peg_c172);
                                                                 }
                                                               }
                                                               if ($s0 === $this->peg_FAILED) {
@@ -4269,33 +4271,33 @@ class MP_Parser {
                                                                   }
                                                                 }
                                                                 if ($s0 === $this->peg_FAILED) {
-                                                                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c171) {
-                                                                    $s0 = $this->peg_c171;
+                                                                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c173) {
+                                                                    $s0 = $this->peg_c173;
                                                                     $this->peg_currPos++;
                                                                   } else {
                                                                     $s0 = $this->peg_FAILED;
                                                                     if ($this->peg_silentFails === 0) {
-                                                                        $this->peg_fail($this->peg_c172);
+                                                                        $this->peg_fail($this->peg_c174);
                                                                     }
                                                                   }
                                                                   if ($s0 === $this->peg_FAILED) {
-                                                                    if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c173) {
-                                                                      $s0 = $this->peg_c173;
+                                                                    if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c175) {
+                                                                      $s0 = $this->peg_c175;
                                                                       $this->peg_currPos += 6;
                                                                     } else {
                                                                       $s0 = $this->peg_FAILED;
                                                                       if ($this->peg_silentFails === 0) {
-                                                                          $this->peg_fail($this->peg_c174);
+                                                                          $this->peg_fail($this->peg_c176);
                                                                       }
                                                                     }
                                                                     if ($s0 === $this->peg_FAILED) {
-                                                                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c175) {
-                                                                        $s0 = $this->peg_c175;
+                                                                      if ($this->input_substr($this->peg_currPos, 6) === $this->peg_c177) {
+                                                                        $s0 = $this->peg_c177;
                                                                         $this->peg_currPos += 6;
                                                                       } else {
                                                                         $s0 = $this->peg_FAILED;
                                                                         if ($this->peg_silentFails === 0) {
-                                                                            $this->peg_fail($this->peg_c176);
+                                                                            $this->peg_fail($this->peg_c178);
                                                                         }
                                                                       }
                                                                     }
@@ -4450,13 +4452,13 @@ class MP_Parser {
         }
         if ($s0 === $this->peg_FAILED) {
           $s0 = $this->peg_currPos;
-          if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c177) {
-            $s1 = $this->peg_c177;
+          if ($this->input_substr($this->peg_currPos, 7) === $this->peg_c179) {
+            $s1 = $this->peg_c179;
             $this->peg_currPos += 7;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c178);
+                $this->peg_fail($this->peg_c180);
             }
           }
           if ($s1 !== $this->peg_FAILED) {
@@ -4475,13 +4477,13 @@ class MP_Parser {
           }
           if ($s0 === $this->peg_FAILED) {
             $s0 = $this->peg_currPos;
-            if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c179) {
-              $s1 = $this->peg_c179;
+            if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c181) {
+              $s1 = $this->peg_c181;
               $this->peg_currPos += 3;
             } else {
               $s1 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c180);
+                  $this->peg_fail($this->peg_c182);
               }
             }
             if ($s1 !== $this->peg_FAILED) {
@@ -4689,13 +4691,13 @@ class MP_Parser {
       }
 
       $s0 = $this->peg_currPos;
-      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) {
-        $s1 = $this->peg_c95;
+      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
+        $s1 = $this->peg_c97;
         $this->peg_currPos++;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c96);
+            $this->peg_fail($this->peg_c98);
         }
       }
       if ($s1 !== $this->peg_FAILED) {
@@ -4713,13 +4715,13 @@ class MP_Parser {
               $s6 = null;
             }
             if ($s6 !== $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                $s7 = $this->peg_c65;
+              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                $s7 = $this->peg_c67;
                 $this->peg_currPos++;
               } else {
                 $s7 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c66);
+                    $this->peg_fail($this->peg_c68);
                 }
               }
               if ($s7 !== $this->peg_FAILED) {
@@ -4756,13 +4758,13 @@ class MP_Parser {
                 $s6 = null;
               }
               if ($s6 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                  $s7 = $this->peg_c65;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                  $s7 = $this->peg_c67;
                   $this->peg_currPos++;
                 } else {
                   $s7 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c66);
+                      $this->peg_fail($this->peg_c68);
                   }
                 }
                 if ($s7 !== $this->peg_FAILED) {
@@ -4798,13 +4800,13 @@ class MP_Parser {
                 $s5 = null;
               }
               if ($s5 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
-                  $s6 = $this->peg_c97;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) {
+                  $s6 = $this->peg_c99;
                   $this->peg_currPos++;
                 } else {
                   $s6 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c98);
+                      $this->peg_fail($this->peg_c100);
                   }
                 }
                 if ($s6 !== $this->peg_FAILED) {
@@ -4837,13 +4839,13 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c95) {
-          $s1 = $this->peg_c95;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
+          $s1 = $this->peg_c97;
           $this->peg_currPos++;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c96);
+              $this->peg_fail($this->peg_c98);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -4852,13 +4854,13 @@ class MP_Parser {
             $s2 = null;
           }
           if ($s2 !== $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c97) {
-              $s3 = $this->peg_c97;
+            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c99) {
+              $s3 = $this->peg_c99;
               $this->peg_currPos++;
             } else {
               $s3 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c98);
+                  $this->peg_fail($this->peg_c100);
               }
             }
             if ($s3 !== $this->peg_FAILED) {
@@ -5082,13 +5084,13 @@ class MP_Parser {
         }
         if ($s0 === $this->peg_FAILED) {
           $s0 = $this->peg_currPos;
-          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c181) {
-            $s1 = $this->peg_c181;
+          if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) {
+            $s1 = $this->peg_c183;
             $this->peg_currPos++;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c182);
+                $this->peg_fail($this->peg_c184);
             }
           }
           if ($s1 !== $this->peg_FAILED) {
@@ -5104,13 +5106,13 @@ class MP_Parser {
                   $s4 = null;
                 }
                 if ($s4 !== $this->peg_FAILED) {
-                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c181) {
-                    $s5 = $this->peg_c181;
+                  if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) {
+                    $s5 = $this->peg_c183;
                     $this->peg_currPos++;
                   } else {
                     $s5 = $this->peg_FAILED;
                     if ($this->peg_silentFails === 0) {
-                        $this->peg_fail($this->peg_c182);
+                        $this->peg_fail($this->peg_c184);
                     }
                   }
                   if ($s5 !== $this->peg_FAILED) {
@@ -5240,13 +5242,13 @@ class MP_Parser {
       }
 
       $s0 = $this->peg_currPos;
-      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) {
-        $s1 = $this->peg_c183;
+      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) {
+        $s1 = $this->peg_c185;
         $this->peg_currPos++;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c184);
+            $this->peg_fail($this->peg_c186);
         }
       }
       if ($s1 !== $this->peg_FAILED) {
@@ -5264,13 +5266,13 @@ class MP_Parser {
               $s6 = null;
             }
             if ($s6 !== $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                $s7 = $this->peg_c65;
+              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                $s7 = $this->peg_c67;
                 $this->peg_currPos++;
               } else {
                 $s7 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c66);
+                    $this->peg_fail($this->peg_c68);
                 }
               }
               if ($s7 !== $this->peg_FAILED) {
@@ -5307,13 +5309,13 @@ class MP_Parser {
                 $s6 = null;
               }
               if ($s6 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                  $s7 = $this->peg_c65;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                  $s7 = $this->peg_c67;
                   $this->peg_currPos++;
                 } else {
                   $s7 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c66);
+                      $this->peg_fail($this->peg_c68);
                   }
                 }
                 if ($s7 !== $this->peg_FAILED) {
@@ -5349,13 +5351,13 @@ class MP_Parser {
                 $s5 = null;
               }
               if ($s5 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) {
-                  $s6 = $this->peg_c185;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) {
+                  $s6 = $this->peg_c187;
                   $this->peg_currPos++;
                 } else {
                   $s6 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c186);
+                      $this->peg_fail($this->peg_c188);
                   }
                 }
                 if ($s6 !== $this->peg_FAILED) {
@@ -5388,13 +5390,13 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c183) {
-          $s1 = $this->peg_c183;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) {
+          $s1 = $this->peg_c185;
           $this->peg_currPos++;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c184);
+              $this->peg_fail($this->peg_c186);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -5403,13 +5405,13 @@ class MP_Parser {
             $s2 = null;
           }
           if ($s2 !== $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c185) {
-              $s3 = $this->peg_c185;
+            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) {
+              $s3 = $this->peg_c187;
               $this->peg_currPos++;
             } else {
               $s3 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c186);
+                  $this->peg_fail($this->peg_c188);
               }
             }
             if ($s3 !== $this->peg_FAILED) {
@@ -5446,13 +5448,13 @@ class MP_Parser {
       }
 
       $s0 = $this->peg_currPos;
-      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) {
-        $s1 = $this->peg_c187;
+      if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) {
+        $s1 = $this->peg_c189;
         $this->peg_currPos++;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c188);
+            $this->peg_fail($this->peg_c190);
         }
       }
       if ($s1 !== $this->peg_FAILED) {
@@ -5470,13 +5472,13 @@ class MP_Parser {
               $s6 = null;
             }
             if ($s6 !== $this->peg_FAILED) {
-              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                $s7 = $this->peg_c65;
+              if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                $s7 = $this->peg_c67;
                 $this->peg_currPos++;
               } else {
                 $s7 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c66);
+                    $this->peg_fail($this->peg_c68);
                 }
               }
               if ($s7 !== $this->peg_FAILED) {
@@ -5513,13 +5515,13 @@ class MP_Parser {
                 $s6 = null;
               }
               if ($s6 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c65) {
-                  $s7 = $this->peg_c65;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c67) {
+                  $s7 = $this->peg_c67;
                   $this->peg_currPos++;
                 } else {
                   $s7 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c66);
+                      $this->peg_fail($this->peg_c68);
                   }
                 }
                 if ($s7 !== $this->peg_FAILED) {
@@ -5555,13 +5557,13 @@ class MP_Parser {
                 $s5 = null;
               }
               if ($s5 !== $this->peg_FAILED) {
-                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) {
-                  $s6 = $this->peg_c189;
+                if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c191) {
+                  $s6 = $this->peg_c191;
                   $this->peg_currPos++;
                 } else {
                   $s6 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c190);
+                      $this->peg_fail($this->peg_c192);
                   }
                 }
                 if ($s6 !== $this->peg_FAILED) {
@@ -5594,13 +5596,13 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = $this->peg_currPos;
-        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c187) {
-          $s1 = $this->peg_c187;
+        if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) {
+          $s1 = $this->peg_c189;
           $this->peg_currPos++;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c188);
+              $this->peg_fail($this->peg_c190);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
@@ -5609,13 +5611,13 @@ class MP_Parser {
             $s2 = null;
           }
           if ($s2 !== $this->peg_FAILED) {
-            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c189) {
-              $s3 = $this->peg_c189;
+            if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c191) {
+              $s3 = $this->peg_c191;
               $this->peg_currPos++;
             } else {
               $s3 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c190);
+                  $this->peg_fail($this->peg_c192);
               }
             }
             if ($s3 !== $this->peg_FAILED) {
@@ -5680,24 +5682,24 @@ class MP_Parser {
       $this->peg_silentFails++;
       $s0 = $this->peg_currPos;
       $s1 = array();
-      if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
         $s2 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s2 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c193);
+            $this->peg_fail($this->peg_c195);
         }
       }
       while ($s2 !== $this->peg_FAILED) {
         $s1[] = $s2;
-        if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+        if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
           $s2 = $this->input_substr($this->peg_currPos, 1);
           $this->peg_currPos++;
         } else {
           $s2 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c193);
+              $this->peg_fail($this->peg_c195);
           }
         }
       }
@@ -5707,24 +5709,24 @@ class MP_Parser {
         $s4 = $this->peg_parseComment();
         if ($s4 !== $this->peg_FAILED) {
           $s5 = array();
-          if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+          if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
             $s6 = $this->input_substr($this->peg_currPos, 1);
             $this->peg_currPos++;
           } else {
             $s6 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c193);
+                $this->peg_fail($this->peg_c195);
             }
           }
           while ($s6 !== $this->peg_FAILED) {
             $s5[] = $s6;
-            if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+            if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
               $s6 = $this->input_substr($this->peg_currPos, 1);
               $this->peg_currPos++;
             } else {
               $s6 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c193);
+                  $this->peg_fail($this->peg_c195);
               }
             }
           }
@@ -5746,24 +5748,24 @@ class MP_Parser {
             $s4 = $this->peg_parseComment();
             if ($s4 !== $this->peg_FAILED) {
               $s5 = array();
-              if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+              if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
                 $s6 = $this->input_substr($this->peg_currPos, 1);
                 $this->peg_currPos++;
               } else {
                 $s6 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c193);
+                    $this->peg_fail($this->peg_c195);
                 }
               }
               while ($s6 !== $this->peg_FAILED) {
                 $s5[] = $s6;
-                if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+                if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
                   $s6 = $this->input_substr($this->peg_currPos, 1);
                   $this->peg_currPos++;
                 } else {
                   $s6 = $this->peg_FAILED;
                   if ($this->peg_silentFails === 0) {
-                      $this->peg_fail($this->peg_c193);
+                      $this->peg_fail($this->peg_c195);
                   }
                 }
               }
@@ -5795,25 +5797,25 @@ class MP_Parser {
       }
       if ($s0 === $this->peg_FAILED) {
         $s0 = array();
-        if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+        if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
           $s1 = $this->input_substr($this->peg_currPos, 1);
           $this->peg_currPos++;
         } else {
           $s1 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c193);
+              $this->peg_fail($this->peg_c195);
           }
         }
         if ($s1 !== $this->peg_FAILED) {
           while ($s1 !== $this->peg_FAILED) {
             $s0[] = $s1;
-            if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+            if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
               $s1 = $this->input_substr($this->peg_currPos, 1);
               $this->peg_currPos++;
             } else {
               $s1 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c193);
+                  $this->peg_fail($this->peg_c195);
               }
             }
           }
@@ -5825,7 +5827,7 @@ class MP_Parser {
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c191);
+            $this->peg_fail($this->peg_c193);
         }
       }
 
@@ -5846,25 +5848,25 @@ class MP_Parser {
 
       $this->peg_silentFails++;
       $s0 = array();
-      if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
         $s1 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c193);
+            $this->peg_fail($this->peg_c195);
         }
       }
       if ($s1 !== $this->peg_FAILED) {
         while ($s1 !== $this->peg_FAILED) {
           $s0[] = $s1;
-          if (peg_regex_test($this->peg_c192, $this->input_substr($this->peg_currPos, 1))) {
+          if (peg_regex_test($this->peg_c194, $this->input_substr($this->peg_currPos, 1))) {
             $s1 = $this->input_substr($this->peg_currPos, 1);
             $this->peg_currPos++;
           } else {
             $s1 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c193);
+                $this->peg_fail($this->peg_c195);
             }
           }
         }
@@ -5875,7 +5877,7 @@ class MP_Parser {
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c191);
+            $this->peg_fail($this->peg_c193);
         }
       }
 
@@ -5895,53 +5897,53 @@ class MP_Parser {
       }
 
       $this->peg_silentFails++;
-      if (peg_regex_test($this->peg_c195, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c197, $this->input_substr($this->peg_currPos, 1))) {
         $s0 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c196);
+            $this->peg_fail($this->peg_c198);
         }
       }
       if ($s0 === $this->peg_FAILED) {
-        if (peg_regex_test($this->peg_c197, $this->input_substr($this->peg_currPos, 1))) {
+        if (peg_regex_test($this->peg_c199, $this->input_substr($this->peg_currPos, 1))) {
           $s0 = $this->input_substr($this->peg_currPos, 1);
           $this->peg_currPos++;
         } else {
           $s0 = $this->peg_FAILED;
           if ($this->peg_silentFails === 0) {
-              $this->peg_fail($this->peg_c198);
+              $this->peg_fail($this->peg_c200);
           }
         }
         if ($s0 === $this->peg_FAILED) {
-          if (peg_regex_test($this->peg_c199, $this->input_substr($this->peg_currPos, 1))) {
+          if (peg_regex_test($this->peg_c201, $this->input_substr($this->peg_currPos, 1))) {
             $s0 = $this->input_substr($this->peg_currPos, 1);
             $this->peg_currPos++;
           } else {
             $s0 = $this->peg_FAILED;
             if ($this->peg_silentFails === 0) {
-                $this->peg_fail($this->peg_c200);
+                $this->peg_fail($this->peg_c202);
             }
           }
           if ($s0 === $this->peg_FAILED) {
-            if (peg_regex_test($this->peg_c201, $this->input_substr($this->peg_currPos, 1))) {
+            if (peg_regex_test($this->peg_c203, $this->input_substr($this->peg_currPos, 1))) {
               $s0 = $this->input_substr($this->peg_currPos, 1);
               $this->peg_currPos++;
             } else {
               $s0 = $this->peg_FAILED;
               if ($this->peg_silentFails === 0) {
-                  $this->peg_fail($this->peg_c202);
+                  $this->peg_fail($this->peg_c204);
               }
             }
             if ($s0 === $this->peg_FAILED) {
-              if (peg_regex_test($this->peg_c203, $this->input_substr($this->peg_currPos, 1))) {
+              if (peg_regex_test($this->peg_c205, $this->input_substr($this->peg_currPos, 1))) {
                 $s0 = $this->input_substr($this->peg_currPos, 1);
                 $this->peg_currPos++;
               } else {
                 $s0 = $this->peg_FAILED;
                 if ($this->peg_silentFails === 0) {
-                    $this->peg_fail($this->peg_c204);
+                    $this->peg_fail($this->peg_c206);
                 }
               }
             }
@@ -5952,7 +5954,7 @@ class MP_Parser {
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c194);
+            $this->peg_fail($this->peg_c196);
         }
       }
 
@@ -5972,20 +5974,20 @@ class MP_Parser {
       }
 
       $this->peg_silentFails++;
-      if (peg_regex_test($this->peg_c206, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c208, $this->input_substr($this->peg_currPos, 1))) {
         $s0 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c207);
+            $this->peg_fail($this->peg_c209);
         }
       }
       $this->peg_silentFails--;
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c205);
+            $this->peg_fail($this->peg_c207);
         }
       }
 
@@ -6005,20 +6007,20 @@ class MP_Parser {
       }
 
       $this->peg_silentFails++;
-      if (peg_regex_test($this->peg_c209, $this->input_substr($this->peg_currPos, 1))) {
+      if (peg_regex_test($this->peg_c211, $this->input_substr($this->peg_currPos, 1))) {
         $s0 = $this->input_substr($this->peg_currPos, 1);
         $this->peg_currPos++;
       } else {
         $s0 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c210);
+            $this->peg_fail($this->peg_c212);
         }
       }
       $this->peg_silentFails--;
       if ($s0 === $this->peg_FAILED) {
         $s1 = $this->peg_FAILED;
         if ($this->peg_silentFails === 0) {
-            $this->peg_fail($this->peg_c208);
+            $this->peg_fail($this->peg_c210);
         }
       }
 
@@ -6050,8 +6052,8 @@ class MP_Parser {
     $this->peg_c3 = array( "type" => "literal", "value" => "let ", "description" => "\"let \"" );
     $this->peg_c4 = " ";
     $this->peg_c5 = array( "type" => "literal", "value" => " ", "description" => "\" \"" );
-    $this->peg_c6 = ";";
-    $this->peg_c7 = array( "type" => "literal", "value" => ";", "description" => "\";\"" );
+    $this->peg_c6 = "/^[;\\\$]/";
+    $this->peg_c7 = array( "type" => "class", "value" => "[;\$]", "description" => "[;\$]" );
     $this->peg_c8 = array("type" => "other", "description" => "integer" );
     $this->peg_c9 = "/^[0-9]/";
     $this->peg_c10 = array( "type" => "class", "value" => "[0-9]", "description" => "[0-9]" );
@@ -6096,165 +6098,167 @@ class MP_Parser {
     $this->peg_c49 = array("type" => "other", "description" => "annotation" );
     $this->peg_c50 = "ignore";
     $this->peg_c51 = array( "type" => "literal", "value" => "ignore", "description" => "\"ignore\"" );
-    $this->peg_c52 = "function";
-    $this->peg_c53 = array( "type" => "literal", "value" => "function", "description" => "\"function\"" );
-    $this->peg_c54 = "=>";
-    $this->peg_c55 = array( "type" => "literal", "value" => "=>", "description" => "\"=>\"" );
-    $this->peg_c56 = "assume";
-    $this->peg_c57 = array( "type" => "literal", "value" => "assume", "description" => "\"assume\"" );
-    $this->peg_c58 = array("type" => "other", "description" => "identifier" );
-    $this->peg_c59 = "/^[a-zA-Z]/";
-    $this->peg_c60 = array( "type" => "class", "value" => "[a-zA-Z]", "description" => "[a-zA-Z]" );
-    $this->peg_c61 = "_";
-    $this->peg_c62 = array( "type" => "literal", "value" => "_", "description" => "\"_\"" );
-    $this->peg_c63 = "%";
-    $this->peg_c64 = array( "type" => "literal", "value" => "%", "description" => "\"%\"" );
-    $this->peg_c65 = ",";
-    $this->peg_c66 = array( "type" => "literal", "value" => ",", "description" => "\",\"" );
-    $this->peg_c67 = ":";
-    $this->peg_c68 = array( "type" => "literal", "value" => ":", "description" => "\":\"" );
-    $this->peg_c69 = "if";
-    $this->peg_c70 = array( "type" => "literal", "value" => "if", "description" => "\"if\"" );
-    $this->peg_c71 = "then";
-    $this->peg_c72 = array( "type" => "literal", "value" => "then", "description" => "\"then\"" );
-    $this->peg_c73 = "elseif";
-    $this->peg_c74 = array( "type" => "literal", "value" => "elseif", "description" => "\"elseif\"" );
-    $this->peg_c75 = "else";
-    $this->peg_c76 = array( "type" => "literal", "value" => "else", "description" => "\"else\"" );
-    $this->peg_c77 = "do";
-    $this->peg_c78 = array( "type" => "literal", "value" => "do", "description" => "\"do\"" );
-    $this->peg_c79 = "for";
-    $this->peg_c80 = array( "type" => "literal", "value" => "for", "description" => "\"for\"" );
-    $this->peg_c81 = "from";
-    $this->peg_c82 = array( "type" => "literal", "value" => "from", "description" => "\"from\"" );
-    $this->peg_c83 = "step";
-    $this->peg_c84 = array( "type" => "literal", "value" => "step", "description" => "\"step\"" );
-    $this->peg_c85 = "next";
-    $this->peg_c86 = array( "type" => "literal", "value" => "next", "description" => "\"next\"" );
-    $this->peg_c87 = "in";
-    $this->peg_c88 = array( "type" => "literal", "value" => "in", "description" => "\"in\"" );
-    $this->peg_c89 = "thru";
-    $this->peg_c90 = array( "type" => "literal", "value" => "thru", "description" => "\"thru\"" );
-    $this->peg_c91 = "while";
-    $this->peg_c92 = array( "type" => "literal", "value" => "while", "description" => "\"while\"" );
-    $this->peg_c93 = "unless";
-    $this->peg_c94 = array( "type" => "literal", "value" => "unless", "description" => "\"unless\"" );
-    $this->peg_c95 = "(";
-    $this->peg_c96 = array( "type" => "literal", "value" => "(", "description" => "\"(\"" );
-    $this->peg_c97 = ")";
-    $this->peg_c98 = array( "type" => "literal", "value" => ")", "description" => "\")\"" );
-    $this->peg_c99 = "#pm#";
-    $this->peg_c100 = array( "type" => "literal", "value" => "#pm#", "description" => "\"#pm#\"" );
-    $this->peg_c101 = "+-";
-    $this->peg_c102 = array( "type" => "literal", "value" => "+-", "description" => "\"+-\"" );
-    $this->peg_c103 = "-";
-    $this->peg_c104 = array( "type" => "literal", "value" => "-", "description" => "\"-\"" );
-    $this->peg_c105 = "+";
-    $this->peg_c106 = array( "type" => "literal", "value" => "+", "description" => "\"+\"" );
-    $this->peg_c107 = "''";
-    $this->peg_c108 = array( "type" => "literal", "value" => "''", "description" => "\"''\"" );
-    $this->peg_c109 = "'";
-    $this->peg_c110 = array( "type" => "literal", "value" => "'", "description" => "\"'\"" );
-    $this->peg_c111 = "not ";
-    $this->peg_c112 = array( "type" => "literal", "value" => "not ", "description" => "\"not \"" );
-    $this->peg_c113 = "nounnot ";
-    $this->peg_c114 = array( "type" => "literal", "value" => "nounnot ", "description" => "\"nounnot \"" );
-    $this->peg_c115 = "%not ";
-    $this->peg_c116 = array( "type" => "literal", "value" => "%not ", "description" => "\"%not \"" );
-    $this->peg_c117 = "?? ";
-    $this->peg_c118 = array( "type" => "literal", "value" => "?? ", "description" => "\"?? \"" );
-    $this->peg_c119 = "? ";
-    $this->peg_c120 = array( "type" => "literal", "value" => "? ", "description" => "\"? \"" );
-    $this->peg_c121 = "?";
-    $this->peg_c122 = array( "type" => "literal", "value" => "?", "description" => "\"?\"" );
-    $this->peg_c123 = "!!";
-    $this->peg_c124 = array( "type" => "literal", "value" => "!!", "description" => "\"!!\"" );
-    $this->peg_c125 = "!";
-    $this->peg_c126 = array( "type" => "literal", "value" => "!", "description" => "\"!\"" );
-    $this->peg_c127 = "**";
-    $this->peg_c128 = array( "type" => "literal", "value" => "**", "description" => "\"**\"" );
-    $this->peg_c129 = "^^";
-    $this->peg_c130 = array( "type" => "literal", "value" => "^^", "description" => "\"^^\"" );
-    $this->peg_c131 = "^";
-    $this->peg_c132 = array( "type" => "literal", "value" => "^", "description" => "\"^\"" );
-    $this->peg_c133 = "%and";
-    $this->peg_c134 = array( "type" => "literal", "value" => "%and", "description" => "\"%and\"" );
-    $this->peg_c135 = "%or";
-    $this->peg_c136 = array( "type" => "literal", "value" => "%or", "description" => "\"%or\"" );
-    $this->peg_c137 = "and";
-    $this->peg_c138 = array( "type" => "literal", "value" => "and", "description" => "\"and\"" );
-    $this->peg_c139 = "or";
-    $this->peg_c140 = array( "type" => "literal", "value" => "or", "description" => "\"or\"" );
-    $this->peg_c141 = "nounand";
-    $this->peg_c142 = array( "type" => "literal", "value" => "nounand", "description" => "\"nounand\"" );
-    $this->peg_c143 = "nounor";
-    $this->peg_c144 = array( "type" => "literal", "value" => "nounor", "description" => "\"nounor\"" );
-    $this->peg_c145 = "nand";
-    $this->peg_c146 = array( "type" => "literal", "value" => "nand", "description" => "\"nand\"" );
-    $this->peg_c147 = "nor";
-    $this->peg_c148 = array( "type" => "literal", "value" => "nor", "description" => "\"nor\"" );
-    $this->peg_c149 = "implies";
-    $this->peg_c150 = array( "type" => "literal", "value" => "implies", "description" => "\"implies\"" );
-    $this->peg_c151 = "xor";
-    $this->peg_c152 = array( "type" => "literal", "value" => "xor", "description" => "\"xor\"" );
-    $this->peg_c153 = "xnor";
-    $this->peg_c154 = array( "type" => "literal", "value" => "xnor", "description" => "\"xnor\"" );
-    $this->peg_c155 = "#";
-    $this->peg_c156 = array( "type" => "literal", "value" => "#", "description" => "\"#\"" );
-    $this->peg_c157 = "::=";
-    $this->peg_c158 = array( "type" => "literal", "value" => "::=", "description" => "\"::=\"" );
-    $this->peg_c159 = ":=";
-    $this->peg_c160 = array( "type" => "literal", "value" => ":=", "description" => "\":=\"" );
-    $this->peg_c161 = "::";
-    $this->peg_c162 = array( "type" => "literal", "value" => "::", "description" => "\"::\"" );
-    $this->peg_c163 = "<=";
-    $this->peg_c164 = array( "type" => "literal", "value" => "<=", "description" => "\"<=\"" );
-    $this->peg_c165 = "<";
-    $this->peg_c166 = array( "type" => "literal", "value" => "<", "description" => "\"<\"" );
-    $this->peg_c167 = ">=";
-    $this->peg_c168 = array( "type" => "literal", "value" => ">=", "description" => "\">=\"" );
-    $this->peg_c169 = ">";
-    $this->peg_c170 = array( "type" => "literal", "value" => ">", "description" => "\">\"" );
-    $this->peg_c171 = "~";
-    $this->peg_c172 = array( "type" => "literal", "value" => "~", "description" => "\"~\"" );
-    $this->peg_c173 = "@@IS@@";
-    $this->peg_c174 = array( "type" => "literal", "value" => "@@IS@@", "description" => "\"@@IS@@\"" );
-    $this->peg_c175 = "@@Is@@";
-    $this->peg_c176 = array( "type" => "literal", "value" => "@@Is@@", "description" => "\"@@Is@@\"" );
-    $this->peg_c177 = "nounnot";
-    $this->peg_c178 = array( "type" => "literal", "value" => "nounnot", "description" => "\"nounnot\"" );
-    $this->peg_c179 = "not";
-    $this->peg_c180 = array( "type" => "literal", "value" => "not", "description" => "\"not\"" );
-    $this->peg_c181 = "|";
-    $this->peg_c182 = array( "type" => "literal", "value" => "|", "description" => "\"|\"" );
-    $this->peg_c183 = "[";
-    $this->peg_c184 = array( "type" => "literal", "value" => "[", "description" => "\"[\"" );
-    $this->peg_c185 = "]";
-    $this->peg_c186 = array( "type" => "literal", "value" => "]", "description" => "\"]\"" );
-    $this->peg_c187 = "{";
-    $this->peg_c188 = array( "type" => "literal", "value" => "{", "description" => "\"{\"" );
-    $this->peg_c189 = "}";
-    $this->peg_c190 = array( "type" => "literal", "value" => "}", "description" => "\"}\"" );
-    $this->peg_c191 = array("type" => "other", "description" => "whitespace" );
-    $this->peg_c192 = "/^[ \\t\\n\\r\\x0B\\f \\x{FEFF}  \\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}\\n-\\r]/";
-    $this->peg_c193 = array( "type" => "class", "value" => "[ \t\n\r\x0B\f \x{FEFF}  \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]", "description" => "[ \t\n\r\x0B\f \x{FEFF}  \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]" );
-    $this->peg_c194 = array("type" => "other", "description" => "unicode letter character" );
-    $this->peg_c195 = "/^[a-zµß-öø-\\x{00FF}\\x{0101}\\x{0103}\\x{0105}\\x{0107}\\x{0109}\\x{010B}\\x{010D}\\x{010F}\\x{0111}\\x{0113}\\x{0115}\\x{0117}\\x{0119}\\x{011B}\\x{011D}\\x{011F}\\x{0121}\\x{0123}\\x{0125}\\x{0127}\\x{0129}\\x{012B}\\x{012D}\\x{012F}\\x{0131}\\x{0133}\\x{0135}\\x{0137}-\\x{0138}\\x{013A}\\x{013C}\\x{013E}\\x{0140}\\x{0142}\\x{0144}\\x{0146}\\x{0148}-\\x{0149}\\x{014B}\\x{014D}\\x{014F}\\x{0151}\\x{0153}\\x{0155}\\x{0157}\\x{0159}\\x{015B}\\x{015D}\\x{015F}\\x{0161}\\x{0163}\\x{0165}\\x{0167}\\x{0169}\\x{016B}\\x{016D}\\x{016F}\\x{0171}\\x{0173}\\x{0175}\\x{0177}\\x{017A}\\x{017C}\\x{017E}-\\x{0180}\\x{0183}\\x{0185}\\x{0188}\\x{018C}-\\x{018D}\\x{0192}\\x{0195}\\x{0199}-\\x{019B}\\x{019E}\\x{01A1}\\x{01A3}\\x{01A5}\\x{01A8}\\x{01AA}-\\x{01AB}\\x{01AD}\\x{01B0}\\x{01B4}\\x{01B6}\\x{01B9}-\\x{01BA}\\x{01BD}-\\x{01BF}\\x{01C6}\\x{01C9}\\x{01CC}\\x{01CE}\\x{01D0}\\x{01D2}\\x{01D4}\\x{01D6}\\x{01D8}\\x{01DA}\\x{01DC}-\\x{01DD}\\x{01DF}\\x{01E1}\\x{01E3}\\x{01E5}\\x{01E7}\\x{01E9}\\x{01EB}\\x{01ED}\\x{01EF}-\\x{01F0}\\x{01F3}\\x{01F5}\\x{01F9}\\x{01FB}\\x{01FD}\\x{01FF}\\x{0201}\\x{0203}\\x{0205}\\x{0207}\\x{0209}\\x{020B}\\x{020D}\\x{020F}\\x{0211}\\x{0213}\\x{0215}\\x{0217}\\x{0219}\\x{021B}\\x{021D}\\x{021F}\\x{0221}\\x{0223}\\x{0225}\\x{0227}\\x{0229}\\x{022B}\\x{022D}\\x{022F}\\x{0231}\\x{0233}-\\x{0239}\\x{023C}\\x{023F}-\\x{0240}\\x{0242}\\x{0247}\\x{0249}\\x{024B}\\x{024D}\\x{024F}-\\x{0293}\\x{0295}-\\x{02AF}\\x{0371}\\x{0373}\\x{0377}\\x{037B}-\\x{037D}\\x{0390}\\x{03AC}-\\x{03CE}\\x{03D0}-\\x{03D1}\\x{03D5}-\\x{03D7}\\x{03D9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03E3}\\x{03E5}\\x{03E7}\\x{03E9}\\x{03EB}\\x{03ED}\\x{03EF}-\\x{03F3}\\x{03F5}\\x{03F8}\\x{03FB}-\\x{03FC}\\x{0430}-\\x{045F}\\x{0461}\\x{0463}\\x{0465}\\x{0467}\\x{0469}\\x{046B}\\x{046D}\\x{046F}\\x{0471}\\x{0473}\\x{0475}\\x{0477}\\x{0479}\\x{047B}\\x{047D}\\x{047F}\\x{0481}\\x{048B}\\x{048D}\\x{048F}\\x{0491}\\x{0493}\\x{0495}\\x{0497}\\x{0499}\\x{049B}\\x{049D}\\x{049F}\\x{04A1}\\x{04A3}\\x{04A5}\\x{04A7}\\x{04A9}\\x{04AB}\\x{04AD}\\x{04AF}\\x{04B1}\\x{04B3}\\x{04B5}\\x{04B7}\\x{04B9}\\x{04BB}\\x{04BD}\\x{04BF}\\x{04C2}\\x{04C4}\\x{04C6}\\x{04C8}\\x{04CA}\\x{04CC}\\x{04CE}-\\x{04CF}\\x{04D1}\\x{04D3}\\x{04D5}\\x{04D7}\\x{04D9}\\x{04DB}\\x{04DD}\\x{04DF}\\x{04E1}\\x{04E3}\\x{04E5}\\x{04E7}\\x{04E9}\\x{04EB}\\x{04ED}\\x{04EF}\\x{04F1}\\x{04F3}\\x{04F5}\\x{04F7}\\x{04F9}\\x{04FB}\\x{04FD}\\x{04FF}\\x{0501}\\x{0503}\\x{0505}\\x{0507}\\x{0509}\\x{050B}\\x{050D}\\x{050F}\\x{0511}\\x{0513}\\x{0515}\\x{0517}\\x{0519}\\x{051B}\\x{051D}\\x{051F}\\x{0521}\\x{0523}\\x{0525}\\x{0527}\\x{0529}\\x{052B}\\x{052D}\\x{052F}\\x{0561}-\\x{0587}\\x{13F8}-\\x{13FD}\\x{1D00}-\\x{1D2B}\\x{1D6B}-\\x{1D77}\\x{1D79}-\\x{1D9A}\\x{1E01}\\x{1E03}\\x{1E05}\\x{1E07}\\x{1E09}\\x{1E0B}\\x{1E0D}\\x{1E0F}\\x{1E11}\\x{1E13}\\x{1E15}\\x{1E17}\\x{1E19}\\x{1E1B}\\x{1E1D}\\x{1E1F}\\x{1E21}\\x{1E23}\\x{1E25}\\x{1E27}\\x{1E29}\\x{1E2B}\\x{1E2D}\\x{1E2F}\\x{1E31}\\x{1E33}\\x{1E35}\\x{1E37}\\x{1E39}\\x{1E3B}\\x{1E3D}\\x{1E3F}\\x{1E41}\\x{1E43}\\x{1E45}\\x{1E47}\\x{1E49}\\x{1E4B}\\x{1E4D}\\x{1E4F}\\x{1E51}\\x{1E53}\\x{1E55}\\x{1E57}\\x{1E59}\\x{1E5B}\\x{1E5D}\\x{1E5F}\\x{1E61}\\x{1E63}\\x{1E65}\\x{1E67}\\x{1E69}\\x{1E6B}\\x{1E6D}\\x{1E6F}\\x{1E71}\\x{1E73}\\x{1E75}\\x{1E77}\\x{1E79}\\x{1E7B}\\x{1E7D}\\x{1E7F}\\x{1E81}\\x{1E83}\\x{1E85}\\x{1E87}\\x{1E89}\\x{1E8B}\\x{1E8D}\\x{1E8F}\\x{1E91}\\x{1E93}\\x{1E95}-\\x{1E9D}\\x{1E9F}\\x{1EA1}\\x{1EA3}\\x{1EA5}\\x{1EA7}\\x{1EA9}\\x{1EAB}\\x{1EAD}\\x{1EAF}\\x{1EB1}\\x{1EB3}\\x{1EB5}\\x{1EB7}\\x{1EB9}\\x{1EBB}\\x{1EBD}\\x{1EBF}\\x{1EC1}\\x{1EC3}\\x{1EC5}\\x{1EC7}\\x{1EC9}\\x{1ECB}\\x{1ECD}\\x{1ECF}\\x{1ED1}\\x{1ED3}\\x{1ED5}\\x{1ED7}\\x{1ED9}\\x{1EDB}\\x{1EDD}\\x{1EDF}\\x{1EE1}\\x{1EE3}\\x{1EE5}\\x{1EE7}\\x{1EE9}\\x{1EEB}\\x{1EED}\\x{1EEF}\\x{1EF1}\\x{1EF3}\\x{1EF5}\\x{1EF7}\\x{1EF9}\\x{1EFB}\\x{1EFD}\\x{1EFF}-\\x{1F07}\\x{1F10}-\\x{1F15}\\x{1F20}-\\x{1F27}\\x{1F30}-\\x{1F37}\\x{1F40}-\\x{1F45}\\x{1F50}-\\x{1F57}\\x{1F60}-\\x{1F67}\\x{1F70}-\\x{1F7D}\\x{1F80}-\\x{1F87}\\x{1F90}-\\x{1F97}\\x{1FA0}-\\x{1FA7}\\x{1FB0}-\\x{1FB4}\\x{1FB6}-\\x{1FB7}\\x{1FBE}\\x{1FC2}-\\x{1FC4}\\x{1FC6}-\\x{1FC7}\\x{1FD0}-\\x{1FD3}\\x{1FD6}-\\x{1FD7}\\x{1FE0}-\\x{1FE7}\\x{1FF2}-\\x{1FF4}\\x{1FF6}-\\x{1FF7}\\x{210A}\\x{210E}-\\x{210F}\\x{2113}\\x{212F}\\x{2134}\\x{2139}\\x{213C}-\\x{213D}\\x{2146}-\\x{2149}\\x{214E}\\x{2184}\\x{2C30}-\\x{2C5E}\\x{2C61}\\x{2C65}-\\x{2C66}\\x{2C68}\\x{2C6A}\\x{2C6C}\\x{2C71}\\x{2C73}-\\x{2C74}\\x{2C76}-\\x{2C7B}\\x{2C81}\\x{2C83}\\x{2C85}\\x{2C87}\\x{2C89}\\x{2C8B}\\x{2C8D}\\x{2C8F}\\x{2C91}\\x{2C93}\\x{2C95}\\x{2C97}\\x{2C99}\\x{2C9B}\\x{2C9D}\\x{2C9F}\\x{2CA1}\\x{2CA3}\\x{2CA5}\\x{2CA7}\\x{2CA9}\\x{2CAB}\\x{2CAD}\\x{2CAF}\\x{2CB1}\\x{2CB3}\\x{2CB5}\\x{2CB7}\\x{2CB9}\\x{2CBB}\\x{2CBD}\\x{2CBF}\\x{2CC1}\\x{2CC3}\\x{2CC5}\\x{2CC7}\\x{2CC9}\\x{2CCB}\\x{2CCD}\\x{2CCF}\\x{2CD1}\\x{2CD3}\\x{2CD5}\\x{2CD7}\\x{2CD9}\\x{2CDB}\\x{2CDD}\\x{2CDF}\\x{2CE1}\\x{2CE3}-\\x{2CE4}\\x{2CEC}\\x{2CEE}\\x{2CF3}\\x{2D00}-\\x{2D25}\\x{2D27}\\x{2D2D}\\x{A641}\\x{A643}\\x{A645}\\x{A647}\\x{A649}\\x{A64B}\\x{A64D}\\x{A64F}\\x{A651}\\x{A653}\\x{A655}\\x{A657}\\x{A659}\\x{A65B}\\x{A65D}\\x{A65F}\\x{A661}\\x{A663}\\x{A665}\\x{A667}\\x{A669}\\x{A66B}\\x{A66D}\\x{A681}\\x{A683}\\x{A685}\\x{A687}\\x{A689}\\x{A68B}\\x{A68D}\\x{A68F}\\x{A691}\\x{A693}\\x{A695}\\x{A697}\\x{A699}\\x{A69B}\\x{A723}\\x{A725}\\x{A727}\\x{A729}\\x{A72B}\\x{A72D}\\x{A72F}-\\x{A731}\\x{A733}\\x{A735}\\x{A737}\\x{A739}\\x{A73B}\\x{A73D}\\x{A73F}\\x{A741}\\x{A743}\\x{A745}\\x{A747}\\x{A749}\\x{A74B}\\x{A74D}\\x{A74F}\\x{A751}\\x{A753}\\x{A755}\\x{A757}\\x{A759}\\x{A75B}\\x{A75D}\\x{A75F}\\x{A761}\\x{A763}\\x{A765}\\x{A767}\\x{A769}\\x{A76B}\\x{A76D}\\x{A76F}\\x{A771}-\\x{A778}\\x{A77A}\\x{A77C}\\x{A77F}\\x{A781}\\x{A783}\\x{A785}\\x{A787}\\x{A78C}\\x{A78E}\\x{A791}\\x{A793}-\\x{A795}\\x{A797}\\x{A799}\\x{A79B}\\x{A79D}\\x{A79F}\\x{A7A1}\\x{A7A3}\\x{A7A5}\\x{A7A7}\\x{A7A9}\\x{A7B5}\\x{A7B7}\\x{A7FA}\\x{AB30}-\\x{AB5A}\\x{AB60}-\\x{AB65}\\x{AB70}-\\x{ABBF}\\x{FB00}-\\x{FB06}\\x{FB13}-\\x{FB17}\\x{FF41}-\\x{FF5A}]/";
-    $this->peg_c196 = array( "type" => "class", "value" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]", "description" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]" );
-    $this->peg_c197 = "/^[\\x{02B0}-\\x{02C1}\\x{02C6}-\\x{02D1}\\x{02E0}-\\x{02E4}\\x{02EC}\\x{02EE}\\x{0374}\\x{037A}\\x{0559}\\x{0640}\\x{06E5}-\\x{06E6}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{081A}\\x{0824}\\x{0828}\\x{0971}\\x{0E46}\\x{0EC6}\\x{10FC}\\x{17D7}\\x{1843}\\x{1AA7}\\x{1C78}-\\x{1C7D}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{2C7C}-\\x{2C7D}\\x{2D6F}\\x{2E2F}\\x{3005}\\x{3031}-\\x{3035}\\x{303B}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A717}-\\x{A71F}\\x{A770}\\x{A788}\\x{A7F8}-\\x{A7F9}\\x{A9CF}\\x{A9E6}\\x{AA70}\\x{AADD}\\x{AAF3}-\\x{AAF4}\\x{AB5C}-\\x{AB5F}\\x{FF70}\\x{FF9E}-\\x{FF9F}]/";
-    $this->peg_c198 = array( "type" => "class", "value" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]", "description" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]" );
-    $this->peg_c199 = "/^[ªº\\x{01BB}\\x{01C0}-\\x{01C3}\\x{0294}\\x{05D0}-\\x{05EA}\\x{05F0}-\\x{05F2}\\x{0620}-\\x{063F}\\x{0641}-\\x{064A}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D5}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0710}\\x{0712}-\\x{072F}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07CA}-\\x{07EA}\\x{0800}-\\x{0815}\\x{0840}-\\x{0858}\\x{08A0}-\\x{08B4}\\x{0904}-\\x{0939}\\x{093D}\\x{0950}\\x{0958}-\\x{0961}\\x{0972}-\\x{0980}\\x{0985}-\\x{098C}\\x{098F}-\\x{0990}\\x{0993}-\\x{09A8}\\x{09AA}-\\x{09B0}\\x{09B2}\\x{09B6}-\\x{09B9}\\x{09BD}\\x{09CE}\\x{09DC}-\\x{09DD}\\x{09DF}-\\x{09E1}\\x{09F0}-\\x{09F1}\\x{0A05}-\\x{0A0A}\\x{0A0F}-\\x{0A10}\\x{0A13}-\\x{0A28}\\x{0A2A}-\\x{0A30}\\x{0A32}-\\x{0A33}\\x{0A35}-\\x{0A36}\\x{0A38}-\\x{0A39}\\x{0A59}-\\x{0A5C}\\x{0A5E}\\x{0A72}-\\x{0A74}\\x{0A85}-\\x{0A8D}\\x{0A8F}-\\x{0A91}\\x{0A93}-\\x{0AA8}\\x{0AAA}-\\x{0AB0}\\x{0AB2}-\\x{0AB3}\\x{0AB5}-\\x{0AB9}\\x{0ABD}\\x{0AD0}\\x{0AE0}-\\x{0AE1}\\x{0AF9}\\x{0B05}-\\x{0B0C}\\x{0B0F}-\\x{0B10}\\x{0B13}-\\x{0B28}\\x{0B2A}-\\x{0B30}\\x{0B32}-\\x{0B33}\\x{0B35}-\\x{0B39}\\x{0B3D}\\x{0B5C}-\\x{0B5D}\\x{0B5F}-\\x{0B61}\\x{0B71}\\x{0B83}\\x{0B85}-\\x{0B8A}\\x{0B8E}-\\x{0B90}\\x{0B92}-\\x{0B95}\\x{0B99}-\\x{0B9A}\\x{0B9C}\\x{0B9E}-\\x{0B9F}\\x{0BA3}-\\x{0BA4}\\x{0BA8}-\\x{0BAA}\\x{0BAE}-\\x{0BB9}\\x{0BD0}\\x{0C05}-\\x{0C0C}\\x{0C0E}-\\x{0C10}\\x{0C12}-\\x{0C28}\\x{0C2A}-\\x{0C39}\\x{0C3D}\\x{0C58}-\\x{0C5A}\\x{0C60}-\\x{0C61}\\x{0C85}-\\x{0C8C}\\x{0C8E}-\\x{0C90}\\x{0C92}-\\x{0CA8}\\x{0CAA}-\\x{0CB3}\\x{0CB5}-\\x{0CB9}\\x{0CBD}\\x{0CDE}\\x{0CE0}-\\x{0CE1}\\x{0CF1}-\\x{0CF2}\\x{0D05}-\\x{0D0C}\\x{0D0E}-\\x{0D10}\\x{0D12}-\\x{0D3A}\\x{0D3D}\\x{0D4E}\\x{0D5F}-\\x{0D61}\\x{0D7A}-\\x{0D7F}\\x{0D85}-\\x{0D96}\\x{0D9A}-\\x{0DB1}\\x{0DB3}-\\x{0DBB}\\x{0DBD}\\x{0DC0}-\\x{0DC6}\\x{0E01}-\\x{0E30}\\x{0E32}-\\x{0E33}\\x{0E40}-\\x{0E45}\\x{0E81}-\\x{0E82}\\x{0E84}\\x{0E87}-\\x{0E88}\\x{0E8A}\\x{0E8D}\\x{0E94}-\\x{0E97}\\x{0E99}-\\x{0E9F}\\x{0EA1}-\\x{0EA3}\\x{0EA5}\\x{0EA7}\\x{0EAA}-\\x{0EAB}\\x{0EAD}-\\x{0EB0}\\x{0EB2}-\\x{0EB3}\\x{0EBD}\\x{0EC0}-\\x{0EC4}\\x{0EDC}-\\x{0EDF}\\x{0F00}\\x{0F40}-\\x{0F47}\\x{0F49}-\\x{0F6C}\\x{0F88}-\\x{0F8C}\\x{1000}-\\x{102A}\\x{103F}\\x{1050}-\\x{1055}\\x{105A}-\\x{105D}\\x{1061}\\x{1065}-\\x{1066}\\x{106E}-\\x{1070}\\x{1075}-\\x{1081}\\x{108E}\\x{10D0}-\\x{10FA}\\x{10FD}-\\x{1248}\\x{124A}-\\x{124D}\\x{1250}-\\x{1256}\\x{1258}\\x{125A}-\\x{125D}\\x{1260}-\\x{1288}\\x{128A}-\\x{128D}\\x{1290}-\\x{12B0}\\x{12B2}-\\x{12B5}\\x{12B8}-\\x{12BE}\\x{12C0}\\x{12C2}-\\x{12C5}\\x{12C8}-\\x{12D6}\\x{12D8}-\\x{1310}\\x{1312}-\\x{1315}\\x{1318}-\\x{135A}\\x{1380}-\\x{138F}\\x{1401}-\\x{166C}\\x{166F}-\\x{167F}\\x{1681}-\\x{169A}\\x{16A0}-\\x{16EA}\\x{16F1}-\\x{16F8}\\x{1700}-\\x{170C}\\x{170E}-\\x{1711}\\x{1720}-\\x{1731}\\x{1740}-\\x{1751}\\x{1760}-\\x{176C}\\x{176E}-\\x{1770}\\x{1780}-\\x{17B3}\\x{17DC}\\x{1820}-\\x{1842}\\x{1844}-\\x{1877}\\x{1880}-\\x{18A8}\\x{18AA}\\x{18B0}-\\x{18F5}\\x{1900}-\\x{191E}\\x{1950}-\\x{196D}\\x{1970}-\\x{1974}\\x{1980}-\\x{19AB}\\x{19B0}-\\x{19C9}\\x{1A00}-\\x{1A16}\\x{1A20}-\\x{1A54}\\x{1B05}-\\x{1B33}\\x{1B45}-\\x{1B4B}\\x{1B83}-\\x{1BA0}\\x{1BAE}-\\x{1BAF}\\x{1BBA}-\\x{1BE5}\\x{1C00}-\\x{1C23}\\x{1C4D}-\\x{1C4F}\\x{1C5A}-\\x{1C77}\\x{1CE9}-\\x{1CEC}\\x{1CEE}-\\x{1CF1}\\x{1CF5}-\\x{1CF6}\\x{2135}-\\x{2138}\\x{2D30}-\\x{2D67}\\x{2D80}-\\x{2D96}\\x{2DA0}-\\x{2DA6}\\x{2DA8}-\\x{2DAE}\\x{2DB0}-\\x{2DB6}\\x{2DB8}-\\x{2DBE}\\x{2DC0}-\\x{2DC6}\\x{2DC8}-\\x{2DCE}\\x{2DD0}-\\x{2DD6}\\x{2DD8}-\\x{2DDE}\\x{3006}\\x{303C}\\x{3041}-\\x{3096}\\x{309F}\\x{30A1}-\\x{30FA}\\x{30FF}\\x{3105}-\\x{312D}\\x{3131}-\\x{318E}\\x{31A0}-\\x{31BA}\\x{31F0}-\\x{31FF}\\x{3400}-\\x{4DB5}\\x{4E00}-\\x{9FD5}\\x{A000}-\\x{A014}\\x{A016}-\\x{A48C}\\x{A4D0}-\\x{A4F7}\\x{A500}-\\x{A60B}\\x{A610}-\\x{A61F}\\x{A62A}-\\x{A62B}\\x{A66E}\\x{A6A0}-\\x{A6E5}\\x{A78F}\\x{A7F7}\\x{A7FB}-\\x{A801}\\x{A803}-\\x{A805}\\x{A807}-\\x{A80A}\\x{A80C}-\\x{A822}\\x{A840}-\\x{A873}\\x{A882}-\\x{A8B3}\\x{A8F2}-\\x{A8F7}\\x{A8FB}\\x{A8FD}\\x{A90A}-\\x{A925}\\x{A930}-\\x{A946}\\x{A960}-\\x{A97C}\\x{A984}-\\x{A9B2}\\x{A9E0}-\\x{A9E4}\\x{A9E7}-\\x{A9EF}\\x{A9FA}-\\x{A9FE}\\x{AA00}-\\x{AA28}\\x{AA40}-\\x{AA42}\\x{AA44}-\\x{AA4B}\\x{AA60}-\\x{AA6F}\\x{AA71}-\\x{AA76}\\x{AA7A}\\x{AA7E}-\\x{AAAF}\\x{AAB1}\\x{AAB5}-\\x{AAB6}\\x{AAB9}-\\x{AABD}\\x{AAC0}\\x{AAC2}\\x{AADB}-\\x{AADC}\\x{AAE0}-\\x{AAEA}\\x{AAF2}\\x{AB01}-\\x{AB06}\\x{AB09}-\\x{AB0E}\\x{AB11}-\\x{AB16}\\x{AB20}-\\x{AB26}\\x{AB28}-\\x{AB2E}\\x{ABC0}-\\x{ABE2}\\x{AC00}-\\x{D7A3}\\x{D7B0}-\\x{D7C6}\\x{D7CB}-\\x{D7FB}\\x{F900}-\\x{FA6D}\\x{FA70}-\\x{FAD9}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB38}-\\x{FB3C}\\x{FB3E}\\x{FB40}-\\x{FB41}\\x{FB43}-\\x{FB44}\\x{FB46}-\\x{FBB1}\\x{FBD3}-\\x{FD3D}\\x{FD50}-\\x{FD8F}\\x{FD92}-\\x{FDC7}\\x{FDF0}-\\x{FDFB}\\x{FE70}-\\x{FE74}\\x{FE76}-\\x{FEFC}\\x{FF66}-\\x{FF6F}\\x{FF71}-\\x{FF9D}\\x{FFA0}-\\x{FFBE}\\x{FFC2}-\\x{FFC7}\\x{FFCA}-\\x{FFCF}\\x{FFD2}-\\x{FFD7}\\x{FFDA}-\\x{FFDC}]/";
-    $this->peg_c200 = array( "type" => "class", "value" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]", "description" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]" );
-    $this->peg_c201 = "/^[\\x{01C5}\\x{01C8}\\x{01CB}\\x{01F2}\\x{1F88}-\\x{1F8F}\\x{1F98}-\\x{1F9F}\\x{1FA8}-\\x{1FAF}\\x{1FBC}\\x{1FCC}\\x{1FFC}]/";
-    $this->peg_c202 = array( "type" => "class", "value" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]", "description" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]" );
-    $this->peg_c203 = "/^[A-ZÀ-ÖØ-Þ\\x{0100}\\x{0102}\\x{0104}\\x{0106}\\x{0108}\\x{010A}\\x{010C}\\x{010E}\\x{0110}\\x{0112}\\x{0114}\\x{0116}\\x{0118}\\x{011A}\\x{011C}\\x{011E}\\x{0120}\\x{0122}\\x{0124}\\x{0126}\\x{0128}\\x{012A}\\x{012C}\\x{012E}\\x{0130}\\x{0132}\\x{0134}\\x{0136}\\x{0139}\\x{013B}\\x{013D}\\x{013F}\\x{0141}\\x{0143}\\x{0145}\\x{0147}\\x{014A}\\x{014C}\\x{014E}\\x{0150}\\x{0152}\\x{0154}\\x{0156}\\x{0158}\\x{015A}\\x{015C}\\x{015E}\\x{0160}\\x{0162}\\x{0164}\\x{0166}\\x{0168}\\x{016A}\\x{016C}\\x{016E}\\x{0170}\\x{0172}\\x{0174}\\x{0176}\\x{0178}-\\x{0179}\\x{017B}\\x{017D}\\x{0181}-\\x{0182}\\x{0184}\\x{0186}-\\x{0187}\\x{0189}-\\x{018B}\\x{018E}-\\x{0191}\\x{0193}-\\x{0194}\\x{0196}-\\x{0198}\\x{019C}-\\x{019D}\\x{019F}-\\x{01A0}\\x{01A2}\\x{01A4}\\x{01A6}-\\x{01A7}\\x{01A9}\\x{01AC}\\x{01AE}-\\x{01AF}\\x{01B1}-\\x{01B3}\\x{01B5}\\x{01B7}-\\x{01B8}\\x{01BC}\\x{01C4}\\x{01C7}\\x{01CA}\\x{01CD}\\x{01CF}\\x{01D1}\\x{01D3}\\x{01D5}\\x{01D7}\\x{01D9}\\x{01DB}\\x{01DE}\\x{01E0}\\x{01E2}\\x{01E4}\\x{01E6}\\x{01E8}\\x{01EA}\\x{01EC}\\x{01EE}\\x{01F1}\\x{01F4}\\x{01F6}-\\x{01F8}\\x{01FA}\\x{01FC}\\x{01FE}\\x{0200}\\x{0202}\\x{0204}\\x{0206}\\x{0208}\\x{020A}\\x{020C}\\x{020E}\\x{0210}\\x{0212}\\x{0214}\\x{0216}\\x{0218}\\x{021A}\\x{021C}\\x{021E}\\x{0220}\\x{0222}\\x{0224}\\x{0226}\\x{0228}\\x{022A}\\x{022C}\\x{022E}\\x{0230}\\x{0232}\\x{023A}-\\x{023B}\\x{023D}-\\x{023E}\\x{0241}\\x{0243}-\\x{0246}\\x{0248}\\x{024A}\\x{024C}\\x{024E}\\x{0370}\\x{0372}\\x{0376}\\x{037F}\\x{0386}\\x{0388}-\\x{038A}\\x{038C}\\x{038E}-\\x{038F}\\x{0391}-\\x{03A1}\\x{03A3}-\\x{03AB}\\x{03CF}\\x{03D2}-\\x{03D4}\\x{03D8}\\x{03DA}\\x{03DC}\\x{03DE}\\x{03E0}\\x{03E2}\\x{03E4}\\x{03E6}\\x{03E8}\\x{03EA}\\x{03EC}\\x{03EE}\\x{03F4}\\x{03F7}\\x{03F9}-\\x{03FA}\\x{03FD}-\\x{042F}\\x{0460}\\x{0462}\\x{0464}\\x{0466}\\x{0468}\\x{046A}\\x{046C}\\x{046E}\\x{0470}\\x{0472}\\x{0474}\\x{0476}\\x{0478}\\x{047A}\\x{047C}\\x{047E}\\x{0480}\\x{048A}\\x{048C}\\x{048E}\\x{0490}\\x{0492}\\x{0494}\\x{0496}\\x{0498}\\x{049A}\\x{049C}\\x{049E}\\x{04A0}\\x{04A2}\\x{04A4}\\x{04A6}\\x{04A8}\\x{04AA}\\x{04AC}\\x{04AE}\\x{04B0}\\x{04B2}\\x{04B4}\\x{04B6}\\x{04B8}\\x{04BA}\\x{04BC}\\x{04BE}\\x{04C0}-\\x{04C1}\\x{04C3}\\x{04C5}\\x{04C7}\\x{04C9}\\x{04CB}\\x{04CD}\\x{04D0}\\x{04D2}\\x{04D4}\\x{04D6}\\x{04D8}\\x{04DA}\\x{04DC}\\x{04DE}\\x{04E0}\\x{04E2}\\x{04E4}\\x{04E6}\\x{04E8}\\x{04EA}\\x{04EC}\\x{04EE}\\x{04F0}\\x{04F2}\\x{04F4}\\x{04F6}\\x{04F8}\\x{04FA}\\x{04FC}\\x{04FE}\\x{0500}\\x{0502}\\x{0504}\\x{0506}\\x{0508}\\x{050A}\\x{050C}\\x{050E}\\x{0510}\\x{0512}\\x{0514}\\x{0516}\\x{0518}\\x{051A}\\x{051C}\\x{051E}\\x{0520}\\x{0522}\\x{0524}\\x{0526}\\x{0528}\\x{052A}\\x{052C}\\x{052E}\\x{0531}-\\x{0556}\\x{10A0}-\\x{10C5}\\x{10C7}\\x{10CD}\\x{13A0}-\\x{13F5}\\x{1E00}\\x{1E02}\\x{1E04}\\x{1E06}\\x{1E08}\\x{1E0A}\\x{1E0C}\\x{1E0E}\\x{1E10}\\x{1E12}\\x{1E14}\\x{1E16}\\x{1E18}\\x{1E1A}\\x{1E1C}\\x{1E1E}\\x{1E20}\\x{1E22}\\x{1E24}\\x{1E26}\\x{1E28}\\x{1E2A}\\x{1E2C}\\x{1E2E}\\x{1E30}\\x{1E32}\\x{1E34}\\x{1E36}\\x{1E38}\\x{1E3A}\\x{1E3C}\\x{1E3E}\\x{1E40}\\x{1E42}\\x{1E44}\\x{1E46}\\x{1E48}\\x{1E4A}\\x{1E4C}\\x{1E4E}\\x{1E50}\\x{1E52}\\x{1E54}\\x{1E56}\\x{1E58}\\x{1E5A}\\x{1E5C}\\x{1E5E}\\x{1E60}\\x{1E62}\\x{1E64}\\x{1E66}\\x{1E68}\\x{1E6A}\\x{1E6C}\\x{1E6E}\\x{1E70}\\x{1E72}\\x{1E74}\\x{1E76}\\x{1E78}\\x{1E7A}\\x{1E7C}\\x{1E7E}\\x{1E80}\\x{1E82}\\x{1E84}\\x{1E86}\\x{1E88}\\x{1E8A}\\x{1E8C}\\x{1E8E}\\x{1E90}\\x{1E92}\\x{1E94}\\x{1E9E}\\x{1EA0}\\x{1EA2}\\x{1EA4}\\x{1EA6}\\x{1EA8}\\x{1EAA}\\x{1EAC}\\x{1EAE}\\x{1EB0}\\x{1EB2}\\x{1EB4}\\x{1EB6}\\x{1EB8}\\x{1EBA}\\x{1EBC}\\x{1EBE}\\x{1EC0}\\x{1EC2}\\x{1EC4}\\x{1EC6}\\x{1EC8}\\x{1ECA}\\x{1ECC}\\x{1ECE}\\x{1ED0}\\x{1ED2}\\x{1ED4}\\x{1ED6}\\x{1ED8}\\x{1EDA}\\x{1EDC}\\x{1EDE}\\x{1EE0}\\x{1EE2}\\x{1EE4}\\x{1EE6}\\x{1EE8}\\x{1EEA}\\x{1EEC}\\x{1EEE}\\x{1EF0}\\x{1EF2}\\x{1EF4}\\x{1EF6}\\x{1EF8}\\x{1EFA}\\x{1EFC}\\x{1EFE}\\x{1F08}-\\x{1F0F}\\x{1F18}-\\x{1F1D}\\x{1F28}-\\x{1F2F}\\x{1F38}-\\x{1F3F}\\x{1F48}-\\x{1F4D}\\x{1F59}\\x{1F5B}\\x{1F5D}\\x{1F5F}\\x{1F68}-\\x{1F6F}\\x{1FB8}-\\x{1FBB}\\x{1FC8}-\\x{1FCB}\\x{1FD8}-\\x{1FDB}\\x{1FE8}-\\x{1FEC}\\x{1FF8}-\\x{1FFB}\\x{2102}\\x{2107}\\x{210B}-\\x{210D}\\x{2110}-\\x{2112}\\x{2115}\\x{2119}-\\x{211D}\\x{2124}\\x{2126}\\x{2128}\\x{212A}-\\x{212D}\\x{2130}-\\x{2133}\\x{213E}-\\x{213F}\\x{2145}\\x{2183}\\x{2C00}-\\x{2C2E}\\x{2C60}\\x{2C62}-\\x{2C64}\\x{2C67}\\x{2C69}\\x{2C6B}\\x{2C6D}-\\x{2C70}\\x{2C72}\\x{2C75}\\x{2C7E}-\\x{2C80}\\x{2C82}\\x{2C84}\\x{2C86}\\x{2C88}\\x{2C8A}\\x{2C8C}\\x{2C8E}\\x{2C90}\\x{2C92}\\x{2C94}\\x{2C96}\\x{2C98}\\x{2C9A}\\x{2C9C}\\x{2C9E}\\x{2CA0}\\x{2CA2}\\x{2CA4}\\x{2CA6}\\x{2CA8}\\x{2CAA}\\x{2CAC}\\x{2CAE}\\x{2CB0}\\x{2CB2}\\x{2CB4}\\x{2CB6}\\x{2CB8}\\x{2CBA}\\x{2CBC}\\x{2CBE}\\x{2CC0}\\x{2CC2}\\x{2CC4}\\x{2CC6}\\x{2CC8}\\x{2CCA}\\x{2CCC}\\x{2CCE}\\x{2CD0}\\x{2CD2}\\x{2CD4}\\x{2CD6}\\x{2CD8}\\x{2CDA}\\x{2CDC}\\x{2CDE}\\x{2CE0}\\x{2CE2}\\x{2CEB}\\x{2CED}\\x{2CF2}\\x{A640}\\x{A642}\\x{A644}\\x{A646}\\x{A648}\\x{A64A}\\x{A64C}\\x{A64E}\\x{A650}\\x{A652}\\x{A654}\\x{A656}\\x{A658}\\x{A65A}\\x{A65C}\\x{A65E}\\x{A660}\\x{A662}\\x{A664}\\x{A666}\\x{A668}\\x{A66A}\\x{A66C}\\x{A680}\\x{A682}\\x{A684}\\x{A686}\\x{A688}\\x{A68A}\\x{A68C}\\x{A68E}\\x{A690}\\x{A692}\\x{A694}\\x{A696}\\x{A698}\\x{A69A}\\x{A722}\\x{A724}\\x{A726}\\x{A728}\\x{A72A}\\x{A72C}\\x{A72E}\\x{A732}\\x{A734}\\x{A736}\\x{A738}\\x{A73A}\\x{A73C}\\x{A73E}\\x{A740}\\x{A742}\\x{A744}\\x{A746}\\x{A748}\\x{A74A}\\x{A74C}\\x{A74E}\\x{A750}\\x{A752}\\x{A754}\\x{A756}\\x{A758}\\x{A75A}\\x{A75C}\\x{A75E}\\x{A760}\\x{A762}\\x{A764}\\x{A766}\\x{A768}\\x{A76A}\\x{A76C}\\x{A76E}\\x{A779}\\x{A77B}\\x{A77D}-\\x{A77E}\\x{A780}\\x{A782}\\x{A784}\\x{A786}\\x{A78B}\\x{A78D}\\x{A790}\\x{A792}\\x{A796}\\x{A798}\\x{A79A}\\x{A79C}\\x{A79E}\\x{A7A0}\\x{A7A2}\\x{A7A4}\\x{A7A6}\\x{A7A8}\\x{A7AA}-\\x{A7AD}\\x{A7B0}-\\x{A7B4}\\x{A7B6}\\x{FF21}-\\x{FF3A}]/";
-    $this->peg_c204 = array( "type" => "class", "value" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]", "description" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]" );
-    $this->peg_c205 = array("type" => "other", "description" => "unicode superscript/subscript character" );
-    $this->peg_c206 = "/^[²³¹\\x{2070}-\\x{209C}\\x{2C7C}\\x{1D62}-\\x{1D6A}]/";
-    $this->peg_c207 = array( "type" => "class", "value" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]", "description" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]" );
-    $this->peg_c208 = array("type" => "other", "description" => "special unicode chars" );
-    $this->peg_c209 = "/^[µ\\x{0370}-\\x{0371}\\x{037F}\\x{0391}-\\x{0392}\\x{0393}-\\x{0394}\\x{0395}-\\x{0396}\\x{0397}-\\x{0398}\\x{0399}-\\x{039A}\\x{039B}-\\x{039C}\\x{039D}-\\x{039E}\\x{039F}-\\x{03A0}\\x{03A1}\\x{03A3}-\\x{03A4}\\x{03A5}-\\x{03A6}\\x{03A7}-\\x{03A8}\\x{03A9}\\x{03B1}-\\x{03B2}\\x{03B3}-\\x{03B4}\\x{03B5}-\\x{03B6}\\x{03B7}-\\x{03B8}\\x{03B9}-\\x{03BA}\\x{03BB}-\\x{03BC}\\x{03BD}-\\x{03BE}\\x{03BF}-\\x{03C0}\\x{03C1}-\\x{03C2}\\x{03C3}-\\x{03C4}\\x{03C5}-\\x{03C6}\\x{03C7}-\\x{03C8}\\x{03C9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03F7}-\\x{03F8}\\x{03FA}-\\x{03FB}\\x{1D26}-\\x{1D27}\\x{1D28}-\\x{1D29}\\x{1D2A}\\x{2102}\\x{2107}\\x{210A}-\\x{210B}\\x{210C}-\\x{210D}\\x{210E}-\\x{210F}\\x{2110}-\\x{2111}\\x{2112}-\\x{2113}\\x{2115}\\x{2119}-\\x{211A}\\x{211B}-\\x{211C}\\x{211D}\\x{2124}\\x{2126}-\\x{2127}\\x{2128}\\x{212B}-\\x{212C}\\x{212D}\\x{212F}-\\x{2130}\\x{2131}\\x{2133}-\\x{2134}\\x{2135}-\\x{2136}\\x{2137}-\\x{2138}\\x{213C}-\\x{213D}\\x{213E}-\\x{213F}\\x{2145}-\\x{2146}\\x{2147}-\\x{2148}\\x{2149}\\x{2205}\\x{221E}\\x{29B0}\\x{AB65}]/";
-    $this->peg_c210 = array( "type" => "class", "value" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]", "description" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]" );
+    $this->peg_c52 = ";";
+    $this->peg_c53 = array( "type" => "literal", "value" => ";", "description" => "\";\"" );
+    $this->peg_c54 = "function";
+    $this->peg_c55 = array( "type" => "literal", "value" => "function", "description" => "\"function\"" );
+    $this->peg_c56 = "=>";
+    $this->peg_c57 = array( "type" => "literal", "value" => "=>", "description" => "\"=>\"" );
+    $this->peg_c58 = "assume";
+    $this->peg_c59 = array( "type" => "literal", "value" => "assume", "description" => "\"assume\"" );
+    $this->peg_c60 = array("type" => "other", "description" => "identifier" );
+    $this->peg_c61 = "/^[a-zA-Z]/";
+    $this->peg_c62 = array( "type" => "class", "value" => "[a-zA-Z]", "description" => "[a-zA-Z]" );
+    $this->peg_c63 = "_";
+    $this->peg_c64 = array( "type" => "literal", "value" => "_", "description" => "\"_\"" );
+    $this->peg_c65 = "%";
+    $this->peg_c66 = array( "type" => "literal", "value" => "%", "description" => "\"%\"" );
+    $this->peg_c67 = ",";
+    $this->peg_c68 = array( "type" => "literal", "value" => ",", "description" => "\",\"" );
+    $this->peg_c69 = ":";
+    $this->peg_c70 = array( "type" => "literal", "value" => ":", "description" => "\":\"" );
+    $this->peg_c71 = "if";
+    $this->peg_c72 = array( "type" => "literal", "value" => "if", "description" => "\"if\"" );
+    $this->peg_c73 = "then";
+    $this->peg_c74 = array( "type" => "literal", "value" => "then", "description" => "\"then\"" );
+    $this->peg_c75 = "elseif";
+    $this->peg_c76 = array( "type" => "literal", "value" => "elseif", "description" => "\"elseif\"" );
+    $this->peg_c77 = "else";
+    $this->peg_c78 = array( "type" => "literal", "value" => "else", "description" => "\"else\"" );
+    $this->peg_c79 = "do";
+    $this->peg_c80 = array( "type" => "literal", "value" => "do", "description" => "\"do\"" );
+    $this->peg_c81 = "for";
+    $this->peg_c82 = array( "type" => "literal", "value" => "for", "description" => "\"for\"" );
+    $this->peg_c83 = "from";
+    $this->peg_c84 = array( "type" => "literal", "value" => "from", "description" => "\"from\"" );
+    $this->peg_c85 = "step";
+    $this->peg_c86 = array( "type" => "literal", "value" => "step", "description" => "\"step\"" );
+    $this->peg_c87 = "next";
+    $this->peg_c88 = array( "type" => "literal", "value" => "next", "description" => "\"next\"" );
+    $this->peg_c89 = "in";
+    $this->peg_c90 = array( "type" => "literal", "value" => "in", "description" => "\"in\"" );
+    $this->peg_c91 = "thru";
+    $this->peg_c92 = array( "type" => "literal", "value" => "thru", "description" => "\"thru\"" );
+    $this->peg_c93 = "while";
+    $this->peg_c94 = array( "type" => "literal", "value" => "while", "description" => "\"while\"" );
+    $this->peg_c95 = "unless";
+    $this->peg_c96 = array( "type" => "literal", "value" => "unless", "description" => "\"unless\"" );
+    $this->peg_c97 = "(";
+    $this->peg_c98 = array( "type" => "literal", "value" => "(", "description" => "\"(\"" );
+    $this->peg_c99 = ")";
+    $this->peg_c100 = array( "type" => "literal", "value" => ")", "description" => "\")\"" );
+    $this->peg_c101 = "#pm#";
+    $this->peg_c102 = array( "type" => "literal", "value" => "#pm#", "description" => "\"#pm#\"" );
+    $this->peg_c103 = "+-";
+    $this->peg_c104 = array( "type" => "literal", "value" => "+-", "description" => "\"+-\"" );
+    $this->peg_c105 = "-";
+    $this->peg_c106 = array( "type" => "literal", "value" => "-", "description" => "\"-\"" );
+    $this->peg_c107 = "+";
+    $this->peg_c108 = array( "type" => "literal", "value" => "+", "description" => "\"+\"" );
+    $this->peg_c109 = "''";
+    $this->peg_c110 = array( "type" => "literal", "value" => "''", "description" => "\"''\"" );
+    $this->peg_c111 = "'";
+    $this->peg_c112 = array( "type" => "literal", "value" => "'", "description" => "\"'\"" );
+    $this->peg_c113 = "not ";
+    $this->peg_c114 = array( "type" => "literal", "value" => "not ", "description" => "\"not \"" );
+    $this->peg_c115 = "nounnot ";
+    $this->peg_c116 = array( "type" => "literal", "value" => "nounnot ", "description" => "\"nounnot \"" );
+    $this->peg_c117 = "%not ";
+    $this->peg_c118 = array( "type" => "literal", "value" => "%not ", "description" => "\"%not \"" );
+    $this->peg_c119 = "?? ";
+    $this->peg_c120 = array( "type" => "literal", "value" => "?? ", "description" => "\"?? \"" );
+    $this->peg_c121 = "? ";
+    $this->peg_c122 = array( "type" => "literal", "value" => "? ", "description" => "\"? \"" );
+    $this->peg_c123 = "?";
+    $this->peg_c124 = array( "type" => "literal", "value" => "?", "description" => "\"?\"" );
+    $this->peg_c125 = "!!";
+    $this->peg_c126 = array( "type" => "literal", "value" => "!!", "description" => "\"!!\"" );
+    $this->peg_c127 = "!";
+    $this->peg_c128 = array( "type" => "literal", "value" => "!", "description" => "\"!\"" );
+    $this->peg_c129 = "**";
+    $this->peg_c130 = array( "type" => "literal", "value" => "**", "description" => "\"**\"" );
+    $this->peg_c131 = "^^";
+    $this->peg_c132 = array( "type" => "literal", "value" => "^^", "description" => "\"^^\"" );
+    $this->peg_c133 = "^";
+    $this->peg_c134 = array( "type" => "literal", "value" => "^", "description" => "\"^\"" );
+    $this->peg_c135 = "%and";
+    $this->peg_c136 = array( "type" => "literal", "value" => "%and", "description" => "\"%and\"" );
+    $this->peg_c137 = "%or";
+    $this->peg_c138 = array( "type" => "literal", "value" => "%or", "description" => "\"%or\"" );
+    $this->peg_c139 = "and";
+    $this->peg_c140 = array( "type" => "literal", "value" => "and", "description" => "\"and\"" );
+    $this->peg_c141 = "or";
+    $this->peg_c142 = array( "type" => "literal", "value" => "or", "description" => "\"or\"" );
+    $this->peg_c143 = "nounand";
+    $this->peg_c144 = array( "type" => "literal", "value" => "nounand", "description" => "\"nounand\"" );
+    $this->peg_c145 = "nounor";
+    $this->peg_c146 = array( "type" => "literal", "value" => "nounor", "description" => "\"nounor\"" );
+    $this->peg_c147 = "nand";
+    $this->peg_c148 = array( "type" => "literal", "value" => "nand", "description" => "\"nand\"" );
+    $this->peg_c149 = "nor";
+    $this->peg_c150 = array( "type" => "literal", "value" => "nor", "description" => "\"nor\"" );
+    $this->peg_c151 = "implies";
+    $this->peg_c152 = array( "type" => "literal", "value" => "implies", "description" => "\"implies\"" );
+    $this->peg_c153 = "xor";
+    $this->peg_c154 = array( "type" => "literal", "value" => "xor", "description" => "\"xor\"" );
+    $this->peg_c155 = "xnor";
+    $this->peg_c156 = array( "type" => "literal", "value" => "xnor", "description" => "\"xnor\"" );
+    $this->peg_c157 = "#";
+    $this->peg_c158 = array( "type" => "literal", "value" => "#", "description" => "\"#\"" );
+    $this->peg_c159 = "::=";
+    $this->peg_c160 = array( "type" => "literal", "value" => "::=", "description" => "\"::=\"" );
+    $this->peg_c161 = ":=";
+    $this->peg_c162 = array( "type" => "literal", "value" => ":=", "description" => "\":=\"" );
+    $this->peg_c163 = "::";
+    $this->peg_c164 = array( "type" => "literal", "value" => "::", "description" => "\"::\"" );
+    $this->peg_c165 = "<=";
+    $this->peg_c166 = array( "type" => "literal", "value" => "<=", "description" => "\"<=\"" );
+    $this->peg_c167 = "<";
+    $this->peg_c168 = array( "type" => "literal", "value" => "<", "description" => "\"<\"" );
+    $this->peg_c169 = ">=";
+    $this->peg_c170 = array( "type" => "literal", "value" => ">=", "description" => "\">=\"" );
+    $this->peg_c171 = ">";
+    $this->peg_c172 = array( "type" => "literal", "value" => ">", "description" => "\">\"" );
+    $this->peg_c173 = "~";
+    $this->peg_c174 = array( "type" => "literal", "value" => "~", "description" => "\"~\"" );
+    $this->peg_c175 = "@@IS@@";
+    $this->peg_c176 = array( "type" => "literal", "value" => "@@IS@@", "description" => "\"@@IS@@\"" );
+    $this->peg_c177 = "@@Is@@";
+    $this->peg_c178 = array( "type" => "literal", "value" => "@@Is@@", "description" => "\"@@Is@@\"" );
+    $this->peg_c179 = "nounnot";
+    $this->peg_c180 = array( "type" => "literal", "value" => "nounnot", "description" => "\"nounnot\"" );
+    $this->peg_c181 = "not";
+    $this->peg_c182 = array( "type" => "literal", "value" => "not", "description" => "\"not\"" );
+    $this->peg_c183 = "|";
+    $this->peg_c184 = array( "type" => "literal", "value" => "|", "description" => "\"|\"" );
+    $this->peg_c185 = "[";
+    $this->peg_c186 = array( "type" => "literal", "value" => "[", "description" => "\"[\"" );
+    $this->peg_c187 = "]";
+    $this->peg_c188 = array( "type" => "literal", "value" => "]", "description" => "\"]\"" );
+    $this->peg_c189 = "{";
+    $this->peg_c190 = array( "type" => "literal", "value" => "{", "description" => "\"{\"" );
+    $this->peg_c191 = "}";
+    $this->peg_c192 = array( "type" => "literal", "value" => "}", "description" => "\"}\"" );
+    $this->peg_c193 = array("type" => "other", "description" => "whitespace" );
+    $this->peg_c194 = "/^[ \\t\\n\\r\\x0B\\f \\x{FEFF}  \\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}\\n-\\r]/";
+    $this->peg_c195 = array( "type" => "class", "value" => "[ \t\n\r\x0B\f \x{FEFF}  \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]", "description" => "[ \t\n\r\x0B\f \x{FEFF}  \x{1680}\x{2000}-\x{200A}\x{202F}\x{205F}\x{3000}\n-\r]" );
+    $this->peg_c196 = array("type" => "other", "description" => "unicode letter character" );
+    $this->peg_c197 = "/^[a-zµß-öø-\\x{00FF}\\x{0101}\\x{0103}\\x{0105}\\x{0107}\\x{0109}\\x{010B}\\x{010D}\\x{010F}\\x{0111}\\x{0113}\\x{0115}\\x{0117}\\x{0119}\\x{011B}\\x{011D}\\x{011F}\\x{0121}\\x{0123}\\x{0125}\\x{0127}\\x{0129}\\x{012B}\\x{012D}\\x{012F}\\x{0131}\\x{0133}\\x{0135}\\x{0137}-\\x{0138}\\x{013A}\\x{013C}\\x{013E}\\x{0140}\\x{0142}\\x{0144}\\x{0146}\\x{0148}-\\x{0149}\\x{014B}\\x{014D}\\x{014F}\\x{0151}\\x{0153}\\x{0155}\\x{0157}\\x{0159}\\x{015B}\\x{015D}\\x{015F}\\x{0161}\\x{0163}\\x{0165}\\x{0167}\\x{0169}\\x{016B}\\x{016D}\\x{016F}\\x{0171}\\x{0173}\\x{0175}\\x{0177}\\x{017A}\\x{017C}\\x{017E}-\\x{0180}\\x{0183}\\x{0185}\\x{0188}\\x{018C}-\\x{018D}\\x{0192}\\x{0195}\\x{0199}-\\x{019B}\\x{019E}\\x{01A1}\\x{01A3}\\x{01A5}\\x{01A8}\\x{01AA}-\\x{01AB}\\x{01AD}\\x{01B0}\\x{01B4}\\x{01B6}\\x{01B9}-\\x{01BA}\\x{01BD}-\\x{01BF}\\x{01C6}\\x{01C9}\\x{01CC}\\x{01CE}\\x{01D0}\\x{01D2}\\x{01D4}\\x{01D6}\\x{01D8}\\x{01DA}\\x{01DC}-\\x{01DD}\\x{01DF}\\x{01E1}\\x{01E3}\\x{01E5}\\x{01E7}\\x{01E9}\\x{01EB}\\x{01ED}\\x{01EF}-\\x{01F0}\\x{01F3}\\x{01F5}\\x{01F9}\\x{01FB}\\x{01FD}\\x{01FF}\\x{0201}\\x{0203}\\x{0205}\\x{0207}\\x{0209}\\x{020B}\\x{020D}\\x{020F}\\x{0211}\\x{0213}\\x{0215}\\x{0217}\\x{0219}\\x{021B}\\x{021D}\\x{021F}\\x{0221}\\x{0223}\\x{0225}\\x{0227}\\x{0229}\\x{022B}\\x{022D}\\x{022F}\\x{0231}\\x{0233}-\\x{0239}\\x{023C}\\x{023F}-\\x{0240}\\x{0242}\\x{0247}\\x{0249}\\x{024B}\\x{024D}\\x{024F}-\\x{0293}\\x{0295}-\\x{02AF}\\x{0371}\\x{0373}\\x{0377}\\x{037B}-\\x{037D}\\x{0390}\\x{03AC}-\\x{03CE}\\x{03D0}-\\x{03D1}\\x{03D5}-\\x{03D7}\\x{03D9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03E3}\\x{03E5}\\x{03E7}\\x{03E9}\\x{03EB}\\x{03ED}\\x{03EF}-\\x{03F3}\\x{03F5}\\x{03F8}\\x{03FB}-\\x{03FC}\\x{0430}-\\x{045F}\\x{0461}\\x{0463}\\x{0465}\\x{0467}\\x{0469}\\x{046B}\\x{046D}\\x{046F}\\x{0471}\\x{0473}\\x{0475}\\x{0477}\\x{0479}\\x{047B}\\x{047D}\\x{047F}\\x{0481}\\x{048B}\\x{048D}\\x{048F}\\x{0491}\\x{0493}\\x{0495}\\x{0497}\\x{0499}\\x{049B}\\x{049D}\\x{049F}\\x{04A1}\\x{04A3}\\x{04A5}\\x{04A7}\\x{04A9}\\x{04AB}\\x{04AD}\\x{04AF}\\x{04B1}\\x{04B3}\\x{04B5}\\x{04B7}\\x{04B9}\\x{04BB}\\x{04BD}\\x{04BF}\\x{04C2}\\x{04C4}\\x{04C6}\\x{04C8}\\x{04CA}\\x{04CC}\\x{04CE}-\\x{04CF}\\x{04D1}\\x{04D3}\\x{04D5}\\x{04D7}\\x{04D9}\\x{04DB}\\x{04DD}\\x{04DF}\\x{04E1}\\x{04E3}\\x{04E5}\\x{04E7}\\x{04E9}\\x{04EB}\\x{04ED}\\x{04EF}\\x{04F1}\\x{04F3}\\x{04F5}\\x{04F7}\\x{04F9}\\x{04FB}\\x{04FD}\\x{04FF}\\x{0501}\\x{0503}\\x{0505}\\x{0507}\\x{0509}\\x{050B}\\x{050D}\\x{050F}\\x{0511}\\x{0513}\\x{0515}\\x{0517}\\x{0519}\\x{051B}\\x{051D}\\x{051F}\\x{0521}\\x{0523}\\x{0525}\\x{0527}\\x{0529}\\x{052B}\\x{052D}\\x{052F}\\x{0561}-\\x{0587}\\x{13F8}-\\x{13FD}\\x{1D00}-\\x{1D2B}\\x{1D6B}-\\x{1D77}\\x{1D79}-\\x{1D9A}\\x{1E01}\\x{1E03}\\x{1E05}\\x{1E07}\\x{1E09}\\x{1E0B}\\x{1E0D}\\x{1E0F}\\x{1E11}\\x{1E13}\\x{1E15}\\x{1E17}\\x{1E19}\\x{1E1B}\\x{1E1D}\\x{1E1F}\\x{1E21}\\x{1E23}\\x{1E25}\\x{1E27}\\x{1E29}\\x{1E2B}\\x{1E2D}\\x{1E2F}\\x{1E31}\\x{1E33}\\x{1E35}\\x{1E37}\\x{1E39}\\x{1E3B}\\x{1E3D}\\x{1E3F}\\x{1E41}\\x{1E43}\\x{1E45}\\x{1E47}\\x{1E49}\\x{1E4B}\\x{1E4D}\\x{1E4F}\\x{1E51}\\x{1E53}\\x{1E55}\\x{1E57}\\x{1E59}\\x{1E5B}\\x{1E5D}\\x{1E5F}\\x{1E61}\\x{1E63}\\x{1E65}\\x{1E67}\\x{1E69}\\x{1E6B}\\x{1E6D}\\x{1E6F}\\x{1E71}\\x{1E73}\\x{1E75}\\x{1E77}\\x{1E79}\\x{1E7B}\\x{1E7D}\\x{1E7F}\\x{1E81}\\x{1E83}\\x{1E85}\\x{1E87}\\x{1E89}\\x{1E8B}\\x{1E8D}\\x{1E8F}\\x{1E91}\\x{1E93}\\x{1E95}-\\x{1E9D}\\x{1E9F}\\x{1EA1}\\x{1EA3}\\x{1EA5}\\x{1EA7}\\x{1EA9}\\x{1EAB}\\x{1EAD}\\x{1EAF}\\x{1EB1}\\x{1EB3}\\x{1EB5}\\x{1EB7}\\x{1EB9}\\x{1EBB}\\x{1EBD}\\x{1EBF}\\x{1EC1}\\x{1EC3}\\x{1EC5}\\x{1EC7}\\x{1EC9}\\x{1ECB}\\x{1ECD}\\x{1ECF}\\x{1ED1}\\x{1ED3}\\x{1ED5}\\x{1ED7}\\x{1ED9}\\x{1EDB}\\x{1EDD}\\x{1EDF}\\x{1EE1}\\x{1EE3}\\x{1EE5}\\x{1EE7}\\x{1EE9}\\x{1EEB}\\x{1EED}\\x{1EEF}\\x{1EF1}\\x{1EF3}\\x{1EF5}\\x{1EF7}\\x{1EF9}\\x{1EFB}\\x{1EFD}\\x{1EFF}-\\x{1F07}\\x{1F10}-\\x{1F15}\\x{1F20}-\\x{1F27}\\x{1F30}-\\x{1F37}\\x{1F40}-\\x{1F45}\\x{1F50}-\\x{1F57}\\x{1F60}-\\x{1F67}\\x{1F70}-\\x{1F7D}\\x{1F80}-\\x{1F87}\\x{1F90}-\\x{1F97}\\x{1FA0}-\\x{1FA7}\\x{1FB0}-\\x{1FB4}\\x{1FB6}-\\x{1FB7}\\x{1FBE}\\x{1FC2}-\\x{1FC4}\\x{1FC6}-\\x{1FC7}\\x{1FD0}-\\x{1FD3}\\x{1FD6}-\\x{1FD7}\\x{1FE0}-\\x{1FE7}\\x{1FF2}-\\x{1FF4}\\x{1FF6}-\\x{1FF7}\\x{210A}\\x{210E}-\\x{210F}\\x{2113}\\x{212F}\\x{2134}\\x{2139}\\x{213C}-\\x{213D}\\x{2146}-\\x{2149}\\x{214E}\\x{2184}\\x{2C30}-\\x{2C5E}\\x{2C61}\\x{2C65}-\\x{2C66}\\x{2C68}\\x{2C6A}\\x{2C6C}\\x{2C71}\\x{2C73}-\\x{2C74}\\x{2C76}-\\x{2C7B}\\x{2C81}\\x{2C83}\\x{2C85}\\x{2C87}\\x{2C89}\\x{2C8B}\\x{2C8D}\\x{2C8F}\\x{2C91}\\x{2C93}\\x{2C95}\\x{2C97}\\x{2C99}\\x{2C9B}\\x{2C9D}\\x{2C9F}\\x{2CA1}\\x{2CA3}\\x{2CA5}\\x{2CA7}\\x{2CA9}\\x{2CAB}\\x{2CAD}\\x{2CAF}\\x{2CB1}\\x{2CB3}\\x{2CB5}\\x{2CB7}\\x{2CB9}\\x{2CBB}\\x{2CBD}\\x{2CBF}\\x{2CC1}\\x{2CC3}\\x{2CC5}\\x{2CC7}\\x{2CC9}\\x{2CCB}\\x{2CCD}\\x{2CCF}\\x{2CD1}\\x{2CD3}\\x{2CD5}\\x{2CD7}\\x{2CD9}\\x{2CDB}\\x{2CDD}\\x{2CDF}\\x{2CE1}\\x{2CE3}-\\x{2CE4}\\x{2CEC}\\x{2CEE}\\x{2CF3}\\x{2D00}-\\x{2D25}\\x{2D27}\\x{2D2D}\\x{A641}\\x{A643}\\x{A645}\\x{A647}\\x{A649}\\x{A64B}\\x{A64D}\\x{A64F}\\x{A651}\\x{A653}\\x{A655}\\x{A657}\\x{A659}\\x{A65B}\\x{A65D}\\x{A65F}\\x{A661}\\x{A663}\\x{A665}\\x{A667}\\x{A669}\\x{A66B}\\x{A66D}\\x{A681}\\x{A683}\\x{A685}\\x{A687}\\x{A689}\\x{A68B}\\x{A68D}\\x{A68F}\\x{A691}\\x{A693}\\x{A695}\\x{A697}\\x{A699}\\x{A69B}\\x{A723}\\x{A725}\\x{A727}\\x{A729}\\x{A72B}\\x{A72D}\\x{A72F}-\\x{A731}\\x{A733}\\x{A735}\\x{A737}\\x{A739}\\x{A73B}\\x{A73D}\\x{A73F}\\x{A741}\\x{A743}\\x{A745}\\x{A747}\\x{A749}\\x{A74B}\\x{A74D}\\x{A74F}\\x{A751}\\x{A753}\\x{A755}\\x{A757}\\x{A759}\\x{A75B}\\x{A75D}\\x{A75F}\\x{A761}\\x{A763}\\x{A765}\\x{A767}\\x{A769}\\x{A76B}\\x{A76D}\\x{A76F}\\x{A771}-\\x{A778}\\x{A77A}\\x{A77C}\\x{A77F}\\x{A781}\\x{A783}\\x{A785}\\x{A787}\\x{A78C}\\x{A78E}\\x{A791}\\x{A793}-\\x{A795}\\x{A797}\\x{A799}\\x{A79B}\\x{A79D}\\x{A79F}\\x{A7A1}\\x{A7A3}\\x{A7A5}\\x{A7A7}\\x{A7A9}\\x{A7B5}\\x{A7B7}\\x{A7FA}\\x{AB30}-\\x{AB5A}\\x{AB60}-\\x{AB65}\\x{AB70}-\\x{ABBF}\\x{FB00}-\\x{FB06}\\x{FB13}-\\x{FB17}\\x{FF41}-\\x{FF5A}]/";
+    $this->peg_c198 = array( "type" => "class", "value" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]", "description" => "[a-zµß-öø-\x{00FF}\x{0101}\x{0103}\x{0105}\x{0107}\x{0109}\x{010B}\x{010D}\x{010F}\x{0111}\x{0113}\x{0115}\x{0117}\x{0119}\x{011B}\x{011D}\x{011F}\x{0121}\x{0123}\x{0125}\x{0127}\x{0129}\x{012B}\x{012D}\x{012F}\x{0131}\x{0133}\x{0135}\x{0137}-\x{0138}\x{013A}\x{013C}\x{013E}\x{0140}\x{0142}\x{0144}\x{0146}\x{0148}-\x{0149}\x{014B}\x{014D}\x{014F}\x{0151}\x{0153}\x{0155}\x{0157}\x{0159}\x{015B}\x{015D}\x{015F}\x{0161}\x{0163}\x{0165}\x{0167}\x{0169}\x{016B}\x{016D}\x{016F}\x{0171}\x{0173}\x{0175}\x{0177}\x{017A}\x{017C}\x{017E}-\x{0180}\x{0183}\x{0185}\x{0188}\x{018C}-\x{018D}\x{0192}\x{0195}\x{0199}-\x{019B}\x{019E}\x{01A1}\x{01A3}\x{01A5}\x{01A8}\x{01AA}-\x{01AB}\x{01AD}\x{01B0}\x{01B4}\x{01B6}\x{01B9}-\x{01BA}\x{01BD}-\x{01BF}\x{01C6}\x{01C9}\x{01CC}\x{01CE}\x{01D0}\x{01D2}\x{01D4}\x{01D6}\x{01D8}\x{01DA}\x{01DC}-\x{01DD}\x{01DF}\x{01E1}\x{01E3}\x{01E5}\x{01E7}\x{01E9}\x{01EB}\x{01ED}\x{01EF}-\x{01F0}\x{01F3}\x{01F5}\x{01F9}\x{01FB}\x{01FD}\x{01FF}\x{0201}\x{0203}\x{0205}\x{0207}\x{0209}\x{020B}\x{020D}\x{020F}\x{0211}\x{0213}\x{0215}\x{0217}\x{0219}\x{021B}\x{021D}\x{021F}\x{0221}\x{0223}\x{0225}\x{0227}\x{0229}\x{022B}\x{022D}\x{022F}\x{0231}\x{0233}-\x{0239}\x{023C}\x{023F}-\x{0240}\x{0242}\x{0247}\x{0249}\x{024B}\x{024D}\x{024F}-\x{0293}\x{0295}-\x{02AF}\x{0371}\x{0373}\x{0377}\x{037B}-\x{037D}\x{0390}\x{03AC}-\x{03CE}\x{03D0}-\x{03D1}\x{03D5}-\x{03D7}\x{03D9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03E3}\x{03E5}\x{03E7}\x{03E9}\x{03EB}\x{03ED}\x{03EF}-\x{03F3}\x{03F5}\x{03F8}\x{03FB}-\x{03FC}\x{0430}-\x{045F}\x{0461}\x{0463}\x{0465}\x{0467}\x{0469}\x{046B}\x{046D}\x{046F}\x{0471}\x{0473}\x{0475}\x{0477}\x{0479}\x{047B}\x{047D}\x{047F}\x{0481}\x{048B}\x{048D}\x{048F}\x{0491}\x{0493}\x{0495}\x{0497}\x{0499}\x{049B}\x{049D}\x{049F}\x{04A1}\x{04A3}\x{04A5}\x{04A7}\x{04A9}\x{04AB}\x{04AD}\x{04AF}\x{04B1}\x{04B3}\x{04B5}\x{04B7}\x{04B9}\x{04BB}\x{04BD}\x{04BF}\x{04C2}\x{04C4}\x{04C6}\x{04C8}\x{04CA}\x{04CC}\x{04CE}-\x{04CF}\x{04D1}\x{04D3}\x{04D5}\x{04D7}\x{04D9}\x{04DB}\x{04DD}\x{04DF}\x{04E1}\x{04E3}\x{04E5}\x{04E7}\x{04E9}\x{04EB}\x{04ED}\x{04EF}\x{04F1}\x{04F3}\x{04F5}\x{04F7}\x{04F9}\x{04FB}\x{04FD}\x{04FF}\x{0501}\x{0503}\x{0505}\x{0507}\x{0509}\x{050B}\x{050D}\x{050F}\x{0511}\x{0513}\x{0515}\x{0517}\x{0519}\x{051B}\x{051D}\x{051F}\x{0521}\x{0523}\x{0525}\x{0527}\x{0529}\x{052B}\x{052D}\x{052F}\x{0561}-\x{0587}\x{13F8}-\x{13FD}\x{1D00}-\x{1D2B}\x{1D6B}-\x{1D77}\x{1D79}-\x{1D9A}\x{1E01}\x{1E03}\x{1E05}\x{1E07}\x{1E09}\x{1E0B}\x{1E0D}\x{1E0F}\x{1E11}\x{1E13}\x{1E15}\x{1E17}\x{1E19}\x{1E1B}\x{1E1D}\x{1E1F}\x{1E21}\x{1E23}\x{1E25}\x{1E27}\x{1E29}\x{1E2B}\x{1E2D}\x{1E2F}\x{1E31}\x{1E33}\x{1E35}\x{1E37}\x{1E39}\x{1E3B}\x{1E3D}\x{1E3F}\x{1E41}\x{1E43}\x{1E45}\x{1E47}\x{1E49}\x{1E4B}\x{1E4D}\x{1E4F}\x{1E51}\x{1E53}\x{1E55}\x{1E57}\x{1E59}\x{1E5B}\x{1E5D}\x{1E5F}\x{1E61}\x{1E63}\x{1E65}\x{1E67}\x{1E69}\x{1E6B}\x{1E6D}\x{1E6F}\x{1E71}\x{1E73}\x{1E75}\x{1E77}\x{1E79}\x{1E7B}\x{1E7D}\x{1E7F}\x{1E81}\x{1E83}\x{1E85}\x{1E87}\x{1E89}\x{1E8B}\x{1E8D}\x{1E8F}\x{1E91}\x{1E93}\x{1E95}-\x{1E9D}\x{1E9F}\x{1EA1}\x{1EA3}\x{1EA5}\x{1EA7}\x{1EA9}\x{1EAB}\x{1EAD}\x{1EAF}\x{1EB1}\x{1EB3}\x{1EB5}\x{1EB7}\x{1EB9}\x{1EBB}\x{1EBD}\x{1EBF}\x{1EC1}\x{1EC3}\x{1EC5}\x{1EC7}\x{1EC9}\x{1ECB}\x{1ECD}\x{1ECF}\x{1ED1}\x{1ED3}\x{1ED5}\x{1ED7}\x{1ED9}\x{1EDB}\x{1EDD}\x{1EDF}\x{1EE1}\x{1EE3}\x{1EE5}\x{1EE7}\x{1EE9}\x{1EEB}\x{1EED}\x{1EEF}\x{1EF1}\x{1EF3}\x{1EF5}\x{1EF7}\x{1EF9}\x{1EFB}\x{1EFD}\x{1EFF}-\x{1F07}\x{1F10}-\x{1F15}\x{1F20}-\x{1F27}\x{1F30}-\x{1F37}\x{1F40}-\x{1F45}\x{1F50}-\x{1F57}\x{1F60}-\x{1F67}\x{1F70}-\x{1F7D}\x{1F80}-\x{1F87}\x{1F90}-\x{1F97}\x{1FA0}-\x{1FA7}\x{1FB0}-\x{1FB4}\x{1FB6}-\x{1FB7}\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FC7}\x{1FD0}-\x{1FD3}\x{1FD6}-\x{1FD7}\x{1FE0}-\x{1FE7}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FF7}\x{210A}\x{210E}-\x{210F}\x{2113}\x{212F}\x{2134}\x{2139}\x{213C}-\x{213D}\x{2146}-\x{2149}\x{214E}\x{2184}\x{2C30}-\x{2C5E}\x{2C61}\x{2C65}-\x{2C66}\x{2C68}\x{2C6A}\x{2C6C}\x{2C71}\x{2C73}-\x{2C74}\x{2C76}-\x{2C7B}\x{2C81}\x{2C83}\x{2C85}\x{2C87}\x{2C89}\x{2C8B}\x{2C8D}\x{2C8F}\x{2C91}\x{2C93}\x{2C95}\x{2C97}\x{2C99}\x{2C9B}\x{2C9D}\x{2C9F}\x{2CA1}\x{2CA3}\x{2CA5}\x{2CA7}\x{2CA9}\x{2CAB}\x{2CAD}\x{2CAF}\x{2CB1}\x{2CB3}\x{2CB5}\x{2CB7}\x{2CB9}\x{2CBB}\x{2CBD}\x{2CBF}\x{2CC1}\x{2CC3}\x{2CC5}\x{2CC7}\x{2CC9}\x{2CCB}\x{2CCD}\x{2CCF}\x{2CD1}\x{2CD3}\x{2CD5}\x{2CD7}\x{2CD9}\x{2CDB}\x{2CDD}\x{2CDF}\x{2CE1}\x{2CE3}-\x{2CE4}\x{2CEC}\x{2CEE}\x{2CF3}\x{2D00}-\x{2D25}\x{2D27}\x{2D2D}\x{A641}\x{A643}\x{A645}\x{A647}\x{A649}\x{A64B}\x{A64D}\x{A64F}\x{A651}\x{A653}\x{A655}\x{A657}\x{A659}\x{A65B}\x{A65D}\x{A65F}\x{A661}\x{A663}\x{A665}\x{A667}\x{A669}\x{A66B}\x{A66D}\x{A681}\x{A683}\x{A685}\x{A687}\x{A689}\x{A68B}\x{A68D}\x{A68F}\x{A691}\x{A693}\x{A695}\x{A697}\x{A699}\x{A69B}\x{A723}\x{A725}\x{A727}\x{A729}\x{A72B}\x{A72D}\x{A72F}-\x{A731}\x{A733}\x{A735}\x{A737}\x{A739}\x{A73B}\x{A73D}\x{A73F}\x{A741}\x{A743}\x{A745}\x{A747}\x{A749}\x{A74B}\x{A74D}\x{A74F}\x{A751}\x{A753}\x{A755}\x{A757}\x{A759}\x{A75B}\x{A75D}\x{A75F}\x{A761}\x{A763}\x{A765}\x{A767}\x{A769}\x{A76B}\x{A76D}\x{A76F}\x{A771}-\x{A778}\x{A77A}\x{A77C}\x{A77F}\x{A781}\x{A783}\x{A785}\x{A787}\x{A78C}\x{A78E}\x{A791}\x{A793}-\x{A795}\x{A797}\x{A799}\x{A79B}\x{A79D}\x{A79F}\x{A7A1}\x{A7A3}\x{A7A5}\x{A7A7}\x{A7A9}\x{A7B5}\x{A7B7}\x{A7FA}\x{AB30}-\x{AB5A}\x{AB60}-\x{AB65}\x{AB70}-\x{ABBF}\x{FB00}-\x{FB06}\x{FB13}-\x{FB17}\x{FF41}-\x{FF5A}]" );
+    $this->peg_c199 = "/^[\\x{02B0}-\\x{02C1}\\x{02C6}-\\x{02D1}\\x{02E0}-\\x{02E4}\\x{02EC}\\x{02EE}\\x{0374}\\x{037A}\\x{0559}\\x{0640}\\x{06E5}-\\x{06E6}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{081A}\\x{0824}\\x{0828}\\x{0971}\\x{0E46}\\x{0EC6}\\x{10FC}\\x{17D7}\\x{1843}\\x{1AA7}\\x{1C78}-\\x{1C7D}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{2C7C}-\\x{2C7D}\\x{2D6F}\\x{2E2F}\\x{3005}\\x{3031}-\\x{3035}\\x{303B}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A717}-\\x{A71F}\\x{A770}\\x{A788}\\x{A7F8}-\\x{A7F9}\\x{A9CF}\\x{A9E6}\\x{AA70}\\x{AADD}\\x{AAF3}-\\x{AAF4}\\x{AB5C}-\\x{AB5F}\\x{FF70}\\x{FF9E}-\\x{FF9F}]/";
+    $this->peg_c200 = array( "type" => "class", "value" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]", "description" => "[\x{02B0}-\x{02C1}\x{02C6}-\x{02D1}\x{02E0}-\x{02E4}\x{02EC}\x{02EE}\x{0374}\x{037A}\x{0559}\x{0640}\x{06E5}-\x{06E6}\x{07F4}-\x{07F5}\x{07FA}\x{081A}\x{0824}\x{0828}\x{0971}\x{0E46}\x{0EC6}\x{10FC}\x{17D7}\x{1843}\x{1AA7}\x{1C78}-\x{1C7D}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{2071}\x{207F}\x{2090}-\x{209C}\x{2C7C}-\x{2C7D}\x{2D6F}\x{2E2F}\x{3005}\x{3031}-\x{3035}\x{303B}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A67F}\x{A69C}-\x{A69D}\x{A717}-\x{A71F}\x{A770}\x{A788}\x{A7F8}-\x{A7F9}\x{A9CF}\x{A9E6}\x{AA70}\x{AADD}\x{AAF3}-\x{AAF4}\x{AB5C}-\x{AB5F}\x{FF70}\x{FF9E}-\x{FF9F}]" );
+    $this->peg_c201 = "/^[ªº\\x{01BB}\\x{01C0}-\\x{01C3}\\x{0294}\\x{05D0}-\\x{05EA}\\x{05F0}-\\x{05F2}\\x{0620}-\\x{063F}\\x{0641}-\\x{064A}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D5}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0710}\\x{0712}-\\x{072F}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07CA}-\\x{07EA}\\x{0800}-\\x{0815}\\x{0840}-\\x{0858}\\x{08A0}-\\x{08B4}\\x{0904}-\\x{0939}\\x{093D}\\x{0950}\\x{0958}-\\x{0961}\\x{0972}-\\x{0980}\\x{0985}-\\x{098C}\\x{098F}-\\x{0990}\\x{0993}-\\x{09A8}\\x{09AA}-\\x{09B0}\\x{09B2}\\x{09B6}-\\x{09B9}\\x{09BD}\\x{09CE}\\x{09DC}-\\x{09DD}\\x{09DF}-\\x{09E1}\\x{09F0}-\\x{09F1}\\x{0A05}-\\x{0A0A}\\x{0A0F}-\\x{0A10}\\x{0A13}-\\x{0A28}\\x{0A2A}-\\x{0A30}\\x{0A32}-\\x{0A33}\\x{0A35}-\\x{0A36}\\x{0A38}-\\x{0A39}\\x{0A59}-\\x{0A5C}\\x{0A5E}\\x{0A72}-\\x{0A74}\\x{0A85}-\\x{0A8D}\\x{0A8F}-\\x{0A91}\\x{0A93}-\\x{0AA8}\\x{0AAA}-\\x{0AB0}\\x{0AB2}-\\x{0AB3}\\x{0AB5}-\\x{0AB9}\\x{0ABD}\\x{0AD0}\\x{0AE0}-\\x{0AE1}\\x{0AF9}\\x{0B05}-\\x{0B0C}\\x{0B0F}-\\x{0B10}\\x{0B13}-\\x{0B28}\\x{0B2A}-\\x{0B30}\\x{0B32}-\\x{0B33}\\x{0B35}-\\x{0B39}\\x{0B3D}\\x{0B5C}-\\x{0B5D}\\x{0B5F}-\\x{0B61}\\x{0B71}\\x{0B83}\\x{0B85}-\\x{0B8A}\\x{0B8E}-\\x{0B90}\\x{0B92}-\\x{0B95}\\x{0B99}-\\x{0B9A}\\x{0B9C}\\x{0B9E}-\\x{0B9F}\\x{0BA3}-\\x{0BA4}\\x{0BA8}-\\x{0BAA}\\x{0BAE}-\\x{0BB9}\\x{0BD0}\\x{0C05}-\\x{0C0C}\\x{0C0E}-\\x{0C10}\\x{0C12}-\\x{0C28}\\x{0C2A}-\\x{0C39}\\x{0C3D}\\x{0C58}-\\x{0C5A}\\x{0C60}-\\x{0C61}\\x{0C85}-\\x{0C8C}\\x{0C8E}-\\x{0C90}\\x{0C92}-\\x{0CA8}\\x{0CAA}-\\x{0CB3}\\x{0CB5}-\\x{0CB9}\\x{0CBD}\\x{0CDE}\\x{0CE0}-\\x{0CE1}\\x{0CF1}-\\x{0CF2}\\x{0D05}-\\x{0D0C}\\x{0D0E}-\\x{0D10}\\x{0D12}-\\x{0D3A}\\x{0D3D}\\x{0D4E}\\x{0D5F}-\\x{0D61}\\x{0D7A}-\\x{0D7F}\\x{0D85}-\\x{0D96}\\x{0D9A}-\\x{0DB1}\\x{0DB3}-\\x{0DBB}\\x{0DBD}\\x{0DC0}-\\x{0DC6}\\x{0E01}-\\x{0E30}\\x{0E32}-\\x{0E33}\\x{0E40}-\\x{0E45}\\x{0E81}-\\x{0E82}\\x{0E84}\\x{0E87}-\\x{0E88}\\x{0E8A}\\x{0E8D}\\x{0E94}-\\x{0E97}\\x{0E99}-\\x{0E9F}\\x{0EA1}-\\x{0EA3}\\x{0EA5}\\x{0EA7}\\x{0EAA}-\\x{0EAB}\\x{0EAD}-\\x{0EB0}\\x{0EB2}-\\x{0EB3}\\x{0EBD}\\x{0EC0}-\\x{0EC4}\\x{0EDC}-\\x{0EDF}\\x{0F00}\\x{0F40}-\\x{0F47}\\x{0F49}-\\x{0F6C}\\x{0F88}-\\x{0F8C}\\x{1000}-\\x{102A}\\x{103F}\\x{1050}-\\x{1055}\\x{105A}-\\x{105D}\\x{1061}\\x{1065}-\\x{1066}\\x{106E}-\\x{1070}\\x{1075}-\\x{1081}\\x{108E}\\x{10D0}-\\x{10FA}\\x{10FD}-\\x{1248}\\x{124A}-\\x{124D}\\x{1250}-\\x{1256}\\x{1258}\\x{125A}-\\x{125D}\\x{1260}-\\x{1288}\\x{128A}-\\x{128D}\\x{1290}-\\x{12B0}\\x{12B2}-\\x{12B5}\\x{12B8}-\\x{12BE}\\x{12C0}\\x{12C2}-\\x{12C5}\\x{12C8}-\\x{12D6}\\x{12D8}-\\x{1310}\\x{1312}-\\x{1315}\\x{1318}-\\x{135A}\\x{1380}-\\x{138F}\\x{1401}-\\x{166C}\\x{166F}-\\x{167F}\\x{1681}-\\x{169A}\\x{16A0}-\\x{16EA}\\x{16F1}-\\x{16F8}\\x{1700}-\\x{170C}\\x{170E}-\\x{1711}\\x{1720}-\\x{1731}\\x{1740}-\\x{1751}\\x{1760}-\\x{176C}\\x{176E}-\\x{1770}\\x{1780}-\\x{17B3}\\x{17DC}\\x{1820}-\\x{1842}\\x{1844}-\\x{1877}\\x{1880}-\\x{18A8}\\x{18AA}\\x{18B0}-\\x{18F5}\\x{1900}-\\x{191E}\\x{1950}-\\x{196D}\\x{1970}-\\x{1974}\\x{1980}-\\x{19AB}\\x{19B0}-\\x{19C9}\\x{1A00}-\\x{1A16}\\x{1A20}-\\x{1A54}\\x{1B05}-\\x{1B33}\\x{1B45}-\\x{1B4B}\\x{1B83}-\\x{1BA0}\\x{1BAE}-\\x{1BAF}\\x{1BBA}-\\x{1BE5}\\x{1C00}-\\x{1C23}\\x{1C4D}-\\x{1C4F}\\x{1C5A}-\\x{1C77}\\x{1CE9}-\\x{1CEC}\\x{1CEE}-\\x{1CF1}\\x{1CF5}-\\x{1CF6}\\x{2135}-\\x{2138}\\x{2D30}-\\x{2D67}\\x{2D80}-\\x{2D96}\\x{2DA0}-\\x{2DA6}\\x{2DA8}-\\x{2DAE}\\x{2DB0}-\\x{2DB6}\\x{2DB8}-\\x{2DBE}\\x{2DC0}-\\x{2DC6}\\x{2DC8}-\\x{2DCE}\\x{2DD0}-\\x{2DD6}\\x{2DD8}-\\x{2DDE}\\x{3006}\\x{303C}\\x{3041}-\\x{3096}\\x{309F}\\x{30A1}-\\x{30FA}\\x{30FF}\\x{3105}-\\x{312D}\\x{3131}-\\x{318E}\\x{31A0}-\\x{31BA}\\x{31F0}-\\x{31FF}\\x{3400}-\\x{4DB5}\\x{4E00}-\\x{9FD5}\\x{A000}-\\x{A014}\\x{A016}-\\x{A48C}\\x{A4D0}-\\x{A4F7}\\x{A500}-\\x{A60B}\\x{A610}-\\x{A61F}\\x{A62A}-\\x{A62B}\\x{A66E}\\x{A6A0}-\\x{A6E5}\\x{A78F}\\x{A7F7}\\x{A7FB}-\\x{A801}\\x{A803}-\\x{A805}\\x{A807}-\\x{A80A}\\x{A80C}-\\x{A822}\\x{A840}-\\x{A873}\\x{A882}-\\x{A8B3}\\x{A8F2}-\\x{A8F7}\\x{A8FB}\\x{A8FD}\\x{A90A}-\\x{A925}\\x{A930}-\\x{A946}\\x{A960}-\\x{A97C}\\x{A984}-\\x{A9B2}\\x{A9E0}-\\x{A9E4}\\x{A9E7}-\\x{A9EF}\\x{A9FA}-\\x{A9FE}\\x{AA00}-\\x{AA28}\\x{AA40}-\\x{AA42}\\x{AA44}-\\x{AA4B}\\x{AA60}-\\x{AA6F}\\x{AA71}-\\x{AA76}\\x{AA7A}\\x{AA7E}-\\x{AAAF}\\x{AAB1}\\x{AAB5}-\\x{AAB6}\\x{AAB9}-\\x{AABD}\\x{AAC0}\\x{AAC2}\\x{AADB}-\\x{AADC}\\x{AAE0}-\\x{AAEA}\\x{AAF2}\\x{AB01}-\\x{AB06}\\x{AB09}-\\x{AB0E}\\x{AB11}-\\x{AB16}\\x{AB20}-\\x{AB26}\\x{AB28}-\\x{AB2E}\\x{ABC0}-\\x{ABE2}\\x{AC00}-\\x{D7A3}\\x{D7B0}-\\x{D7C6}\\x{D7CB}-\\x{D7FB}\\x{F900}-\\x{FA6D}\\x{FA70}-\\x{FAD9}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB38}-\\x{FB3C}\\x{FB3E}\\x{FB40}-\\x{FB41}\\x{FB43}-\\x{FB44}\\x{FB46}-\\x{FBB1}\\x{FBD3}-\\x{FD3D}\\x{FD50}-\\x{FD8F}\\x{FD92}-\\x{FDC7}\\x{FDF0}-\\x{FDFB}\\x{FE70}-\\x{FE74}\\x{FE76}-\\x{FEFC}\\x{FF66}-\\x{FF6F}\\x{FF71}-\\x{FF9D}\\x{FFA0}-\\x{FFBE}\\x{FFC2}-\\x{FFC7}\\x{FFCA}-\\x{FFCF}\\x{FFD2}-\\x{FFD7}\\x{FFDA}-\\x{FFDC}]/";
+    $this->peg_c202 = array( "type" => "class", "value" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]", "description" => "[ªº\x{01BB}\x{01C0}-\x{01C3}\x{0294}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}\x{0620}-\x{063F}\x{0641}-\x{064A}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FF}\x{0710}\x{0712}-\x{072F}\x{074D}-\x{07A5}\x{07B1}\x{07CA}-\x{07EA}\x{0800}-\x{0815}\x{0840}-\x{0858}\x{08A0}-\x{08B4}\x{0904}-\x{0939}\x{093D}\x{0950}\x{0958}-\x{0961}\x{0972}-\x{0980}\x{0985}-\x{098C}\x{098F}-\x{0990}\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09BD}\x{09CE}\x{09DC}-\x{09DD}\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AD0}\x{0AE0}-\x{0AE1}\x{0AF9}\x{0B05}-\x{0B0C}\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}\x{0B35}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B71}\x{0B83}\x{0B85}-\x{0B8A}\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB9}\x{0BD0}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}\x{0C2A}-\x{0C39}\x{0C3D}\x{0C58}-\x{0C5A}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CBD}\x{0CDE}\x{0CE0}-\x{0CE1}\x{0CF1}-\x{0CF2}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D3A}\x{0D3D}\x{0D4E}\x{0D5F}-\x{0D61}\x{0D7A}-\x{0D7F}\x{0D85}-\x{0D96}\x{0D9A}-\x{0DB1}\x{0DB3}-\x{0DBB}\x{0DBD}\x{0DC0}-\x{0DC6}\x{0E01}-\x{0E30}\x{0E32}-\x{0E33}\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}\x{0EC0}-\x{0EC4}\x{0EDC}-\x{0EDF}\x{0F00}\x{0F40}-\x{0F47}\x{0F49}-\x{0F6C}\x{0F88}-\x{0F8C}\x{1000}-\x{102A}\x{103F}\x{1050}-\x{1055}\x{105A}-\x{105D}\x{1061}\x{1065}-\x{1066}\x{106E}-\x{1070}\x{1075}-\x{1081}\x{108E}\x{10D0}-\x{10FA}\x{10FD}-\x{1248}\x{124A}-\x{124D}\x{1250}-\x{1256}\x{1258}\x{125A}-\x{125D}\x{1260}-\x{1288}\x{128A}-\x{128D}\x{1290}-\x{12B0}\x{12B2}-\x{12B5}\x{12B8}-\x{12BE}\x{12C0}\x{12C2}-\x{12C5}\x{12C8}-\x{12D6}\x{12D8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135A}\x{1380}-\x{138F}\x{1401}-\x{166C}\x{166F}-\x{167F}\x{1681}-\x{169A}\x{16A0}-\x{16EA}\x{16F1}-\x{16F8}\x{1700}-\x{170C}\x{170E}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176C}\x{176E}-\x{1770}\x{1780}-\x{17B3}\x{17DC}\x{1820}-\x{1842}\x{1844}-\x{1877}\x{1880}-\x{18A8}\x{18AA}\x{18B0}-\x{18F5}\x{1900}-\x{191E}\x{1950}-\x{196D}\x{1970}-\x{1974}\x{1980}-\x{19AB}\x{19B0}-\x{19C9}\x{1A00}-\x{1A16}\x{1A20}-\x{1A54}\x{1B05}-\x{1B33}\x{1B45}-\x{1B4B}\x{1B83}-\x{1BA0}\x{1BAE}-\x{1BAF}\x{1BBA}-\x{1BE5}\x{1C00}-\x{1C23}\x{1C4D}-\x{1C4F}\x{1C5A}-\x{1C77}\x{1CE9}-\x{1CEC}\x{1CEE}-\x{1CF1}\x{1CF5}-\x{1CF6}\x{2135}-\x{2138}\x{2D30}-\x{2D67}\x{2D80}-\x{2D96}\x{2DA0}-\x{2DA6}\x{2DA8}-\x{2DAE}\x{2DB0}-\x{2DB6}\x{2DB8}-\x{2DBE}\x{2DC0}-\x{2DC6}\x{2DC8}-\x{2DCE}\x{2DD0}-\x{2DD6}\x{2DD8}-\x{2DDE}\x{3006}\x{303C}\x{3041}-\x{3096}\x{309F}\x{30A1}-\x{30FA}\x{30FF}\x{3105}-\x{312D}\x{3131}-\x{318E}\x{31A0}-\x{31BA}\x{31F0}-\x{31FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FD5}\x{A000}-\x{A014}\x{A016}-\x{A48C}\x{A4D0}-\x{A4F7}\x{A500}-\x{A60B}\x{A610}-\x{A61F}\x{A62A}-\x{A62B}\x{A66E}\x{A6A0}-\x{A6E5}\x{A78F}\x{A7F7}\x{A7FB}-\x{A801}\x{A803}-\x{A805}\x{A807}-\x{A80A}\x{A80C}-\x{A822}\x{A840}-\x{A873}\x{A882}-\x{A8B3}\x{A8F2}-\x{A8F7}\x{A8FB}\x{A8FD}\x{A90A}-\x{A925}\x{A930}-\x{A946}\x{A960}-\x{A97C}\x{A984}-\x{A9B2}\x{A9E0}-\x{A9E4}\x{A9E7}-\x{A9EF}\x{A9FA}-\x{A9FE}\x{AA00}-\x{AA28}\x{AA40}-\x{AA42}\x{AA44}-\x{AA4B}\x{AA60}-\x{AA6F}\x{AA71}-\x{AA76}\x{AA7A}\x{AA7E}-\x{AAAF}\x{AAB1}\x{AAB5}-\x{AAB6}\x{AAB9}-\x{AABD}\x{AAC0}\x{AAC2}\x{AADB}-\x{AADC}\x{AAE0}-\x{AAEA}\x{AAF2}\x{AB01}-\x{AB06}\x{AB09}-\x{AB0E}\x{AB11}-\x{AB16}\x{AB20}-\x{AB26}\x{AB28}-\x{AB2E}\x{ABC0}-\x{ABE2}\x{AC00}-\x{D7A3}\x{D7B0}-\x{D7C6}\x{D7CB}-\x{D7FB}\x{F900}-\x{FA6D}\x{FA70}-\x{FAD9}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB38}-\x{FB3C}\x{FB3E}\x{FB40}-\x{FB41}\x{FB43}-\x{FB44}\x{FB46}-\x{FBB1}\x{FBD3}-\x{FD3D}\x{FD50}-\x{FD8F}\x{FD92}-\x{FDC7}\x{FDF0}-\x{FDFB}\x{FE70}-\x{FE74}\x{FE76}-\x{FEFC}\x{FF66}-\x{FF6F}\x{FF71}-\x{FF9D}\x{FFA0}-\x{FFBE}\x{FFC2}-\x{FFC7}\x{FFCA}-\x{FFCF}\x{FFD2}-\x{FFD7}\x{FFDA}-\x{FFDC}]" );
+    $this->peg_c203 = "/^[\\x{01C5}\\x{01C8}\\x{01CB}\\x{01F2}\\x{1F88}-\\x{1F8F}\\x{1F98}-\\x{1F9F}\\x{1FA8}-\\x{1FAF}\\x{1FBC}\\x{1FCC}\\x{1FFC}]/";
+    $this->peg_c204 = array( "type" => "class", "value" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]", "description" => "[\x{01C5}\x{01C8}\x{01CB}\x{01F2}\x{1F88}-\x{1F8F}\x{1F98}-\x{1F9F}\x{1FA8}-\x{1FAF}\x{1FBC}\x{1FCC}\x{1FFC}]" );
+    $this->peg_c205 = "/^[A-ZÀ-ÖØ-Þ\\x{0100}\\x{0102}\\x{0104}\\x{0106}\\x{0108}\\x{010A}\\x{010C}\\x{010E}\\x{0110}\\x{0112}\\x{0114}\\x{0116}\\x{0118}\\x{011A}\\x{011C}\\x{011E}\\x{0120}\\x{0122}\\x{0124}\\x{0126}\\x{0128}\\x{012A}\\x{012C}\\x{012E}\\x{0130}\\x{0132}\\x{0134}\\x{0136}\\x{0139}\\x{013B}\\x{013D}\\x{013F}\\x{0141}\\x{0143}\\x{0145}\\x{0147}\\x{014A}\\x{014C}\\x{014E}\\x{0150}\\x{0152}\\x{0154}\\x{0156}\\x{0158}\\x{015A}\\x{015C}\\x{015E}\\x{0160}\\x{0162}\\x{0164}\\x{0166}\\x{0168}\\x{016A}\\x{016C}\\x{016E}\\x{0170}\\x{0172}\\x{0174}\\x{0176}\\x{0178}-\\x{0179}\\x{017B}\\x{017D}\\x{0181}-\\x{0182}\\x{0184}\\x{0186}-\\x{0187}\\x{0189}-\\x{018B}\\x{018E}-\\x{0191}\\x{0193}-\\x{0194}\\x{0196}-\\x{0198}\\x{019C}-\\x{019D}\\x{019F}-\\x{01A0}\\x{01A2}\\x{01A4}\\x{01A6}-\\x{01A7}\\x{01A9}\\x{01AC}\\x{01AE}-\\x{01AF}\\x{01B1}-\\x{01B3}\\x{01B5}\\x{01B7}-\\x{01B8}\\x{01BC}\\x{01C4}\\x{01C7}\\x{01CA}\\x{01CD}\\x{01CF}\\x{01D1}\\x{01D3}\\x{01D5}\\x{01D7}\\x{01D9}\\x{01DB}\\x{01DE}\\x{01E0}\\x{01E2}\\x{01E4}\\x{01E6}\\x{01E8}\\x{01EA}\\x{01EC}\\x{01EE}\\x{01F1}\\x{01F4}\\x{01F6}-\\x{01F8}\\x{01FA}\\x{01FC}\\x{01FE}\\x{0200}\\x{0202}\\x{0204}\\x{0206}\\x{0208}\\x{020A}\\x{020C}\\x{020E}\\x{0210}\\x{0212}\\x{0214}\\x{0216}\\x{0218}\\x{021A}\\x{021C}\\x{021E}\\x{0220}\\x{0222}\\x{0224}\\x{0226}\\x{0228}\\x{022A}\\x{022C}\\x{022E}\\x{0230}\\x{0232}\\x{023A}-\\x{023B}\\x{023D}-\\x{023E}\\x{0241}\\x{0243}-\\x{0246}\\x{0248}\\x{024A}\\x{024C}\\x{024E}\\x{0370}\\x{0372}\\x{0376}\\x{037F}\\x{0386}\\x{0388}-\\x{038A}\\x{038C}\\x{038E}-\\x{038F}\\x{0391}-\\x{03A1}\\x{03A3}-\\x{03AB}\\x{03CF}\\x{03D2}-\\x{03D4}\\x{03D8}\\x{03DA}\\x{03DC}\\x{03DE}\\x{03E0}\\x{03E2}\\x{03E4}\\x{03E6}\\x{03E8}\\x{03EA}\\x{03EC}\\x{03EE}\\x{03F4}\\x{03F7}\\x{03F9}-\\x{03FA}\\x{03FD}-\\x{042F}\\x{0460}\\x{0462}\\x{0464}\\x{0466}\\x{0468}\\x{046A}\\x{046C}\\x{046E}\\x{0470}\\x{0472}\\x{0474}\\x{0476}\\x{0478}\\x{047A}\\x{047C}\\x{047E}\\x{0480}\\x{048A}\\x{048C}\\x{048E}\\x{0490}\\x{0492}\\x{0494}\\x{0496}\\x{0498}\\x{049A}\\x{049C}\\x{049E}\\x{04A0}\\x{04A2}\\x{04A4}\\x{04A6}\\x{04A8}\\x{04AA}\\x{04AC}\\x{04AE}\\x{04B0}\\x{04B2}\\x{04B4}\\x{04B6}\\x{04B8}\\x{04BA}\\x{04BC}\\x{04BE}\\x{04C0}-\\x{04C1}\\x{04C3}\\x{04C5}\\x{04C7}\\x{04C9}\\x{04CB}\\x{04CD}\\x{04D0}\\x{04D2}\\x{04D4}\\x{04D6}\\x{04D8}\\x{04DA}\\x{04DC}\\x{04DE}\\x{04E0}\\x{04E2}\\x{04E4}\\x{04E6}\\x{04E8}\\x{04EA}\\x{04EC}\\x{04EE}\\x{04F0}\\x{04F2}\\x{04F4}\\x{04F6}\\x{04F8}\\x{04FA}\\x{04FC}\\x{04FE}\\x{0500}\\x{0502}\\x{0504}\\x{0506}\\x{0508}\\x{050A}\\x{050C}\\x{050E}\\x{0510}\\x{0512}\\x{0514}\\x{0516}\\x{0518}\\x{051A}\\x{051C}\\x{051E}\\x{0520}\\x{0522}\\x{0524}\\x{0526}\\x{0528}\\x{052A}\\x{052C}\\x{052E}\\x{0531}-\\x{0556}\\x{10A0}-\\x{10C5}\\x{10C7}\\x{10CD}\\x{13A0}-\\x{13F5}\\x{1E00}\\x{1E02}\\x{1E04}\\x{1E06}\\x{1E08}\\x{1E0A}\\x{1E0C}\\x{1E0E}\\x{1E10}\\x{1E12}\\x{1E14}\\x{1E16}\\x{1E18}\\x{1E1A}\\x{1E1C}\\x{1E1E}\\x{1E20}\\x{1E22}\\x{1E24}\\x{1E26}\\x{1E28}\\x{1E2A}\\x{1E2C}\\x{1E2E}\\x{1E30}\\x{1E32}\\x{1E34}\\x{1E36}\\x{1E38}\\x{1E3A}\\x{1E3C}\\x{1E3E}\\x{1E40}\\x{1E42}\\x{1E44}\\x{1E46}\\x{1E48}\\x{1E4A}\\x{1E4C}\\x{1E4E}\\x{1E50}\\x{1E52}\\x{1E54}\\x{1E56}\\x{1E58}\\x{1E5A}\\x{1E5C}\\x{1E5E}\\x{1E60}\\x{1E62}\\x{1E64}\\x{1E66}\\x{1E68}\\x{1E6A}\\x{1E6C}\\x{1E6E}\\x{1E70}\\x{1E72}\\x{1E74}\\x{1E76}\\x{1E78}\\x{1E7A}\\x{1E7C}\\x{1E7E}\\x{1E80}\\x{1E82}\\x{1E84}\\x{1E86}\\x{1E88}\\x{1E8A}\\x{1E8C}\\x{1E8E}\\x{1E90}\\x{1E92}\\x{1E94}\\x{1E9E}\\x{1EA0}\\x{1EA2}\\x{1EA4}\\x{1EA6}\\x{1EA8}\\x{1EAA}\\x{1EAC}\\x{1EAE}\\x{1EB0}\\x{1EB2}\\x{1EB4}\\x{1EB6}\\x{1EB8}\\x{1EBA}\\x{1EBC}\\x{1EBE}\\x{1EC0}\\x{1EC2}\\x{1EC4}\\x{1EC6}\\x{1EC8}\\x{1ECA}\\x{1ECC}\\x{1ECE}\\x{1ED0}\\x{1ED2}\\x{1ED4}\\x{1ED6}\\x{1ED8}\\x{1EDA}\\x{1EDC}\\x{1EDE}\\x{1EE0}\\x{1EE2}\\x{1EE4}\\x{1EE6}\\x{1EE8}\\x{1EEA}\\x{1EEC}\\x{1EEE}\\x{1EF0}\\x{1EF2}\\x{1EF4}\\x{1EF6}\\x{1EF8}\\x{1EFA}\\x{1EFC}\\x{1EFE}\\x{1F08}-\\x{1F0F}\\x{1F18}-\\x{1F1D}\\x{1F28}-\\x{1F2F}\\x{1F38}-\\x{1F3F}\\x{1F48}-\\x{1F4D}\\x{1F59}\\x{1F5B}\\x{1F5D}\\x{1F5F}\\x{1F68}-\\x{1F6F}\\x{1FB8}-\\x{1FBB}\\x{1FC8}-\\x{1FCB}\\x{1FD8}-\\x{1FDB}\\x{1FE8}-\\x{1FEC}\\x{1FF8}-\\x{1FFB}\\x{2102}\\x{2107}\\x{210B}-\\x{210D}\\x{2110}-\\x{2112}\\x{2115}\\x{2119}-\\x{211D}\\x{2124}\\x{2126}\\x{2128}\\x{212A}-\\x{212D}\\x{2130}-\\x{2133}\\x{213E}-\\x{213F}\\x{2145}\\x{2183}\\x{2C00}-\\x{2C2E}\\x{2C60}\\x{2C62}-\\x{2C64}\\x{2C67}\\x{2C69}\\x{2C6B}\\x{2C6D}-\\x{2C70}\\x{2C72}\\x{2C75}\\x{2C7E}-\\x{2C80}\\x{2C82}\\x{2C84}\\x{2C86}\\x{2C88}\\x{2C8A}\\x{2C8C}\\x{2C8E}\\x{2C90}\\x{2C92}\\x{2C94}\\x{2C96}\\x{2C98}\\x{2C9A}\\x{2C9C}\\x{2C9E}\\x{2CA0}\\x{2CA2}\\x{2CA4}\\x{2CA6}\\x{2CA8}\\x{2CAA}\\x{2CAC}\\x{2CAE}\\x{2CB0}\\x{2CB2}\\x{2CB4}\\x{2CB6}\\x{2CB8}\\x{2CBA}\\x{2CBC}\\x{2CBE}\\x{2CC0}\\x{2CC2}\\x{2CC4}\\x{2CC6}\\x{2CC8}\\x{2CCA}\\x{2CCC}\\x{2CCE}\\x{2CD0}\\x{2CD2}\\x{2CD4}\\x{2CD6}\\x{2CD8}\\x{2CDA}\\x{2CDC}\\x{2CDE}\\x{2CE0}\\x{2CE2}\\x{2CEB}\\x{2CED}\\x{2CF2}\\x{A640}\\x{A642}\\x{A644}\\x{A646}\\x{A648}\\x{A64A}\\x{A64C}\\x{A64E}\\x{A650}\\x{A652}\\x{A654}\\x{A656}\\x{A658}\\x{A65A}\\x{A65C}\\x{A65E}\\x{A660}\\x{A662}\\x{A664}\\x{A666}\\x{A668}\\x{A66A}\\x{A66C}\\x{A680}\\x{A682}\\x{A684}\\x{A686}\\x{A688}\\x{A68A}\\x{A68C}\\x{A68E}\\x{A690}\\x{A692}\\x{A694}\\x{A696}\\x{A698}\\x{A69A}\\x{A722}\\x{A724}\\x{A726}\\x{A728}\\x{A72A}\\x{A72C}\\x{A72E}\\x{A732}\\x{A734}\\x{A736}\\x{A738}\\x{A73A}\\x{A73C}\\x{A73E}\\x{A740}\\x{A742}\\x{A744}\\x{A746}\\x{A748}\\x{A74A}\\x{A74C}\\x{A74E}\\x{A750}\\x{A752}\\x{A754}\\x{A756}\\x{A758}\\x{A75A}\\x{A75C}\\x{A75E}\\x{A760}\\x{A762}\\x{A764}\\x{A766}\\x{A768}\\x{A76A}\\x{A76C}\\x{A76E}\\x{A779}\\x{A77B}\\x{A77D}-\\x{A77E}\\x{A780}\\x{A782}\\x{A784}\\x{A786}\\x{A78B}\\x{A78D}\\x{A790}\\x{A792}\\x{A796}\\x{A798}\\x{A79A}\\x{A79C}\\x{A79E}\\x{A7A0}\\x{A7A2}\\x{A7A4}\\x{A7A6}\\x{A7A8}\\x{A7AA}-\\x{A7AD}\\x{A7B0}-\\x{A7B4}\\x{A7B6}\\x{FF21}-\\x{FF3A}]/";
+    $this->peg_c206 = array( "type" => "class", "value" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]", "description" => "[A-ZÀ-ÖØ-Þ\x{0100}\x{0102}\x{0104}\x{0106}\x{0108}\x{010A}\x{010C}\x{010E}\x{0110}\x{0112}\x{0114}\x{0116}\x{0118}\x{011A}\x{011C}\x{011E}\x{0120}\x{0122}\x{0124}\x{0126}\x{0128}\x{012A}\x{012C}\x{012E}\x{0130}\x{0132}\x{0134}\x{0136}\x{0139}\x{013B}\x{013D}\x{013F}\x{0141}\x{0143}\x{0145}\x{0147}\x{014A}\x{014C}\x{014E}\x{0150}\x{0152}\x{0154}\x{0156}\x{0158}\x{015A}\x{015C}\x{015E}\x{0160}\x{0162}\x{0164}\x{0166}\x{0168}\x{016A}\x{016C}\x{016E}\x{0170}\x{0172}\x{0174}\x{0176}\x{0178}-\x{0179}\x{017B}\x{017D}\x{0181}-\x{0182}\x{0184}\x{0186}-\x{0187}\x{0189}-\x{018B}\x{018E}-\x{0191}\x{0193}-\x{0194}\x{0196}-\x{0198}\x{019C}-\x{019D}\x{019F}-\x{01A0}\x{01A2}\x{01A4}\x{01A6}-\x{01A7}\x{01A9}\x{01AC}\x{01AE}-\x{01AF}\x{01B1}-\x{01B3}\x{01B5}\x{01B7}-\x{01B8}\x{01BC}\x{01C4}\x{01C7}\x{01CA}\x{01CD}\x{01CF}\x{01D1}\x{01D3}\x{01D5}\x{01D7}\x{01D9}\x{01DB}\x{01DE}\x{01E0}\x{01E2}\x{01E4}\x{01E6}\x{01E8}\x{01EA}\x{01EC}\x{01EE}\x{01F1}\x{01F4}\x{01F6}-\x{01F8}\x{01FA}\x{01FC}\x{01FE}\x{0200}\x{0202}\x{0204}\x{0206}\x{0208}\x{020A}\x{020C}\x{020E}\x{0210}\x{0212}\x{0214}\x{0216}\x{0218}\x{021A}\x{021C}\x{021E}\x{0220}\x{0222}\x{0224}\x{0226}\x{0228}\x{022A}\x{022C}\x{022E}\x{0230}\x{0232}\x{023A}-\x{023B}\x{023D}-\x{023E}\x{0241}\x{0243}-\x{0246}\x{0248}\x{024A}\x{024C}\x{024E}\x{0370}\x{0372}\x{0376}\x{037F}\x{0386}\x{0388}-\x{038A}\x{038C}\x{038E}-\x{038F}\x{0391}-\x{03A1}\x{03A3}-\x{03AB}\x{03CF}\x{03D2}-\x{03D4}\x{03D8}\x{03DA}\x{03DC}\x{03DE}\x{03E0}\x{03E2}\x{03E4}\x{03E6}\x{03E8}\x{03EA}\x{03EC}\x{03EE}\x{03F4}\x{03F7}\x{03F9}-\x{03FA}\x{03FD}-\x{042F}\x{0460}\x{0462}\x{0464}\x{0466}\x{0468}\x{046A}\x{046C}\x{046E}\x{0470}\x{0472}\x{0474}\x{0476}\x{0478}\x{047A}\x{047C}\x{047E}\x{0480}\x{048A}\x{048C}\x{048E}\x{0490}\x{0492}\x{0494}\x{0496}\x{0498}\x{049A}\x{049C}\x{049E}\x{04A0}\x{04A2}\x{04A4}\x{04A6}\x{04A8}\x{04AA}\x{04AC}\x{04AE}\x{04B0}\x{04B2}\x{04B4}\x{04B6}\x{04B8}\x{04BA}\x{04BC}\x{04BE}\x{04C0}-\x{04C1}\x{04C3}\x{04C5}\x{04C7}\x{04C9}\x{04CB}\x{04CD}\x{04D0}\x{04D2}\x{04D4}\x{04D6}\x{04D8}\x{04DA}\x{04DC}\x{04DE}\x{04E0}\x{04E2}\x{04E4}\x{04E6}\x{04E8}\x{04EA}\x{04EC}\x{04EE}\x{04F0}\x{04F2}\x{04F4}\x{04F6}\x{04F8}\x{04FA}\x{04FC}\x{04FE}\x{0500}\x{0502}\x{0504}\x{0506}\x{0508}\x{050A}\x{050C}\x{050E}\x{0510}\x{0512}\x{0514}\x{0516}\x{0518}\x{051A}\x{051C}\x{051E}\x{0520}\x{0522}\x{0524}\x{0526}\x{0528}\x{052A}\x{052C}\x{052E}\x{0531}-\x{0556}\x{10A0}-\x{10C5}\x{10C7}\x{10CD}\x{13A0}-\x{13F5}\x{1E00}\x{1E02}\x{1E04}\x{1E06}\x{1E08}\x{1E0A}\x{1E0C}\x{1E0E}\x{1E10}\x{1E12}\x{1E14}\x{1E16}\x{1E18}\x{1E1A}\x{1E1C}\x{1E1E}\x{1E20}\x{1E22}\x{1E24}\x{1E26}\x{1E28}\x{1E2A}\x{1E2C}\x{1E2E}\x{1E30}\x{1E32}\x{1E34}\x{1E36}\x{1E38}\x{1E3A}\x{1E3C}\x{1E3E}\x{1E40}\x{1E42}\x{1E44}\x{1E46}\x{1E48}\x{1E4A}\x{1E4C}\x{1E4E}\x{1E50}\x{1E52}\x{1E54}\x{1E56}\x{1E58}\x{1E5A}\x{1E5C}\x{1E5E}\x{1E60}\x{1E62}\x{1E64}\x{1E66}\x{1E68}\x{1E6A}\x{1E6C}\x{1E6E}\x{1E70}\x{1E72}\x{1E74}\x{1E76}\x{1E78}\x{1E7A}\x{1E7C}\x{1E7E}\x{1E80}\x{1E82}\x{1E84}\x{1E86}\x{1E88}\x{1E8A}\x{1E8C}\x{1E8E}\x{1E90}\x{1E92}\x{1E94}\x{1E9E}\x{1EA0}\x{1EA2}\x{1EA4}\x{1EA6}\x{1EA8}\x{1EAA}\x{1EAC}\x{1EAE}\x{1EB0}\x{1EB2}\x{1EB4}\x{1EB6}\x{1EB8}\x{1EBA}\x{1EBC}\x{1EBE}\x{1EC0}\x{1EC2}\x{1EC4}\x{1EC6}\x{1EC8}\x{1ECA}\x{1ECC}\x{1ECE}\x{1ED0}\x{1ED2}\x{1ED4}\x{1ED6}\x{1ED8}\x{1EDA}\x{1EDC}\x{1EDE}\x{1EE0}\x{1EE2}\x{1EE4}\x{1EE6}\x{1EE8}\x{1EEA}\x{1EEC}\x{1EEE}\x{1EF0}\x{1EF2}\x{1EF4}\x{1EF6}\x{1EF8}\x{1EFA}\x{1EFC}\x{1EFE}\x{1F08}-\x{1F0F}\x{1F18}-\x{1F1D}\x{1F28}-\x{1F2F}\x{1F38}-\x{1F3F}\x{1F48}-\x{1F4D}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}\x{1F68}-\x{1F6F}\x{1FB8}-\x{1FBB}\x{1FC8}-\x{1FCB}\x{1FD8}-\x{1FDB}\x{1FE8}-\x{1FEC}\x{1FF8}-\x{1FFB}\x{2102}\x{2107}\x{210B}-\x{210D}\x{2110}-\x{2112}\x{2115}\x{2119}-\x{211D}\x{2124}\x{2126}\x{2128}\x{212A}-\x{212D}\x{2130}-\x{2133}\x{213E}-\x{213F}\x{2145}\x{2183}\x{2C00}-\x{2C2E}\x{2C60}\x{2C62}-\x{2C64}\x{2C67}\x{2C69}\x{2C6B}\x{2C6D}-\x{2C70}\x{2C72}\x{2C75}\x{2C7E}-\x{2C80}\x{2C82}\x{2C84}\x{2C86}\x{2C88}\x{2C8A}\x{2C8C}\x{2C8E}\x{2C90}\x{2C92}\x{2C94}\x{2C96}\x{2C98}\x{2C9A}\x{2C9C}\x{2C9E}\x{2CA0}\x{2CA2}\x{2CA4}\x{2CA6}\x{2CA8}\x{2CAA}\x{2CAC}\x{2CAE}\x{2CB0}\x{2CB2}\x{2CB4}\x{2CB6}\x{2CB8}\x{2CBA}\x{2CBC}\x{2CBE}\x{2CC0}\x{2CC2}\x{2CC4}\x{2CC6}\x{2CC8}\x{2CCA}\x{2CCC}\x{2CCE}\x{2CD0}\x{2CD2}\x{2CD4}\x{2CD6}\x{2CD8}\x{2CDA}\x{2CDC}\x{2CDE}\x{2CE0}\x{2CE2}\x{2CEB}\x{2CED}\x{2CF2}\x{A640}\x{A642}\x{A644}\x{A646}\x{A648}\x{A64A}\x{A64C}\x{A64E}\x{A650}\x{A652}\x{A654}\x{A656}\x{A658}\x{A65A}\x{A65C}\x{A65E}\x{A660}\x{A662}\x{A664}\x{A666}\x{A668}\x{A66A}\x{A66C}\x{A680}\x{A682}\x{A684}\x{A686}\x{A688}\x{A68A}\x{A68C}\x{A68E}\x{A690}\x{A692}\x{A694}\x{A696}\x{A698}\x{A69A}\x{A722}\x{A724}\x{A726}\x{A728}\x{A72A}\x{A72C}\x{A72E}\x{A732}\x{A734}\x{A736}\x{A738}\x{A73A}\x{A73C}\x{A73E}\x{A740}\x{A742}\x{A744}\x{A746}\x{A748}\x{A74A}\x{A74C}\x{A74E}\x{A750}\x{A752}\x{A754}\x{A756}\x{A758}\x{A75A}\x{A75C}\x{A75E}\x{A760}\x{A762}\x{A764}\x{A766}\x{A768}\x{A76A}\x{A76C}\x{A76E}\x{A779}\x{A77B}\x{A77D}-\x{A77E}\x{A780}\x{A782}\x{A784}\x{A786}\x{A78B}\x{A78D}\x{A790}\x{A792}\x{A796}\x{A798}\x{A79A}\x{A79C}\x{A79E}\x{A7A0}\x{A7A2}\x{A7A4}\x{A7A6}\x{A7A8}\x{A7AA}-\x{A7AD}\x{A7B0}-\x{A7B4}\x{A7B6}\x{FF21}-\x{FF3A}]" );
+    $this->peg_c207 = array("type" => "other", "description" => "unicode superscript/subscript character" );
+    $this->peg_c208 = "/^[²³¹\\x{2070}-\\x{209C}\\x{2C7C}\\x{1D62}-\\x{1D6A}]/";
+    $this->peg_c209 = array( "type" => "class", "value" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]", "description" => "[²³¹\x{2070}-\x{209C}\x{2C7C}\x{1D62}-\x{1D6A}]" );
+    $this->peg_c210 = array("type" => "other", "description" => "special unicode chars" );
+    $this->peg_c211 = "/^[µ\\x{0370}-\\x{0371}\\x{037F}\\x{0391}-\\x{0392}\\x{0393}-\\x{0394}\\x{0395}-\\x{0396}\\x{0397}-\\x{0398}\\x{0399}-\\x{039A}\\x{039B}-\\x{039C}\\x{039D}-\\x{039E}\\x{039F}-\\x{03A0}\\x{03A1}\\x{03A3}-\\x{03A4}\\x{03A5}-\\x{03A6}\\x{03A7}-\\x{03A8}\\x{03A9}\\x{03B1}-\\x{03B2}\\x{03B3}-\\x{03B4}\\x{03B5}-\\x{03B6}\\x{03B7}-\\x{03B8}\\x{03B9}-\\x{03BA}\\x{03BB}-\\x{03BC}\\x{03BD}-\\x{03BE}\\x{03BF}-\\x{03C0}\\x{03C1}-\\x{03C2}\\x{03C3}-\\x{03C4}\\x{03C5}-\\x{03C6}\\x{03C7}-\\x{03C8}\\x{03C9}\\x{03DB}\\x{03DD}\\x{03DF}\\x{03E1}\\x{03F7}-\\x{03F8}\\x{03FA}-\\x{03FB}\\x{1D26}-\\x{1D27}\\x{1D28}-\\x{1D29}\\x{1D2A}\\x{2102}\\x{2107}\\x{210A}-\\x{210B}\\x{210C}-\\x{210D}\\x{210E}-\\x{210F}\\x{2110}-\\x{2111}\\x{2112}-\\x{2113}\\x{2115}\\x{2119}-\\x{211A}\\x{211B}-\\x{211C}\\x{211D}\\x{2124}\\x{2126}-\\x{2127}\\x{2128}\\x{212B}-\\x{212C}\\x{212D}\\x{212F}-\\x{2130}\\x{2131}\\x{2133}-\\x{2134}\\x{2135}-\\x{2136}\\x{2137}-\\x{2138}\\x{213C}-\\x{213D}\\x{213E}-\\x{213F}\\x{2145}-\\x{2146}\\x{2147}-\\x{2148}\\x{2149}\\x{2205}\\x{221E}\\x{29B0}\\x{AB65}]/";
+    $this->peg_c212 = array( "type" => "class", "value" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]", "description" => "[µ\x{0370}-\x{0371}\x{037F}\x{0391}-\x{0392}\x{0393}-\x{0394}\x{0395}-\x{0396}\x{0397}-\x{0398}\x{0399}-\x{039A}\x{039B}-\x{039C}\x{039D}-\x{039E}\x{039F}-\x{03A0}\x{03A1}\x{03A3}-\x{03A4}\x{03A5}-\x{03A6}\x{03A7}-\x{03A8}\x{03A9}\x{03B1}-\x{03B2}\x{03B3}-\x{03B4}\x{03B5}-\x{03B6}\x{03B7}-\x{03B8}\x{03B9}-\x{03BA}\x{03BB}-\x{03BC}\x{03BD}-\x{03BE}\x{03BF}-\x{03C0}\x{03C1}-\x{03C2}\x{03C3}-\x{03C4}\x{03C5}-\x{03C6}\x{03C7}-\x{03C8}\x{03C9}\x{03DB}\x{03DD}\x{03DF}\x{03E1}\x{03F7}-\x{03F8}\x{03FA}-\x{03FB}\x{1D26}-\x{1D27}\x{1D28}-\x{1D29}\x{1D2A}\x{2102}\x{2107}\x{210A}-\x{210B}\x{210C}-\x{210D}\x{210E}-\x{210F}\x{2110}-\x{2111}\x{2112}-\x{2113}\x{2115}\x{2119}-\x{211A}\x{211B}-\x{211C}\x{211D}\x{2124}\x{2126}-\x{2127}\x{2128}\x{212B}-\x{212C}\x{212D}\x{212F}-\x{2130}\x{2131}\x{2133}-\x{2134}\x{2135}-\x{2136}\x{2137}-\x{2138}\x{213C}-\x{213D}\x{213E}-\x{213F}\x{2145}-\x{2146}\x{2147}-\x{2148}\x{2149}\x{2205}\x{221E}\x{29B0}\x{AB65}]" );
 
     $peg_startRuleFunctions = array( 'Root' => array($this, "peg_parseRoot"), 'Equivline' => array($this, "peg_parseEquivline") );
     $peg_startRuleFunction  = array($this, "peg_parseRoot");
diff --git a/stack/maximaparser/corrective_parser.php b/stack/maximaparser/corrective_parser.php
index 05d47c8443ffab2a11dc8ea3141d972969a76037..8865e46d4849ed26c5cebfa4cc41f7304733bedc 100644
--- a/stack/maximaparser/corrective_parser.php
+++ b/stack/maximaparser/corrective_parser.php
@@ -461,8 +461,8 @@ class maxima_corrective_parser {
                    $exception->expected[4]['type'] === 'end' &&
                    $exception->expected[5]['type'] === 'other' && $exception->expected[5]['description'] === 'whitespace') {
             // This is a sensitive check matching the expectations of the parser....
-            // This is extra special, if we have an unencpsulated comma we might be parsing for an evaluation
-            // flag but not find the assingment of flag value...
+            // This is extra special, if we have an unencapsulated comma we might be parsing for an evaluation
+            // flag but not find the assignment of flag value...
             $errors[] = stack_string('stackCas_unencpsulated_comma');
             $answernote[] = 'unencapsulated_comma';
         } else if ($nextchar === '' && ($foundchar !== '' && mb_strpos($disallowedfinalchars, $foundchar) !== false)) {
diff --git a/stack/questiontest.php b/stack/questiontest.php
index 31f27252dc1c0dea6e322657434ee7e4a813859e..c50804b7d00b3f70867d8539a71f4b75c8b9080c 100644
--- a/stack/questiontest.php
+++ b/stack/questiontest.php
@@ -73,11 +73,6 @@ class stack_question_test {
      * @return stack_question_test_result the test results.
      */
     public function test_question($questionid, $seed, $context) {
-
-        // We don't permit completely empty test cases.
-        // Completely empty test cases always pass, which is spurious in the bulk test.
-        $emptytestcase = true;
-
         // Create a completely clean version of the question usage we will use.
         // Evaluated state is stored in question variables etc.
         $question = question_bank::load_question($questionid);
@@ -98,6 +93,27 @@ class stack_question_test {
         $response = self::compute_response($question, $this->inputs);
         $quba->process_action($slot, $response);
 
+        $results = $this->process_results($question, $response);
+
+        if ($this->testcase) {
+            $this->save_result($question, $results);
+        }
+
+        return $results;
+    }
+
+    /**
+     * Seperate out from Moodle-specific parts of test_question() to allow
+     * use in the API
+     *
+     * @param question_definition $question
+     * @param array $response
+     * @return stack_question_test_result
+     */
+    public function process_results($question, $response) {
+        // We don't permit completely empty test cases.
+        // Completely empty test cases always pass, which is spurious in the bulk test.
+        $emptytestcase = true;
         $results = new stack_question_test_result($this);
         $results->set_questionpenalty($question->penalty);
         foreach ($this->inputs as $inputname => $notused) {
@@ -138,11 +154,6 @@ class stack_question_test {
         }
 
         $results->emptytestcase = $emptytestcase;
-
-        if ($this->testcase) {
-            $this->save_result($question, $results);
-        }
-
         return $results;
     }
 
diff --git a/stack/questiontestresult.php b/stack/questiontestresult.php
index 8e013366152e3a369d751ddc53e8160f499ddee4..779673879295a4c8404e7c282bf048c033b00c00 100644
--- a/stack/questiontestresult.php
+++ b/stack/questiontestresult.php
@@ -245,6 +245,51 @@ class stack_question_test_result {
         return true;
     }
 
+    /**
+     * @return array whether the test passed successfully + outcomes, inputs and reasons for failure.
+     */
+    public function passed_with_reasons() {
+        $passed = true;
+        $reason = '';
+        $inputs = [];
+        $outcomes = [];
+        if ($this->emptytestcase) {
+            $passed = false;
+            $reason = stack_string('questiontestempty');
+        } else {
+            foreach ($this->get_input_states() as $inputname => $inputstate) {
+                $inputval = ($inputstate->input === false) ? '' : $inputstate->input;
+                $inputs[$inputname] = [
+                    'inputexpression' => $inputname,
+                    'inputentered' => $inputval,
+                    'inputmodified' => $inputstate->modified,
+                    'inputdisplayed' => stack_ouput_castext($inputstate->display),
+                    'inputstatus' => stack_string('inputstatusname' . $inputstate->status),
+                    'errors' => $inputstate->errors,
+                ];
+
+            }
+
+            foreach ($this->get_prt_states() as $prtname => $state) {
+                $outcomes[$prtname] = [
+                    'outcome' => $state->testoutcome,
+                    'score' => $state->score,
+                    'penalty' => $state->penalty,
+                    'answernote' => $state->answernote,
+                    'expectedscore' => $state->expectedscore,
+                    'expectedpenalty' => $state->expectedpenalty,
+                    'expectedanswernote' => $state->expectedanswernote,
+                    'feedback' => $state->feedback,
+                    'reason' => $state->reason,
+                ];
+                if (!$state->testoutcome) {
+                    $passed = false;
+                }
+            }
+        }
+        return ['passed' => $passed, 'reason' => $reason, 'inputs' => $inputs, 'outcomes' => $outcomes];
+    }
+
     /**
      * Create an HTML output of the test result.
      */
diff --git a/tests/api_controller_test.php b/tests/api_controller_test.php
index 562f099ce57eadab182604e68e3888ff7d80761b..348d76d05977c55e0ca7972fe12a22eae7f508fd 100644
--- a/tests/api_controller_test.php
+++ b/tests/api_controller_test.php
@@ -29,34 +29,28 @@ require_once(__DIR__ . '../../api/controller/DownloadController.php');
 require_once(__DIR__ . '../../api/controller/GradingController.php');
 require_once(__DIR__ . '../../api/controller/RenderController.php');
 require_once(__DIR__ . '../../api/controller/ValidationController.php');
+require_once(__DIR__ . '../../api/controller/TestController.php');
 
 
 use api\controller\DownloadController;
 use api\controller\GradingController;
 use api\controller\RenderController;
 use api\controller\ValidationController;
+use api\controller\TestController;
 use api\util\StackIframeHolder;
 use stack_api_test_data;
 use Psr\Http\Message\ResponseInterface as ResponseInt;
+use Psr\Http\Message\StreamInterface as StreamInt;
 use Psr\Http\Message\ServerRequestInterface as RequestInt;
 use qtype_stack_testcase;
 
-/**
- * Class to fake the response output object and store the actual JSON
- */
-class MockBody {
-    public object $output;
-    public function write() {
-        $this->output = json_decode(func_get_args()[0]);
-        return $this->output;
-    }
-}
-
 /**
  * @group qtype_stack
  * @covers \qtype_stack
  */
 class api_controller_test extends qtype_stack_testcase {
+    /** @var object used to store output */
+    public object $output;
     /** @var object used to store output */
     public object $result;
     /** @var array the api call data */
@@ -111,11 +105,27 @@ class api_controller_test extends qtype_stack_testcase {
             ->setMethods($methods)
             ->getMock();
 
-        $this->result = new MockBody();
+        $reflection = new \ReflectionClass(StreamInt::class);
+        $methods = [];
+        foreach ($reflection->getMethods() as $method) {
+            $methods[] = $method->name;
+        }
+
+        $this->result = $this->getMockBuilder(StreamInt::class)
+            ->setMockClassName('StreamInterface')
+            ->setMethods($methods)
+            ->getMock();
 
-        // The controllers call getBody() on the response object but then call write() on the result.
-        // We return a MockBody object with a write method which updates the test's result property
-        // so we can actually perform some asserts.
+        $this->result->expects($this->any())->method('write')->will($this->returnCallback(
+            function() {
+                $this->output = json_decode(func_get_args()[0]);
+                return 1;
+            })
+        );
+
+        // The controllers call getBody() on the response object but then call write() on the result
+        // so we have to mock both. We override the write method to write to a propery of the testsuite
+        // so we have something easily accessible to perform some asserts on.
         $this->response->expects($this->any())->method('getBody')->will($this->returnCallback(
             function() {
                 return $this->result;
@@ -138,18 +148,18 @@ class api_controller_test extends qtype_stack_testcase {
         $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices');
         $rc = new RenderController();
         $rc->__invoke($this->request, $this->response, []);
-        $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->result->output->questionrender);
-        $this->assertEquals(86, $this->result->output->questionseed);
-        $this->assertEquals('matrix([35,30],[28,24])', $this->result->output->questioninputs->ans1->samplesolution->_val);
+        $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->output->questionrender);
+        $this->assertEquals(86, $this->output->questionseed);
+        $this->assertEquals('matrix([35,30],[28,24])', $this->output->questioninputs->ans1->samplesolution->_val);
         $this->assertMatchesRegularExpression('/^<div class="matrixsquarebrackets"><table class="matrixtable"/',
-                $this->result->output->questioninputs->ans1->render);
-        $this->assertMatchesRegularExpression('/^<p>To multiply matrices/', $this->result->output->questionsamplesolutiontext);
-        $this->assertEquals(0, count((array)$this->result->output->questionassets));
-        $this->assertContains(86, $this->result->output->questionvariants);
-        $this->assertContains(219862533, $this->result->output->questionvariants);
-        $this->assertContains(1167893775, $this->result->output->questionvariants);
-        $this->assertEquals(3, count($this->result->output->questionvariants));
-        $this->assertEquals(0, count($this->result->output->iframes));
+                $this->output->questioninputs->ans1->render);
+        $this->assertMatchesRegularExpression('/^<p>To multiply matrices/', $this->output->questionsamplesolutiontext);
+        $this->assertEquals(0, count((array)$this->output->questionassets));
+        $this->assertContains(86, $this->output->questionvariants);
+        $this->assertContains(219862533, $this->output->questionvariants);
+        $this->assertContains(1167893775, $this->output->questionvariants);
+        $this->assertEquals(3, count($this->output->questionvariants));
+        $this->assertEquals(0, count($this->output->iframes));
     }
 
     public function test_render_specified_seed() {
@@ -157,33 +167,33 @@ class api_controller_test extends qtype_stack_testcase {
         $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices');
         $rc = new RenderController();
         $rc->__invoke($this->request, $this->response, []);
-        $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->result->output->questionrender);
-        $this->assertEquals(219862533, $this->result->output->questionseed);
+        $this->assertMatchesRegularExpression('/^<p>Calculate/', $this->output->questionrender);
+        $this->assertEquals(219862533, $this->output->questionseed);
     }
 
     public function test_render_plots() {
         $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('plots');
         $rc = new RenderController();
         $rc->__invoke($this->request, $this->response, []);
-        $this->assertEquals(4, count((array)$this->result->output->questionassets));
-        $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-1-0.svg'}));
-        $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-2-0.svg'}));
-        $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-3-0.svg'}));
-        $this->assertEquals(true, isset($this->result->output->questionassets->{'input-ans1-4-0.svg'}));
+        $this->assertEquals(4, count((array)$this->output->questionassets));
+        $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-1-0.svg'}));
+        $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-2-0.svg'}));
+        $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-3-0.svg'}));
+        $this->assertEquals(true, isset($this->output->questionassets->{'input-ans1-4-0.svg'}));
     }
 
     public function test_render_iframes() {
         $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('iframes');
         $rc = new RenderController();
         $rc->__invoke($this->request, $this->response, []);
-        $this->assertEquals(1, count($this->result->output->iframes));
+        $this->assertEquals(1, count($this->output->iframes));
     }
 
     public function test_render_download() {
         $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('download');
         $rc = new RenderController();
         $rc->__invoke($this->request, $this->response, []);
-        $this->assertMatchesRegularExpression('/javascript\:download\(\'data.csv\'\, 1\)/s', $this->result->output->questionrender);
+        $this->assertMatchesRegularExpression('/javascript\:download\(\'data.csv\'\, 1\)/s', $this->output->questionrender);
     }
 
     public function test_validation() {
@@ -193,8 +203,8 @@ class api_controller_test extends qtype_stack_testcase {
         $vc = new ValidationController();
         $vc->__invoke($this->request, $this->response, []);
         $this->assertMatchesRegularExpression('/\\\[ \\\left\[\\begin\{array\}\{cc\} 1 & 2 \\\\ 3 & 4 \\end{array}\\right\] \\\]/s',
-                $this->result->output->validation);
-        $this->assertEquals(0, count($this->result->output->iframes));
+                $this->output->validation);
+        $this->assertEquals(0, count($this->output->iframes));
     }
 
     public function test_grade() {
@@ -203,17 +213,17 @@ class api_controller_test extends qtype_stack_testcase {
         $this->requestdata['inputName'] = 'ans1';
         $gc = new GradingController();
         $gc->__invoke($this->request, $this->response, []);
-        $this->assertEquals(true, $this->result->output->isgradable);
-        $this->assertEquals(1, $this->result->output->score);
-        $this->assertEquals(1, $this->result->output->scores->prt1);
-        $this->assertEquals(1, $this->result->output->scores->total);
-        $this->assertEquals(1, $this->result->output->scoreweights->prt1);
-        $this->assertEquals(5, $this->result->output->scoreweights->total);
-        $this->assertEquals('<p>[[feedback:prt1]]</p>', $this->result->output->specificfeedback);
-        $this->assertStringContainsString('correct', $this->result->output->prts->prt1);
-        $this->assertEquals(0, count((array)$this->result->output->gradingassets));
-        $this->assertEquals('Seed: 86; ans1: matrix([35,30],[28,24]) [valid]; prt1: !', $this->result->output->responsesummary);
-        $this->assertEquals(0, count($this->result->output->iframes));
+        $this->assertEquals(true, $this->output->isgradable);
+        $this->assertEquals(1, $this->output->score);
+        $this->assertEquals(1, $this->output->scores->prt1);
+        $this->assertEquals(1, $this->output->scores->total);
+        $this->assertEquals(1, $this->output->scoreweights->prt1);
+        $this->assertEquals(5, $this->output->scoreweights->total);
+        $this->assertEquals('<p>[[feedback:prt1]]</p>', $this->output->specificfeedback);
+        $this->assertStringContainsString('correct', $this->output->prts->prt1);
+        $this->assertEquals(0, count((array)$this->output->gradingassets));
+        $this->assertEquals('Seed: 86; ans1: matrix([35,30],[28,24]) [valid]; prt1: !', $this->output->responsesummary);
+        $this->assertEquals(0, count($this->output->iframes));
     }
 
     public function test_grade_scores() {
@@ -222,18 +232,18 @@ class api_controller_test extends qtype_stack_testcase {
         $this->requestdata['inputName'] = 'ans1';
         $gc = new GradingController();
         $gc->__invoke($this->request, $this->response, []);
-        $this->assertEquals(true, $this->result->output->isgradable);
-        $this->assertEqualsWithDelta(0.9, $this->result->output->score, 0.0001);
-        $this->assertEquals(1, $this->result->output->scores->prt1);
-        $this->assertEquals(1, $this->result->output->scores->prt2);
-        $this->assertEquals(0, $this->result->output->scores->prt3);
-        $this->assertEquals(1, $this->result->output->scores->prt4);
-        $this->assertEqualsWithDelta(0.9, $this->result->output->scores->total, 0.0001);
-        $this->assertEqualsWithDelta(0.7, $this->result->output->scoreweights->prt1, 0.0001);
-        $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt2, 0.0001);
-        $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt3, 0.0001);
-        $this->assertEqualsWithDelta(0.1, $this->result->output->scoreweights->prt4, 0.0001);
-        $this->assertEquals(10, $this->result->output->scoreweights->total);
+        $this->assertEquals(true, $this->output->isgradable);
+        $this->assertEqualsWithDelta(0.9, $this->output->score, 0.0001);
+        $this->assertEquals(1, $this->output->scores->prt1);
+        $this->assertEquals(1, $this->output->scores->prt2);
+        $this->assertEquals(0, $this->output->scores->prt3);
+        $this->assertEquals(1, $this->output->scores->prt4);
+        $this->assertEqualsWithDelta(0.9, $this->output->scores->total, 0.0001);
+        $this->assertEqualsWithDelta(0.7, $this->output->scoreweights->prt1, 0.0001);
+        $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt2, 0.0001);
+        $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt3, 0.0001);
+        $this->assertEqualsWithDelta(0.1, $this->output->scoreweights->prt4, 0.0001);
+        $this->assertEquals(10, $this->output->scoreweights->total);
     }
 
     public function test_download() {
@@ -251,4 +261,95 @@ class api_controller_test extends qtype_stack_testcase {
         $this->expectOutputRegex('/^A,B,C\n0.37,5.04,2.72/s');
     }
 
+    public function test_test_controller() {
+        $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('matrices');
+        $this->requestdata['filepath'] = 'testpath/test.xml';
+        $tc = new TestController();
+        $tc->__invoke($this->request, $this->response, []);
+        $results = $this->output;
+        $this->assertEquals('test_3_matrix', $results->name);
+        $this->assertEquals(false, $results->isupgradeerror);
+        $this->assertEquals(true, $results->isgeneralfeedback );
+        $this->assertEquals(true, $results->isdeployedseeds);
+        $this->assertEquals(true, $results->israndomvariants);
+        $this->assertEquals(true, $results->istests);
+        // Three seeds.
+        $this->assertEquals(3, count(get_object_vars($results->results)));
+        $this->assertEquals(4, $results->results->{'86'}->passes);
+        $this->assertEquals(0, $results->results->{'86'}->fails);
+        $this->assertEquals('', $results->results->{'86'}->messages);
+        $this->assertEquals(4, count(get_object_vars($results->results->{'86'}->outcomes)));
+    }
+
+    public function test_test_controller_fail() {
+        $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test');
+        $this->requestdata['filepath'] = 'testpath/test.xml';
+        $tc = new TestController();
+        $tc->__invoke($this->request, $this->response, []);
+        $results = $this->output;
+        $this->assertEquals('Algebraic input', $results->name);
+        $this->assertEquals(false, $results->isupgradeerror);
+        $this->assertEquals(false, $results->isgeneralfeedback );
+        $this->assertEquals(false, $results->isdeployedseeds);
+        $this->assertEquals(false, $results->israndomvariants);
+        $this->assertEquals(true, $results->istests);
+        // No seeds.
+        $this->assertEquals(1, count(get_object_vars($results->results)));
+        $this->assertEquals(0, $results->results->noseed->passes);
+        $this->assertEquals(2, $results->results->noseed->fails);
+        $this->assertEquals(stack_string('questiontestempty'), $results->results->noseed->messages);
+        $this->assertEquals('', $results->messages);
+        $this->assertEquals(2, count(get_object_vars($results->results->noseed->outcomes)));
+    }
+
+    public function test_test_controller_upgrade() {
+        $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test2');
+        $this->requestdata['filepath'] = 'testpath/test.xml';
+        $tc = new TestController();
+        $tc->__invoke($this->request, $this->response, []);
+        $results = $this->output;
+        $this->assertEquals('Algebraic input', $results->name);
+        $this->assertEquals(true, $results->isupgradeerror);
+        $this->assertEquals(false, $results->isgeneralfeedback );
+        $this->assertEquals(false, $results->isdeployedseeds);
+        $this->assertEquals(false, $results->israndomvariants);
+        $this->assertEquals(false, $results->istests);
+        $this->assertStringContainsString('missing or empty', $results->messages);
+        $this->assertEquals([], $results->results);
+    }
+
+    public function test_test_controller_default_test_fail() {
+        $this->requestdata['questionDefinition'] = stack_api_test_data::get_question_string('test3');
+        $this->requestdata['filepath'] = 'testpath/test.xml';
+        $tc = new TestController();
+        $tc->__invoke($this->request, $this->response, []);
+        $results = $this->output;
+        $this->assertEquals('Algebraic input', $results->name);
+        $this->assertEquals(false, $results->isupgradeerror);
+        $this->assertEquals(false, $results->isgeneralfeedback );
+        $this->assertEquals(false, $results->isdeployedseeds);
+        $this->assertEquals(false, $results->israndomvariants);
+        $this->assertEquals(false, $results->istests);
+        $this->assertEquals(stack_string('default_test_fail'), $results->results->noseed->messages);
+        $this->assertEquals(1, $results->results->noseed->fails);
+        $this->assertEquals(0, $results->results->noseed->passes);
+    }
+
+    public function test_test_controller_default_test_pass() {
+        $this->requestdata['questionDefinition'] =
+            str_replace('<tans>wrong</tans>', '<tans>ta</tans>', stack_api_test_data::get_question_string('test3'));
+        $this->requestdata['filepath'] = 'testpath/test.xml';
+        $tc = new TestController();
+        $tc->__invoke($this->request, $this->response, []);
+        $results = $this->output;
+        $this->assertEquals('Algebraic input', $results->name);
+        $this->assertEquals(false, $results->isupgradeerror);
+        $this->assertEquals(false, $results->isgeneralfeedback );
+        $this->assertEquals(false, $results->isdeployedseeds);
+        $this->assertEquals(false, $results->israndomvariants);
+        $this->assertEquals(false, $results->istests);
+        $this->assertEquals('', $results->results->noseed->messages);
+        $this->assertEquals(0, $results->results->noseed->fails);
+        $this->assertEquals(1, $results->results->noseed->passes);
+    }
 }
diff --git a/tests/api_stackquestionloader_test.php b/tests/api_stackquestionloader_test.php
index 79d9ccacffbf602780ba2402f6de2519bd787d88..586291bbdea0624cf84763e769f0a7022bcbe5a3 100644
--- a/tests/api_stackquestionloader_test.php
+++ b/tests/api_stackquestionloader_test.php
@@ -40,7 +40,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase {
     public function test_question_loader() {
         $xml = stack_api_test_data::get_question_string('matrices');
         $ql = new StackQuestionLoader();
-        $question = $ql->loadXML($xml);
+        $question = $ql->loadXML($xml)['question'];
 
         // Testing a representative selection of fields.
         $this->assertEquals('test_3_matrix', $question->name);
@@ -66,7 +66,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase {
         global $CFG;
         $xml = stack_api_test_data::get_question_string('usedefaults');
         $ql = new StackQuestionLoader();
-        $question = $ql->loadXML($xml);
+        $question = $ql->loadXML($xml)['question'];
         $this->assertEquals($question->options->get_option('decimals'), get_config('qtype_stack', 'decimals'));
         $this->assertEquals($question->options->get_option('scientificnotation'),
                 get_config('qtype_stack', 'scientificnotation'));
@@ -97,7 +97,7 @@ class api_stackquestionloader_test extends qtype_stack_testcase {
         global $CFG;
         $xml = stack_api_test_data::get_question_string('optionset');
         $ql = new StackQuestionLoader();
-        $question = $ql->loadXML($xml);
+        $question = $ql->loadXML($xml)['question'];
         $this->assertEquals($question->options->get_option('decimals'), ',');
         $this->assertEquals($question->options->get_option('scientificnotation'), '*10');
         $this->assertEquals($question->options->get_option('assumepos'), true);
diff --git a/tests/caskeyval_test.php b/tests/caskeyval_test.php
index db398a15653fe42a30665b1cc908ad2bbd9cb3a2..f8a5a1dcbb5fb4639f3a81d06b65434a9a5250ce 100644
--- a/tests/caskeyval_test.php
+++ b/tests/caskeyval_test.php
@@ -77,6 +77,7 @@ class caskeyval_test extends qtype_stack_testcase {
                 // In the new setup the parsing of the keyvals does not match the sessions created above.
                 // This is because of a failure to split the text into statements.
                 // This is a serious drawback when we try to identify which statement is throwing an error!
+            ["a:x^2$ b:(x+1)^2", true, $cs1],
             ["a:x^2) \n b:(x+1)^2", false, $cs0],
             ['a:x^2); b:(x+1)^2', false, $cs0],
             ['a:1/0', true, $cs2],
@@ -107,6 +108,16 @@ class caskeyval_test extends qtype_stack_testcase {
         $this->assertEquals($s->get_by_key('ta3')->get_evaluationform(), 'ta3:x = 1 nounor x = 2');
     }
 
+    public function test_equations_2() {
+        $at1 = new stack_cas_keyval('ta1 : x=1$ ta2 : x^2-2*x=1$ ta3:x=1 nounor x=2', null, 123);
+        $at1->instantiate();
+        $s = $at1->get_session();
+        $s->instantiate();
+        $this->assertEquals($s->get_by_key('ta1')->get_evaluationform(), 'ta1:x = 1');
+        $this->assertEquals($s->get_by_key('ta2')->get_evaluationform(), 'ta2:x^2-2*x = 1');
+        $this->assertEquals($s->get_by_key('ta3')->get_evaluationform(), 'ta3:x = 1 nounor x = 2');
+    }
+
     public function test_keyval_session_keyval_0() {
         $kvin = "";
         $at1 = new stack_cas_keyval($kvin, null, 123);
@@ -228,7 +239,7 @@ class caskeyval_test extends qtype_stack_testcase {
 
         $kv = new stack_cas_keyval($tests);
         $this->assertFalse($kv->get_valid());
-        $expected = ['The characters @, $ and \ are not allowed in CAS input.'];
+        $expected = ['The characters @ and \ are not allowed in CAS input.'];
         $this->assertEquals($expected, $kv->get_errors());
     }
 
@@ -318,4 +329,45 @@ class caskeyval_test extends qtype_stack_testcase {
         ];
         $this->assertEquals($expected, $kv->get_errors());
     }
+
+    public function test_stack_compile() {
+        $tests = 'stack_reset_vars(true);ordergreat(i,j,k);p:matrix([-7],[2],[-3]);' .
+                 'q:matrix([i],[j],[k]);v:dotproduct(p,q);';
+        $kv = new stack_cas_keyval($tests);
+        $this->assertTrue($kv->get_valid());
+        $expected = [
+        ];
+        $compiled = $kv->compile('kv-test');
+
+        $expected = '(_EC(errcatch(stack_reset_vars(true)),"kv-test/1:1-1:2"),' .
+                    '_EC(errcatch(ordergreat(i,j,k)),"kv-test/1:24-1:2"),true)';
+        $this->assertEquals($expected, $compiled['blockexternal']);
+        $expected = '(_EC(errcatch(p:(%_C(matrix),matrix([-7],[2],[-3]))),"kv-test/1:42-1:2"),' .
+                    '_EC(errcatch(q:(%_C(matrix),matrix([i],[j],[k]))),"kv-test/1:66-1:2"),' .
+                    '_EC(errcatch(v:(%_C(dotproduct),dotproduct(p,q))),"kv-test/1:88-1:2"),true)';
+        $this->assertEquals($expected, $compiled['statement']);
+        $expected = null;
+        $this->assertEquals($expected, $compiled['contextvariables']);
+    }
+
+    public function test_stack_compile_preamble_end1() {
+        $tests = 'stack_reset_vars(true);n1:1;ordergreat(i,j,k);%_stack_preamble_end;' .
+            'p:matrix([-7],[2],[-3]);' .
+            'q:matrix([i],[j],[k]);v:dotproduct(p,q);';
+        $kv = new stack_cas_keyval($tests);
+        $this->assertTrue($kv->get_valid());
+        $expected = [
+        ];
+        $compiled = $kv->compile('kv-test');
+
+        $expected = '(_EC(errcatch(stack_reset_vars(true)),"kv-test/1:1-1:2"),' .
+            '_EC(errcatch(ordergreat(i,j,k)),"kv-test/1:29-1:2"),true)';
+        $this->assertEquals($expected, $compiled['blockexternal']);
+        $expected = '(_EC(errcatch(p:(%_C(matrix),matrix([-7],[2],[-3]))),"kv-test/1:68-1:2"),' .
+            '_EC(errcatch(q:(%_C(matrix),matrix([i],[j],[k]))),"kv-test/1:92-1:2"),' .
+            '_EC(errcatch(v:(%_C(dotproduct),dotproduct(p,q))),"kv-test/1:114-1:2"),true)';
+        $this->assertEquals($expected, $compiled['statement']);
+        $expected = '(_EC(errcatch(n1:1),"kv-test/1:24-1:2"),true)';
+        $this->assertEquals($expected, $compiled['contextvariables']);
+    }
 }
diff --git a/tests/cassession2_test.php b/tests/cassession2_test.php
index d910bd21373352937dfc2b770ff5bd0a6b6a4120..a1c41ded756c21074a3f3ba8ac162396c0fb150c 100644
--- a/tests/cassession2_test.php
+++ b/tests/cassession2_test.php
@@ -2493,10 +2493,12 @@ class cassession2_test extends qtype_stack_testcase {
         $s1 = [];
         $t1 = [];
         // Block external commands, such as ordergreat, are pulled out the front.
-        $t1[] = ['f:x*y*z', 'z*y*x'];
-        $t1[] = ['ordergreat(x,y,z)', 'done'];
-        $t1[] = ['g:x*y*z', 'z*y*x'];
-        $t1[] = ['h:exdowncase(X*Y*Z)', 'z*y*x'];
+        // So they apply to the whole session.
+        $t1[] = ['f:x*y*z+a', 'y*z*x+a'];
+        $t1[] = ['ordergreat(x,z,y)', '__s1'];
+        $t1[] = ['g:x*y*z+1', 'y*z*x+1'];
+        $t1[] = ['h:exdowncase(X*Y*Z)', 'y*z*x'];
+        $t1[] = ['k:ev(exdowncase(X*Y*Z),simp)', 'y*z*x'];
         $t1[] = ['ATAlgEquiv(exdowncase(x),x)', '[true,true,"",""]'];
 
         foreach ($t1 as $i => $case) {
@@ -2511,7 +2513,8 @@ class cassession2_test extends qtype_stack_testcase {
         foreach ($s->get_contextvariables() as $i => $v) {
             $a[$i] = $v->get_evaluationform();
         }
-        $this->assertEquals(['(%_C(ordergreat),ordergreat(x,y,z))'], $a);
+        // Note that ordergreat is no longer a context variable.  It's in the preamble.
+        $this->assertEquals([], $a);
 
         foreach ($t1 as $i => $t) {
             $this->assertEquals($t[1], $s1[$i]->get_value());
diff --git a/tests/castext_test.php b/tests/castext_test.php
index db009b1f4897380a8f10b8fdd40e7a2aa46fa040..11f2ab97da009d17ed39d282773942f69eddb085 100644
--- a/tests/castext_test.php
+++ b/tests/castext_test.php
@@ -816,12 +816,13 @@ class castext_test extends qtype_stack_testcase {
         }
         $cs2 = new stack_cas_session2($s2, null, 0);
 
-        $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,2)@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}', '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();
 
-        $this->assertEquals('\({2.72}\), \({4.000}\), \({4.000}\)', $at1->get_rendered());
+        $this->assertEquals('\({2.72}\), \({4.000}\), \({4.000}\), \({3}\), \({1}\)', $at1->get_rendered());
     }
 
     /**
@@ -835,12 +836,14 @@ class castext_test extends qtype_stack_testcase {
         }
         $cs2 = new stack_cas_session2($s2, null, 0);
 
-        $at1 = castext2_evaluatable::make_from_source('{@dispdp(a,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}', '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}\)', $at1->get_rendered());
+        $this->assertEquals('\({3\cdot x^2}\), \({-4.000}\), \({-4.000}\), \({3}\), \({1}\)', 
+            $at1->get_rendered());
     }
 
     /**
@@ -854,7 +857,8 @@ class castext_test extends qtype_stack_testcase {
         }
         $cs2 = new stack_cas_session2($s2, null, 0);
 
-        $at1 = castext2_evaluatable::make_from_source('{@dispdp(a1,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}', 'test-case');
+        $at1 = castext2_evaluatable::make_from_source('{@dispdp(a1,0)*x^2@}, {@dispdp(b,3)@}, {@dispsf(b,4)@}, ' .
+            '{@decimalplaces(a,0)@}, {@decimalplaces(1,2)@}', 'test-case');
         $this->assertTrue($at1->get_valid());
         $cs2->add_statement($at1);
         $cs2->instantiate();
@@ -2025,6 +2029,24 @@ class castext_test extends qtype_stack_testcase {
         $this->assertEquals('\({bigcup_{k = 1}^{\infty } {A}_{k}}\)', $at2->get_rendered());
     }
 
+    /**
+     * @covers \qtype_stack\stack_cas_castext2_latex
+     * @covers \qtype_stack\stack_cas_keyval
+     */
+    public function test_texput_hat() {
+        $vars = 'texput(hat, lambda([ex], sconcat("\\\\hat{", tex1(first(ex)), "}")));';
+        $at1 = new stack_cas_keyval($vars, null, 123);
+        $this->assertTrue($at1->get_valid());
+
+        $cs2 = $at1->get_session();
+        $at2 = castext2_evaluatable::make_from_source('{@1+hat(s)@}', 'test-case');
+        $this->assertTrue($at2->get_valid());
+        $cs2->add_statement($at2);
+        $cs2->instantiate();
+
+        $this->assertEquals('\({\hat{s}+1}\)', $at2->get_rendered());
+    }
+
     /**
      * @covers \qtype_stack\stack_cas_castext2_latex
      * @covers \qtype_stack\stack_cas_keyval
@@ -2332,4 +2354,45 @@ class castext_test extends qtype_stack_testcase {
         $this->assertEquals('Underscore characters are not permitted in this input.',
             $at2->get_rendered());
     }
+
+    /**
+     * @covers \qtype_stack\stack_cas_castext2_latex
+     * @covers \qtype_stack\stack_cas_keyval
+     */
+    public function test_unary_minus_zeros() {
+        $options = new stack_options();
+        $options->set_option('simplify', false);
+        $cs2 = new stack_cas_session2([], $options, 123456);
+
+        $textinput = "{@x-0@}, {@x-0.0@}, {@x*(-0.0)@}, {@-27@}.";
+        $at1 = castext2_evaluatable::make_from_source($textinput, 'test-case');
+        $this->assertTrue($at1->get_valid());
+        $cs2->add_statement($at1);
+        $cs2->instantiate();
+
+        $this->assertEquals('\({x-0}\), \({x-0.0}\), \({x\cdot \left(-0.0\right)}\), \({-27}\).',
+            $at1->get_rendered());
+    }
+
+    /**
+     * @covers \qtype_stack\stack_cas_castext2_latex
+     * @covers \qtype_stack\stack_cas_keyval
+     */
+    public function test_make_mult_sgn_stackunits() {
+        $options = new stack_options();
+        $options->set_option('simplify', false);
+        $cs2 = new stack_cas_session2([], $options, 123456);
+
+        $textinput = '{@stackunits(10,m/s)@}, ' .
+            '{@(texput(multsgnstackunits, "\\\\cdot "), stackunits(1, s^-1))@}, ' .
+            '{@(texput(multsgnstackunits, "\\\\, "), stackunits(1, s^-1))@}. ' .
+            'Multiplication unaffected: {@(texput(multsgnstackunits, "\\\\, "), a*b)@}.';
+        $at1 = castext2_evaluatable::make_from_source($textinput, 'test-case');
+        $this->assertTrue($at1->get_valid());
+        $cs2->add_statement($at1);
+        $cs2->instantiate();
+
+        $this->assertEquals('\({10\, \frac{m}{s}}\), \({1\cdot s^ {- 1 }}\), \({1\, s^ {- 1 }}\). ' .
+            'Multiplication unaffected: \({a\cdot b}\).', $at1->get_rendered());
+    }
 }
diff --git a/tests/fixtures/apifixtures.class.php b/tests/fixtures/apifixtures.class.php
index ed1d53eb39601f7880297145fb2d84f3bc5d093e..3dffd7eae8056ecf396e01428e213ebcc4708b37 100644
--- a/tests/fixtures/apifixtures.class.php
+++ b/tests/fixtures/apifixtures.class.php
@@ -1392,6 +1392,344 @@ class stack_api_test_data {
             </qtest>
           </question>
         </quiz>',
+        'test' => '
+        <quiz>
+          <question type="stack">
+            <name>
+              <text>Algebraic input</text>
+            </name>
+            <questiontext format="html">
+              <text><![CDATA[<p>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p>
+        <p>(Note, this assumes single variable variable names)</p>]]></text>
+            </questiontext>
+            <generalfeedback format="html">
+              <text></text>
+            </generalfeedback>
+            <defaultgrade>1.0000000</defaultgrade>
+            <penalty>0.1000000</penalty>
+            <hidden>0</hidden>
+            <idnumber></idnumber>
+            <stackversion>
+              <text>2020123000</text>
+            </stackversion>
+            <questionvariables>
+              <text>ta:a*b</text>
+            </questionvariables>
+            <specificfeedback format="html">
+              <text>[[feedback:prt1]]</text>
+            </specificfeedback>
+            <questionnote>
+              <text></text>
+            </questionnote>
+            <questionsimplify>1</questionsimplify>
+            <assumepositive>0</assumepositive>
+            <assumereal>0</assumereal>
+            <prtcorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:green;">
+              <i class="fa fa-check"></i></span> Correct answer, well done.]]></text>
+            </prtcorrect>
+            <prtpartiallycorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:orange;">
+              <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text>
+            </prtpartiallycorrect>
+            <prtincorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:red;">
+              <i class="fa fa-times"></i></span> Incorrect answer.]]></text>
+            </prtincorrect>
+            <multiplicationsign>dot</multiplicationsign>
+            <sqrtsign>1</sqrtsign>
+            <complexno>i</complexno>
+            <inversetrig>cos-1</inversetrig>
+            <logicsymbol>lang</logicsymbol>
+            <matrixparens>[</matrixparens>
+            <variantsselectionseed></variantsselectionseed>
+            <input>
+              <name>ans1</name>
+              <type>algebraic</type>
+              <tans>ta</tans>
+              <boxsize>15</boxsize>
+              <strictsyntax>1</strictsyntax>
+              <insertstars>2</insertstars>
+              <syntaxhint></syntaxhint>
+              <syntaxattribute>0</syntaxattribute>
+              <forbidwords>solve</forbidwords>
+              <allowwords></allowwords>
+              <forbidfloat>1</forbidfloat>
+              <requirelowestterms>0</requirelowestterms>
+              <checkanswertype>1</checkanswertype>
+              <mustverify>1</mustverify>
+              <showvalidation>1</showvalidation>
+              <options></options>
+            </input>
+            <prt>
+              <name>prt1</name>
+              <value>1.0000000</value>
+              <autosimplify>1</autosimplify>
+              <feedbackstyle>1</feedbackstyle>
+              <feedbackvariables>
+                <text></text>
+              </feedbackvariables>
+              <node>
+                <name>0</name>
+                <answertest>AlgEquiv</answertest>
+                <sans>ans1</sans>
+                <tans>ta</tans>
+                <testoptions></testoptions>
+                <quiet>0</quiet>
+                <truescoremode>=</truescoremode>
+                <truescore>1.0000000</truescore>
+                <truepenalty></truepenalty>
+                <truenextnode>-1</truenextnode>
+                <trueanswernote>prt1-1-T</trueanswernote>
+                <truefeedback format="html">
+                  <text></text>
+                </truefeedback>
+                <falsescoremode>=</falsescoremode>
+                <falsescore>0.0000000</falsescore>
+                <falsepenalty></falsepenalty>
+                <falsenextnode>-1</falsenextnode>
+                <falseanswernote>prt1-1-F</falseanswernote>
+                <falsefeedback format="html">
+                  <text></text>
+                </falsefeedback>
+              </node>
+            </prt>
+            <qtest>
+              <testcase>1</testcase>
+              <testinput>
+                <name>ans1</name>
+                <value>37</value>
+              </testinput>
+              <expected>
+                <name>prt1</name>
+                <expectedscore>1.0000000</expectedscore>
+                <expectedpenalty>0.0000000</expectedpenalty>
+                <expectedanswernote>prt1-1-T</expectedanswernote>
+              </expected>
+            </qtest>
+            <qtest>
+              <testcase>2</testcase>
+              <testinput>
+                <name>ans1</name>
+                <value></value>
+              </testinput>
+              <expected>
+                <name>prt1</name>
+                <expectedscore>1.0000000</expectedscore>
+                <expectedpenalty>0.0000000</expectedpenalty>
+                <expectedanswernote>NULL</expectedanswernote>
+              </expected>
+            </qtest>
+          </question>
+        </quiz>',
+        'test2' => '
+        <quiz>
+          <question type="stack">
+            <name>
+              <text>Algebraic input</text>
+            </name>
+            <questiontext format="html">
+              <text><![CDATA[<p><img src="test.png"></img>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p>
+        <p>(Note, this assumes single variable variable names)</p>]]></text>
+            </questiontext>
+            <generalfeedback format="html">
+              <text></text>
+            </generalfeedback>
+            <defaultgrade>1.0000000</defaultgrade>
+            <penalty>0.1000000</penalty>
+            <hidden>0</hidden>
+            <idnumber></idnumber>
+            <stackversion>
+              <text>2020123000</text>
+            </stackversion>
+            <questionvariables>
+              <text>ta:a*b</text>
+            </questionvariables>
+            <specificfeedback format="html">
+              <text>[[feedback:prt1]]</text>
+            </specificfeedback>
+            <questionnote>
+              <text></text>
+            </questionnote>
+            <questionsimplify>1</questionsimplify>
+            <assumepositive>0</assumepositive>
+            <assumereal>0</assumereal>
+            <prtcorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:green;">
+              <i class="fa fa-check"></i></span> Correct answer, well done.]]></text>
+            </prtcorrect>
+            <prtpartiallycorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:orange;">
+              <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text>
+            </prtpartiallycorrect>
+            <prtincorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:red;">
+              <i class="fa fa-times"></i></span> Incorrect answer.]]></text>
+            </prtincorrect>
+            <multiplicationsign>dot</multiplicationsign>
+            <sqrtsign>1</sqrtsign>
+            <complexno>i</complexno>
+            <inversetrig>cos-1</inversetrig>
+            <logicsymbol>lang</logicsymbol>
+            <matrixparens>[</matrixparens>
+            <variantsselectionseed></variantsselectionseed>
+            <input>
+              <name>ans1</name>
+              <type>algebraic</type>
+              <tans>ta</tans>
+              <boxsize>15</boxsize>
+              <strictsyntax>1</strictsyntax>
+              <insertstars>2</insertstars>
+              <syntaxhint></syntaxhint>
+              <syntaxattribute>0</syntaxattribute>
+              <forbidwords>solve</forbidwords>
+              <allowwords></allowwords>
+              <forbidfloat>1</forbidfloat>
+              <requirelowestterms>0</requirelowestterms>
+              <checkanswertype>1</checkanswertype>
+              <mustverify>1</mustverify>
+              <showvalidation>1</showvalidation>
+              <options></options>
+            </input>
+            <prt>
+              <name>prt1</name>
+              <value>1.0000000</value>
+              <autosimplify>1</autosimplify>
+              <feedbackstyle>1</feedbackstyle>
+              <feedbackvariables>
+                <text></text>
+              </feedbackvariables>
+              <node>
+                <name>0</name>
+                <answertest>AlgEquiv</answertest>
+                <sans>ans1</sans>
+                <tans>ta</tans>
+                <testoptions></testoptions>
+                <quiet>0</quiet>
+                <truescoremode>=</truescoremode>
+                <truescore>1.0000000</truescore>
+                <truepenalty></truepenalty>
+                <truenextnode>-1</truenextnode>
+                <trueanswernote>prt1-1-T</trueanswernote>
+                <truefeedback format="html">
+                  <text></text>
+                </truefeedback>
+                <falsescoremode>=</falsescoremode>
+                <falsescore>0.0000000</falsescore>
+                <falsepenalty></falsepenalty>
+                <falsenextnode>-1</falsenextnode>
+                <falseanswernote>prt1-1-F</falseanswernote>
+                <falsefeedback format="html">
+                  <text></text>
+                </falsefeedback>
+              </node>
+            </prt>
+          </question>
+        </quiz>',
+        'test3' => '
+        <quiz>
+          <question type="stack">
+            <name>
+              <text>Algebraic input</text>
+            </name>
+            <questiontext format="html">
+              <text><![CDATA[<p>Type in {@ta@}.</p><p>[[input:ans1]] [[validation:ans1]]</p>
+        <p>(Note, this assumes single variable variable names)</p>]]></text>
+            </questiontext>
+            <generalfeedback format="html">
+              <text></text>
+            </generalfeedback>
+            <defaultgrade>1.0000000</defaultgrade>
+            <penalty>0.1000000</penalty>
+            <hidden>0</hidden>
+            <idnumber></idnumber>
+            <stackversion>
+              <text>2020123000</text>
+            </stackversion>
+            <questionvariables>
+              <text>ta:a*b</text>
+            </questionvariables>
+            <specificfeedback format="html">
+              <text>[[feedback:prt1]]</text>
+            </specificfeedback>
+            <questionnote>
+              <text></text>
+            </questionnote>
+            <questionsimplify>1</questionsimplify>
+            <assumepositive>0</assumepositive>
+            <assumereal>0</assumereal>
+            <prtcorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:green;">
+              <i class="fa fa-check"></i></span> Correct answer, well done.]]></text>
+            </prtcorrect>
+            <prtpartiallycorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:orange;">
+              <i class="fa fa-adjust"></i></span> Your answer is partially correct.]]></text>
+            </prtpartiallycorrect>
+            <prtincorrect format="html">
+              <text><![CDATA[<span style="font-size: 1.5em; color:red;">
+              <i class="fa fa-times"></i></span> Incorrect answer.]]></text>
+            </prtincorrect>
+            <multiplicationsign>dot</multiplicationsign>
+            <sqrtsign>1</sqrtsign>
+            <complexno>i</complexno>
+            <inversetrig>cos-1</inversetrig>
+            <logicsymbol>lang</logicsymbol>
+            <matrixparens>[</matrixparens>
+            <variantsselectionseed></variantsselectionseed>
+            <input>
+              <name>ans1</name>
+              <type>algebraic</type>
+              <tans>ta</tans>
+              <boxsize>15</boxsize>
+              <strictsyntax>1</strictsyntax>
+              <insertstars>2</insertstars>
+              <syntaxhint></syntaxhint>
+              <syntaxattribute>0</syntaxattribute>
+              <forbidwords>solve</forbidwords>
+              <allowwords></allowwords>
+              <forbidfloat>1</forbidfloat>
+              <requirelowestterms>0</requirelowestterms>
+              <checkanswertype>1</checkanswertype>
+              <mustverify>1</mustverify>
+              <showvalidation>1</showvalidation>
+              <options></options>
+            </input>
+            <prt>
+              <name>prt1</name>
+              <value>1.0000000</value>
+              <autosimplify>1</autosimplify>
+              <feedbackstyle>1</feedbackstyle>
+              <feedbackvariables>
+                <text></text>
+              </feedbackvariables>
+              <node>
+                <name>0</name>
+                <answertest>AlgEquiv</answertest>
+                <sans>ans1</sans>
+                <tans>wrong</tans>
+                <testoptions></testoptions>
+                <quiet>0</quiet>
+                <truescoremode>=</truescoremode>
+                <truescore>1.0000000</truescore>
+                <truepenalty></truepenalty>
+                <truenextnode>-1</truenextnode>
+                <trueanswernote>prt1-1-T</trueanswernote>
+                <truefeedback format="html">
+                  <text></text>
+                </truefeedback>
+                <falsescoremode>=</falsescoremode>
+                <falsescore>0.0000000</falsescore>
+                <falsepenalty></falsepenalty>
+                <falsenextnode>-1</falsenextnode>
+                <falseanswernote>prt1-1-F</falseanswernote>
+                <falsefeedback format="html">
+                  <text></text>
+                </falsefeedback>
+              </node>
+            </prt>
+          </question>
+        </quiz>',
     ];
 
     protected static array $answers = [
diff --git a/tests/fixtures/inputfixtures.class.php b/tests/fixtures/inputfixtures.class.php
index 56e1c41b9c9db43942ce3a89752b23a3a9c8dc0e..49aafc5f4acdfabaccdf8467309fab170c359886 100644
--- a/tests/fixtures/inputfixtures.class.php
+++ b/tests/fixtures/inputfixtures.class.php
@@ -666,7 +666,7 @@ class stack_inputvalidation_test_data {
         ['\sqrt{2+x}', 'php_false', '\sqrt{2+x}', 'cas_false', '', 'illegalcaschars', "Student uses LaTeX"],
         [
             'sin(x),cos(y)', 'php_false', 'sin(x),cos(y)', 'cas_true', '',
-            'unencapsulated_comma', "",
+            'ParseError', "",
         ],
         ['sum(k^n,n,0,3)', 'php_true', 'sum(k^n,n,0,3)', 'cas_true', '\sum_{n=0}^{3}{k^{n}}', '', "Sums and products"],
         [
diff --git a/tests/helper.php b/tests/helper.php
index b0f83073849d3fca6ae4f6ff99b878a77f4700d5..34c780e9f07957220b4e68128fb54a4724661bc0 100644
--- a/tests/helper.php
+++ b/tests/helper.php
@@ -72,6 +72,7 @@ class qtype_stack_test_helper extends question_test_helper {
             'block_locals',       // Make sure local variables within a block are still permitted student input.
             'validator',          // Test teacher-defined input validators and language.
             'feedback',           // Test teacher-defined input feedback and complex numbers.
+            'ordergreat',         // Test the ordergreat function at the question level, e.g. keyvals.
             // Test questions for all the various input types.
             'algebraic_input',
             'algebraic_input_right',
@@ -3536,7 +3537,10 @@ class qtype_stack_test_helper extends question_test_helper {
 
         $q->stackversion = '2020112300';
         $q->name = 'contextvars';
-        $q->questionvariables = "texput(blob, \"\\\\diamond\");\n assume(x>2);\n texput(log, \"\\\\log \", prefix);";
+        $q->questionvariables = "tuptex(z):= block([a,b], [a,b]:args(z), " .
+            "sconcat(\"\\\\left[\",tex1(a),\",\",tex1(b),\"\\\\right)\"));texput(tup, tuptex);" .
+            "vec(ex):=stackvector(ex);%_stack_preamble_end;" .
+            "texput(blob, \"\\\\diamond\");\n assume(x>2);\n texput(log, \"\\\\log \", prefix);";
         $q->questiontext = 'What is {@blob@}? [[input:ans1]] [[validation:ans1]]';
         $q->generalfeedback = 'You should be able to type in {@blob@} as <code>blob</code>.';
 
@@ -3544,7 +3548,7 @@ class qtype_stack_test_helper extends question_test_helper {
         $q->penalty = 0.35; // Non-zero and not the default.
 
         $q->inputs['ans1'] = stack_input_factory::make(
-                'algebraic', 'ans1', 'blob', null, ['boxWidth' => 5, 'allowWords' => 'blob']);
+                'algebraic', 'ans1', 'blob', null, ['boxWidth' => 5, 'allowWords' => 'blob,vec,tup']);
 
         $q->options->set_option('simplify', true);
 
@@ -4026,6 +4030,72 @@ class qtype_stack_test_helper extends question_test_helper {
             return $q;
     }
 
+    /**
+     * @return qtype_stack_question.
+     */
+    public static function make_stack_question_ordergreat() {
+        $q = self::make_a_stack_question();
+
+        $q->name = 'ordergreat';
+        $q->questionvariables = "ordergreat(x,y);\nta:5*y+3*x=1";
+        $q->questiontext = "What is {@ta@}? [[input:ansq]][[validation:ansq]]" .
+                // Below checks this is still a real float.
+                '{@dispdp(float(pi),4)@}';
+        $q->generalfeedback = '';
+        $q->questionnote = '';
+
+        $q->specificfeedback = '[[feedback:firsttree]]';
+        $q->penalty = 0.25; // Non-zero and not the default.
+
+        $q->inputs['ansq'] = stack_input_factory::make(
+            'algebraic', 'ansq', 'ta', null,
+            [
+                'boxWidth' => 20, 'forbidWords' => ''
+            ]);
+
+        // By setting simp:true (the default) we check the re-ordering really happens.
+        $q->options->set_option('simplify', true);
+
+        $prt = new stdClass;
+        $prt->name              = 'firsttree';
+        $prt->id                = 0;
+        $prt->value             = 1;
+        $prt->feedbackstyle     = 1;
+        $prt->feedbackvariables = '';
+        $prt->firstnodename     = '0';
+        $prt->nodes             = [];
+        $prt->autosimplify      = false;
+
+        $newnode = new stdClass;
+        $newnode->id                  = '0';
+        $newnode->nodename            = '0';
+        $newnode->description         = '';
+        $newnode->sans                = 'ansq';
+        $newnode->tans                = 'ta';
+        $newnode->answertest          = 'CasEqual';
+        $newnode->testoptions         = '';
+        $newnode->quiet               = false;
+        $newnode->falsescore          = '0';
+        $newnode->falsescoremode      = '=';
+        $newnode->falsepenalty        = $q->penalty;
+        $newnode->falsefeedback       = "";
+        $newnode->falsefeedbackformat = '1';
+        $newnode->falseanswernote     = 'firsttree-0-0';
+        $newnode->falsenextnode       = '-1';
+        $newnode->truescore           = '1';
+        $newnode->truescoremode       = '=';
+        $newnode->truepenalty         = $q->penalty;
+        $newnode->truefeedback        = "";
+        $newnode->truefeedbackformat  = '1';
+        $newnode->trueanswernote      = 'firsttree-0-1';
+        $newnode->truenextnode        = '-1';
+        $prt->nodes[] = $newnode;
+
+        $q->prts[$prt->name] = new stack_potentialresponse_tree_lite($prt, $prt->value, $q);
+
+        return $q;
+    }
+
     /**
      * 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 b4564f251b947cf802747ffcbf0de304d519f2fb..2a1bb3280f98196cfb14639f2a362be15934c2ad 100644
--- a/tests/input_algebraic_test.php
+++ b/tests/input_algebraic_test.php
@@ -344,6 +344,30 @@ class input_algebraic_test extends qtype_stack_testcase {
         $this->assertEquals('Lowest_Terms', $state->note);
     }
 
+    public function test_validate_student_response_with_minus_zero() {
+        $options = new stack_options();
+        $el = stack_input_factory::make('algebraic', 'sans1', '1/2');
+        $el->set_parameter('forbidFloats', false);
+
+        $state = $el->validate_student_response(['sans1' => "x-0"], $options, '3.14', new stack_cas_security());
+        $this->assertEquals(stack_input::VALID, $state->status);
+        $this->assertEquals('x-0', $state->contentsmodified);
+        $this->assertEquals('\[ x-0 \]', $state->contentsdisplayed);
+        $this->assertEquals('', $state->errors);
+
+        $state = $el->validate_student_response(['sans1' => "x-0.0"], $options, '3.14', new stack_cas_security());
+        $this->assertEquals(stack_input::VALID, $state->status);
+        $this->assertEquals('x-0.0', $state->contentsmodified);
+        $this->assertEquals('\[ x-0.0 \]', $state->contentsdisplayed);
+        $this->assertEquals('', $state->errors);
+
+        $state = $el->validate_student_response(['sans1' => "x*(-0.0)"], $options, '3.14', new stack_cas_security());
+        $this->assertEquals(stack_input::VALID, $state->status);
+        $this->assertEquals('x*(-0.0)', $state->contentsmodified);
+        $this->assertEquals('\[ x\cdot \left(-0.0\right) \]', $state->contentsdisplayed);
+        $this->assertEquals('', $state->errors);
+    }
+
     public function test_validate_student_response_with_rationalized() {
         $options = new stack_options();
         $el = stack_input_factory::make('algebraic', 'sans1', '1/2');
@@ -1613,7 +1637,7 @@ class input_algebraic_test extends qtype_stack_testcase {
                 new stack_cas_security(false, '', '', ['ta']));
         $this->assertEquals($state->status, stack_input::INVALID);
         $this->assertEquals('illegalcaschars', $state->note);
-        $this->assertEquals('The characters @, $ and \ are not allowed in CAS input.', $state->errors);
+        $this->assertEquals('The characters @ and \ are not allowed in CAS input.', $state->errors);
         $this->assertEquals($state->contentsmodified, '');
         // This appears to the student to display correctly, since the TeX is picked up by MathJax.
         $this->assertEquals($state->contentsdisplayed,
diff --git a/tests/walkthrough_adaptive_test.php b/tests/walkthrough_adaptive_test.php
index 57a9158886b734c3bd0d65a331dde2c9546c1a6c..f9663e83bc039ca6765af452db5a9491b09fd67b 100644
--- a/tests/walkthrough_adaptive_test.php
+++ b/tests/walkthrough_adaptive_test.php
@@ -432,7 +432,6 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         // @codingStandardsIgnoreEnd
 
         // Now use the correct answer.
-
         $ta = $q->get_correct_response();
         $sa = $ta['ans1'];
         $this->process_submission(['ans1' => $sa, '-submit' => 1]);
@@ -1312,7 +1311,6 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         $this->check_current_output(
                 new question_no_pattern_expectation('/Your answer is partially correct./')
         );
-
     }
 
     public function test_test3_save_invalid_response_correct_then_stubmit() {
@@ -4026,9 +4024,36 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
                 $this->get_no_hint_visible_expectation()
                 );
 
+        // Process a validate request with a texput function.
+        $this->process_submission(['ans1' => 'vec(x)', '-submit' => 1]);
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+        $this->check_output_contains_text_input('ans1', 'vec(x)');
+        $this->check_output_contains_input_validation('ans1');
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->assert_content_with_maths_contains('\[ {\bf x} \]', $this->currentoutput);
+        $expected = 'Seed: 1; ans1: vec(x) [valid]; firsttree: !';
+        $this->check_response_summary($expected);
+
+        // Process a validate request with a texput function.
+        $this->process_submission(['ans1' => 'tup(3,4)', '-submit' => 1]);
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+        $this->check_output_contains_text_input('ans1', 'tup(3,4)');
+        $this->check_output_contains_input_validation('ans1');
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->assert_content_with_maths_contains('\[ \left[3,4\right) \]', $this->currentoutput);
+        $expected = 'Seed: 1; ans1: tup(3,4) [valid]; firsttree: !';
+        $this->check_response_summary($expected);
+
         // Process a validate request.
         $this->process_submission(['ans1' => 'log(blob)', '-submit' => 1]);
-
         $this->check_current_state(question_state::$todo);
         $this->check_current_mark(null);
         $this->check_prt_score('firsttree', null, null);
@@ -4037,6 +4062,9 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         $this->check_output_contains_input_validation('ans1');
         $this->check_output_does_not_contain_prt_feedback();
         $this->check_output_does_not_contain_stray_placeholders();
+        $this->assert_content_with_maths_contains('\[ \log \left( \diamond \right) \]', $this->currentoutput);
+        $expected = 'Seed: 1; ans1: log(blob) [valid]; firsttree: !';
+        $this->check_response_summary($expected);
 
         // Process a submition of an incorrect answer.
         $this->process_submission(['ans1' => 'log(blob)', 'ans1_val' => 'log(blob)', '-submit' => 1]);
@@ -4044,6 +4072,9 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         $this->check_current_mark(0);
         $this->check_prt_score('firsttree', 0, 0.35);
         $this->check_answer_note('firsttree', 'firsttree-1-F | firsttree-2-F');
+        $this->assert_content_with_maths_contains('\[ \log \left( \diamond \right) \]', $this->currentoutput);
+        $expected = 'Seed: 1; ans1: log(blob) [score]; firsttree: # = 0 | firsttree-1-F | firsttree-2-F';
+        $this->check_response_summary($expected);
 
         // Process the correct answer.  Needs the assumption x>2 for ATAlgEquiv to correctly work.
         $this->process_submission(['ans1' => '6*((x-2)^2)^k', '-submit' => 1]);
@@ -4723,4 +4754,68 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         // This vaidation output is the result of a texput command with a lambda function.
         $this->assert_content_with_maths_contains('\\frac{x}{y}', $this->currentoutput);
     }
+
+    public function test_input_validator_ordergreat() {
+        $q = test_question_maker::make_question('stack', 'ordergreat');
+        $this->start_attempt_at_question($q, 'adaptive', 1);
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+        $this->check_output_contains_text_input('ansq');
+        $this->check_output_does_not_contain_input_validation();
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->check_current_output(
+            new question_pattern_expectation('/What is/'),
+            $this->get_does_not_contain_feedback_expectation(),
+            $this->get_does_not_contain_num_parts_correct(),
+            $this->get_no_hint_visible_expectation()
+            );
+        $this->assert_content_with_maths_contains('\({3\cdot x+5\cdot y=1}\)', $this->currentoutput);
+
+        // Process a validate request.
+        $ia = '7*y+3*x=1';
+        $this->process_submission(['ansq' => $ia, '-submit' => 1]);
+
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+
+        // Check order of variables in validation of answer matches what students type.
+        $expected = 'Seed: 1; ansq: 7*y+3*x=1 [valid]; firsttree: !';
+        $this->check_response_summary($expected);
+        $this->check_output_contains_text_input('ansq', $ia);
+        $this->check_output_contains_input_validation('ansq');
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->assert_content_with_maths_contains('\[ 7\cdot y+3\cdot x=1', $this->currentoutput);
+        // Checks {@pi@} is the value of the constant.
+        $this->assert_content_with_maths_contains('\({3.1416}\)', $this->currentoutput);
+
+        // Jump to score requests for different answers.
+        $ia = '7*y+3*x=1';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 7\cdot y+3\cdot x=1', $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 7*y+3*x=1 [score]; firsttree: # = 0 | ATCASEqual_false. | firsttree-0-0';
+        $this->check_response_summary($expected);
+
+        $ia = '5*y+3*x=1';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 5\cdot y+3\cdot x=1', $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 5*y+3*x=1 [score]; firsttree: # = 0 | ATCASEqual (AlgEquiv-true)ATEquation_sides.' .
+            '| firsttree-0-0';
+        $this->check_response_summary($expected);
+
+        $ia = '3*x+5*y=1';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 3\cdot x+5\cdot y=1', $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 3*x+5*y=1 [score]; firsttree: # = 1 | ATCASEqual_true. | firsttree-0-1';
+        $this->check_response_summary($expected);
+    }
 }
diff --git a/vle_specific.php b/vle_specific.php
index fbd4e7ff261399e0bafa532b78044a6017d579c5..d62e8172170c4e15db9a25b0747d2729a9bd7f47 100644
--- a/vle_specific.php
+++ b/vle_specific.php
@@ -204,7 +204,7 @@ function stack_get_mathjax_url(): string {
             $urlstring = substr($mathjaxconfigurl, 0, $questionpos);
             parse_str($querystring, $queryparams);
             $queryparams = array_merge(['config' => 'TeX-AMS-MML_HTMLorMML'], $queryparams);
-            $querystring = http_build_query($queryparams, null, '&', PHP_QUERY_RFC3986);
+            $querystring = http_build_query($queryparams, '', '&', PHP_QUERY_RFC3986);
             $url = $urlstring . '?' . $querystring;
         } else {
             $url = $mathjaxconfigurl . '?config=TeX-AMS-MML_HTMLorMML';